19 Commits
Author SHA1 Message Date
FlorianMichael b34cc42a65 4.0.0 Release 2024-06-16 18:10:25 +02:00
FlorianMichael 7b1f0a8737 Rename build-logic submodule 2024-06-15 21:14:47 +02:00
FlorianMichael a171e4013b Only accept correct byte type in custom payload 1.8->1.7 2024-06-11 15:38:34 +02:00
FlorianMichael 3e3561c18f Update VV API usage 2024-06-11 15:36:03 +02:00
FlorianMichael 0097a97ab0 Add note for J8 builds 2024-06-06 05:20:24 +02:00
FlorianMichael 6e583a0c8e Remove missing bungee/sponge references 2024-06-06 05:11:00 +02:00
FlorianMichael 780b981c68 Fixup hologram handling 1.8->1.7
Closes https://github.com/ViaVersion/ViaRewind/issues/509
2024-06-06 05:07:47 +02:00
FlorianMichael 5df933f0e2 Fix 1.7->1.8 player action rewriting 2024-06-03 03:02:45 +02:00
FlorianMichael 750a98cb06 Fixup position reading 2024-06-02 17:50:56 +02:00
FlorianMichael 1ebfa0a715 Update Gradle Wrapper 2024-06-01 17:41:58 +02:00
Nassim Jahnke dc82de8ba2 Move Sponge and Bungee modules to separate plugins 2024-05-30 22:45:53 +02:00
Nassim Jahnke 9ecdaa30bf Use unsigned byte for facing direction in player action 2024-05-30 11:33:49 +02:00
FlorianMichael ee69005318 Delete temporary fix for shulker box window titles
Properly fixed by https://github.com/ViaVersion/ViaBackwards/pull/761
2024-05-28 18:11:08 +02:00
FlorianMichael 740a6d9b96 Finish up v5 migration
Also:
- Reduces the amount of anonymous classes
- Removes usages of PacketWrapper#create with raw ids
2024-05-22 23:36:51 +02:00
Nassim Jahnke b1d680468b Update VV API usage 2024-05-22 12:11:11 +02:00
FlorianMichael 64c18af7b6 Update Via API usage 2024-05-18 21:33:21 +02:00
FlorianMichael 6728a8a809 Port to upstream changes (hopefully) 2024-05-15 00:08:22 +02:00
FlorianMichael 0cb70b0a04 Rename protocol packages and classes 2024-05-11 15:18:21 +02:00
FlorianMichael 2f7f108cd8 Bump version to 4.0.0-SNAPSHOT 2024-05-11 15:12:41 +02:00
107 changed files with 4638 additions and 5111 deletions

No files matched your search

+3 -3
View File
@@ -71,9 +71,9 @@ body:
attributes:
label: Additional Server Info
description: |
Do you use a proxy (eg. BungeeCord)? What software do you use and what plugins?
Do you use a proxy (eg. Velocity)? What software do you use and what plugins?
placeholder: |
Example: "I also use BungeeCord with the following plugins: x, y, z"
Example: "I also use Velocity with the following plugins: x, y, z"
validations:
required: false
@@ -82,7 +82,7 @@ body:
label: Checklist
description: Make sure you have followed each of the steps outlined here.
options:
- label: Via plugins are only running on **EITHER** the backend servers (e.g. Paper) **OR** the proxy (e.g. BungeeCord), **not on both**.
- label: Via plugins are only running on **EITHER** the backend servers (e.g. Paper) **OR** the proxy (e.g. Velocity), **not on both**.
required: true
- label: I have included a ViaVersion dump.
required: true
+4
View File
@@ -10,6 +10,8 @@ Runs on 1.9-latest servers or 1.8 clients and lower.
- in **ViaFabric**, put ViaRewind into the `mods` folder
- in **ViaProxy**, put ViaRewind into the `jars` folder
Note: when using ViaFabric <= 1.16.5 or J8 ViaProxy builds, you need [J8 ViaRewind](https://ci.viaversion.com/view/ViaRewind/job/ViaRewind-Java8/) builds.
**Requires [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion) and [ViaBackwards](https://hangar.papermc.io/ViaVersion/ViaBackwards) to be installed..**
Releases/Dev Builds
@@ -37,6 +39,8 @@ Building
After cloning this repository, build the project with Gradle by running `./gradlew build` and take the created jar out
of the `universal/build/libs` directory.
You need JDK 17 or newer to build ViaRewind.
License
-
This project is licensed under the [GNU General Public License Version 3](LICENSE).
File renamed without changes.
@@ -7,27 +7,21 @@ repositories {
maven {
url = uri("https://repo.viaversion.com")
}
maven {
url = uri("https://repo.maven.apache.org/maven2/")
}
maven {
url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
}
maven {
url = uri("https://oss.sonatype.org/content/repositories/snapshots")
}
maven {
url = uri("https://maven.fabricmc.net/")
}
maven {
url = uri("https://repo.spongepowered.org/repository/maven-public/")
}
maven {
url = uri("https://nexus.velocitypowered.com/repository/maven-public/")
}
@@ -47,12 +41,12 @@ base {
description = "ViaBackwards addon to allow 1.8.x and 1.7.x clients on newer server versions."
}
java.sourceCompatibility = JavaVersion.VERSION_1_8
java.sourceCompatibility = JavaVersion.VERSION_17
tasks {
// Variable replacements
processResources {
for (final def file in ["plugin.yml", "bungee.yml", "META-INF/sponge_plugins.json", "fabric.mod.json"]) {
for (final def file in ["plugin.yml", "fabric.mod.json"]) {
filesMatching(file) {
expand(
"version": project.version,
-9
View File
@@ -1,9 +0,0 @@
plugins {
id "com.viaversion.java-conventions"
}
dependencies {
api project(":viarewind-common")
compileOnly(annotationProcessor("net.md-5:bungeecord-api:1.19-R0.1-SNAPSHOT"))
}
-1
View File
@@ -1 +0,0 @@
maven_name=viarewind-bungee
@@ -1,32 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind;
import com.viaversion.viarewind.api.ViaRewindPlatform;
import com.viaversion.viaversion.api.Via;
import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
public class BungeePlugin extends Plugin implements ViaRewindPlatform {
@Override
public void onLoad() {
Via.getManager().addEnableListener(() -> this.init(new File(getDataFolder(), "config.yml")));
}
}
-6
View File
@@ -1,6 +0,0 @@
name: ViaRewind
main: com.viaversion.viarewind.BungeePlugin
authors: [FlorianMichael/EnZaXD, Gerrygames, creeper123321123]
version: ${version}
depends: [ViaVersion, ViaBackwards]
website: https://viaversion.com/rewind
@@ -25,6 +25,7 @@ import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
public class ViaRewindConfig extends Config implements com.viaversion.viarewind.api.ViaRewindConfig {
@@ -39,8 +40,8 @@ public class ViaRewindConfig extends Config implements com.viaversion.viarewind.
private boolean enableOffhand;
private String offhandCommand;
public ViaRewindConfig(File configFile) {
super(configFile);
public ViaRewindConfig(File configFile, Logger logger) {
super(configFile, logger);
}
@Override
@@ -19,9 +19,9 @@ package com.viaversion.viarewind.api;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.ViaRewindConfig;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.Protocol1_7_2_5To1_7_6_10;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.Protocol1_7_6_10To1_7_2_5;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.Protocol1_8To1_7_6_10;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.ProtocolManager;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
@@ -41,7 +41,7 @@ public interface ViaRewindPlatform {
* Initialize ViaRewind
*/
default void init(final File configFile) {
ViaRewindConfig config = new ViaRewindConfig(configFile);
ViaRewindConfig config = new ViaRewindConfig(configFile, getLogger());
config.reload();
Via.getManager().getConfigurationProvider().register(config);
@@ -51,10 +51,10 @@ public interface ViaRewindPlatform {
getLogger().info("Registering protocols...");
final ProtocolManager protocolManager = Via.getManager().getProtocolManager();
protocolManager.registerProtocol(new Protocol1_7_2_5To1_7_6_10(), ProtocolVersion.v1_7_2, ProtocolVersion.v1_7_6);
protocolManager.registerProtocol(new Protocol1_7_6_10To1_8(), ProtocolVersion.v1_7_6, ProtocolVersion.v1_8);
protocolManager.registerProtocol(new Protocol1_7_6_10To1_7_2_5(), ProtocolVersion.v1_7_2, ProtocolVersion.v1_7_6);
protocolManager.registerProtocol(new Protocol1_8To1_7_6_10(), ProtocolVersion.v1_7_6, ProtocolVersion.v1_8);
protocolManager.registerProtocol(new Protocol1_8To1_9(), ProtocolVersion.v1_8, ProtocolVersion.v1_9);
protocolManager.registerProtocol(new Protocol1_9To1_8(), ProtocolVersion.v1_8, ProtocolVersion.v1_9);
}
/**
@@ -17,15 +17,15 @@
*/
package com.viaversion.viarewind.api.data;
import com.viaversion.viabackwards.api.data.BackwardsMappings;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.nbt.tag.CompoundTag;
import java.util.logging.Logger;
public class RewindMappings extends BackwardsMappings {
public class RewindMappingData extends BackwardsMappingData {
public RewindMappings(String unmappedVersion, String mappedVersion) {
public RewindMappingData(String unmappedVersion, String mappedVersion) {
super(unmappedVersion, mappedVersion);
}
@@ -36,6 +36,6 @@ public class RewindMappings extends BackwardsMappings {
@Override
protected CompoundTag readMappingsFile(String name) {
return VRMappingDataLoader.INSTANCE.loadNBTFromDir(name);
return RewindMappingDataLoader.INSTANCE.loadNBTFromDir(name);
}
}
@@ -23,12 +23,12 @@ import com.viaversion.viarewind.ViaRewind;
import java.io.File;
import java.util.logging.Logger;
public class VRMappingDataLoader extends BackwardsMappingDataLoader {
public class RewindMappingDataLoader extends BackwardsMappingDataLoader {
public static final VRMappingDataLoader INSTANCE = new VRMappingDataLoader();
public static final RewindMappingDataLoader INSTANCE = new RewindMappingDataLoader();
public VRMappingDataLoader() {
super(VRMappingDataLoader.class, "assets/viarewind/data/");
public RewindMappingDataLoader() {
super(RewindMappingDataLoader.class, "assets/viarewind/data/");
}
@@ -15,7 +15,7 @@
* 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.utils;
package com.viaversion.viarewind.api.minecraft;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.NibbleArray;
@@ -15,30 +15,31 @@
* 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.metadata;
package com.viaversion.viarewind.api.minecraft.entitydata;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
public enum MetaType1_7_6_10 implements MetaType {
Byte(0, Type.BYTE),
Short(1, Type.SHORT),
Int(2, Type.INT),
Float(3, Type.FLOAT),
String(4, Type.STRING),
Slot(5, Types1_7_6_10.COMPRESSED_NBT_ITEM),
Position(6, Type.VECTOR);
public enum EntityDataTypes1_7_6_10 implements EntityDataType {
BYTE(0, Types.BYTE),
SHORT(1, Types.SHORT),
INT(2, Types.INT),
FLOAT(3, Types.FLOAT),
STRING(4, Types.STRING),
ITEM(5, RewindTypes.COMPRESSED_NBT_ITEM),
POSITION(6, Types.VECTOR);
private final int typeID;
private final Type<?> type;
MetaType1_7_6_10(int typeID, Type<?> type) {
EntityDataTypes1_7_6_10(int typeID, Type<?> type) {
this.typeID = typeID;
this.type = type;
}
public static MetaType1_7_6_10 byId(int id) {
public static EntityDataTypes1_7_6_10 byId(int id) {
return values()[id];
}
@@ -15,7 +15,7 @@
* 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.utils.math;
package com.viaversion.viarewind.api.minecraft.math;
public class AABB {
Vector3d min;
@@ -15,7 +15,7 @@
* 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.utils.math;
package com.viaversion.viarewind.api.minecraft.math;
public class Ray3d {
Vector3d start;
@@ -15,7 +15,7 @@
* 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.utils.math;
package com.viaversion.viarewind.api.minecraft.math;
public class RayTracing {
@@ -15,10 +15,10 @@
* 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.utils.math;
package com.viaversion.viarewind.api.minecraft.math;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.EntityTracker1_9;
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;
@@ -26,7 +26,7 @@ import com.viaversion.viaversion.api.minecraft.Vector;
public class RelativeMoveUtil {
public static Vector[] calculateRelativeMoves(UserConnection user, int entityId, int relX, int relY, int relZ) {
EntityTracker1_9 tracker = user.getEntityTracker(Protocol1_8To1_9.class);
EntityTracker1_9 tracker = user.getEntityTracker(Protocol1_9To1_8.class);
int x;
int y;
@@ -15,7 +15,7 @@
* 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.utils.math;
package com.viaversion.viarewind.api.minecraft.math;
import java.util.Objects;
@@ -15,7 +15,7 @@
* 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.netty;
package com.viaversion.viarewind.api.minecraft.netty;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
@@ -15,7 +15,7 @@
* 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.netty;
package com.viaversion.viarewind.api.minecraft.netty;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
@@ -19,7 +19,7 @@ package com.viaversion.viarewind.api.rewriter;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viarewind.api.data.VRMappingDataLoader;
import com.viaversion.viarewind.api.data.RewindMappingDataLoader;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.libs.gson.JsonObject;
@@ -32,7 +32,7 @@ public class VRBlockItemRewriter<C extends ClientboundPacketType, S extends Serv
@Override
protected JsonObject readMappingsFile(String name) {
return VRMappingDataLoader.INSTANCE.loadFromDataDir(name);
return RewindMappingDataLoader.INSTANCE.loadFromDataDir(name);
}
@Override
@@ -22,20 +22,20 @@ import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_8;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
public abstract class VREntityRewriter<C extends ClientboundPacketType, T extends BackwardsProtocol<C, ?, ?, ?>> extends LegacyEntityRewriter<C, T> {
public VREntityRewriter(T protocol) {
super(protocol, MetaType1_8.String, MetaType1_8.Byte);
super(protocol, EntityDataTypes1_8.STRING, EntityDataTypes1_8.BYTE);
}
public VREntityRewriter(T protocol, MetaType displayType, MetaType displayVisibilityType) {
public VREntityRewriter(T protocol, EntityDataType displayType, EntityDataType displayVisibilityType) {
super(protocol, displayType, displayVisibilityType);
}
@@ -43,11 +43,11 @@ public abstract class VREntityRewriter<C extends ClientboundPacketType, T extend
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
protected void register() {
map(Type.INT); // Entity id
map(Type.UNSIGNED_BYTE); // Game mode
map(Type.BYTE); // Dimension
map(Types.INT); // Entity id
map(Types.UNSIGNED_BYTE); // Game mode
map(Types.BYTE); // Dimension
handler(playerTrackerHandler());
handler(wrapper -> wrapper.user().get(ClientWorld.class).setEnvironment(wrapper.get(Type.BYTE, 0)));
handler(wrapper -> wrapper.user().get(ClientWorld.class).setEnvironment(wrapper.get(Types.BYTE, 0)));
}
});
}
@@ -15,19 +15,19 @@
* 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.primitive;
package com.viaversion.viarewind.api.type;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class ByteIntArrayType extends Type<int[]> {
public class IntArrayType extends Type<int[]> {
public ByteIntArrayType() {
public IntArrayType() {
super(int[].class);
}
@Override
public int[] read(ByteBuf byteBuf) throws Exception {
public int[] read(ByteBuf byteBuf) {
byte size = byteBuf.readByte();
int[] array = new int[size];
for (byte i = 0; i < size; i++) {
@@ -37,7 +37,7 @@ public class ByteIntArrayType extends Type<int[]> {
}
@Override
public void write(ByteBuf byteBuf, int[] array) throws Exception {
public void write(ByteBuf byteBuf, int[] array) {
byteBuf.writeByte(array.length);
for (int i : array) byteBuf.writeInt(i);
}
@@ -15,37 +15,37 @@
* 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.primitive;
package com.viaversion.viarewind.api.type;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
import java.util.function.IntFunction;
public class PositionUYType<T extends Number> extends Type<Position> {
public class PositionVarYType<T extends Number> extends Type<BlockPosition> {
private final Type<T> yType;
private final IntFunction<T> toY;
public PositionUYType(final Type<T> yType, final IntFunction<T> toY) {
super(Position.class);
public PositionVarYType(final Type<T> yType, final IntFunction<T> toY) {
super(BlockPosition.class);
this.yType = yType;
this.toY = toY;
}
@Override
public Position read(ByteBuf buffer) throws Exception {
public BlockPosition read(ByteBuf buffer) {
final int x = buffer.readInt();
final int y = yType.read(buffer).intValue();
final int z = buffer.readInt();
return new Position(x, y, z);
return new BlockPosition(x, y, z);
}
@Override
public void write(ByteBuf buffer, Position value) throws Exception {
public void write(ByteBuf buffer, BlockPosition value) {
buffer.writeInt(value.x());
yType.write(buffer, this.toY.apply(value.y()));
buffer.writeInt(value.z());
@@ -20,36 +20,31 @@ package com.viaversion.viarewind.api.type;
import com.viaversion.viarewind.api.type.item.NBTType;
import com.viaversion.viarewind.api.type.item.ItemArrayType;
import com.viaversion.viarewind.api.type.item.ItemType;
import com.viaversion.viarewind.api.type.metadata.MetadataListType;
import com.viaversion.viarewind.api.type.metadata.MetadataType;
import com.viaversion.viarewind.api.type.primitive.ByteIntArrayType;
import com.viaversion.viarewind.api.type.primitive.PositionUYType;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viarewind.api.type.entitydata.EntityDataListType;
import com.viaversion.viarewind.api.type.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.nbt.tag.CompoundTag;
import java.util.List;
public class Types1_7_6_10 {
/**
* Safe to use before protocol loading
*/
public class RewindTypes {
// Primitives
public static final Type<int[]> BYTE_INT_ARRAY = new ByteIntArrayType(); // Integer array with byte as length indicator
public static final Type<int[]> INT_ARRAY = new IntArrayType(); // Integer array with byte as length indicator
// Positions /shrug
public static final Type<Position> SHORT_POSITION = new PositionUYType<>(Type.SHORT, value -> (short) value);
public static final Type<Position> INT_POSITION = new PositionUYType<>(Type.INT, value -> value);
public static final Type<Position> BYTE_POSITION = new PositionUYType<>(Type.BYTE, value -> (byte) value);
public static final Type<Position> U_BYTE_POSITION = new PositionUYType<>(Type.UNSIGNED_BYTE, value -> (short) value);
public static final Type<BlockPosition> SHORT_POSITION = new PositionVarYType<>(Types.SHORT, value -> (short) value);
public static final Type<BlockPosition> INT_POSITION = new PositionVarYType<>(Types.INT, value -> value);
public static final Type<BlockPosition> BYTE_POSITION = new PositionVarYType<>(Types.BYTE, value -> (byte) value);
public static final Type<BlockPosition> U_BYTE_POSITION = new PositionVarYType<>(Types.UNSIGNED_BYTE, value -> (short) value);
// Items
public static final Type<CompoundTag> COMPRESSED_NBT = new NBTType();
public static final Type<Item> COMPRESSED_NBT_ITEM = new ItemType();
public static final Type<Item[]> COMPRESSED_NBT_ITEM_ARRAY = new ItemArrayType();
// Metadata
public static final Type<Metadata> METADATA = new MetadataType();
public static final Type<List<Metadata>> METADATA_LIST = new MetadataListType();
}
@@ -35,12 +35,12 @@ public class BulkChunkType1_7_6 extends Type<Chunk[]> {
}
@Override
public Chunk[] read(ByteBuf byteBuf) throws Exception {
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/ChunkBulk1_7_6Type.java
}
@Override
public void write(ByteBuf byteBuf, Chunk[] chunks) throws Exception {
public void write(ByteBuf byteBuf, Chunk[] chunks) {
final int chunkCount = chunks.length;
final ByteArrayOutputStream output = new ByteArrayOutputStream();
final int[] chunkX = new int[chunkCount];
@@ -50,8 +50,13 @@ public class BulkChunkType1_7_6 extends Type<Chunk[]> {
for (int i = 0; i < chunkCount; i++) {
final Chunk chunk = chunks[i];
final Pair<byte[], Short> chunkData = ChunkType1_7_6.serialize(chunk);
output.write(chunkData.key());
Pair<byte[], Short> chunkData;
try {
chunkData = ChunkType1_7_6.serialize(chunk);
output.write(chunkData.key());
} catch (Exception e) {
throw new RuntimeException("Unable to serialize chunk", e);
}
chunkX[i] = chunk.getX();
chunkZ[i] = chunk.getZ();
primaryBitMask[i] = (short) chunk.getBitmask();
@@ -17,7 +17,7 @@
*/
package com.viaversion.viarewind.api.type.chunk;
import com.viaversion.viarewind.utils.ExtendedBlockStorage;
import com.viaversion.viarewind.api.minecraft.ExtendedBlockStorage;
import com.viaversion.viaversion.api.minecraft.chunks.*;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.Pair;
@@ -36,13 +36,18 @@ public class ChunkType1_7_6 extends Type<Chunk> {
}
@Override
public Chunk read(ByteBuf byteBuf) throws Exception {
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) throws Exception {
final Pair<byte[], Short> chunkData = serialize(chunk);
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();
@@ -0,0 +1,62 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.api.type.entitydata;
import com.viaversion.viarewind.api.minecraft.entitydata.EntityDataTypes1_7_6_10;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListTypeTemplate;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.List;
public class EntityDataListType extends EntityDataListTypeTemplate {
private final Type<EntityData> type;
public EntityDataListType(Type<EntityData> type) {
this.type = type;
}
@Override
public List<EntityData> read(ByteBuf buffer) {
ArrayList<EntityData> entityData = new ArrayList<>();
EntityData data;
do {
data = type.read(buffer);
if (data != null) {
entityData.add(data);
}
} while (data != null);
return entityData;
}
@Override
public void write(ByteBuf buffer, List<EntityData> entityData) {
for (EntityData meta : entityData) {
type.write(buffer, meta);
}
if (entityData.isEmpty()) {
type.write(buffer, new EntityData(0, EntityDataTypes1_7_6_10.BYTE, (byte) 0));
}
buffer.writeByte(127);
}
}
@@ -15,30 +15,31 @@
* 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.metadata;
package com.viaversion.viarewind.api.type.entitydata;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.type.types.metadata.MetaTypeTemplate;
import com.viaversion.viarewind.api.minecraft.entitydata.EntityDataTypes1_7_6_10;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataTypeTemplate;
import io.netty.buffer.ByteBuf;
public class MetadataType extends MetaTypeTemplate {
public class EntityDataType extends EntityDataTypeTemplate {
@Override
public Metadata read(ByteBuf buffer) throws Exception {
public EntityData read(ByteBuf buffer) {
byte item = buffer.readByte();
if (item == 127) {
return null;
} else {
int typeID = (item & 224) >> 5;
MetaType1_7_6_10 type = MetaType1_7_6_10.byId(typeID);
EntityDataTypes1_7_6_10 type = EntityDataTypes1_7_6_10.byId(typeID);
int id = item & 31;
return new Metadata(id, type, type.type().read(buffer));
return new EntityData(id, type, type.type().read(buffer));
}
}
@Override
public void write(ByteBuf buffer, Metadata meta) throws Exception {
int item = (meta.metaType().typeId() << 5 | meta.id() & 31) & 255;
public void write(ByteBuf buffer, EntityData meta) {
int item = (meta.dataType().typeId() << 5 | meta.id() & 31) & 255;
buffer.writeByte(item);
meta.metaType().type().write(buffer, meta.getValue());
meta.dataType().type().write(buffer, meta.getValue());
}
}
@@ -17,9 +17,10 @@
*/
package com.viaversion.viarewind.api.type.item;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public class ItemArrayType extends Type<Item[]> {
@@ -29,21 +30,21 @@ public class ItemArrayType extends Type<Item[]> {
}
@Override
public Item[] read(ByteBuf buffer) throws Exception {
int amount = Type.SHORT.readPrimitive(buffer);
public Item[] read(ByteBuf buffer) {
int amount = Types.SHORT.readPrimitive(buffer);
Item[] items = new Item[amount];
for (int i = 0; i < amount; ++i) {
items[i] = Types1_7_6_10.COMPRESSED_NBT_ITEM.read(buffer);
items[i] = RewindTypes.COMPRESSED_NBT_ITEM.read(buffer);
}
return items;
}
@Override
public void write(ByteBuf buffer, Item[] items) throws Exception {
Type.SHORT.writePrimitive(buffer, (short) items.length);
public void write(ByteBuf buffer, Item[] items) {
Types.SHORT.writePrimitive(buffer, (short) items.length);
for (Item item : items) {
Types1_7_6_10.COMPRESSED_NBT_ITEM.write(buffer, item);
RewindTypes.COMPRESSED_NBT_ITEM.write(buffer, item);
}
}
}
@@ -17,7 +17,7 @@
*/
package com.viaversion.viarewind.api.type.item;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
@@ -30,7 +30,7 @@ public class ItemType extends Type<Item> {
}
@Override
public Item read(ByteBuf buffer) throws Exception {
public Item read(ByteBuf buffer) {
short id = buffer.readShort();
if (id < 0) {
return null;
@@ -39,19 +39,19 @@ public class ItemType extends Type<Item> {
item.setIdentifier(id);
item.setAmount(buffer.readByte());
item.setData(buffer.readShort());
item.setTag(Types1_7_6_10.COMPRESSED_NBT.read(buffer));
item.setTag(RewindTypes.COMPRESSED_NBT.read(buffer));
return item;
}
@Override
public void write(ByteBuf buffer, Item item) throws Exception {
public void write(ByteBuf buffer, Item item) {
if (item == null) {
buffer.writeShort(-1);
} else {
buffer.writeShort(item.identifier());
buffer.writeByte(item.amount());
buffer.writeShort(item.data());
Types1_7_6_10.COMPRESSED_NBT.write(buffer, item.tag());
RewindTypes.COMPRESSED_NBT.write(buffer, item.tag());
}
}
}
@@ -18,8 +18,8 @@
package com.viaversion.viarewind.api.type.item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.io.NBTIO;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.io.NBTIO;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
@@ -34,7 +34,7 @@ public class NBTType extends Type<CompoundTag> {
}
@Override
public CompoundTag read(ByteBuf buffer) throws IOException {
public CompoundTag read(ByteBuf buffer) {
short length = buffer.readShort();
if (length <= 0) {
return null;
@@ -44,11 +44,13 @@ public class NBTType extends Type<CompoundTag> {
try (GZIPInputStream gzipStream = new GZIPInputStream(new ByteBufInputStream(compressed))) {
return NBTIO.reader(CompoundTag.class).named().read(gzipStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void write(ByteBuf buffer, CompoundTag nbt) throws Exception {
public void write(ByteBuf buffer, CompoundTag nbt) {
if (nbt == null) {
buffer.writeShort(-1);
return;
@@ -58,6 +60,8 @@ public class NBTType extends Type<CompoundTag> {
try {
try (GZIPOutputStream gzipStream = new GZIPOutputStream(new ByteBufOutputStream(compressedBuf))) {
NBTIO.writer().named().write(gzipStream, nbt);
} catch (IOException e) {
throw new RuntimeException(e);
}
buffer.writeShort(compressedBuf.readableBytes());
@@ -1,54 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.api.type.metadata;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.type.types.metadata.MetaListTypeTemplate;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.List;
public class MetadataListType extends MetaListTypeTemplate {
@Override
public List<Metadata> read(ByteBuf buffer) throws Exception {
ArrayList<Metadata> list = new ArrayList<>();
Metadata m;
do {
m = Types1_7_6_10.METADATA.read(buffer);
if (m != null) {
list.add(m);
}
} while (m != null);
return list;
}
@Override
public void write(ByteBuf buffer, List<Metadata> metadata) throws Exception {
for (Metadata meta : metadata) {
Types1_7_6_10.METADATA.write(buffer, meta);
}
if (metadata.isEmpty()) {
Types1_7_6_10.METADATA.write(buffer, new Metadata(0, MetaType1_7_6_10.Byte, (byte) 0));
}
buffer.writeByte(127);
}
}
@@ -0,0 +1,15 @@
package com.viaversion.viarewind.api.type.version;
import com.viaversion.viarewind.api.type.entitydata.EntityDataListType;
import com.viaversion.viarewind.api.type.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.type.Type;
import java.util.List;
public class Types1_7_6_10 {
public static final Type<EntityData> ENTITY_DATA = new EntityDataType();
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -1,98 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
public enum ClientboundPackets1_7_2_5 implements ClientboundPacketType {
KEEP_ALIVE, // 0x00
JOIN_GAME, // 0x01
CHAT_MESSAGE, // 0x02
TIME_UPDATE, // 0x03
ENTITY_EQUIPMENT, // 0x04
SPAWN_POSITION, // 0x05
UPDATE_HEALTH, // 0x06
RESPAWN, // 0x07
PLAYER_POSITION, // 0x08
HELD_ITEM_CHANGE, // 0x09
USE_BED, // 0x0A
ENTITY_ANIMATION, // 0x0B
SPAWN_PLAYER, // 0x0C
COLLECT_ITEM, // 0x0D
SPAWN_ENTITY, // 0x0E
SPAWN_MOB, // 0x0F
SPAWN_PAINTING, // 0x10
SPAWN_EXPERIENCE_ORB, // 0x11
ENTITY_VELOCITY, // 0x12
DESTROY_ENTITIES, // 0x13
ENTITY_MOVEMENT, // 0x14
ENTITY_POSITION, // 0x15
ENTITY_ROTATION, // 0x16
ENTITY_POSITION_AND_ROTATION, // 0x17
ENTITY_TELEPORT, // 0x18
ENTITY_HEAD_LOOK, // 0x19
ENTITY_STATUS, // 0x1A
ATTACH_ENTITY, // 0x1B
ENTITY_METADATA, // 0x1C
ENTITY_EFFECT, // 0x1D
REMOVE_ENTITY_EFFECT, // 0x1E
SET_EXPERIENCE, // 0x1F
ENTITY_PROPERTIES, // 0x20
CHUNK_DATA, // 0x21
MULTI_BLOCK_CHANGE, // 0x22
BLOCK_CHANGE, // 0x23
BLOCK_ACTION, // 0x24
BLOCK_BREAK_ANIMATION, // 0x25
MAP_BULK_CHUNK, // 0x26
EXPLOSION, // 0x27
EFFECT, // 0x28
NAMED_SOUND, // 0x29
SPAWN_PARTICLE, // 0x2A
GAME_EVENT, // 0x2B
SPAWN_GLOBAL_ENTITY, // 0x2C
OPEN_WINDOW, // 0x2D
CLOSE_WINDOW, // 0x2E
SET_SLOT, // 0x2F
WINDOW_ITEMS, // 0x30
WINDOW_PROPERTY, // 0x31
WINDOW_CONFIRMATION, // 0x32
UPDATE_SIGN, // 0x33
MAP_DATA, // 0x34
BLOCK_ENTITY_DATA, // 0x35
OPEN_SIGN_EDITOR, // 0x36
STATISTICS, // 0x37
PLAYER_INFO, // 0x38
PLAYER_ABILITIES, // 0x39
TAB_COMPLETE, // 0x3A
SCOREBOARD_OBJECTIVE, // 0x3B
UPDATE_SCORE, // 0x3C
DISPLAY_SCOREBOARD, // 0x3D
TEAMS, // 0x3E
PLUGIN_MESSAGE, // 0x3F
DISCONNECT; // 0x40
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -1,330 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.data;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ClientboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.metadata.MetaIndex;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viarewind.api.type.metadata.MetaType1_7_6_10;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.metadata.MetadataRewriter1_7_6_10To1_8;
import com.viaversion.viarewind.utils.math.AABB;
import com.viaversion.viarewind.utils.math.Vector3d;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.data.entity.TrackedEntityImpl;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEvent;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEventImpl;
import java.util.ArrayList;
import java.util.List;
public class VirtualHologramEntity {
private final List<Metadata> metadataTracker = new ArrayList<>();
private double locX, locY, locZ;
private final UserConnection user;
private final int entityId;
private int[] entityIds = null;
private State currentState = null;
private String name = null;
private float yaw, pitch;
private float headYaw;
private boolean small = false;
private boolean marker = false;
public VirtualHologramEntity(final UserConnection user, final int entityId) {
this.user = user;
this.entityId = entityId;
}
public void setPosition(final double x, final double y, final double z) throws Exception {
if (x == this.locX && y == this.locY && z == this.locZ) return;
this.locX = x;
this.locY = y;
this.locZ = z;
updateLocation(false);
}
public void setRelativePosition(final double x, final double y, final double z) throws Exception {
if (x == 0.0 && y == 0.0 && z == 0.0) return;
this.locX += x;
this.locY += y;
this.locZ += z;
updateLocation(false);
}
public void setRotation(final float yaw, final float pitch) throws Exception {
if (this.yaw == yaw || this.headYaw == yaw || this.pitch == pitch) return;
this.yaw = yaw;
this.headYaw = yaw;
this.pitch = pitch;
updateLocation(false);
}
public void setHeadYaw(float yaw) throws Exception {
if (this.headYaw == yaw) return;
this.headYaw = yaw;
updateLocation(false);
}
public void syncState(final MetadataRewriter1_7_6_10To1_8 entityRewriter, final List<Metadata> metadataList) throws Exception {
// Merge metadata updates into current tracker
for (Metadata metadata : metadataList) {
metadataTracker.removeIf(m -> m.id() == metadata.id());
metadataTracker.add(metadata);
}
// Filter armor stand data to calculate emulation
byte flags = 0;
byte armorStandFlags = 0;
for (Metadata metadata : metadataTracker) {
if (metadata.id() == 0 && metadata.metaType() == MetaType1_8.Byte) {
flags = ((Number) metadata.getValue()).byteValue();
} else if (metadata.id() == 2 && metadata.metaType() == MetaType1_8.String) {
name = metadata.getValue().toString();
if (name != null && name.isEmpty()) name = null;
} else if (metadata.id() == 10 && metadata.metaType() == MetaType1_8.Byte) {
armorStandFlags = ((Number) metadata.getValue()).byteValue();
}
}
final boolean invisible = (flags & 0x20) != 0;
small = (armorStandFlags & 0x01) != 0;
marker = (armorStandFlags & 0x10) != 0;
State prevState = currentState;
if (invisible && name != null) {
currentState = State.HOLOGRAM;
} else {
currentState = State.ZOMBIE;
}
if (currentState != prevState) {
deleteEntity();
sendSpawnPacket(entityRewriter);
} else {
sendMetadataUpdate(entityRewriter);
updateLocation(false);
}
}
private void updateLocation(final boolean remount) throws Exception {
if (entityIds == null) {
return;
}
if (currentState == State.ZOMBIE) {
teleportEntity(entityId, locX, locY, locZ, yaw, pitch);
final PacketWrapper entityHeadLook = PacketWrapper.create(ClientboundPackets1_7_2_5.ENTITY_HEAD_LOOK, user);
entityHeadLook.write(Type.INT, entityId);
entityHeadLook.write(Type.BYTE, (byte) ((headYaw / 360f) * 256));
entityHeadLook.send(Protocol1_7_6_10To1_8.class);
} else if (currentState == State.HOLOGRAM) {
if (remount) {
PacketWrapper detach = PacketWrapper.create(ClientboundPackets1_7_2_5.ATTACH_ENTITY, user);
detach.write(Type.INT, entityIds[1]);
detach.write(Type.INT, -1);
detach.write(Type.BOOLEAN, false);
detach.send(Protocol1_7_6_10To1_8.class);
}
// Don't ask me where this offset is coming from
teleportEntity(entityIds[0], locX, (locY + (marker ? 54.85 : small ? 56 : 57) - 0.16), locZ, 0, 0); // Skull
if (remount) {
teleportEntity(entityIds[1], locX, locY + 56.75, locZ, 0, 0); // Horse
PacketWrapper attach = PacketWrapper.create(ClientboundPackets1_7_2_5.ATTACH_ENTITY, null, user);
attach.write(Type.INT, entityIds[1]);
attach.write(Type.INT, entityIds[0]);
attach.write(Type.BOOLEAN, false);
attach.send(Protocol1_7_6_10To1_8.class);
}
}
}
protected void teleportEntity(final int entityId, final double x, final double y, final double z, final float yaw, final float pitch) throws Exception {
final PacketWrapper entityTeleport = PacketWrapper.create(ClientboundPackets1_7_2_5.ENTITY_TELEPORT, user);
entityTeleport.write(Type.INT, entityId); // entity id
entityTeleport.write(Type.INT, (int) (x * 32.0)); // x
entityTeleport.write(Type.INT, (int) (y * 32.0)); // y
entityTeleport.write(Type.INT, (int) (z * 32.0)); // z
entityTeleport.write(Type.BYTE, (byte) ((yaw / 360f) * 256)); // yaw
entityTeleport.write(Type.BYTE, (byte) ((pitch / 360f) * 256)); // pitch
entityTeleport.send(Protocol1_7_6_10To1_8.class);
}
protected void spawnEntity(final int entityId, final int type, final double locX, final double locY, final double locZ) throws Exception {
final PacketWrapper spawnMob = PacketWrapper.create(ClientboundPackets1_7_2_5.SPAWN_MOB, null, user);
spawnMob.write(Type.VAR_INT, entityId); // entity id
spawnMob.write(Type.UNSIGNED_BYTE, (short) type); // type
spawnMob.write(Type.INT, (int) (locX * 32.0)); // x
spawnMob.write(Type.INT, (int) (locY * 32.0)); // y
spawnMob.write(Type.INT, (int) (locZ * 32.0)); // z
spawnMob.write(Type.BYTE, (byte) 0); // yaw
spawnMob.write(Type.BYTE, (byte) 0); // pitch
spawnMob.write(Type.BYTE, (byte) 0); // head pitch
spawnMob.write(Type.SHORT, (short) 0); // velocity x
spawnMob.write(Type.SHORT, (short) 0); // velocity y
spawnMob.write(Type.SHORT, (short) 0); // velocity z
spawnMob.write(Types1_7_6_10.METADATA_LIST, new ArrayList<>()); // metadata
spawnMob.send(Protocol1_7_6_10To1_8.class);
}
public void sendMetadataUpdate(final MetadataRewriter1_7_6_10To1_8 entityRewriter) throws Exception {
if (entityIds == null) {
return;
}
final PacketWrapper metadataPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.ENTITY_METADATA, user);
if (currentState == State.ZOMBIE) {
writeZombieMeta(entityRewriter, metadataPacket);
} else if (currentState == State.HOLOGRAM) {
writeHologramMeta(metadataPacket);
} else {
return;
}
metadataPacket.send(Protocol1_7_6_10To1_8.class);
}
private void writeZombieMeta(final MetadataRewriter1_7_6_10To1_8 entityRewriter, PacketWrapper wrapper) {
wrapper.write(Type.INT, entityIds[0]);
// Filter metadata sent by the server and convert them together with our custom metadata
final List<Metadata> metadataList = new ArrayList<>();
for (Metadata metadata : metadataTracker) {
// Remove non existent metadata
if (metadata.id() < 0 || metadata.id() > 9) {
continue;
}
metadataList.add(new Metadata(metadata.id(), metadata.metaType(), metadata.getValue()));
}
if (small) {
metadataList.add(new Metadata(12, MetaType1_8.Byte, (byte) 1));
}
// Push metadata from the server through metadata conversion 1.7->1.8
for (Metadata metadata : metadataList.toArray(new Metadata[0])) {
final MetaHandlerEvent event = new MetaHandlerEventImpl(wrapper.user(), new TrackedEntityImpl(EntityTypes1_10.EntityType.ZOMBIE), -1, metadata, metadataList);
try {
entityRewriter.handleMetadata(event, metadata);
} catch (Exception e) {
metadataList.remove(metadata);
break;
}
if (event.cancelled()) {
metadataList.remove(metadata);
break;
}
}
wrapper.write(Types1_7_6_10.METADATA_LIST, metadataList);
}
private void writeHologramMeta(PacketWrapper wrapper) {
wrapper.write(Type.INT, entityIds[1]);
// Directly write 1.7 metadata here since we are making them up
final List<Metadata> metadataList = new ArrayList<>();
metadataList.add(new Metadata(MetaIndex.ENTITY_AGEABLE_AGE.getIndex(), MetaType1_7_6_10.Int, -1700000));
metadataList.add(new Metadata(MetaIndex.ENTITY_LIVING_NAME_TAG.getIndex(), MetaType1_7_6_10.String, name));
metadataList.add(new Metadata(MetaIndex.ENTITY_LIVING_NAME_TAG_VISIBILITY.getIndex(), MetaType1_7_6_10.Byte, (byte) 1));
wrapper.write(Types1_7_6_10.METADATA_LIST, metadataList);
}
public void sendSpawnPacket(final MetadataRewriter1_7_6_10To1_8 entityRewriter) throws Exception {
if (entityIds != null) {
deleteEntity();
}
if (currentState == State.ZOMBIE) {
spawnEntity(entityId, 54, locX, locY, locZ);
entityIds = new int[]{entityId};
} else if (currentState == State.HOLOGRAM) {
final int[] entityIds = { entityId, additionalEntityId() };
final PacketWrapper spawnSkull = PacketWrapper.create(ClientboundPackets1_7_2_5.SPAWN_ENTITY, user);
spawnSkull.write(Type.VAR_INT, entityIds[0]);
spawnSkull.write(Type.BYTE, (byte) 66);
spawnSkull.write(Type.INT, (int) (locX * 32.0));
spawnSkull.write(Type.INT, (int) (locY * 32.0));
spawnSkull.write(Type.INT, (int) (locZ * 32.0));
spawnSkull.write(Type.BYTE, (byte) 0);
spawnSkull.write(Type.BYTE, (byte) 0);
spawnSkull.write(Type.INT, 0);
spawnSkull.send(Protocol1_7_6_10To1_8.class);
spawnEntity(entityIds[1], 100, locX, locY, locZ); // Horse
this.entityIds = entityIds;
}
sendMetadataUpdate(entityRewriter);
updateLocation(true);
}
public AABB getBoundingBox() {
final double width = this.small ? 0.25 : 0.5;
final double height = this.small ? 0.9875 : 1.975;
final Vector3d min = new Vector3d(this.locX - width / 2, this.locY, this.locZ - width / 2);
final Vector3d max = new Vector3d(this.locX + width / 2, this.locY + height, this.locZ + width / 2);
return new AABB(min, max);
}
private int additionalEntityId() {
return Integer.MAX_VALUE - 16000 - entityId;
}
public void deleteEntity() throws Exception {
if (entityIds == null) {
return;
}
final PacketWrapper despawn = PacketWrapper.create(ClientboundPackets1_7_2_5.DESTROY_ENTITIES, user);
despawn.write(Type.BYTE, (byte) entityIds.length);
for (int id : entityIds) {
despawn.write(Type.INT, id);
}
entityIds = null;
despawn.send(Protocol1_7_6_10To1_8.class);
}
private enum State {
HOLOGRAM, ZOMBIE
}
public int getEntityId() {
return entityId;
}
}
@@ -1,216 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.metadata;
import com.viaversion.viarewind.api.type.metadata.MetaType1_7_6_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_8;
import com.viaversion.viaversion.util.Pair;
import java.util.HashMap;
import java.util.Optional;
public enum MetaIndex {
ENTITY_FLAGS(EntityTypes1_10.EntityType.ENTITY, 0, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
ENTITY_AIR(EntityTypes1_10.EntityType.ENTITY, 1, MetaType1_7_6_10.Short, MetaType1_8.Short),
ENTITY_NAME_TAG(EntityTypes1_10.EntityType.ENTITY, -1, null, 2, MetaType1_8.String),
ENTITY_NAME_TAG_VISIBILITY(EntityTypes1_10.EntityType.ENTITY, -1, null, 3, MetaType1_8.Byte),
ENTITY_SILENT(EntityTypes1_10.EntityType.ENTITY, -1, null, 4, MetaType1_8.Byte),
ENTITY_LIVING_HEALTH(EntityTypes1_10.EntityType.ENTITY_LIVING, 6, MetaType1_7_6_10.Float, MetaType1_8.Float),
ENTITY_LIVING_POTION_EFFECT_COLOR(EntityTypes1_10.EntityType.ENTITY_LIVING, 7, MetaType1_7_6_10.Int, MetaType1_8.Int),
ENTITY_LIVING_IS_POTION_EFFECT_AMBIENT(EntityTypes1_10.EntityType.ENTITY_LIVING, 8, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
ENTITY_LIVING_ARROWS(EntityTypes1_10.EntityType.ENTITY_LIVING, 9, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
ENTITY_LIVING_NAME_TAG(EntityTypes1_10.EntityType.ENTITY_LIVING, 10, MetaType1_7_6_10.String, 2, MetaType1_8.String),
ENTITY_LIVING_NAME_TAG_VISIBILITY(EntityTypes1_10.EntityType.ENTITY_LIVING, 11, MetaType1_7_6_10.Byte, 3, MetaType1_8.Byte),
ENTITY_LIVING_AI(EntityTypes1_10.EntityType.ENTITY_LIVING, -1, null, 15, MetaType1_8.Byte),
ENTITY_AGEABLE_AGE(EntityTypes1_10.EntityType.ENTITY_AGEABLE, 12, MetaType1_7_6_10.Int, MetaType1_8.Byte),
ARMOR_STAND_FLAGS(EntityTypes1_10.EntityType.ARMOR_STAND, -1, null, 10, MetaType1_8.Byte),
ARMOR_STAND_HEAD_POSITION(EntityTypes1_10.EntityType.ARMOR_STAND, -1, null, 11, MetaType1_8.Rotation),
ARMOR_STAND_BODY_POSITION(EntityTypes1_10.EntityType.ARMOR_STAND, -1, null, 12, MetaType1_8.Rotation),
ARMOR_STAND_LEFT_ARM_POSITION(EntityTypes1_10.EntityType.ARMOR_STAND, -1, null, 13, MetaType1_8.Rotation),
ARMOR_STAND_RIGHT_ARM_POSITION(EntityTypes1_10.EntityType.ARMOR_STAND, -1, null, 14, MetaType1_8.Rotation),
ARMOR_STAND_LEFT_LEG_POSITION(EntityTypes1_10.EntityType.ARMOR_STAND, -1, null, 15, MetaType1_8.Rotation),
ARMOR_STAND_RIGHT_LEG_POSITION(EntityTypes1_10.EntityType.ARMOR_STAND, -1, null, 16, MetaType1_8.Rotation),
HUMAN_SKIN_FLAGS(EntityTypes1_10.EntityType.ENTITY_HUMAN, 16, MetaType1_7_6_10.Byte, 10, MetaType1_8.Byte),
HUMAN_UNUSED(EntityTypes1_10.EntityType.ENTITY_HUMAN, -1, null, 16, MetaType1_8.Byte),
HUMAN_ABSORPTION_HEATS(EntityTypes1_10.EntityType.ENTITY_HUMAN, 17, MetaType1_7_6_10.Float, MetaType1_8.Float),
HUMAN_SCORE(EntityTypes1_10.EntityType.ENTITY_HUMAN, 18, MetaType1_7_6_10.Int, MetaType1_8.Int),
HORSE_FLAGS(EntityTypes1_10.EntityType.HORSE, 16, MetaType1_7_6_10.Int, MetaType1_8.Int),
HORSE_TYPE(EntityTypes1_10.EntityType.HORSE, 19, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
HORSE_COLOR(EntityTypes1_10.EntityType.HORSE, 20, MetaType1_7_6_10.Int, MetaType1_8.Int),
HORSE_OWNER(EntityTypes1_10.EntityType.HORSE, 21, MetaType1_7_6_10.String, MetaType1_8.String),
HORSE_ARMOR(EntityTypes1_10.EntityType.HORSE, 22, MetaType1_7_6_10.Int, MetaType1_8.Int),
BAT_HANGING(EntityTypes1_10.EntityType.BAT, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
TAMEABLE_FLAGS(EntityTypes1_10.EntityType.ENTITY_TAMEABLE_ANIMAL, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
TAMEABLE_OWNER(EntityTypes1_10.EntityType.ENTITY_TAMEABLE_ANIMAL, 17, MetaType1_7_6_10.String, MetaType1_8.String),
OCELOT_TYPE(EntityTypes1_10.EntityType.OCELOT, 18, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
WOLF_FLAGS(EntityTypes1_10.EntityType.WOLF, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
WOLF_HEALTH(EntityTypes1_10.EntityType.WOLF, 18, MetaType1_7_6_10.Float, MetaType1_8.Float),
WOLF_BEGGING(EntityTypes1_10.EntityType.WOLF, 19, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
WOLF_COLLAR_COLOR(EntityTypes1_10.EntityType.WOLF, 20, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
PIG_SADDLE(EntityTypes1_10.EntityType.PIG, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
SHEEP_COLOR_OR_SHEARED(EntityTypes1_10.EntityType.SHEEP, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
VILLAGER_TYPE(EntityTypes1_10.EntityType.VILLAGER, 16, MetaType1_7_6_10.Int, MetaType1_8.Int),
ENDERMAN_CARRIED_BLOCK(EntityTypes1_10.EntityType.ENDERMAN, 16, null, MetaType1_8.Short),
ENDERMAN_CARRIED_BLOCK_DATA(EntityTypes1_10.EntityType.ENDERMAN, 17, null, MetaType1_8.Byte),
ENDERMAN_IS_SCREAMING(EntityTypes1_10.EntityType.ENDERMAN, 18, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
ZOMBIE_CHILD(EntityTypes1_10.EntityType.ZOMBIE, 12, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
ZOMBIE_VILLAGER(EntityTypes1_10.EntityType.ZOMBIE, 13, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
ZOMBIE_CONVERTING(EntityTypes1_10.EntityType.ZOMBIE, 14, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
BLAZE_ON_FIRE(EntityTypes1_10.EntityType.BLAZE, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
SPIDER_CLIMBING(EntityTypes1_10.EntityType.SPIDER, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
CREEPER_STATE(EntityTypes1_10.EntityType.CREEPER, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
CREEPER_POWERED(EntityTypes1_10.EntityType.CREEPER, 17, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
CREEPER_IGNITED(EntityTypes1_10.EntityType.CREEPER, 18, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
GHAST_STATE(EntityTypes1_10.EntityType.GHAST, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
GHAST_IS_POWERED(EntityTypes1_10.EntityType.GHAST, 17, null, MetaType1_8.Byte),
SLIME_SIZE(EntityTypes1_10.EntityType.SLIME, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
SKELETON_TYPE(EntityTypes1_10.EntityType.SKELETON, 13, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
WITCH_AGGRESSIVE(EntityTypes1_10.EntityType.WITCH, 21, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
IRON_GOLEM_IS_PLAYER_CREATED(EntityTypes1_10.EntityType.IRON_GOLEM, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
WITHER_WATCHED_TARGET_1(EntityTypes1_10.EntityType.WITHER, 17, MetaType1_7_6_10.Int, MetaType1_8.Int),
WITHER_WATCHED_TARGET_2(EntityTypes1_10.EntityType.WITHER, 18, MetaType1_7_6_10.Int, MetaType1_8.Int),
WITHER_WATCHED_TARGET_3(EntityTypes1_10.EntityType.WITHER, 19, MetaType1_7_6_10.Int, MetaType1_8.Int),
WITHER_INVULNERABLE_TIME(EntityTypes1_10.EntityType.WITHER, 20, MetaType1_7_6_10.Int, MetaType1_8.Int),
GUARDIAN_FLAGS(EntityTypes1_10.EntityType.GUARDIAN, 16, null, MetaType1_8.Byte),
GUARDIAN_TARGET(EntityTypes1_10.EntityType.GUARDIAN, 17, null, MetaType1_8.Int),
BOAT_TIME_SINCE_HIT(EntityTypes1_10.EntityType.BOAT, 17, MetaType1_7_6_10.Int, MetaType1_8.Int),
BOAT_FORWARD_DIRECTION(EntityTypes1_10.EntityType.BOAT, 18, MetaType1_7_6_10.Int, MetaType1_8.Int),
BOAT_DAMAGE_TAKEN(EntityTypes1_10.EntityType.BOAT, 19, MetaType1_7_6_10.Float, MetaType1_8.Float),
MINECART_SHAKING_POWER(EntityTypes1_10.EntityType.MINECART_ABSTRACT, 17, MetaType1_7_6_10.Int, MetaType1_8.Int),
MINECART_SHAKING_DIRECTION(EntityTypes1_10.EntityType.MINECART_ABSTRACT, 18, MetaType1_7_6_10.Int, MetaType1_8.Int),
MINECART_DAMAGE_TAKEN(EntityTypes1_10.EntityType.MINECART_ABSTRACT, 19, MetaType1_7_6_10.Float, MetaType1_8.Float),
MINECART_BLOCK_INSIDE(EntityTypes1_10.EntityType.MINECART_ABSTRACT, 20, MetaType1_7_6_10.Int, MetaType1_8.Int),
MINECART_BLOCK_Y(EntityTypes1_10.EntityType.MINECART_ABSTRACT, 21, MetaType1_7_6_10.Int, MetaType1_8.Int),
MINECART_SHOW_BLOCK(EntityTypes1_10.EntityType.MINECART_ABSTRACT, 22, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
FURNACE_MINECART_IS_POWERED(EntityTypes1_10.EntityType.MINECART_FURNACE, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
ITEM_ITEM(EntityTypes1_10.EntityType.DROPPED_ITEM, 10, MetaType1_7_6_10.Slot, MetaType1_8.Slot),
ARROW_IS_CRITICAL(EntityTypes1_10.EntityType.ARROW, 16, MetaType1_7_6_10.Byte, MetaType1_8.Byte),
FIREWORK_INFO(EntityTypes1_10.EntityType.FIREWORK, 8, MetaType1_7_6_10.Slot, MetaType1_8.Slot),
ITEM_FRAME_ITEM(EntityTypes1_10.EntityType.ITEM_FRAME, 2, MetaType1_7_6_10.Slot, 8, MetaType1_8.Slot),
ITEM_FRAME_ROTATION(EntityTypes1_10.EntityType.ITEM_FRAME, 3, MetaType1_7_6_10.Byte, 9, MetaType1_8.Byte),
ENDER_CRYSTAL_HEALTH(EntityTypes1_10.EntityType.ENDER_CRYSTAL, 8, MetaType1_7_6_10.Int, 9, MetaType1_8.Int);
private static final HashMap<Pair<EntityTypes1_10.EntityType, Integer>, MetaIndex> metadataRewrites = new HashMap<>();
static {
for (MetaIndex index : MetaIndex.values()) {
metadataRewrites.put(new Pair<>(index.getClazz(), index.getNewIndex()), index);
}
}
private final EntityTypes1_10.EntityType clazz;
private final int newIndex;
private final MetaType1_8 newType;
private final MetaType1_7_6_10 oldType;
private final int index;
MetaIndex(EntityTypes1_10.EntityType type, int index, MetaType1_7_6_10 oldType, MetaType1_8 newType) {
this.clazz = type;
this.index = index;
this.newIndex = index;
this.oldType = oldType;
this.newType = newType;
}
MetaIndex(EntityTypes1_10.EntityType type, int index, MetaType1_7_6_10 oldType, int newIndex, MetaType1_8 newType) {
this.clazz = type;
this.index = index;
this.oldType = oldType;
this.newIndex = newIndex;
this.newType = newType;
}
private static Optional<MetaIndex> getIndex(EntityType type, int index) {
Pair<EntityType, Integer> pair = new Pair<>(type, index);
if (metadataRewrites.containsKey(pair)) {
return Optional.of(metadataRewrites.get(pair));
}
return Optional.empty();
}
public EntityTypes1_10.EntityType getClazz() {
return clazz;
}
public int getNewIndex() {
return newIndex;
}
public MetaType1_8 getNewType() {
return newType;
}
public MetaType1_7_6_10 getOldType() {
return oldType;
}
public int getIndex() {
return index;
}
public static MetaIndex searchIndex(EntityType type, int index) {
EntityType currentType = type;
do {
Optional<MetaIndex> optMeta = getIndex(currentType, index);
if (optMeta.isPresent()) {
return optMeta.get();
}
currentType = currentType.getParent();
} while (currentType != null);
return null;
}
}
@@ -1,435 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.metadata;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.api.rewriter.VREntityRewriter;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viarewind.api.type.metadata.MetaType1_7_6_10;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ClientboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.data.VirtualHologramEntity;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.EntityTracker1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.GameProfileStorage;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.Scoreboard;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10.EntityType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_8;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEvent;
import com.viaversion.viaversion.util.IdAndData;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class MetadataRewriter1_7_6_10To1_8 extends VREntityRewriter<ClientboundPackets1_8, Protocol1_7_6_10To1_8> {
public MetadataRewriter1_7_6_10To1_8(Protocol1_7_6_10To1_8 protocol) {
super(protocol, MetaType1_7_6_10.String, MetaType1_7_6_10.Byte);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_8.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity id
map(Type.UNSIGNED_BYTE); // Game mode
map(Type.BYTE); // Dimension
map(Type.UNSIGNED_BYTE); // Difficulty
map(Type.UNSIGNED_BYTE); // Max players
map(Type.STRING); // Level type
read(Type.BOOLEAN); // Reduced debug info
handler(playerTrackerHandler());
handler(wrapper -> {
final int entityId = wrapper.get(Type.INT, 0);
if (ViaRewind.getConfig().isReplaceAdventureMode()) {
if (wrapper.get(Type.UNSIGNED_BYTE, 0) == 2) { // adventure
wrapper.set(Type.UNSIGNED_BYTE, 0, (short) 0); // survival
}
}
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
tracker.addPlayer(entityId, wrapper.user().getProtocolInfo().getUuid());
tracker.setClientEntityGameMode(wrapper.get(Type.UNSIGNED_BYTE, 0));
wrapper.user().get(ClientWorld.class).setEnvironment(wrapper.get(Type.BYTE, 0));
// Reset on Velocity server change
wrapper.user().put(new Scoreboard(wrapper.user()));
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.DESTROY_ENTITIES, wrapper -> {
final int[] entities = wrapper.read(Type.VAR_INT_ARRAY_PRIMITIVE);
untrackEntities(wrapper.user(), entities);
wrapper.cancel();
// Split entity destroy packets into smaller packets because 1.8 can handle more entities at once then 1.7 can.
final List<List<Integer>> parts = Lists.partition(Ints.asList(entities), Byte.MAX_VALUE);
for (List<Integer> part : parts) {
final PacketWrapper destroy = PacketWrapper.create(ClientboundPackets1_7_2_5.DESTROY_ENTITIES, wrapper.user());
destroy.write(Types1_7_6_10.BYTE_INT_ARRAY, part.stream().mapToInt(Integer::intValue).toArray());
destroy.scheduleSend(Protocol1_7_6_10To1_8.class);
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_METADATA, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // Entity id
map(Types1_8.METADATA_LIST, Types1_7_6_10.METADATA_LIST); // Metadata
handler(wrapper -> {
final int entityId = wrapper.get(Type.INT, 0);
final List<Metadata> metadata = wrapper.get(Types1_7_6_10.METADATA_LIST, 0);
handleMetadata(entityId, metadata, wrapper.user());
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.BYTE); // Type id
map(Type.INT); // X
map(Type.INT); // Y
map(Type.INT); // Z
map(Type.BYTE); // Pitch
map(Type.BYTE); // Yaw
map(Type.INT); // Data
// Track entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(id -> EntityTypes1_10.ObjectType.findById(id).orElse(null)));
handler(wrapper -> {
final int entityId = wrapper.get(Type.VAR_INT, 0);
final EntityTypes1_10.EntityType type = EntityTypes1_10.getTypeFromId(wrapper.get(Type.BYTE, 0), true);
int x = wrapper.get(Type.INT, 0);
int y = wrapper.get(Type.INT, 1);
int z = wrapper.get(Type.INT, 2);
byte pitch = wrapper.get(Type.BYTE, 1);
byte yaw = wrapper.get(Type.BYTE, 2);
int data = wrapper.get(Type.INT, 3);
if (type == EntityTypes1_10.ObjectType.ITEM_FRAME.getType()) {
switch (yaw) {
case -128:
z += 32;
yaw = 0;
break;
case -64:
x -= 32;
yaw = -64;
break;
case 0:
z -= 32;
yaw = -128;
break;
case 64:
x += 32;
yaw = 64;
break;
}
} else if (type == EntityTypes1_10.ObjectType.ARMOR_STAND.getType()) {
wrapper.cancel();
final EntityTracker1_8 tracker = tracker(wrapper.user());
final VirtualHologramEntity hologram = tracker.getHolograms().get(entityId);
hologram.setPosition(x / 32.0, y / 32.0, z / 32.0);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
hologram.setHeadYaw(yaw * 360f / 256);
} else if (type != null && type.isOrHasParent(EntityTypes1_10.EntityType.FALLING_BLOCK)) {
int blockId = data & 0xFFF;
int blockData = data >> 12 & 0xF;
final IdAndData replace = protocol.getItemRewriter().handleBlock(blockId, blockData);
if (replace != null) {
blockId = replace.getId();
blockData = replace.getData();
}
wrapper.set(Type.INT, 3, data = (blockId | blockData << 16));
}
wrapper.set(Type.INT, 0, x);
wrapper.set(Type.INT, 1, y);
wrapper.set(Type.INT, 2, z);
wrapper.set(Type.BYTE, 2, yaw);
if (data > 0) {
wrapper.passthrough(Type.SHORT); // Velocity x
wrapper.passthrough(Type.SHORT); // Velocity y
wrapper.passthrough(Type.SHORT); // Velocity z
}
});
}
});
registerTracker(ClientboundPackets1_8.SPAWN_EXPERIENCE_ORB, EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_8.SPAWN_GLOBAL_ENTITY, EntityType.LIGHTNING);
protocol.registerClientbound(ClientboundPackets1_8.SPAWN_PAINTING, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.STRING); // Title
map(Type.POSITION1_8, Types1_7_6_10.INT_POSITION); // Position
map(Type.UNSIGNED_BYTE, Type.INT); // Rotation
handler(wrapper -> {
final int entityId = wrapper.get(Type.VAR_INT, 0);
final Position position = wrapper.get(Types1_7_6_10.INT_POSITION, 0);
final int rotation = wrapper.get(Type.INT, 0);
int modX = 0;
int modZ = 0;
switch (rotation) {
case 0:
modZ = -1;
break;
case 1:
modX = 1;
break;
case 2:
modZ = 1;
break;
case 3:
modX = -1;
break;
}
wrapper.set(Types1_7_6_10.INT_POSITION, 0, new Position(position.x() + modX, position.y(), position.z() + modZ));
addTrackedEntity(wrapper, entityId, EntityTypes1_10.EntityType.PAINTING);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.UNSIGNED_BYTE); // Entity type
map(Type.INT); // X
map(Type.INT); // Y
map(Type.INT); // Z
map(Type.BYTE); // Yaw
map(Type.BYTE); // Pitch
map(Type.BYTE); // Head yaw
map(Type.SHORT); // Velocity x
map(Type.SHORT); // Velocity y
map(Type.SHORT); // Velocity z
map(Types1_8.METADATA_LIST, Types1_7_6_10.METADATA_LIST); // Metadata
handler(getTrackerHandler(Type.UNSIGNED_BYTE, 0));
handler(getMobSpawnRewriter(Types1_7_6_10.METADATA_LIST));
// Handle holograms
handler(wrapper -> {
final short typeId = wrapper.get(Type.UNSIGNED_BYTE, 0);
final EntityTypes1_10.EntityType type = EntityTypes1_10.getTypeFromId(typeId, false);
if (type == EntityTypes1_10.EntityType.ARMOR_STAND) {
wrapper.cancel();
final int entityId = wrapper.get(Type.VAR_INT, 0);
final int x = wrapper.get(Type.INT, 0);
final int y = wrapper.get(Type.INT, 1);
final int z = wrapper.get(Type.INT, 2);
final byte pitch = wrapper.get(Type.BYTE, 1);
final byte yaw = wrapper.get(Type.BYTE, 0);
final byte headYaw = wrapper.get(Type.BYTE, 2);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(entityId);
hologram.setPosition(x / 32.0, y / 32.0, z / 32.0);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
hologram.setHeadYaw(headYaw * 360f / 256);
hologram.syncState(protocol().getEntityRewriter(), wrapper.get(Types1_7_6_10.METADATA_LIST, 0));
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // entity id
handler(wrapper -> {
final UUID uuid = wrapper.read(Type.UUID);
wrapper.write(Type.STRING, uuid.toString()); // map to string
final GameProfileStorage gameProfileStorage = wrapper.user().get(GameProfileStorage.class);
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null) {
wrapper.write(Type.STRING, ""); // name
wrapper.write(Type.VAR_INT, 0); // properties count
} else {
wrapper.write(Type.STRING, gameProfile.name.length() > 16 ? gameProfile.name.substring(0, 16) : gameProfile.name); // name
wrapper.write(Type.VAR_INT, gameProfile.properties.size()); // properties count
for (GameProfileStorage.Property property : gameProfile.properties) {
wrapper.write(Type.STRING, property.name); // property name
wrapper.write(Type.STRING, property.value); // property value
wrapper.write(Type.STRING, property.signature == null ? "" : property.signature); // property signature
}
}
final int entityId = wrapper.get(Type.VAR_INT, 0);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
if (gameProfile != null && gameProfile.gamemode == 3) { // Spectator mode
for (short i = 0; i < 5; i++) {
final PacketWrapper entityEquipment = PacketWrapper.create(ClientboundPackets1_7_2_5.ENTITY_EQUIPMENT, wrapper.user());
entityEquipment.write(Type.INT, entityId);
entityEquipment.write(Type.SHORT, i);
entityEquipment.write(Types1_7_6_10.COMPRESSED_NBT_ITEM, i == 4 ? gameProfile.getSkull() : null);
entityEquipment.scheduleSend(Protocol1_7_6_10To1_8.class);
}
}
tracker.addPlayer(entityId, uuid);
});
map(Type.INT); // x
map(Type.INT); // y
map(Type.INT); // z
map(Type.BYTE); // yaw
map(Type.BYTE); // pitch
map(Type.SHORT); // Current item
map(Types1_8.METADATA_LIST, Types1_7_6_10.METADATA_LIST); // metadata
handler(getTrackerAndMetaHandler(Types1_7_6_10.METADATA_LIST, EntityTypes1_10.EntityType.PLAYER));
}
});
}
@Override
protected void registerRewrites() {
// Handle new entities
mapEntityTypeWithData(EntityType.GUARDIAN, EntityType.SQUID).plainName();
mapEntityTypeWithData(EntityType.ENDERMITE, EntityType.SQUID).plainName();
mapEntityTypeWithData(EntityType.RABBIT, EntityType.CHICKEN).plainName();
// Metadata rewrite
filter().handler((event, meta) -> {
try {
handleMetadata(event, meta);
} catch (Exception e) {
if (Via.getManager().isDebug()) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "An error occurred with entity metadata: " + meta, e);
}
event.cancel();
}
});
}
public void handleMetadata(MetaHandlerEvent event, Metadata metadata) throws Exception {
if (event.entityType() == EntityType.ARMOR_STAND) {
final EntityTracker1_8 tracker = tracker(event.user());
tracker.getHolograms().get(event.entityId()).syncState(this, event.metadataList());
event.cancel(); // We are rewriting metadata manually
return;
}
final MetaIndex metaIndex = MetaIndex.searchIndex(event.entityType(), metadata.id());
if (metaIndex == null) {
// Almost certainly bad data, remove it
event.cancel();
return;
}
if (metaIndex.getOldType() == null) {
event.cancel();
return;
}
final Object value = metadata.getValue();
metadata.setTypeAndValue(metaIndex.getNewType(), value);
metadata.setMetaTypeUnsafe(metaIndex.getOldType());
metadata.setId(metaIndex.getIndex());
switch (metaIndex.getOldType()) {
case Int:
if (metaIndex.getNewType() == MetaType1_8.Byte) {
metadata.setValue(((Byte) value).intValue());
if (metaIndex == MetaIndex.ENTITY_AGEABLE_AGE) {
if ((Integer) metadata.getValue() < 0) {
metadata.setValue(-25000);
}
}
}
if (metaIndex.getNewType() == MetaType1_8.Short) {
metadata.setValue(((Short) value).intValue());
}
if (metaIndex.getNewType() == MetaType1_8.Int) {
metadata.setValue(value);
}
break;
case Byte:
if (metaIndex.getNewType() == MetaType1_8.Int) {
metadata.setValue(((Integer) value).byteValue());
}
if (metaIndex.getNewType() == MetaType1_8.Byte) {
if (metaIndex == MetaIndex.ITEM_FRAME_ROTATION) {
metadata.setValue(Integer.valueOf((Byte) value % 4).byteValue());
} else {
metadata.setValue(value);
}
}
if (metaIndex == MetaIndex.HUMAN_SKIN_FLAGS) {
byte flags = (byte) value;
boolean cape = (flags & 0x01) != 0;
flags = (byte) (cape ? 0x00 : 0x02);
metadata.setValue(flags);
}
break;
case Slot:
metadata.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), (Item) value));
break;
case Float:
case String:
case Short:
case Position:
metadata.setValue(value);
break;
default:
event.cancel();
break;
}
}
@Override
public EntityTypes1_10.EntityType typeFromId(int type) {
return EntityTypes1_10.getTypeFromId(type, false);
}
@Override
public EntityTypes1_10.EntityType objectTypeFromId(int type) {
return EntityTypes1_10.getTypeFromId(type, true);
}
}
@@ -1,315 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.packets;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.data.VirtualHologramEntity;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.EntityTracker1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.GameProfileStorage;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.PlayerSessionStorage;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import java.util.UUID;
public class EntityPackets1_8 {
public static void register(Protocol1_7_6_10To1_8 protocol) {
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_EQUIPMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.SHORT); // slot
map(Type.ITEM1_8, Types1_7_6_10.COMPRESSED_NBT_ITEM); // item
// remap item
handler(wrapper -> {
final Item item = wrapper.get(Types1_7_6_10.COMPRESSED_NBT_ITEM, 0);
protocol.getItemRewriter().handleItemToClient(wrapper.user(), item);
wrapper.set(Types1_7_6_10.COMPRESSED_NBT_ITEM, 0, item);
});
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final int id = wrapper.get(Type.INT, 0);
int limit = tracker.clientEntityId() == id ? 3 : 4;
if (wrapper.get(Type.SHORT, 0) > limit) {
wrapper.cancel();
}
});
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final short slot = wrapper.get(Type.SHORT, 0);
final UUID uuid = tracker.getPlayerUUID(wrapper.get(Type.INT, 0));
if (uuid == null) return;
final Item item = wrapper.get(Types1_7_6_10.COMPRESSED_NBT_ITEM, 0);
wrapper.user().get(PlayerSessionStorage.class).setPlayerEquipment(uuid, item, slot);
final GameProfileStorage storage = wrapper.user().get(GameProfileStorage.class);
GameProfileStorage.GameProfile profile = storage.get(uuid);
if (profile != null && profile.gamemode == 3) { // spectator mode didn't exist in 1.7.10
wrapper.cancel();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.USE_BED, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.POSITION1_8, Types1_7_6_10.U_BYTE_POSITION); // position
}
});
protocol.registerClientbound(ClientboundPackets1_8.COLLECT_ITEM, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // collected entity id
map(Type.VAR_INT, Type.INT); // collector entity id
handler(wrapper -> wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class).removeEntity(wrapper.get(Type.INT, 0)));
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_VELOCITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_MOVEMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.BYTE); // x
map(Type.BYTE); // y
map(Type.BYTE); // z
read(Type.BOOLEAN); // on ground
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Type.INT, 0));
if (hologram != null) {
wrapper.cancel();
final int x = wrapper.get(Type.BYTE, 0);
final int y = wrapper.get(Type.BYTE, 1);
final int z = wrapper.get(Type.BYTE, 2);
hologram.setRelativePosition(x / 32.0, y / 32.0, z / 32.0);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_ROTATION, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.BYTE); // yaw
map(Type.BYTE); // pitch
read(Type.BOOLEAN); // on ground
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Type.INT, 0));
if (hologram != null) {
wrapper.cancel();
final int yaw = wrapper.get(Type.BYTE, 0);
final int pitch = wrapper.get(Type.BYTE, 1);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_POSITION_AND_ROTATION, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.BYTE); // x
map(Type.BYTE); // y
map(Type.BYTE); // z
map(Type.BYTE); // yaw
map(Type.BYTE); // pitch
read(Type.BOOLEAN); // on ground
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Type.INT, 0));
if (hologram != null) {
wrapper.cancel();
final int x = wrapper.get(Type.BYTE, 0);
final int y = wrapper.get(Type.BYTE, 1);
final int z = wrapper.get(Type.BYTE, 2);
final int yaw = wrapper.get(Type.BYTE, 3);
final int pitch = wrapper.get(Type.BYTE, 4);
hologram.setRelativePosition(x / 32.0, y / 32.0, z / 32.0);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_TELEPORT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.INT); // x
map(Type.INT); // y
map(Type.INT); // z
map(Type.BYTE); // yaw
map(Type.BYTE); // pitch
read(Type.BOOLEAN); // on ground
handler(wrapper -> {
final int entityId = wrapper.get(Type.INT, 0);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
if (tracker.entityType(entityId) == EntityTypes1_10.EntityType.MINECART_ABSTRACT) { // TODO | Realign all entities?
int y = wrapper.get(Type.INT, 2);
y += 12;
wrapper.set(Type.INT, 2, y);
}
final VirtualHologramEntity hologram = tracker.getHolograms().get(entityId);
if (hologram != null) {
wrapper.cancel();
final int x = wrapper.get(Type.INT, 1);
final int y = wrapper.get(Type.INT, 2);
final int z = wrapper.get(Type.INT, 3);
final int yaw = wrapper.get(Type.BYTE, 0);
final int pitch = wrapper.get(Type.BYTE, 1);
hologram.setPosition(x / 32.0, y / 32.0, z / 32.0);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_HEAD_LOOK, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.BYTE); // head yaw
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Type.INT, 0));
if (hologram != null) {
wrapper.cancel();
final int yaw = wrapper.get(Type.BYTE, 0);
hologram.setHeadYaw(yaw * 360f / 256);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ATTACH_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // riding entity id
map(Type.INT); // vehicle entity id
map(Type.BOOLEAN); // leash state
handler(wrapper -> {
final boolean leash = wrapper.get(Type.BOOLEAN, 0);
if (!leash) {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final int passenger = wrapper.get(Type.INT, 0);
final int vehicle = wrapper.get(Type.INT, 1);
tracker.setPassenger(vehicle, passenger);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.BYTE); // effect id
map(Type.BYTE); // amplifier
map(Type.VAR_INT, Type.SHORT); // duration
read(Type.BYTE); // hide particles
}
});
protocol.registerClientbound(ClientboundPackets1_8.REMOVE_ENTITY_EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
map(Type.BYTE); // effect id
}
});
protocol.registerClientbound(ClientboundPackets1_8.ENTITY_PROPERTIES, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // entity id
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
if (tracker.getHolograms().containsKey(wrapper.get(Type.INT, 0))) { // Don't handle properties for hologram emulation
wrapper.cancel();
return;
}
final int amount = wrapper.passthrough(Type.INT);
for (int i = 0; i < amount; i++) {
wrapper.passthrough(Type.STRING); // id
wrapper.passthrough(Type.DOUBLE); // value
int modifierLength = wrapper.read(Type.VAR_INT);
wrapper.write(Type.SHORT, (short) modifierLength);
for (int j = 0; j < modifierLength; j++) {
wrapper.passthrough(Type.UUID); // modifier uuid
wrapper.passthrough(Type.DOUBLE); // modifier amount
wrapper.passthrough(Type.BYTE); // modifier operation
}
}
});
}
});
protocol.cancelClientbound(ClientboundPackets1_8.UPDATE_ENTITY_NBT);
}
}
@@ -1,876 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.packets;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ClientboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ServerboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.provider.TitleRenderProvider;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.*;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viarewind.utils.math.AABB;
import com.viaversion.viarewind.utils.math.Ray3d;
import com.viaversion.viarewind.utils.math.RayTracing;
import com.viaversion.viarewind.utils.math.Vector3d;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.Environment;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.util.ComponentUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;
public class PlayerPackets1_8 {
public static void register(Protocol1_7_6_10To1_8 protocol) {
protocol.registerClientbound(ClientboundPackets1_8.CHAT_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.COMPONENT); // chat message
handler(wrapper -> {
final int position = wrapper.read(Type.BYTE);
if (position == 2) { // above hotbar
wrapper.cancel();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SPAWN_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8, Types1_7_6_10.INT_POSITION); // spawn position
}
});
protocol.registerClientbound(ClientboundPackets1_8.UPDATE_HEALTH, new PacketHandlers() {
@Override
public void register() {
map(Type.FLOAT); // health
map(Type.VAR_INT, Type.SHORT); // food
map(Type.FLOAT); // food saturation
}
});
protocol.registerClientbound(ClientboundPackets1_8.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // dimension
map(Type.UNSIGNED_BYTE); // difficulty
map(Type.UNSIGNED_BYTE); // game mode
handler(wrapper -> {
if (ViaRewind.getConfig().isReplaceAdventureMode()) {
if (wrapper.get(Type.UNSIGNED_BYTE, 1) == 2) {
wrapper.set(Type.UNSIGNED_BYTE, 1, (short) 0);
}
}
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
tracker.setClientEntityGameMode(wrapper.get(Type.UNSIGNED_BYTE, 1));
final Environment dimension = Environment.getEnvironmentById(wrapper.get(Type.INT, 0));
final ClientWorld world = wrapper.user().get(ClientWorld.class);
if (world.getEnvironment() != dimension) {
// Clear entities on dimension change and re-track player
world.setEnvironment(dimension.id());
tracker.clearEntities();
tracker.addEntity(tracker.clientEntityId(), EntityTypes1_10.EntityType.PLAYER);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.PLAYER_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE); // x
map(Type.DOUBLE); // y
map(Type.DOUBLE); // z
map(Type.FLOAT); // yaw
map(Type.FLOAT); // pitch
handler(wrapper -> {
final double x = wrapper.get(Type.DOUBLE, 0);
double y = wrapper.get(Type.DOUBLE, 1);
final double z = wrapper.get(Type.DOUBLE, 2);
final float yaw = wrapper.get(Type.FLOAT, 0);
final float pitch = wrapper.get(Type.FLOAT, 1);
final PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
final int flags = wrapper.read(Type.BYTE);
// x, y, and z
if ((flags & 0x01) == 0x01) wrapper.set(Type.DOUBLE, 0, x + playerSession.getPosX());
if ((flags & 0x02) == 0x02) y += playerSession.getPosY();
playerSession.receivedPosY = y;
wrapper.set(Type.DOUBLE, 1, y + 1.62F);
if ((flags & 0x04) == 0x04) wrapper.set(Type.DOUBLE, 2, z + playerSession.getPosZ());
// yaw and pitch
if ((flags & 0x08) == 0x08) wrapper.set(Type.FLOAT, 0, yaw + playerSession.yaw);
if ((flags & 0x10) == 0x10) wrapper.set(Type.FLOAT, 1, pitch + playerSession.pitch);
wrapper.write(Type.BOOLEAN, playerSession.onGround);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
if (tracker.spectatingClientEntityId != tracker.clientEntityId()) {
wrapper.cancel();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_EXPERIENCE, new PacketHandlers() {
@Override
public void register() {
map(Type.FLOAT); // experience bar
map(Type.VAR_INT, Type.SHORT); // level
map(Type.VAR_INT, Type.SHORT); // total experience
}
});
protocol.registerClientbound(ClientboundPackets1_8.GAME_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // reason
map(Type.FLOAT); // value
handler(wrapper -> {
if (wrapper.get(Type.UNSIGNED_BYTE, 0) != 3) return; // Change game mode
int gameMode = wrapper.get(Type.FLOAT, 0).intValue();
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
if (gameMode == 3 || tracker.isSpectator()) {
UUID myId = wrapper.user().getProtocolInfo().getUuid();
Item[] equipment = new Item[4];
if (gameMode == 3) {
GameProfileStorage.GameProfile profile = wrapper.user().get(GameProfileStorage.class).get(myId);
equipment[3] = profile == null ? null : profile.getSkull();
} else {
for (int i = 0; i < equipment.length; i++) {
equipment[i] = wrapper.user().get(PlayerSessionStorage.class).getPlayerEquipment(myId, i);
}
}
for (int i = 0; i < equipment.length; i++) {
PacketWrapper setSlot = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_SLOT, wrapper.user());
setSlot.write(Type.BYTE, (byte) 0);
setSlot.write(Type.SHORT, (short) (8 - i));
setSlot.write(Types1_7_6_10.COMPRESSED_NBT_ITEM, equipment[i]);
setSlot.scheduleSend(Protocol1_7_6_10To1_8.class);
}
}
if (gameMode == 2 && ViaRewind.getConfig().isReplaceAdventureMode()) {
gameMode = 0;
wrapper.set(Type.FLOAT, 0, 0.0f);
}
tracker.setClientEntityGameMode(gameMode);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.OPEN_SIGN_EDITOR, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8, Types1_7_6_10.INT_POSITION); // position
}
});
protocol.registerClientbound(ClientboundPackets1_8.PLAYER_INFO, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.cancel();
int action = wrapper.read(Type.VAR_INT);
int count = wrapper.read(Type.VAR_INT);
GameProfileStorage gameProfileStorage = wrapper.user().get(GameProfileStorage.class);
for (int i = 0; i < count; i++) {
UUID uuid = wrapper.read(Type.UUID);
if (action == 0) {
String name = wrapper.read(Type.STRING);
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null) gameProfile = gameProfileStorage.put(uuid, name);
int propertyCount = wrapper.read(Type.VAR_INT);
while (propertyCount-- > 0) {
String propertyName = wrapper.read(Type.STRING);
String propertyValue = wrapper.read(Type.STRING);
String propertySignature = wrapper.read(Type.OPTIONAL_STRING);
gameProfile.properties.add(new GameProfileStorage.Property(propertyName, propertyValue, propertySignature));
}
int gamemode = wrapper.read(Type.VAR_INT);
int ping = wrapper.read(Type.VAR_INT);
gameProfile.ping = ping;
gameProfile.gamemode = gamemode;
JsonElement displayName = wrapper.read(Type.OPTIONAL_COMPONENT);
if (displayName != null) {
gameProfile.setDisplayName(ChatUtil.jsonToLegacy(wrapper.user(), displayName));
}
PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, null, wrapper.user());
packet.write(Type.STRING, gameProfile.getDisplayName());
packet.write(Type.BOOLEAN, true);
packet.write(Type.SHORT, (short) ping);
packet.scheduleSend(Protocol1_7_6_10To1_8.class);
} else if (action == 1) {
int gamemode = wrapper.read(Type.VAR_INT);
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null || gameProfile.gamemode == gamemode) continue;
if (gamemode == 3 || gameProfile.gamemode == 3) {
EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
int entityId = tracker.getPlayerEntityId(uuid);
boolean isOwnPlayer = entityId == tracker.clientEntityId();
if (entityId != -1) {
// Weirdly, PlayerEntity has only 4 slots instead of 5
Item[] equipment = new Item[isOwnPlayer ? 4 : 5];
if (gamemode == 3) {
equipment[isOwnPlayer ? 3 : 4] = gameProfile.getSkull();
} else {
for (int j = 0; j < equipment.length; j++) {
equipment[j] = wrapper.user().get(PlayerSessionStorage.class).getPlayerEquipment(uuid, j);
}
}
for (short slot = 0; slot < equipment.length; slot++) {
PacketWrapper equipmentPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.ENTITY_EQUIPMENT, wrapper.user());
equipmentPacket.write(Type.INT, entityId);
equipmentPacket.write(Type.SHORT, slot);
equipmentPacket.write(Types1_7_6_10.COMPRESSED_NBT_ITEM, equipment[slot]);
equipmentPacket.scheduleSend(Protocol1_7_6_10To1_8.class);
}
}
}
gameProfile.gamemode = gamemode;
} else if (action == 2) {
int ping = wrapper.read(Type.VAR_INT);
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null) continue;
PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, null, wrapper.user());
packet.write(Type.STRING, gameProfile.getDisplayName());
packet.write(Type.BOOLEAN, false);
packet.write(Type.SHORT, (short) gameProfile.ping);
packet.scheduleSend(Protocol1_7_6_10To1_8.class);
gameProfile.ping = ping;
packet = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, null, wrapper.user());
packet.write(Type.STRING, gameProfile.getDisplayName());
packet.write(Type.BOOLEAN, true);
packet.write(Type.SHORT, (short) ping);
packet.scheduleSend(Protocol1_7_6_10To1_8.class);
} else if (action == 3) {
JsonElement displayNameComponent = wrapper.read(Type.OPTIONAL_COMPONENT);
String displayName = displayNameComponent != null ? ChatUtil.jsonToLegacy(wrapper.user(), displayNameComponent) : null;
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null || gameProfile.displayName == null && displayName == null) continue;
PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, null, wrapper.user());
packet.write(Type.STRING, gameProfile.getDisplayName());
packet.write(Type.BOOLEAN, false);
packet.write(Type.SHORT, (short) gameProfile.ping);
packet.scheduleSend(Protocol1_7_6_10To1_8.class);
if (gameProfile.displayName == null && displayName != null || gameProfile.displayName != null && displayName == null || !gameProfile.displayName.equals(displayName)) {
gameProfile.setDisplayName(displayName);
}
packet = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, null, wrapper.user());
packet.write(Type.STRING, gameProfile.getDisplayName());
packet.write(Type.BOOLEAN, true);
packet.write(Type.SHORT, (short) gameProfile.ping);
packet.scheduleSend(Protocol1_7_6_10To1_8.class);
} else if (action == 4) {
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.remove(uuid);
if (gameProfile == null) continue;
PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, null, wrapper.user());
packet.write(Type.STRING, gameProfile.getDisplayName());
packet.write(Type.BOOLEAN, false);
packet.write(Type.SHORT, (short) gameProfile.ping);
packet.scheduleSend(Protocol1_7_6_10To1_8.class);
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.PLAYER_ABILITIES, new PacketHandlers() {
@Override
public void register() {
map(Type.BYTE);
map(Type.FLOAT);
map(Type.FLOAT);
handler(wrapper -> {
byte flags = wrapper.get(Type.BYTE, 0);
float flySpeed = wrapper.get(Type.FLOAT, 0);
float walkSpeed = wrapper.get(Type.FLOAT, 1);
PlayerSessionStorage abilities = wrapper.user().get(PlayerSessionStorage.class);
abilities.invincible = (flags & 8) == 8;
abilities.allowFly = (flags & 4) == 4;
abilities.flying = (flags & 2) == 2;
abilities.creative = (flags & 1) == 1;
abilities.flySpeed = flySpeed;
abilities.walkSpeed = walkSpeed;
if (abilities.sprinting && abilities.flying) {
wrapper.set(Type.FLOAT, 0, abilities.flySpeed * 2.0f);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.PLUGIN_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
handlerSoftFail(wrapper -> {
String channel = wrapper.get(Type.STRING, 0);
if (channel.equals("MC|TrList")) {
wrapper.passthrough(Type.INT); //Window Id
int size;
if (wrapper.isReadable(Type.BYTE, 0)) {
size = wrapper.passthrough(Type.BYTE);
} else {
size = wrapper.passthrough(Type.UNSIGNED_BYTE);
}
for (int i = 0; i < size; i++) {
Item item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Type.ITEM1_8));
wrapper.write(Types1_7_6_10.COMPRESSED_NBT_ITEM, item); //Buy Item 1
item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Type.ITEM1_8));
wrapper.write(Types1_7_6_10.COMPRESSED_NBT_ITEM, item); //Buy Item 3
boolean has3Items = wrapper.passthrough(Type.BOOLEAN);
if (has3Items) {
item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Type.ITEM1_8));
wrapper.write(Types1_7_6_10.COMPRESSED_NBT_ITEM, item); //Buy Item 2
}
wrapper.passthrough(Type.BOOLEAN); //Unavailable
wrapper.read(Type.INT); //Uses
wrapper.read(Type.INT); //Max Uses
}
} else if (channel.equals("MC|Brand")) {
wrapper.write(Type.REMAINING_BYTES, wrapper.read(Type.STRING).getBytes(StandardCharsets.UTF_8));
}
wrapper.cancel();
wrapper.setPacketType(null);
ByteBuf newPacketBuf = Unpooled.buffer();
wrapper.writeToBuffer(newPacketBuf);
PacketWrapper newWrapper = PacketWrapper.create(ClientboundPackets1_7_2_5.PLUGIN_MESSAGE, newPacketBuf, wrapper.user());
newWrapper.passthrough(Type.STRING);
if (newPacketBuf.readableBytes() <= Short.MAX_VALUE) {
newWrapper.write(Type.SHORT, (short) newPacketBuf.readableBytes());
newWrapper.send(Protocol1_7_6_10To1_8.class);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.CAMERA, null, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.cancel();
final int entityId = wrapper.read(Type.VAR_INT);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
if (tracker.spectatingClientEntityId != entityId) {
tracker.setSpectating(entityId);
}
});
}
});
//Title
protocol.registerClientbound(ClientboundPackets1_8.TITLE, null, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.cancel();
TitleRenderProvider titleRenderProvider = Via.getManager().getProviders().get(TitleRenderProvider.class);
if (titleRenderProvider == null) return;
int action = wrapper.read(Type.VAR_INT);
UUID uuid = wrapper.user().getProtocolInfo().getUuid();
switch (action) {
case 0:
titleRenderProvider.setTitle(uuid, wrapper.read(Type.STRING));
break;
case 1:
titleRenderProvider.setSubTitle(uuid, wrapper.read(Type.STRING));
break;
case 2:
titleRenderProvider.setTimings(uuid, wrapper.read(Type.INT), wrapper.read(Type.INT), wrapper.read(Type.INT));
break;
case 3:
titleRenderProvider.clear(uuid);
break;
case 4:
titleRenderProvider.reset(uuid);
break;
}
});
}
});
//Player List Header And Footer
protocol.cancelClientbound(ClientboundPackets1_8.TAB_LIST);
//Resource Pack Send
protocol.registerClientbound(ClientboundPackets1_8.RESOURCE_PACK, ClientboundPackets1_7_2_5.PLUGIN_MESSAGE, new PacketHandlers() {
@Override
public void register() {
create(Type.STRING, "MC|RPack");
handler(wrapper -> {
ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
try {
// Url
Type.STRING.write(buf, wrapper.read(Type.STRING));
wrapper.write(Type.SHORT_BYTE_ARRAY, Type.REMAINING_BYTES.read(buf));
} finally {
buf.release();
}
});
read(Type.STRING); // Hash
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.CHAT_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
String msg = wrapper.get(Type.STRING, 0);
if (tracker.isSpectator() && msg.toLowerCase().startsWith("/stp ")) { // TODO add setting
String username = msg.split(" ")[1];
GameProfileStorage storage = wrapper.user().get(GameProfileStorage.class);
GameProfileStorage.GameProfile profile = storage.get(username, true);
if (profile != null && profile.uuid != null) {
wrapper.cancel();
PacketWrapper teleportPacket = PacketWrapper.create(0x18, null, wrapper.user());
teleportPacket.write(Type.UUID, profile.uuid);
teleportPacket.send(Protocol1_7_6_10To1_8.class);
}
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.INTERACT_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.INT, Type.VAR_INT);
map(Type.BYTE, Type.VAR_INT);
handler(wrapper -> {
int mode = wrapper.get(Type.VAR_INT, 1);
if (mode != 0) {
return;
}
final int entityId = wrapper.get(Type.VAR_INT, 0);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final PlayerSessionStorage position = wrapper.user().get(PlayerSessionStorage.class);
if (tracker.getHolograms().containsKey(entityId)) {
final AABB boundingBox = tracker.getHolograms().get(entityId).getBoundingBox();
Vector3d pos = new Vector3d(position.getPosX(), position.getPosY() + 1.8, position.getPosZ());
double yaw = Math.toRadians(position.yaw);
double pitch = Math.toRadians(position.pitch);
Vector3d dir = new Vector3d(-Math.cos(pitch) * Math.sin(yaw), -Math.sin(pitch), Math.cos(pitch) * Math.cos(yaw));
Ray3d ray = new Ray3d(pos, dir);
Vector3d intersection = RayTracing.trace(ray, boundingBox, 5.0);
if (intersection == null) {
return;
}
intersection.substract(boundingBox.getMin());
mode = 2;
wrapper.set(Type.VAR_INT, 1, mode);
wrapper.write(Type.FLOAT, (float) intersection.getX());
wrapper.write(Type.FLOAT, (float) intersection.getY());
wrapper.write(Type.FLOAT, (float) intersection.getZ());
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_MOVEMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.BOOLEAN);
handler(wrapper -> {
PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
playerSession.onGround = wrapper.get(Type.BOOLEAN, 0);
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE); //X
map(Type.DOUBLE); //Y
read(Type.DOUBLE);
map(Type.DOUBLE); //Z
map(Type.BOOLEAN); //OnGround
handler(wrapper -> {
double x = wrapper.get(Type.DOUBLE, 0);
double feetY = wrapper.get(Type.DOUBLE, 1);
double z = wrapper.get(Type.DOUBLE, 2);
PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
playerSession.onGround = wrapper.get(Type.BOOLEAN, 0);
playerSession.setPos(x, feetY, z);
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_ROTATION, new PacketHandlers() {
@Override
public void register() {
map(Type.FLOAT);
map(Type.FLOAT);
map(Type.BOOLEAN);
handler(wrapper -> {
PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
playerSession.yaw = wrapper.get(Type.FLOAT, 0);
playerSession.pitch = wrapper.get(Type.FLOAT, 1);
playerSession.onGround = wrapper.get(Type.BOOLEAN, 0);
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_POSITION_AND_ROTATION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE); //X
map(Type.DOUBLE); //Y
read(Type.DOUBLE);
map(Type.DOUBLE); //Z
map(Type.FLOAT); //Yaw
map(Type.FLOAT); //Pitch
map(Type.BOOLEAN); //OnGround
handler(wrapper -> {
double x = wrapper.get(Type.DOUBLE, 0);
double feetY = wrapper.get(Type.DOUBLE, 1);
double z = wrapper.get(Type.DOUBLE, 2);
float yaw = wrapper.get(Type.FLOAT, 0);
float pitch = wrapper.get(Type.FLOAT, 1);
PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
playerSession.onGround = wrapper.get(Type.BOOLEAN, 0);
playerSession.setPos(x, feetY, z);
playerSession.yaw = yaw;
playerSession.pitch = pitch;
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_DIGGING, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); //Status
handler(wrapper -> {
int x = wrapper.read(Type.INT);
int y = wrapper.read(Type.UNSIGNED_BYTE);
int z = wrapper.read(Type.INT);
wrapper.write(Type.POSITION1_8, new Position(x, y, z));
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_BLOCK_PLACEMENT, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
int x = wrapper.read(Type.INT);
int y = wrapper.read(Type.UNSIGNED_BYTE);
int z = wrapper.read(Type.INT);
wrapper.write(Type.POSITION1_8, new Position(x, y, z));
wrapper.passthrough(Type.BYTE); //Direction
Item item = wrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM);
item = protocol.getItemRewriter().handleItemToServer(wrapper.user(), item);
wrapper.write(Type.ITEM1_8, item);
for (int i = 0; i < 3; i++) {
wrapper.passthrough(Type.BYTE);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.ANIMATION, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
int entityId = wrapper.read(Type.INT);
int animation = wrapper.read(Type.BYTE); //Animation
if (animation == 1) return;
wrapper.cancel();
//1.7 vanilla client is not sending this packet with animation!=1
switch (animation) {
case 104:
animation = 0;
break;
case 105:
animation = 1;
break;
case 3:
animation = 2;
break;
default:
return;
}
PacketWrapper entityAction = PacketWrapper.create(0x0B, null, wrapper.user());
entityAction.write(Type.VAR_INT, entityId);
entityAction.write(Type.VAR_INT, animation);
entityAction.write(Type.VAR_INT, 0);
entityAction.send(Protocol1_7_6_10To1_8.class);
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.ENTITY_ACTION, new PacketHandlers() {
@Override
public void register() {
map(Type.INT, Type.VAR_INT); //Entity Id
handler(wrapper -> wrapper.write(Type.VAR_INT, wrapper.read(Type.BYTE) - 1)); //Action Id
map(Type.INT, Type.VAR_INT); //Action Parameter
handler(wrapper -> {
int action = wrapper.get(Type.VAR_INT, 1);
if (action == 3 || action == 4) {
PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
playerSession.sprinting = action == 3;
PacketWrapper abilitiesPacket = PacketWrapper.create(0x39, null, wrapper.user());
abilitiesPacket.write(Type.BYTE, playerSession.combineAbilities());
abilitiesPacket.write(Type.FLOAT, playerSession.sprinting ? playerSession.flySpeed * 2.0f : playerSession.flySpeed);
abilitiesPacket.write(Type.FLOAT, playerSession.walkSpeed);
abilitiesPacket.scheduleSend(Protocol1_7_6_10To1_8.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.STEER_VEHICLE, new PacketHandlers() {
@Override
public void register() {
map(Type.FLOAT); //Sideways
map(Type.FLOAT); //Forwards
handler(wrapper -> {
boolean jump = wrapper.read(Type.BOOLEAN);
boolean unmount = wrapper.read(Type.BOOLEAN);
short flags = 0;
if (jump) flags += 0x01;
if (unmount) flags += 0x02;
wrapper.write(Type.UNSIGNED_BYTE, flags);
if (unmount) {
EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
if (tracker.spectatingClientEntityId != tracker.clientEntityId()) {
PacketWrapper sneakPacket = PacketWrapper.create(0x0B, null, wrapper.user());
sneakPacket.write(Type.VAR_INT, tracker.clientEntityId());
sneakPacket.write(Type.VAR_INT, 0); //Start sneaking
sneakPacket.write(Type.VAR_INT, 0); //Action Parameter
PacketWrapper unsneakPacket = PacketWrapper.create(0x0B, null, wrapper.user());
unsneakPacket.write(Type.VAR_INT, tracker.clientEntityId());
unsneakPacket.write(Type.VAR_INT, 1); //Stop sneaking
unsneakPacket.write(Type.VAR_INT, 0); //Action Parameter
sneakPacket.scheduleSendToServer(Protocol1_7_6_10To1_8.class);
}
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.UPDATE_SIGN, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
int x = wrapper.read(Type.INT);
int y = wrapper.read(Type.SHORT);
int z = wrapper.read(Type.INT);
wrapper.write(Type.POSITION1_8, new Position(x, y, z));
for (int i = 0; i < 4; i++) {
final String line = wrapper.read(Type.STRING);
wrapper.write(Type.COMPONENT, ComponentUtil.legacyToJson(line));
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_ABILITIES, new PacketHandlers() {
@Override
public void register() {
map(Type.BYTE);
map(Type.FLOAT);
map(Type.FLOAT);
handler(wrapper -> {
PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
if (playerSession.allowFly) {
byte flags = wrapper.get(Type.BYTE, 0);
playerSession.flying = (flags & 2) == 2;
}
wrapper.set(Type.FLOAT, 0, playerSession.flySpeed);
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.TAB_COMPLETE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
create(Type.OPTIONAL_POSITION1_8, null);
handler(wrapper -> {
String msg = wrapper.get(Type.STRING, 0);
if (msg.toLowerCase().startsWith("/stp ")) {
wrapper.cancel();
String[] args = msg.split(" ");
if (args.length <= 2) {
String prefix = args.length == 1 ? "" : args[1];
GameProfileStorage storage = wrapper.user().get(GameProfileStorage.class);
List<GameProfileStorage.GameProfile> profiles = storage.getAllWithPrefix(prefix, true);
PacketWrapper tabComplete = PacketWrapper.create(0x3A, null, wrapper.user());
tabComplete.write(Type.VAR_INT, profiles.size());
for (GameProfileStorage.GameProfile profile : profiles) {
tabComplete.write(Type.STRING, profile.name);
}
tabComplete.scheduleSend(Protocol1_7_6_10To1_8.class);
}
}
});
}
});
//Client Settings
protocol.registerServerbound(ServerboundPackets1_7_2_5.CLIENT_SETTINGS, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
map(Type.BYTE);
map(Type.BYTE);
map(Type.BOOLEAN);
read(Type.BYTE);
handler(wrapper -> {
boolean cape = wrapper.read(Type.BOOLEAN);
wrapper.write(Type.UNSIGNED_BYTE, (short) (cape ? 127 : 126));
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLUGIN_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
read(Type.SHORT); // Length
handler(wrapper -> {
String channel = wrapper.get(Type.STRING, 0);
switch (channel) {
case "MC|TrSel": {
wrapper.passthrough(Type.INT);
wrapper.read(Type.REMAINING_BYTES); // unused data ???
break;
}
case "MC|ItemName": {
byte[] data = wrapper.read(Type.REMAINING_BYTES);
String name = new String(data, StandardCharsets.UTF_8);
wrapper.write(Type.STRING, name);
InventoryTracker windowTracker = wrapper.user().get(InventoryTracker.class);
PacketWrapper updateCost = PacketWrapper.create(0x31, null, wrapper.user());
updateCost.write(Type.UNSIGNED_BYTE, windowTracker.anvilId);
updateCost.write(Type.SHORT, (short) 0);
updateCost.write(Type.SHORT, windowTracker.levelCost);
updateCost.send(Protocol1_7_6_10To1_8.class);
break;
}
case "MC|BEdit":
case "MC|BSign": {
Item book = wrapper.read(Types1_7_6_10.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.write(Type.ITEM1_8, book);
break;
}
case "MC|Brand": {
wrapper.write(Type.STRING, new String(wrapper.read(Type.REMAINING_BYTES), StandardCharsets.UTF_8));
break;
}
}
});
}
});
}
}
@@ -1,253 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.packets;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.Scoreboard;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.util.ChatColorUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ScoreboardPackets1_8 {
public static void register(Protocol1_7_6_10To1_8 protocol) {
protocol.registerClientbound(ClientboundPackets1_8.SCOREBOARD_OBJECTIVE, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
String name = wrapper.passthrough(Type.STRING);
if (name.length() > 16) {
wrapper.set(Type.STRING, 0, name = name.substring(0, 16));
}
byte mode = wrapper.read(Type.BYTE);
Scoreboard scoreboard = wrapper.user().get(Scoreboard.class);
if (mode == 0) {
if (scoreboard.objectiveExists(name)) {
wrapper.cancel();
return;
}
scoreboard.addObjective(name);
} else if (mode == 1) {
if (!scoreboard.objectiveExists(name)) {
wrapper.cancel();
return;
}
if (scoreboard.getColorIndependentSidebar() != null) {
String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent()) {
String sidebar = scoreboard.getColorDependentSidebar().get(color.get());
if (name.equals(sidebar)) {
PacketWrapper sidebarPacket = PacketWrapper.create(0x3D, null, wrapper.user());
sidebarPacket.write(Type.BYTE, (byte) 1);
sidebarPacket.write(Type.STRING, scoreboard.getColorIndependentSidebar());
sidebarPacket.scheduleSend(Protocol1_7_6_10To1_8.class);
}
}
}
scoreboard.removeObjective(name);
} else if (mode == 2) {
if (!scoreboard.objectiveExists(name)) {
wrapper.cancel();
return;
}
}
if (mode == 0 || mode == 2) {
String displayName = wrapper.passthrough(Type.STRING);
if (displayName.length() > 32) {
wrapper.set(Type.STRING, 1, displayName.substring(0, 32));
}
wrapper.read(Type.STRING);
} else {
wrapper.write(Type.STRING, "");
}
wrapper.write(Type.BYTE, mode);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.UPDATE_SCORE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Name
map(Type.VAR_INT, Type.BYTE); // Mode
handler(wrapper -> {
Scoreboard scoreboard = wrapper.user().get(Scoreboard.class);
String name = wrapper.get(Type.STRING, 0);
byte mode = wrapper.get(Type.BYTE, 0);
if (mode == 1) {
name = scoreboard.removeTeamForScore(name);
} else {
name = scoreboard.sendTeamForScore(name);
}
if (name.length() > 16) {
name = ChatColorUtil.stripColor(name);
if (name.length() > 16) {
name = name.substring(0, 16);
}
}
wrapper.set(Type.STRING, 0, name);
String objective = wrapper.read(Type.STRING);
if (objective.length() > 16) {
objective = objective.substring(0, 16);
}
if (mode != 1) {
int score = wrapper.read(Type.VAR_INT);
wrapper.write(Type.STRING, objective);
wrapper.write(Type.INT, score);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.DISPLAY_SCOREBOARD, new PacketHandlers() {
@Override
public void register() {
map(Type.BYTE); // Position
map(Type.STRING); // Score name
handler(wrapper -> {
byte position = wrapper.get(Type.BYTE, 0);
String name = wrapper.get(Type.STRING, 0);
Scoreboard scoreboard = wrapper.user().get(Scoreboard.class);
if (position > 2) { // team specific sidebar
byte receiverTeamColor = (byte) (position - 3);
scoreboard.getColorDependentSidebar().put(receiverTeamColor, name);
String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent() && color.get() == receiverTeamColor) {
position = 1;
} else {
position = -1;
}
} else if (position == 1) { // team independent sidebar
scoreboard.setColorIndependentSidebar(name);
String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent() && scoreboard.getColorDependentSidebar().containsKey(color.get())) {
position = -1;
}
}
if (position == -1) {
wrapper.cancel();
return;
}
wrapper.set(Type.BYTE, 0, position);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.TEAMS, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
handler(wrapper -> {
String team = wrapper.get(Type.STRING, 0);
if (team == null) {
wrapper.cancel();
return;
}
byte mode = wrapper.passthrough(Type.BYTE);
Scoreboard scoreboard = wrapper.user().get(Scoreboard.class);
if (mode != 0 && !scoreboard.teamExists(team)) {
wrapper.cancel();
return;
} else if (mode == 0 && scoreboard.teamExists(team)) {
scoreboard.removeTeam(team);
PacketWrapper remove = PacketWrapper.create(0x3E, null, wrapper.user());
remove.write(Type.STRING, team);
remove.write(Type.BYTE, (byte) 1);
remove.send(Protocol1_7_6_10To1_8.class);
}
if (mode == 0) {
scoreboard.addTeam(team);
} else if (mode == 1) {
scoreboard.removeTeam(team);
}
if (mode == 0 || mode == 2) {
wrapper.passthrough(Type.STRING); // Display name
wrapper.passthrough(Type.STRING); // prefix
wrapper.passthrough(Type.STRING); // suffix
wrapper.passthrough(Type.BYTE); // friendly fire
wrapper.read(Type.STRING); // name tag visibility
byte color = wrapper.read(Type.BYTE);
if (mode == 2 && scoreboard.getTeamColor(team).get() != color) {
String sidebar = scoreboard.getColorDependentSidebar().get(color);
PacketWrapper sidebarPacket = wrapper.create(0x3D);
sidebarPacket.write(Type.BYTE, (byte) 1);
sidebarPacket.write(Type.STRING, sidebar == null ? "" : sidebar);
sidebarPacket.scheduleSend(Protocol1_7_6_10To1_8.class);
}
scoreboard.setTeamColor(team, color);
}
if (mode == 0 || mode == 3 || mode == 4) {
byte color = scoreboard.getTeamColor(team).get();
String[] entries = wrapper.read(Type.STRING_ARRAY);
List<String> entryList = new ArrayList<>();
for (String entry : entries) {
String username = wrapper.user().getProtocolInfo().getUsername();
if (mode == 4) {
if (!scoreboard.isPlayerInTeam(entry, team)) continue;
scoreboard.removePlayerFromTeam(entry, team);
if (entry.equals(username)) {
PacketWrapper sidebarPacket = wrapper.create(0x3D);
sidebarPacket.write(Type.BYTE, (byte) 1);
sidebarPacket.write(Type.STRING, scoreboard.getColorIndependentSidebar() == null ? "" : scoreboard.getColorIndependentSidebar());
sidebarPacket.scheduleSend(Protocol1_7_6_10To1_8.class);
}
} else {
scoreboard.addPlayerToTeam(entry, team);
if (entry.equals(username) && scoreboard.getColorDependentSidebar().containsKey(color)) {
PacketWrapper displayObjective = wrapper.create(0x3D);
displayObjective.write(Type.BYTE, (byte) 1);
displayObjective.write(Type.STRING, scoreboard.getColorDependentSidebar().get(color));
displayObjective.scheduleSend(Protocol1_7_6_10To1_8.class);
}
}
entryList.add(entry);
}
wrapper.write(Type.SHORT, (short) entryList.size());
for (String entry : entryList) {
wrapper.write(Type.STRING, entry);
}
}
});
}
});
}
}
@@ -1,291 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.packets;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.WorldBorderEmulator;
import com.viaversion.viarewind.api.type.chunk.ChunkType1_7_6;
import com.viaversion.viarewind.api.type.chunk.BulkChunkType1_7_6;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.data.ParticleIndex1_7_6_10;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.FixedByteArrayType;
import com.viaversion.viaversion.api.type.types.chunk.BulkChunkType1_8;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_8;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.IdAndData;
public class WorldPackets1_8 {
public static void register(Protocol1_7_6_10To1_8 protocol) {
protocol.registerClientbound(ClientboundPackets1_8.CHUNK_DATA, wrapper -> {
final ClientWorld world = wrapper.user().get(ClientWorld.class);
final Chunk chunk = wrapper.read(ChunkType1_8.forEnvironment(world.getEnvironment()));
protocol.getItemRewriter().handleChunk(chunk);
wrapper.write(ChunkType1_7_6.TYPE, chunk);
});
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_CHANGE, new PacketHandlers() {
@Override
protected void register() {
map(Type.POSITION1_8, Types1_7_6_10.U_BYTE_POSITION); // position
handler(wrapper -> {
int data = wrapper.read(Type.VAR_INT); // block data
data = protocol.getItemRewriter().handleBlockId(data);
wrapper.write(Type.VAR_INT, IdAndData.getId(data)); // block id
wrapper.write(Type.UNSIGNED_BYTE, (short) IdAndData.getData(data)); // block data
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.MULTI_BLOCK_CHANGE, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // chunk x
map(Type.INT); // chunk z
handler(wrapper -> {
final BlockChangeRecord[] records = wrapper.read(Type.BLOCK_CHANGE_RECORD_ARRAY);
wrapper.write(Type.SHORT, (short) records.length); // record count
wrapper.write(Type.INT, records.length * 4); // data array length (position + block id)
for (BlockChangeRecord record : records) {
wrapper.write(Type.SHORT, (short) (record.getSectionX() << 12 | record.getSectionZ() << 8 | record.getY())); // position
wrapper.write(Type.SHORT, (short) protocol.getItemRewriter().handleBlockId(record.getBlockId())); // block id
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_ACTION, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8, Types1_7_6_10.SHORT_POSITION); // position
map(Type.UNSIGNED_BYTE); // type
map(Type.UNSIGNED_BYTE); // data
map(Type.VAR_INT); // block id
}
});
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_BREAK_ANIMATION, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // entity id
map(Type.POSITION1_8, Types1_7_6_10.INT_POSITION); // position
map(Type.BYTE); // progress
}
});
protocol.registerClientbound(ClientboundPackets1_8.MAP_BULK_CHUNK, wrapper -> {
final Chunk[] chunks = wrapper.read(BulkChunkType1_8.TYPE);
for (Chunk chunk : chunks) {
protocol.getItemRewriter().handleChunk(chunk);
}
wrapper.write(BulkChunkType1_7_6.TYPE, chunks);
});
protocol.registerClientbound(ClientboundPackets1_8.EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // effect id
map(Type.POSITION1_8, Types1_7_6_10.BYTE_POSITION); // position
map(Type.INT); // data
map(Type.BOOLEAN); // disable relative volume
}
});
protocol.registerClientbound(ClientboundPackets1_8.SPAWN_PARTICLE, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final int particleId = wrapper.read(Type.INT); // particle id
ParticleIndex1_7_6_10 particle = ParticleIndex1_7_6_10.find(particleId);
if (particle == null) particle = ParticleIndex1_7_6_10.CRIT;
wrapper.write(Type.STRING, particle.name); // particle name
});
read(Type.BOOLEAN); // long distance
map(Type.FLOAT); // x
map(Type.FLOAT); // y
map(Type.FLOAT); // z
map(Type.FLOAT); // offset x
map(Type.FLOAT); // offset y
map(Type.FLOAT); // offset z
map(Type.FLOAT); // particle data
map(Type.INT); // particle count
handler(wrapper -> {
String name = wrapper.get(Type.STRING, 0);
ParticleIndex1_7_6_10 particle = ParticleIndex1_7_6_10.find(name);
if (particle == ParticleIndex1_7_6_10.ICON_CRACK || particle == ParticleIndex1_7_6_10.BLOCK_CRACK || particle == ParticleIndex1_7_6_10.BLOCK_DUST) {
int id = wrapper.read(Type.VAR_INT);
int data = particle == ParticleIndex1_7_6_10.ICON_CRACK ? wrapper.read(Type.VAR_INT) : id / 4096;
id %= 4096;
if (id >= 256 && id <= 422 || id >= 2256 && id <= 2267) { //item
particle = ParticleIndex1_7_6_10.ICON_CRACK;
} else if (id >= 0 && id <= 164 || id >= 170 && id <= 175) {
if (particle == ParticleIndex1_7_6_10.ICON_CRACK)
particle = ParticleIndex1_7_6_10.BLOCK_CRACK;
} else {
wrapper.cancel();
return;
}
name = particle.name + "_" + id + "_" + data;
}
wrapper.set(Type.STRING, 0, name);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.UPDATE_SIGN, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8, Types1_7_6_10.SHORT_POSITION); // position
handler(wrapper -> {
for (int i = 0; i < 4; i++) {
String line = wrapper.read(Type.STRING);
line = ChatUtil.jsonToLegacy(wrapper.user(), line);
line = ChatUtil.removeUnusedColor(line, '0');
if (line.length() > 15) {
line = ChatColorUtil.stripColor(line);
if (line.length() > 15) line = line.substring(0, 15);
}
wrapper.write(Type.STRING, line);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.MAP_DATA, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.cancel();
final int id = wrapper.read(Type.VAR_INT);
final byte scale = wrapper.read(Type.BYTE);
final int iconCount = wrapper.read(Type.VAR_INT);
byte[] icons = new byte[iconCount * 4];
for (int i = 0; i < iconCount; i++) {
final int directionAndType = wrapper.read(Type.BYTE);
icons[i * 4] = (byte) (directionAndType >> 4 & 0xF);
icons[i * 4 + 1] = wrapper.read(Type.BYTE); // x
icons[i * 4 + 2] = wrapper.read(Type.BYTE); // z
icons[i * 4 + 3] = (byte) (directionAndType & 0xF);
}
final short columns = wrapper.read(Type.UNSIGNED_BYTE);
if (columns > 0) {
final short rows = wrapper.read(Type.UNSIGNED_BYTE);
final short x = wrapper.read(Type.UNSIGNED_BYTE);
final short z = wrapper.read(Type.UNSIGNED_BYTE);
final byte[] data = wrapper.read(Type.BYTE_ARRAY_PRIMITIVE);
for (int column = 0; column < columns; column++) {
byte[] columnData = new byte[rows + 3];
columnData[0] = 0;
columnData[1] = (byte) (x + column);
columnData[2] = (byte) z;
for (int i = 0; i < rows; i++) {
columnData[i + 3] = data[column + i * columns];
}
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_DATA, wrapper.user());
mapData.write(Type.VAR_INT, id); // map id
mapData.write(Type.SHORT, (short) columnData.length); // data length
mapData.write(new FixedByteArrayType(columnData.length), columnData); // data
mapData.send(Protocol1_7_6_10To1_8.class);
}
}
if (iconCount > 0) {
final byte[] iconData = new byte[iconCount * 3 + 1];
iconData[0] = 1;
for (int i = 0; i < iconCount; i++) {
iconData[i * 3 + 1] = (byte) (icons[i * 4] << 4 | icons[i * 4 + 3] & 0xF);
iconData[i * 3 + 2] = icons[i * 4 + 1];
iconData[i * 3 + 3] = icons[i * 4 + 2];
}
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_DATA, wrapper.user());
mapData.write(Type.VAR_INT, id); // map id
mapData.write(Type.SHORT, (short) iconData.length); // data length
mapData.write(new FixedByteArrayType(iconData.length), iconData); // data
mapData.send(Protocol1_7_6_10To1_8.class);
}
// Update scale
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_DATA, wrapper.user());
mapData.write(Type.VAR_INT, id); // map id
mapData.write(Type.SHORT, (short) 2); // data length
mapData.write(new FixedByteArrayType(2), new byte[]{2, scale}); // data
mapData.send(Protocol1_7_6_10To1_8.class);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8, Types1_7_6_10.SHORT_POSITION); // position
map(Type.UNSIGNED_BYTE); // action
map(Type.NAMED_COMPOUND_TAG, Types1_7_6_10.COMPRESSED_NBT); // nbt
}
});
protocol.cancelClientbound(ClientboundPackets1_8.SERVER_DIFFICULTY);
protocol.cancelClientbound(ClientboundPackets1_8.COMBAT_EVENT);
protocol.registerClientbound(ClientboundPackets1_8.WORLD_BORDER, null, wrapper -> {
final WorldBorderEmulator emulator = wrapper.user().get(WorldBorderEmulator.class);
wrapper.cancel();
final int action = wrapper.read(Type.VAR_INT);
if (action == 0) { // set size
emulator.setSize(wrapper.read(Type.DOUBLE)); // radius
} else if (action == 1) { // lerp size
emulator.lerpSize(wrapper.read(Type.DOUBLE), wrapper.read(Type.DOUBLE), wrapper.read(Type.VAR_LONG)); // old radius, new radius, speed
} else if (action == 2) { // set center
emulator.setCenter(wrapper.read(Type.DOUBLE), wrapper.read(Type.DOUBLE)); // x, z
} else if (action == 3) { // initialize
emulator.init(
wrapper.read(Type.DOUBLE), wrapper.read(Type.DOUBLE), // x, z
wrapper.read(Type.DOUBLE), wrapper.read(Type.DOUBLE), // old radius, new radius
wrapper.read(Type.VAR_LONG) // speed
);
}
});
}
}
@@ -1,337 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_8to1_9.metadata;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.api.rewriter.VREntityRewriter;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.EntityTracker1_9;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.EulerAngle;
import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10.EntityType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_8;
import com.viaversion.viaversion.api.type.types.version.Types1_9;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.metadata.MetaIndex;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEvent;
import com.viaversion.viaversion.util.IdAndData;
import java.util.UUID;
import java.util.logging.Level;
public class MetadataRewriter1_8To1_9 extends VREntityRewriter<ClientboundPackets1_9, Protocol1_8To1_9> {
private static final byte HAND_ACTIVE_BIT = 0;
private static final byte STATUS_USE_BIT = 4;
public MetadataRewriter1_8To1_9(Protocol1_8To1_9 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
registerJoinGame1_8(ClientboundPackets1_9.JOIN_GAME);
registerRemoveEntities(ClientboundPackets1_9.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_9.ENTITY_METADATA, Types1_9.METADATA_LIST, Types1_8.METADATA_LIST);
protocol.registerClientbound(ClientboundPackets1_9.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
read(Type.UUID); // Entity UUID
map(Type.BYTE); // Entity type
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // X
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Y
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Z
map(Type.BYTE); // Pitch
map(Type.BYTE); // Yaw
map(Type.INT); // Data
// Track entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(id -> EntityTypes1_10.ObjectType.findById(id).orElse(null)));
handler(wrapper -> {
final int entityId = wrapper.get(Type.VAR_INT, 0);
final int entityType = wrapper.get(Type.BYTE, 0);
final EntityTypes1_10.EntityType type = EntityTypes1_10.getTypeFromId(entityType, true);
// Cancel new entities which can't be handled properly
if (type == EntityTypes1_10.EntityType.AREA_EFFECT_CLOUD || type == EntityTypes1_10.EntityType.SPECTRAL_ARROW || type == EntityTypes1_10.EntityType.DRAGON_FIREBALL) {
wrapper.cancel();
return;
}
if (type.is(EntityTypes1_10.EntityType.BOAT)) {
byte yaw = wrapper.get(Type.BYTE, 1);
yaw -= 64;
wrapper.set(Type.BYTE, 1, yaw);
int y = wrapper.get(Type.INT, 1);
y += 10;
wrapper.set(Type.INT, 1, y);
}
int data = wrapper.get(Type.INT, 3);
if (type.isOrHasParent(EntityTypes1_10.EntityType.ARROW) && data != 0) {
wrapper.set(Type.INT, 3, --data);
}
if (type.is(EntityTypes1_10.EntityType.FALLING_BLOCK)) {
int blockId = data & 0xFFF;
int blockData = data >> 12 & 0xF;
IdAndData replace = protocol.getItemRewriter().handleBlock(blockId, blockData);
if (replace != null) {
wrapper.set(Type.INT, 3, replace.getId() | replace.getData() << 12);
}
}
if (data > 0) {
wrapper.passthrough(Type.SHORT); // Velocity x
wrapper.passthrough(Type.SHORT); // Velocity y
wrapper.passthrough(Type.SHORT); // Velocity z
} else {
final short velocityX = wrapper.read(Type.SHORT);
final short velocityY = wrapper.read(Type.SHORT);
final short velocityZ = wrapper.read(Type.SHORT);
final PacketWrapper velocityPacket = PacketWrapper.create(ClientboundPackets1_8.ENTITY_VELOCITY, wrapper.user());
velocityPacket.write(Type.VAR_INT, entityId);
velocityPacket.write(Type.SHORT, velocityX);
velocityPacket.write(Type.SHORT, velocityY);
velocityPacket.write(Type.SHORT, velocityZ);
velocityPacket.scheduleSend(Protocol1_8To1_9.class);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.SPAWN_EXPERIENCE_ORB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // X
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Y
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Z
map(Type.SHORT); // Count
handler(wrapper -> {
final int entityId = wrapper.get(Type.VAR_INT, 0);
wrapper.user().getEntityTracker(Protocol1_8To1_9.class).addEntity(entityId, EntityTypes1_10.EntityType.EXPERIENCE_ORB);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.SPAWN_GLOBAL_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.BYTE); // Type
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // X
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Y
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Z
handler(wrapper -> {
final int entityId = wrapper.get(Type.VAR_INT, 0);
wrapper.user().getEntityTracker(Protocol1_8To1_9.class).addEntity(entityId, EntityTypes1_10.EntityType.LIGHTNING);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
read(Type.UUID); // Entity UUID
map(Type.UNSIGNED_BYTE); // Entity type
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // X
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Y
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Z
map(Type.BYTE); // Yaw
map(Type.BYTE); // Pitch
map(Type.BYTE); // Head pitch
map(Type.SHORT); // Velocity x
map(Type.SHORT); // Velocity y
map(Type.SHORT); // Velocity z
map(Types1_9.METADATA_LIST, Types1_8.METADATA_LIST); // Metadata
handler(getTrackerHandler(Type.UNSIGNED_BYTE, 0));
handler(getMobSpawnRewriter(Types1_8.METADATA_LIST));
}
});
protocol.registerClientbound(ClientboundPackets1_9.SPAWN_PAINTING, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
read(Type.UUID); // Entity UUID
map(Type.STRING); // Title
map(Type.POSITION1_8); // Position
map(Type.BYTE, Type.UNSIGNED_BYTE); // Direction
handler(wrapper -> {
final int entityId = wrapper.get(Type.VAR_INT, 0);
wrapper.user().getEntityTracker(Protocol1_8To1_9.class).addEntity(entityId, EntityTypes1_10.EntityType.PAINTING);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.UUID); // Player UUID
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // X
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Y
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Z
map(Type.BYTE); // Yaw
map(Type.BYTE); // Pitch
create(Type.SHORT, (short) 0); // Current item
map(Types1_9.METADATA_LIST, Types1_8.METADATA_LIST); // Metadata
handler(getTrackerAndMetaHandler(Types1_8.METADATA_LIST, EntityTypes1_10.EntityType.PLAYER));
}
});
}
@Override
protected void registerRewrites() {
// Handle new entities
mapEntityTypeWithData(EntityType.SHULKER, EntityType.MAGMA_CUBE).plainName();
mapEntityTypeWithData(EntityType.SHULKER_BULLET, EntityType.WITCH).plainName();
// Metadata rewrite
filter().handler((event, meta) -> {
try {
handleMetadata(event, meta);
} catch (Exception e) {
if (Via.getManager().isDebug()) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "An error occurred with entity metadata: " + meta, e);
}
event.cancel();
}
});
}
private void handleMetadata(MetaHandlerEvent event, Metadata metadata) {
final EntityTracker1_9 tracker = tracker(event.user());
if (metadata.id() == MetaIndex.ENTITY_STATUS.getIndex()) {
tracker.getStatus().put(event.entityId(), (Byte) metadata.value());
}
final MetaIndex metaIndex = MetaIndex1_8to1_9.searchIndex(event.entityType(), metadata.id());
if (metaIndex == null) {
// Almost certainly bad data, remove it
event.cancel();
return;
}
if (metaIndex.getOldType() == null || metaIndex.getNewType() == null) {
if (metaIndex == MetaIndex.PLAYER_HAND) { // Player eating/aiming/drinking
byte status = (byte) tracker.getStatus().getOrDefault(event.entityId(), 0);
if ((((byte) metadata.value()) & 1 << HAND_ACTIVE_BIT) != 0) {
status = (byte) (status | 1 << STATUS_USE_BIT);
} else {
status = (byte) (status & ~(1 << STATUS_USE_BIT));
}
event.createExtraMeta(new Metadata(MetaIndex.ENTITY_STATUS.getIndex(), MetaType1_8.Byte, status));
}
event.cancel();
return;
}
metadata.setId(metaIndex.getIndex());
metadata.setMetaTypeUnsafe(metaIndex.getOldType());
final Object value = metadata.getValue();
switch (metaIndex.getNewType()) {
case Byte:
if (metaIndex.getOldType() == MetaType1_8.Byte) {
metadata.setValue(value);
}
if (metaIndex.getOldType() == MetaType1_8.Int) {
metadata.setValue(((Byte) value).intValue());
}
break;
case OptUUID:
if (metaIndex.getOldType() != MetaType1_8.String) {
event.cancel();
break;
}
final UUID owner = (UUID) value;
metadata.setValue(owner != null ? owner.toString() : "");
break;
case BlockID:
event.cancel();
event.createExtraMeta(new Metadata(metaIndex.getIndex(), MetaType1_8.Short, ((Integer) value).shortValue()));
break;
case VarInt:
if (metaIndex.getOldType() == MetaType1_8.Byte) {
metadata.setValue(((Integer) value).byteValue());
}
if (metaIndex.getOldType() == MetaType1_8.Short) {
metadata.setValue(((Integer) value).shortValue());
}
if (metaIndex.getOldType() == MetaType1_8.Int) {
metadata.setValue(value);
}
break;
case Float:
case String:
case Chat:
metadata.setValue(value);
break;
case Boolean:
final boolean bool = (Boolean) value;
if (metaIndex == MetaIndex.AGEABLE_CREATURE_AGE) {
metadata.setValue((byte) (bool ? -1 : 0));
} else {
metadata.setValue((byte) (bool ? 1 : 0));
}
break;
case Slot:
metadata.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), (Item) value));
break;
case Position:
final Vector vector = (Vector) value;
metadata.setValue(vector);
break;
case Vector3F:
final EulerAngle angle = (EulerAngle) value;
metadata.setValue(angle);
break;
default:
event.cancel();
break;
}
}
@Override
public EntityType typeFromId(int type) {
return EntityTypes1_10.getTypeFromId(type, false);
}
@Override
public EntityType objectTypeFromId(int type) {
return EntityTypes1_10.getTypeFromId(type, true);
}
}
@@ -1,333 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_8to1_9.packets;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.CooldownStorage;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.EntityTracker1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.LevitationStorage;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.PlayerPositionTracker;
import com.viaversion.viarewind.utils.math.RelativeMoveUtil;
import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.fastutil.ints.IntArrayList;
import com.viaversion.viaversion.libs.fastutil.ints.IntList;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
import com.viaversion.viaversion.util.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class EntityPackets1_9 {
public static void register(final Protocol1_8To1_9 protocol) {
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_STATUS, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity id
handler(wrapper -> {
final byte status = wrapper.read(Type.BYTE);
if (status > 23) { // Remove op permission level 0-4 (24-28)
wrapper.cancel();
return;
}
wrapper.write(Type.BYTE, status);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_POSITION, wrapper -> {
final int entityId = wrapper.passthrough(Type.VAR_INT);
final int deltaX = wrapper.read(Type.SHORT);
final int deltaY = wrapper.read(Type.SHORT);
final int deltaZ = wrapper.read(Type.SHORT);
final Vector[] moves = RelativeMoveUtil.calculateRelativeMoves(wrapper.user(), entityId, deltaX, deltaY, deltaZ);
wrapper.write(Type.BYTE, (byte) moves[0].blockX());
wrapper.write(Type.BYTE, (byte) moves[0].blockY());
wrapper.write(Type.BYTE, (byte) moves[0].blockZ());
final boolean onGround = wrapper.passthrough(Type.BOOLEAN);
if (moves.length > 1) {
final PacketWrapper secondPacket = PacketWrapper.create(ClientboundPackets1_8.ENTITY_POSITION, wrapper.user());
secondPacket.write(Type.VAR_INT, entityId);
secondPacket.write(Type.BYTE, (byte) moves[1].blockX());
secondPacket.write(Type.BYTE, (byte) moves[1].blockY());
secondPacket.write(Type.BYTE, (byte) moves[1].blockZ());
secondPacket.write(Type.BOOLEAN, onGround);
secondPacket.scheduleSend(Protocol1_8To1_9.class);
}
});
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_POSITION_AND_ROTATION, wrapper -> {
final int entityId = wrapper.passthrough(Type.VAR_INT);
final int deltaX = wrapper.read(Type.SHORT);
final int deltaY = wrapper.read(Type.SHORT);
final int deltaZ = wrapper.read(Type.SHORT);
final Vector[] moves = RelativeMoveUtil.calculateRelativeMoves(wrapper.user(), entityId, deltaX, deltaY, deltaZ);
wrapper.write(Type.BYTE, (byte) moves[0].blockX());
wrapper.write(Type.BYTE, (byte) moves[0].blockY());
wrapper.write(Type.BYTE, (byte) moves[0].blockZ());
byte yaw = wrapper.passthrough(Type.BYTE);
final byte pitch = wrapper.passthrough(Type.BYTE);
final boolean onGround = wrapper.passthrough(Type.BOOLEAN);
EntityType type = wrapper.user().getEntityTracker(Protocol1_8To1_9.class).entityType(entityId);
if (type == EntityTypes1_10.EntityType.BOAT) {
yaw -= 64;
wrapper.set(Type.BYTE, 3, yaw);
}
if (moves.length > 1) {
final PacketWrapper secondPacket = PacketWrapper.create(ClientboundPackets1_8.ENTITY_POSITION_AND_ROTATION, wrapper.user());
secondPacket.write(Type.VAR_INT, entityId);
secondPacket.write(Type.BYTE, (byte) moves[1].blockX());
secondPacket.write(Type.BYTE, (byte) moves[1].blockY());
secondPacket.write(Type.BYTE, (byte) moves[1].blockZ());
secondPacket.write(Type.BYTE, yaw);
secondPacket.write(Type.BYTE, pitch);
secondPacket.write(Type.BOOLEAN, onGround);
secondPacket.scheduleSend(Protocol1_8To1_9.class);
}
});
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_ROTATION, wrapper -> {
final int entityId = wrapper.passthrough(Type.VAR_INT);
final EntityType type = wrapper.user().getEntityTracker(Protocol1_8To1_9.class).entityType(entityId);
if (type == EntityTypes1_10.EntityType.BOAT) {
byte yaw = wrapper.read(Type.BYTE);
yaw -= 64;
wrapper.write(Type.BYTE, yaw);
}
});
protocol.registerClientbound(ClientboundPackets1_9.VEHICLE_MOVE, ClientboundPackets1_8.ENTITY_TELEPORT, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
final int vehicle = tracker.getVehicle(tracker.clientEntityId());
if (vehicle == -1) {
wrapper.cancel();
}
wrapper.write(Type.VAR_INT, vehicle);
});
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // X
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Y
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Z
map(Type.FLOAT, Protocol1_8To1_9.DEGREES_TO_ANGLE); // Yaw
map(Type.FLOAT, Protocol1_8To1_9.DEGREES_TO_ANGLE); // Pitch
handler(wrapper -> {
if (wrapper.isCancelled()) return;
final PlayerPositionTracker position = wrapper.user().get(PlayerPositionTracker.class);
double x = wrapper.get(Type.INT, 0) / 32d;
double y = wrapper.get(Type.INT, 1) / 32d;
double z = wrapper.get(Type.INT, 2) / 32d;
position.setPos(x, y, z);
});
create(Type.BOOLEAN, true);
handler(wrapper -> {
final int entityId = wrapper.get(Type.VAR_INT, 0);
final EntityType type = wrapper.user().getEntityTracker(Protocol1_8To1_9.class).entityType(entityId);
if (type == EntityTypes1_10.EntityType.BOAT) {
byte yaw = wrapper.get(Type.BYTE, 1);
yaw -= 64;
wrapper.set(Type.BYTE, 0, yaw);
int y = wrapper.get(Type.INT, 1);
y += 10;
wrapper.set(Type.INT, 1, y);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.REMOVE_ENTITY_EFFECT, wrapper -> {
final int entityId = wrapper.passthrough(Type.VAR_INT);
final int effectId = wrapper.passthrough(Type.BYTE);
if (effectId > 23) { // Throw away new effects
wrapper.cancel();
}
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
if (effectId == 25 && entityId == tracker.clientEntityId()) {
wrapper.user().get(LevitationStorage.class).setActive(false);
}
});
protocol.registerClientbound(ClientboundPackets1_9.ATTACH_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Attached entity id
map(Type.INT); // Holding entity id
create(Type.BOOLEAN, true); // Leash
}
});
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_EQUIPMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
handler(wrapper -> {
// todo check if this is correct for the own player
int slot = wrapper.read(Type.VAR_INT);
if (slot == 1) {
wrapper.cancel();
} else if (slot > 1) {
slot -= 1;
}
wrapper.write(Type.SHORT, (short) slot);
});
map(Type.ITEM1_8); // Item
handler(wrapper -> protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.get(Type.ITEM1_8, 0)));
}
});
protocol.registerClientbound(ClientboundPackets1_9.SET_PASSENGERS, null, wrapper -> {
wrapper.cancel();
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
final int vehicle = wrapper.read(Type.VAR_INT);
final IntList oldPassengers = tracker.getPassengers(vehicle);
final int count = wrapper.read(Type.VAR_INT);
final IntList passengers = new IntArrayList();
for (int i = 0; i < count; i++) {
passengers.add(wrapper.read(Type.VAR_INT));
}
tracker.setPassengers(vehicle, passengers);
if (!oldPassengers.isEmpty()) {
for (Integer passenger : oldPassengers) {
final PacketWrapper detach = PacketWrapper.create(ClientboundPackets1_8.ATTACH_ENTITY, wrapper.user());
detach.write(Type.INT, passenger); // Attached entity id
detach.write(Type.INT, -1); // Holding entity id
detach.write(Type.BOOLEAN, false); // Leash
detach.scheduleSend(Protocol1_8To1_9.class);
}
}
for (int i = 0; i < count; i++) {
final int attachedEntityId = passengers.getInt(i);
final int holdingEntityId = i == 0 ? vehicle : passengers.getInt(i - 1);
final PacketWrapper attach = PacketWrapper.create(ClientboundPackets1_8.ATTACH_ENTITY, wrapper.user());
attach.write(Type.INT, attachedEntityId);
attach.write(Type.INT, holdingEntityId);
attach.write(Type.BOOLEAN, false); // Leash
attach.scheduleSend(Protocol1_8To1_9.class);
}
});
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_TELEPORT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // X
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Y
map(Type.DOUBLE, Protocol1_8To1_9.DOUBLE_TO_INT_TIMES_32); // Z
map(Type.BYTE); // Yaw
map(Type.BYTE); // Pitch
map(Type.BOOLEAN); // On ground
handler(wrapper -> {
final int entityId = wrapper.get(Type.VAR_INT, 0);
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
if (tracker.entityType(entityId) == EntityTypes1_10.EntityType.BOAT) {
byte yaw = wrapper.get(Type.BYTE, 1);
yaw -= 64;
wrapper.set(Type.BYTE, 0, yaw);
int y = wrapper.get(Type.INT, 1);
y += 10;
wrapper.set(Type.INT, 1, y);
}
tracker.resetEntityOffset(entityId);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_PROPERTIES, wrapper -> {
final int entityId = wrapper.passthrough(Type.VAR_INT);
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
final boolean player = entityId == tracker.clientEntityId();
// Throw away new attributes and track attack speed
int removed = 0;
final int size = wrapper.passthrough(Type.INT);
for (int i = 0; i < size; i++) {
final String key = wrapper.read(Type.STRING);
final double value = wrapper.read(Type.DOUBLE);
final int modifierSize = wrapper.read(Type.VAR_INT);
final boolean valid = protocol.getItemRewriter().VALID_ATTRIBUTES.contains(key);
if (valid) {
wrapper.write(Type.STRING, key);
wrapper.write(Type.DOUBLE, value);
wrapper.write(Type.VAR_INT, modifierSize);
}
final List<Pair<Byte, Double>> modifiers = new ArrayList<>();
for (int j = 0; j < modifierSize; j++) {
final UUID modifierId = wrapper.read(Type.UUID); // UUID
final double amount = wrapper.read(Type.DOUBLE); // Amount
final byte operation = wrapper.read(Type.BYTE); // Operation
if (valid) {
wrapper.write(Type.UUID, modifierId);
wrapper.write(Type.DOUBLE, amount);
wrapper.write(Type.BYTE, operation);
}
modifiers.add(new Pair<>(operation, amount));
}
if (!valid) {
if (player && key.equals("generic.attackSpeed")) {
wrapper.user().get(CooldownStorage.class).setAttackSpeed(value, modifiers);
}
removed++;
}
}
wrapper.set(Type.INT, 0, size - removed);
});
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_EFFECT, wrapper -> {
final int entityId = wrapper.passthrough(Type.VAR_INT);
final int effectId = wrapper.passthrough(Type.BYTE);
final byte amplifier = wrapper.passthrough(Type.BYTE);
if (effectId > 23) { // Throw away new effects
wrapper.cancel();
}
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
if (effectId == 25 && entityId == tracker.clientEntityId()) {
final LevitationStorage levitation = wrapper.user().get(LevitationStorage.class);
levitation.setActive(true);
levitation.setAmplifier(amplifier);
}
});
}
}
@@ -1,537 +0,0 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.protocol1_8to1_9.packets;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.*;
import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_8;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.protocols.protocol1_8.ServerboundPackets1_8;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ServerboundPackets1_9;
import java.util.ArrayList;
import java.util.UUID;
public class PlayerPackets1_9 {
public static void register(final Protocol1_8To1_9 protocol) {
protocol.registerClientbound(ClientboundPackets1_9.BOSSBAR, null, wrapper -> {
wrapper.cancel();
final BossBarStorage bossbar = wrapper.user().get(BossBarStorage.class);
final UUID uuid = wrapper.read(Type.UUID);
final int action = wrapper.read(Type.VAR_INT);
if (action == 0 /* add */) {
final JsonElement title = wrapper.read(Type.COMPONENT);
final float health = wrapper.read(Type.FLOAT);
wrapper.read(Type.VAR_INT); // Color
wrapper.read(Type.VAR_INT); // Division
wrapper.read(Type.UNSIGNED_BYTE); // Flags
bossbar.add(uuid, ChatUtil.jsonToLegacy(wrapper.user(), title), health);
} else if (action == 1 /* remove */) {
bossbar.remove(uuid);
} else if (action == 2 /* update health */) {
final float health = wrapper.read(Type.FLOAT);
bossbar.updateHealth(uuid, health);
} else if (action == 3 /* update title */) {
final JsonElement title = wrapper.read(Type.COMPONENT);
bossbar.updateTitle(uuid, ChatUtil.jsonToLegacy(wrapper.user(), title));
}
});
protocol.registerClientbound(ClientboundPackets1_9.TEAMS, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Team name
map(Type.BYTE); // Mode
handler(wrapper -> {
final byte mode = wrapper.get(Type.BYTE, 0);
if (mode == 0 /* create team */ || mode == 2 /* update team info */) {
wrapper.passthrough(Type.STRING); // Display name
wrapper.passthrough(Type.STRING); // Prefix
wrapper.passthrough(Type.STRING); // Suffix
wrapper.passthrough(Type.BYTE); // Friendly fire
wrapper.passthrough(Type.STRING); // Name tag visibility
wrapper.read(Type.STRING); // Collision rule
}
});
}
});
protocol.cancelClientbound(ClientboundPackets1_9.COOLDOWN);
protocol.registerClientbound(ClientboundPackets1_9.PLUGIN_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Channel
handlerSoftFail(wrapper -> {
final String channel = wrapper.get(Type.STRING, 0);
if (channel.equals("MC|TrList")) {
wrapper.passthrough(Type.INT); // Window id
int size;
if (wrapper.isReadable(Type.BYTE, 0)) {
size = wrapper.passthrough(Type.BYTE);
} else {
size = wrapper.passthrough(Type.UNSIGNED_BYTE);
}
final ItemRewriter<?> itemRewriter = protocol.getItemRewriter();
for (int i = 0; i < size; i++) {
wrapper.write(Type.ITEM1_8, itemRewriter.handleItemToClient(wrapper.user(), wrapper.read(Type.ITEM1_8))); // Buy item 1
wrapper.write(Type.ITEM1_8, itemRewriter.handleItemToClient(wrapper.user(), wrapper.read(Type.ITEM1_8))); // Buy item 3
boolean has3Items = wrapper.passthrough(Type.BOOLEAN);
if (has3Items) {
wrapper.write(Type.ITEM1_8, itemRewriter.handleItemToClient(wrapper.user(), wrapper.read(Type.ITEM1_8))); // Buy item 2
}
wrapper.passthrough(Type.BOOLEAN); //Unavailable
wrapper.passthrough(Type.INT); //Uses
wrapper.passthrough(Type.INT); //Max Uses
}
} else if (channel.equals("MC|BOpen")) {
wrapper.read(Type.VAR_INT);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.PLAYER_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE); // X
map(Type.DOUBLE); // Feet y
map(Type.DOUBLE); // Z
map(Type.FLOAT); // Yaw
map(Type.FLOAT); // Pitch
map(Type.BYTE); // Relative arguments
handler(wrapper -> {
final PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
pos.setConfirmId(wrapper.read(Type.VAR_INT));
byte flags = wrapper.get(Type.BYTE, 0);
double x = wrapper.get(Type.DOUBLE, 0);
double y = wrapper.get(Type.DOUBLE, 1);
double z = wrapper.get(Type.DOUBLE, 2);
float yaw = wrapper.get(Type.FLOAT, 0);
float pitch = wrapper.get(Type.FLOAT, 1);
wrapper.set(Type.BYTE, 0, (byte) 0);
if (flags != 0) {
if ((flags & 0x01) != 0) {
x += pos.getPosX();
wrapper.set(Type.DOUBLE, 0, x);
}
if ((flags & 0x02) != 0) {
y += pos.getPosY();
wrapper.set(Type.DOUBLE, 1, y);
}
if ((flags & 0x04) != 0) {
z += pos.getPosZ();
wrapper.set(Type.DOUBLE, 2, z);
}
if ((flags & 0x08) != 0) {
yaw += pos.getYaw();
wrapper.set(Type.FLOAT, 0, yaw);
}
if ((flags & 0x10) != 0) {
pitch += pos.getPitch();
wrapper.set(Type.FLOAT, 1, pitch);
}
}
pos.setPos(x, y, z);
pos.setYaw(yaw);
pos.setPitch(pitch);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Dimension
handler(wrapper -> wrapper.user().get(BossBarStorage.class).reset());
handler(wrapper -> {
final ClientWorld world = wrapper.user().get(ClientWorld.class);
world.setEnvironment(wrapper.get(Type.INT, 0));
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.CHAT_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Message
handler(wrapper -> {
if (!ViaRewind.getConfig().isEnableOffhand()) {
return;
}
final String msg = wrapper.get(Type.STRING, 0);
if (msg.toLowerCase().trim().startsWith(ViaRewind.getConfig().getOffhandCommand())) {
wrapper.cancel();
final PacketWrapper swapItems = PacketWrapper.create(ServerboundPackets1_9.PLAYER_DIGGING, wrapper.user());
swapItems.write(Type.VAR_INT, 6);
swapItems.write(Type.POSITION1_8, new Position(0, 0, 0));
swapItems.write(Type.BYTE, (byte) 255);
swapItems.sendToServer(Protocol1_8To1_9.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.INTERACT_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Target
map(Type.VAR_INT); // Type
handler(wrapper -> {
final int type = wrapper.get(Type.VAR_INT, 1);
if (type == 2 /* attack */) {
wrapper.passthrough(Type.FLOAT); // Target x
wrapper.passthrough(Type.FLOAT); // Target y
wrapper.passthrough(Type.FLOAT); // Target z
}
if (type == 2 /* attack */ || type == 0 /* interact */) {
wrapper.write(Type.VAR_INT, 0); // Hand
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_MOVEMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.BOOLEAN); // On ground
handler(wrapper -> {
wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
if (tracker.isInsideVehicle(tracker.clientEntityId())) {
wrapper.cancel();
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE); // X
map(Type.DOUBLE); // Feet y
map(Type.DOUBLE); // Z
map(Type.BOOLEAN); // On ground
handler(wrapper -> {
wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
final PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
if (pos.getConfirmId() != -1) {
return;
}
pos.setPos(wrapper.get(Type.DOUBLE, 0), wrapper.get(Type.DOUBLE, 1), wrapper.get(Type.DOUBLE, 2));
pos.setOnGround(wrapper.get(Type.BOOLEAN, 0));
});
handler(wrapper -> wrapper.user().get(BossBarStorage.class).updateLocation());
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_ROTATION, new PacketHandlers() {
@Override
public void register() {
map(Type.FLOAT);
map(Type.FLOAT);
map(Type.BOOLEAN);
handler(wrapper -> {
wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
if (pos.getConfirmId() != -1) return;
pos.setYaw(wrapper.get(Type.FLOAT, 0));
pos.setPitch(wrapper.get(Type.FLOAT, 1));
pos.setOnGround(wrapper.get(Type.BOOLEAN, 0));
});
handler(wrapper -> wrapper.user().get(BossBarStorage.class).updateLocation());
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_POSITION_AND_ROTATION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.FLOAT);
map(Type.FLOAT);
map(Type.BOOLEAN);
handler(wrapper -> {
wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
double x = wrapper.get(Type.DOUBLE, 0);
double y = wrapper.get(Type.DOUBLE, 1);
double z = wrapper.get(Type.DOUBLE, 2);
float yaw = wrapper.get(Type.FLOAT, 0);
float pitch = wrapper.get(Type.FLOAT, 1);
boolean onGround = wrapper.get(Type.BOOLEAN, 0);
PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
if (pos.getConfirmId() != -1) {
if (pos.getPosX() == x && pos.getPosY() == y && pos.getPosZ() == z
&& pos.getYaw() == yaw && pos.getPitch() == pitch) {
PacketWrapper confirmTeleport = wrapper.create(0x00);
confirmTeleport.write(Type.VAR_INT, pos.getConfirmId());
confirmTeleport.sendToServer(Protocol1_8To1_9.class);
pos.setConfirmId(-1);
}
} else {
pos.setPos(x, y, z);
pos.setYaw(yaw);
pos.setPitch(pitch);
pos.setOnGround(onGround);
wrapper.user().get(BossBarStorage.class).updateLocation();
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_DIGGING, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.POSITION1_8);
handler(wrapper -> {
int state = wrapper.get(Type.VAR_INT, 0);
if (state == 0) {
wrapper.user().get(BlockPlaceDestroyTracker.class).setMining();
} else if (state == 2) {
BlockPlaceDestroyTracker tracker = wrapper.user().get(BlockPlaceDestroyTracker.class);
tracker.setMining();
tracker.setLastMining(System.currentTimeMillis() + 100);
wrapper.user().get(CooldownStorage.class).setLastHit(0);
} else if (state == 1) {
BlockPlaceDestroyTracker tracker = wrapper.user().get(BlockPlaceDestroyTracker.class);
tracker.setMining();
tracker.setLastMining(0);
wrapper.user().get(CooldownStorage.class).hit();
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_BLOCK_PLACEMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8);
map(Type.BYTE, Type.VAR_INT);
read(Type.ITEM1_8);
create(Type.VAR_INT, 0); //Main Hand
map(Type.BYTE, Type.UNSIGNED_BYTE);
map(Type.BYTE, Type.UNSIGNED_BYTE);
map(Type.BYTE, Type.UNSIGNED_BYTE);
handler(wrapper -> {
if (wrapper.get(Type.VAR_INT, 0) == -1) {
wrapper.cancel();
PacketWrapper useItem = PacketWrapper.create(0x1D, null, wrapper.user());
useItem.write(Type.VAR_INT, 0);
useItem.sendToServer(Protocol1_8To1_9.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.HELD_ITEM_CHANGE, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> wrapper.user().get(CooldownStorage.class).hit());
}
});
protocol.registerServerbound(ServerboundPackets1_8.ANIMATION, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.cancel();
/* We have to add ArmAnimation to a queue to be sent on PacketPlayInFlying. In 1.9,
* PacketPlayInArmAnimation is sent after PacketPlayInUseEntity, not before like it used to be.
* However, all packets are sent before PacketPlayInFlying. We'd just do a normal delay, but
* it would cause the packet to be sent after PacketPlayInFlying, potentially false flagging
* anticheats that check for this behavior from clients. Since all packets are sent before
* PacketPlayInFlying, if we queue it to be sent right before PacketPlayInFlying is processed,
* we can be certain it will be sent after PacketPlayInUseEntity */
wrapper.cancel();
final PacketWrapper delayedPacket = PacketWrapper.create(0x1A, null, wrapper.user());
delayedPacket.write(Type.VAR_INT, 0); //Main Hand
wrapper.user().get(PlayerPositionTracker.class).queueAnimation(delayedPacket);
});
handler(wrapper -> {
wrapper.user().get(BlockPlaceDestroyTracker.class).updateMining();
wrapper.user().get(CooldownStorage.class).hit();
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.ENTITY_ACTION, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.VAR_INT);
map(Type.VAR_INT);
handler(wrapper -> {
int action = wrapper.get(Type.VAR_INT, 1);
if (action == 6) {
wrapper.set(Type.VAR_INT, 1, 7);
} else if (action == 0) {
PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
if (!pos.isOnGround()) {
PacketWrapper elytra = PacketWrapper.create(0x14, null, wrapper.user());
elytra.write(Type.VAR_INT, wrapper.get(Type.VAR_INT, 0));
elytra.write(Type.VAR_INT, 8);
elytra.write(Type.VAR_INT, 0);
elytra.scheduleSendToServer(Protocol1_8To1_9.class);
}
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.STEER_VEHICLE, new PacketHandlers() {
@Override
public void register() {
map(Type.FLOAT);
map(Type.FLOAT);
map(Type.UNSIGNED_BYTE);
handler(wrapper -> {
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
final int vehicle = tracker.getVehicle(tracker.clientEntityId());
if (vehicle != -1 && tracker.entityType(vehicle) == EntityTypes1_10.EntityType.BOAT) {
PacketWrapper steerBoat = PacketWrapper.create(0x11, null, wrapper.user());
float left = wrapper.get(Type.FLOAT, 0);
float forward = wrapper.get(Type.FLOAT, 1);
steerBoat.write(Type.BOOLEAN, forward != 0.0f || left < 0.0f);
steerBoat.write(Type.BOOLEAN, forward != 0.0f || left > 0.0f);
steerBoat.scheduleSendToServer(Protocol1_8To1_9.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.UPDATE_SIGN, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8);
handler(wrapper -> {
for (int i = 0; i < 4; i++) {
wrapper.write(Type.STRING, ChatUtil.jsonToLegacy(wrapper.user(), wrapper.read(Type.COMPONENT)));
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.TAB_COMPLETE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
create(Type.BOOLEAN, false);
map(Type.OPTIONAL_POSITION1_8);
}
});
protocol.registerServerbound(ServerboundPackets1_8.CLIENT_SETTINGS, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
map(Type.BYTE);
map(Type.BYTE, Type.VAR_INT);
map(Type.BOOLEAN);
map(Type.UNSIGNED_BYTE);
create(Type.VAR_INT, 1);
handler(wrapper -> {
short flags = wrapper.get(Type.UNSIGNED_BYTE, 0);
PacketWrapper updateSkin = PacketWrapper.create(0x1C, null, wrapper.user());
updateSkin.write(Type.VAR_INT, wrapper.user().getEntityTracker(Protocol1_8To1_9.class).clientEntityId());
ArrayList<Metadata> metadata = new ArrayList<>();
metadata.add(new Metadata(10, MetaType1_8.Byte, (byte) flags));
updateSkin.write(Types1_8.METADATA_LIST, metadata);
updateSkin.scheduleSend(Protocol1_8To1_9.class);
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLUGIN_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
handlerSoftFail(wrapper -> {
String channel = wrapper.get(Type.STRING, 0);
if (channel.equals("MC|BEdit") || channel.equals("MC|BSign")) {
Item book = wrapper.passthrough(Type.ITEM);
book.setIdentifier(386);
CompoundTag tag = book.tag();
if (tag.contains("pages")) {
ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
if (pages.size() > ViaRewind.getConfig().getMaxBookPages()) {
wrapper.user().disconnect("Too many book pages");
return;
}
for (int i = 0; i < pages.size(); i++) {
StringTag page = pages.get(i);
String value = page.getValue();
if (value.length() > ViaRewind.getConfig().getMaxBookPageSize()) {
wrapper.user().disconnect("Book page too large");
return;
}
value = ChatUtil.jsonToLegacy(wrapper.user(), value);
page.setValue(value);
}
}
} else if (channel.equals("MC|AdvCdm")) {
wrapper.set(Type.STRING, 0, "MC|AdvCmd");
}
});
}
});
}
}
@@ -15,31 +15,33 @@
* 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.protocol1_7_2_5to1_7_6_10;
package com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
import com.viaversion.viarewind.api.type.version.Types1_7_6_10;
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ClientboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ServerboundPackets1_7_2_5;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Protocol1_7_2_5To1_7_6_10 extends AbstractProtocol<ClientboundPackets1_7_2_5, ClientboundPackets1_7_2_5, ServerboundPackets1_7_2_5, ServerboundPackets1_7_2_5> {
public class Protocol1_7_6_10To1_7_2_5 extends AbstractProtocol<ClientboundPackets1_7_2_5, ClientboundPackets1_7_2_5, ServerboundPackets1_7_2_5, ServerboundPackets1_7_2_5> {
public static final ValueTransformer<String, String> REMOVE_DASHES = new ValueTransformer<String, String>(Type.STRING) {
public static final ValueTransformer<String, String> REMOVE_DASHES = new ValueTransformer<>(Types.STRING) {
@Override
public String transform(PacketWrapper wrapper, String s) {
return s.replace("-", "");
}
};
public Protocol1_7_2_5To1_7_6_10() {
public Protocol1_7_6_10To1_7_2_5() {
super(ClientboundPackets1_7_2_5.class, ClientboundPackets1_7_2_5.class, ServerboundPackets1_7_2_5.class, ServerboundPackets1_7_2_5.class);
}
@@ -48,53 +50,53 @@ public class Protocol1_7_2_5To1_7_6_10 extends AbstractProtocol<ClientboundPacke
this.registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE.getId(), ClientboundLoginPackets.GAME_PROFILE.getId(), new PacketHandlers() {
@Override
public void register() {
map(Type.STRING, REMOVE_DASHES); // Uuid
map(Type.STRING); // Name
map(Types.STRING, REMOVE_DASHES); // Uuid
map(Types.STRING); // Name
}
});
this.registerClientbound(ClientboundPackets1_7_2_5.SPAWN_PLAYER, new PacketHandlers() {
this.registerClientbound(ClientboundPackets1_7_2_5.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.STRING, REMOVE_DASHES); // Uuid
map(Type.STRING); // Name
map(Types.VAR_INT); // Entity id
map(Types.STRING, REMOVE_DASHES); // Uuid
map(Types.STRING); // Name
handler(wrapper -> {
final int size = wrapper.read(Type.VAR_INT); // Data count
final int size = wrapper.read(Types.VAR_INT); // Data count
for (int i = 0; i < size; i++) {
wrapper.read(Type.STRING); // Data name
wrapper.read(Type.STRING); // Data value
wrapper.read(Type.STRING); // Data signature
wrapper.read(Types.STRING); // Data name
wrapper.read(Types.STRING); // Data value
wrapper.read(Types.STRING); // Data signature
}
});
map(Type.INT); // X
map(Type.INT); // Y
map(Type.INT); // Z
map(Type.BYTE); // Yaw
map(Type.BYTE); // Pitch
map(Type.SHORT); // Item in hand
map(Types1_7_6_10.METADATA_LIST); // Metadata
map(Types.INT); // X
map(Types.INT); // Y
map(Types.INT); // Z
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
map(Types.SHORT); // Item in hand
map(Types1_7_6_10.ENTITY_DATA_LIST); // Entity data
}
});
this.registerClientbound(ClientboundPackets1_7_2_5.TEAMS, new PacketHandlers() {
this.registerClientbound(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Team name
map(Type.BYTE); // Mode
map(Types.STRING); // Team name
map(Types.BYTE); // Mode
handler(wrapper -> {
final byte mode = wrapper.get(Type.BYTE, 0);
final byte mode = wrapper.get(Types.BYTE, 0);
if (mode == 0 || mode == 2) { // Team is created or information is updated
wrapper.passthrough(Type.STRING); // Team display name
wrapper.passthrough(Type.STRING); // Team prefix
wrapper.passthrough(Type.STRING); // Team suffix
wrapper.passthrough(Type.BYTE); // Friendly fire
wrapper.passthrough(Types.STRING); // Team display name
wrapper.passthrough(Types.STRING); // Team prefix
wrapper.passthrough(Types.STRING); // Team suffix
wrapper.passthrough(Types.BYTE); // Friendly fire
}
if (mode == 0 || mode == 3 || mode == 4) { // Team is created, player is added or player is removed
List<String> entryList = new ArrayList<>();
final int size = wrapper.read(Type.SHORT);
final int size = wrapper.read(Types.SHORT);
for (int i = 0; i < size; i++) {
entryList.add(wrapper.read(Type.STRING));
entryList.add(wrapper.read(Types.STRING));
}
entryList = entryList.stream()
@@ -102,9 +104,9 @@ public class Protocol1_7_2_5To1_7_6_10 extends AbstractProtocol<ClientboundPacke
.distinct() // remove duplicates
.collect(Collectors.toList());
wrapper.write(Type.SHORT, (short) entryList.size());
wrapper.write(Types.SHORT, (short) entryList.size());
for (String entry : entryList) {
wrapper.write(Type.STRING, entry);
wrapper.write(Types.STRING, entry);
}
}
});
@@ -0,0 +1,98 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
public enum ClientboundPackets1_7_2_5 implements ClientboundPacketType {
KEEP_ALIVE, // 0x00
LOGIN, // 0x01
CHAT, // 0x02
SET_TIME, // 0x03
SET_EQUIPPED_ITEM, // 0x04
SET_DEFAULT_SPAWN_POSITION, // 0x05
SET_HEALTH, // 0x06
RESPAWN, // 0x07
PLAYER_POSITION, // 0x08
SET_CARRIED_ITEM, // 0x09
PLAYER_SLEEP, // 0x0A
ANIMATE, // 0x0B
ADD_PLAYER, // 0x0C
TAKE_ITEM_ENTITY, // 0x0D
ADD_ENTITY, // 0x0E
ADD_MOB, // 0x0F
ADD_PAINTING, // 0x10
ADD_EXPERIENCE_ORB, // 0x11
SET_ENTITY_MOTION, // 0x12
REMOVE_ENTITIES, // 0x13
MOVE_ENTITY, // 0x14
MOVE_ENTITY_POS, // 0x15
MOVE_ENTITY_ROT, // 0x16
MOVE_ENTITY_POS_ROT, // 0x17
TELEPORT_ENTITY, // 0x18
ROTATE_HEAD, // 0x19
ENTITY_EVENT, // 0x1A
SET_ENTITY_LINK, // 0x1B
SET_ENTITY_DATA, // 0x1C
UPDATE_MOB_EFFECT, // 0x1D
REMOVE_MOB_EFFECT, // 0x1E
SET_EXPERIENCE, // 0x1F
UPDATE_ATTRIBUTES, // 0x20
LEVEL_CHUNK, // 0x21
CHUNK_BLOCKS_UPDATE, // 0x22
BLOCK_UPDATE, // 0x23
BLOCK_EVENT, // 0x24
BLOCK_DESTRUCTION, // 0x25
MAP_BULK_CHUNK, // 0x26
EXPLODE, // 0x27
LEVEL_EVENT, // 0x28
CUSTOM_SOUND, // 0x29
LEVEL_PARTICLES, // 0x2A
GAME_EVENT, // 0x2B
ADD_GLOBAL_ENTITY, // 0x2C
OPEN_SCREEN, // 0x2D
CONTAINER_CLOSE, // 0x2E
CONTAINER_SET_SLOT, // 0x2F
CONTAINER_SET_CONTENT, // 0x30
CONTAINER_SET_DATA, // 0x31
CONTAINER_ACK, // 0x32
UPDATE_SIGN, // 0x33
MAP_ITEM_DATA, // 0x34
BLOCK_ENTITY_DATA, // 0x35
OPEN_SIGN_EDITOR, // 0x36
AWARD_STATS, // 0x37
PLAYER_INFO, // 0x38
PLAYER_ABILITIES, // 0x39
COMMAND_SUGGESTIONS, // 0x3A
SET_OBJECTIVE, // 0x3B
SET_SCORE, // 0x3C
SET_DISPLAY_OBJECTIVE, // 0x3D
SET_PLAYER_TEAM, // 0x3E
CUSTOM_PAYLOAD, // 0x3F
DISCONNECT; // 0x40
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -15,35 +15,35 @@
* 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.protocol1_7_2_5to1_7_6_10;
package com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
public enum ServerboundPackets1_7_2_5 implements ServerboundPacketType {
KEEP_ALIVE, // 0x00
CHAT_MESSAGE, // 0x01
INTERACT_ENTITY, // 0x02
PLAYER_MOVEMENT, // 0x03
PLAYER_POSITION, // 0x04
PLAYER_ROTATION, // 0x05
PLAYER_POSITION_AND_ROTATION, // 0x06
PLAYER_DIGGING, // 0x07
PLAYER_BLOCK_PLACEMENT, // 0x08
HELD_ITEM_CHANGE, // 0x09
ANIMATION, // 0x0A
ENTITY_ACTION, // 0x0B
STEER_VEHICLE, // 0x0C
CLOSE_WINDOW, // 0x0D
CLICK_WINDOW, // 0x0E
WINDOW_CONFIRMATION, // 0x0F
CREATIVE_INVENTORY_ACTION, // 0x10
CLICK_WINDOW_BUTTON, // 0x11
UPDATE_SIGN, // 0x12
CHAT, // 0x01
INTERACT, // 0x02
MOVE_PLAYER_STATUS_ONLY, // 0x03
MOVE_PLAYER_POS, // 0x04
MOVE_PLAYER_ROT, // 0x05
MOVE_PLAYER_POS_ROT, // 0x06
PLAYER_ACTION, // 0x07
USE_ITEM_ON, // 0x08
SET_CARRIED_ITEM, // 0x09
SWING, // 0x0A
PLAYER_COMMAND, // 0x0B
PLAYER_INPUT, // 0x0C
CONTAINER_CLOSE, // 0x0D
CONTAINER_CLICK, // 0x0E
CONTAINER_ACK, // 0x0F
SET_CREATIVE_MODE_SLOT, // 0x10
CONTAINER_BUTTON_CLICK, // 0x11
SIGN_UPDATE, // 0x12
PLAYER_ABILITIES, // 0x13
TAB_COMPLETE, // 0x14
CLIENT_SETTINGS, // 0x15
CLIENT_STATUS, // 0x16
PLUGIN_MESSAGE; // 0x17
COMMAND_SUGGESTION, // 0x14
CLIENT_INFORMATION, // 0x15
CLIENT_COMMAND, // 0x16
CUSTOM_PAYLOAD; // 0x17
@Override
public int getId() {
@@ -15,19 +15,19 @@
* 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.protocol1_7_6_10to1_8;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.api.data.RewindMappings;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ClientboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ServerboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.metadata.MetadataRewriter1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.packets.*;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.provider.CompressionHandlerProvider;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.provider.compression.TrackingCompressionHandlerProvider;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.*;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.task.WorldBorderUpdateTask;
import com.viaversion.viarewind.api.data.RewindMappingData;
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ClientboundPackets1_7_2_5;
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.rewriter.EntityPacketRewriter1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter.*;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.CompressionHandlerProvider;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.compression.TrackingCompressionHandlerProvider;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.*;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.task.WorldBorderUpdateTask;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
@@ -36,48 +36,48 @@ import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.protocol1_8.ServerboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
import java.util.concurrent.TimeUnit;
public class Protocol1_7_6_10To1_8 extends BackwardsProtocol<ClientboundPackets1_8, ClientboundPackets1_7_2_5, ServerboundPackets1_8, ServerboundPackets1_7_2_5> {
public class Protocol1_8To1_7_6_10 extends BackwardsProtocol<ClientboundPackets1_8, ClientboundPackets1_7_2_5, ServerboundPackets1_8, ServerboundPackets1_7_2_5> {
public static final RewindMappings MAPPINGS = new RewindMappings("1.8", "1.7.10");
public static final RewindMappingData MAPPINGS = new RewindMappingData("1.8", "1.7.10");
private final BlockItemPackets1_8 itemRewriter = new BlockItemPackets1_8(this);
private final MetadataRewriter1_7_6_10To1_8 metadataRewriter = new MetadataRewriter1_7_6_10To1_8(this);
private final BlockItemPacketRewriter1_8 itemRewriter = new BlockItemPacketRewriter1_8(this);
private final EntityPacketRewriter1_8 entityRewriter = new EntityPacketRewriter1_8(this);
public Protocol1_7_6_10To1_8() {
public Protocol1_8To1_7_6_10() {
super(ClientboundPackets1_8.class, ClientboundPackets1_7_2_5.class, ServerboundPackets1_8.class, ServerboundPackets1_7_2_5.class);
}
@Override
protected void registerPackets() {
itemRewriter.register();
metadataRewriter.register();
entityRewriter.register();
EntityPackets1_8.register(this);
PlayerPackets1_8.register(this);
ScoreboardPackets1_8.register(this);
WorldPackets1_8.register(this);
PlayerPacketRewriter1_8.register(this);
ScoreboardPacketRewriter1_8.register(this);
WorldPacketRewriter1_8.register(this);
this.registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO.getId(), ClientboundLoginPackets.HELLO.getId(), new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // server hash
map(Type.BYTE_ARRAY_PRIMITIVE, Type.SHORT_BYTE_ARRAY); // public key
map(Type.BYTE_ARRAY_PRIMITIVE, Type.SHORT_BYTE_ARRAY); // verification token
map(Types.STRING); // server hash
map(Types.BYTE_ARRAY_PRIMITIVE, Types.SHORT_BYTE_ARRAY); // public key
map(Types.BYTE_ARRAY_PRIMITIVE, Types.SHORT_BYTE_ARRAY); // verification token
}
});
this.registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_COMPRESSION.getId(), ClientboundLoginPackets.LOGIN_COMPRESSION.getId(), new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final int threshold = wrapper.read(Type.VAR_INT);
final int threshold = wrapper.read(Types.VAR_INT);
Via.getManager().getProviders().get(CompressionHandlerProvider.class).onHandleLoginCompressionPacket(wrapper.user(), threshold);
wrapper.cancel();
@@ -88,28 +88,28 @@ public class Protocol1_7_6_10To1_8 extends BackwardsProtocol<ClientboundPackets1
this.registerClientbound(ClientboundPackets1_8.KEEP_ALIVE, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // id
map(Types.VAR_INT, Types.INT); // id
}
});
this.registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY.getId(), ServerboundLoginPackets.ENCRYPTION_KEY.getId(), new PacketHandlers() {
@Override
public void register() {
map(Type.SHORT_BYTE_ARRAY, Type.BYTE_ARRAY_PRIMITIVE); // shared secret
map(Type.SHORT_BYTE_ARRAY, Type.BYTE_ARRAY_PRIMITIVE); // verification token
map(Types.SHORT_BYTE_ARRAY, Types.BYTE_ARRAY_PRIMITIVE); // shared secret
map(Types.SHORT_BYTE_ARRAY, Types.BYTE_ARRAY_PRIMITIVE); // verification token
}
});
this.registerServerbound(ServerboundPackets1_7_2_5.KEEP_ALIVE, new PacketHandlers() {
@Override
public void register() {
map(Type.INT, Type.VAR_INT); // id
map(Types.INT, Types.VAR_INT); // id
}
});
}
@Override
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception {
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws CancelException {
Via.getManager().getProviders().get(CompressionHandlerProvider.class).onTransformPacket(packetWrapper.user());
super.transform(direction, state, packetWrapper);
@@ -122,7 +122,7 @@ public class Protocol1_7_6_10To1_8 extends BackwardsProtocol<ClientboundPackets1
connection.put(new InventoryTracker(connection));
connection.put(new PlayerSessionStorage(connection));
connection.put(new GameProfileStorage(connection));
connection.put(new Scoreboard(connection));
connection.put(new ScoreboardTracker(connection));
connection.put(new CompressionStatusTracker(connection));
connection.put(new WorldBorderEmulator(connection));
@@ -141,18 +141,18 @@ public class Protocol1_7_6_10To1_8 extends BackwardsProtocol<ClientboundPackets1
}
@Override
public RewindMappings getMappingData() {
public RewindMappingData getMappingData() {
return MAPPINGS;
}
@Override
public BlockItemPackets1_8 getItemRewriter() {
public BlockItemPacketRewriter1_8 getItemRewriter() {
return itemRewriter;
}
@Override
public MetadataRewriter1_7_6_10To1_8 getEntityRewriter() {
return metadataRewriter;
public EntityPacketRewriter1_8 getEntityRewriter() {
return entityRewriter;
}
@Override
@@ -0,0 +1,219 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data;
import com.viaversion.viarewind.api.minecraft.entitydata.EntityDataTypes1_7_6_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.util.Pair;
import java.util.HashMap;
import java.util.Optional;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.*;
public enum EntityDataIndex1_7_6_10 {
ENTITY_FLAGS(ENTITY, 0, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
ENTITY_AIR(ENTITY, 1, EntityDataTypes1_7_6_10.SHORT, EntityDataTypes1_8.SHORT),
ENTITY_NAME_TAG(ENTITY, -1, null, 2, EntityDataTypes1_8.STRING),
ENTITY_NAME_TAG_VISIBILITY(ENTITY, -1, null, 3, EntityDataTypes1_8.BYTE),
ENTITY_SILENT(ENTITY, -1, null, 4, EntityDataTypes1_8.BYTE),
LIVING_ENTITY_BASE_HEALTH(LIVING_ENTITY_BASE, 6, EntityDataTypes1_7_6_10.FLOAT, EntityDataTypes1_8.FLOAT),
LIVING_ENTITY_BASE_POTION_EFFECT_COLOR(LIVING_ENTITY_BASE, 7, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
LIVING_ENTITY_BASE_IS_POTION_EFFECT_AMBIENT(LIVING_ENTITY_BASE, 8, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
LIVING_ENTITY_BASE_ARROWS(LIVING_ENTITY_BASE, 9, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
LIVING_ENTITY_BASE_NAME_TAG(LIVING_ENTITY_BASE, 10, EntityDataTypes1_7_6_10.STRING, 2, EntityDataTypes1_8.STRING),
LIVING_ENTITY_BASE_NAME_TAG_VISIBILITY(LIVING_ENTITY_BASE, 11, EntityDataTypes1_7_6_10.BYTE, 3, EntityDataTypes1_8.BYTE),
LIVING_ENTITY_AI(LIVING_ENTITY, -1, null, 15, EntityDataTypes1_8.BYTE),
ABSTRACT_AGEABLE_AGE(ABSTRACT_AGEABLE, 12, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.BYTE),
ARMOR_STAND_FLAGS(ARMOR_STAND, -1, null, 10, EntityDataTypes1_8.BYTE),
ARMOR_STAND_HEAD_POSITION(ARMOR_STAND, -1, null, 11, EntityDataTypes1_8.ROTATIONS),
ARMOR_STAND_BODY_POSITION(ARMOR_STAND, -1, null, 12, EntityDataTypes1_8.ROTATIONS),
ARMOR_STAND_LEFT_ARM_POSITION(ARMOR_STAND, -1, null, 13, EntityDataTypes1_8.ROTATIONS),
ARMOR_STAND_RIGHT_ARM_POSITION(ARMOR_STAND, -1, null, 14, EntityDataTypes1_8.ROTATIONS),
ARMOR_STAND_LEFT_LEG_POSITION(ARMOR_STAND, -1, null, 15, EntityDataTypes1_8.ROTATIONS),
ARMOR_STAND_RIGHT_LEG_POSITION(ARMOR_STAND, -1, null, 16, EntityDataTypes1_8.ROTATIONS),
PLAYER_SKIN_FLAGS(PLAYER, 16, EntityDataTypes1_7_6_10.BYTE, 10, EntityDataTypes1_8.BYTE),
PLAYER_UNUSED(PLAYER, -1, null, 16, EntityDataTypes1_8.BYTE),
PLAYER_ABSORPTION_HEATS(PLAYER, 17, EntityDataTypes1_7_6_10.FLOAT, EntityDataTypes1_8.FLOAT),
PLAYER_SCORE(PLAYER, 18, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
HORSE_FLAGS(HORSE, 16, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
HORSE_TYPE(HORSE, 19, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
HORSE_COLOR(HORSE, 20, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
HORSE_OWNER(HORSE, 21, EntityDataTypes1_7_6_10.STRING, EntityDataTypes1_8.STRING),
HORSE_ARMOR(HORSE, 22, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
BAT_HANGING(BAT, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
TAMABLE_ANIMAL_FLAGS(TAMABLE_ANIMAL, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
TAMABLE_ANIMAL_OWNER(TAMABLE_ANIMAL, 17, EntityDataTypes1_7_6_10.STRING, EntityDataTypes1_8.STRING),
OCELOT_TYPE(OCELOT, 18, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
WOLF_FLAGS(WOLF, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
WOLF_HEALTH(WOLF, 18, EntityDataTypes1_7_6_10.FLOAT, EntityDataTypes1_8.FLOAT),
WOLF_BEGGING(WOLF, 19, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
WOLF_COLLAR_COLOR(WOLF, 20, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
PIG_SADDLE(PIG, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
SHEEP_COLOR_OR_SHEARED(SHEEP, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
VILLAGER_TYPE(VILLAGER, 16, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
ENDERMAN_CARRIED_BLOCK(ENDERMAN, 16, null, EntityDataTypes1_8.SHORT),
ENDERMAN_CARRIED_BLOCK_DATA(ENDERMAN, 17, null, EntityDataTypes1_8.BYTE),
ENDERMAN_IS_SCREAMING(ENDERMAN, 18, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
ZOMBIE_CHILD(ZOMBIE, 12, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
ZOMBIE_VILLAGER(ZOMBIE, 13, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
ZOMBIE_CONVERTING(ZOMBIE, 14, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
BLAZE_ON_FIRE(BLAZE, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
SPIDER_CLIMBING(SPIDER, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
CREEPER_STATE(CREEPER, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
CREEPER_POWERED(CREEPER, 17, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
CREEPER_IGNITED(CREEPER, 18, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
GHAST_STATE(GHAST, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
GHAST_IS_POWERED(GHAST, 17, null, EntityDataTypes1_8.BYTE),
SLIME_SIZE(SLIME, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
SKELETON_TYPE(SKELETON, 13, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
WITCH_AGGRESSIVE(WITCH, 21, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
IRON_GOLEM_IS_PLAYER_CREATED(IRON_GOLEM, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
WITHER_WATCHED_TARGET_1(WITHER, 17, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
WITHER_WATCHED_TARGET_2(WITHER, 18, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
WITHER_WATCHED_TARGET_3(WITHER, 19, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
WITHER_INVULNERABLE_TIME(WITHER, 20, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
GUARDIAN_FLAGS(GUARDIAN, 16, null, EntityDataTypes1_8.BYTE),
GUARDIAN_TARGET(GUARDIAN, 17, null, EntityDataTypes1_8.INT),
BOAT_TIME_SINCE_HIT(BOAT, 17, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
BOAT_FORWARD_DIRECTION(BOAT, 18, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
BOAT_DAMAGE_TAKEN(BOAT, 19, EntityDataTypes1_7_6_10.FLOAT, EntityDataTypes1_8.FLOAT),
ABSTRACT_MINECART_SHAKING_POWER(ABSTRACT_MINECART, 17, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
ABSTRACT_MINECART_SHAKING_DIRECTION(ABSTRACT_MINECART, 18, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
ABSTRACT_MINECART_DAMAGE_TAKEN(ABSTRACT_MINECART, 19, EntityDataTypes1_7_6_10.FLOAT, EntityDataTypes1_8.FLOAT),
ABSTRACT_MINECART_BLOCK_INSIDE(ABSTRACT_MINECART, 20, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
ABSTRACT_MINECART_BLOCK_Y(ABSTRACT_MINECART, 21, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
ABSTRACT_MINECART_SHOW_BLOCK(ABSTRACT_MINECART, 22, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
FURNACE_MINECART_IS_POWERED(FURNACE_MINECART, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
ITEM_ITEM(ITEM, 10, EntityDataTypes1_7_6_10.ITEM, EntityDataTypes1_8.ITEM),
ARROW_IS_CRITICAL(ARROW, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
FIREWORK_ROCKET_INFO(FIREWORK_ROCKET, 8, EntityDataTypes1_7_6_10.ITEM, EntityDataTypes1_8.ITEM),
ITEM_FRAME_ITEM(ITEM_FRAME, 2, EntityDataTypes1_7_6_10.ITEM, 8, EntityDataTypes1_8.ITEM),
ITEM_FRAME_ROTATION(ITEM_FRAME, 3, EntityDataTypes1_7_6_10.BYTE, 9, EntityDataTypes1_8.BYTE),
END_CRYSTAL_HEALTH(END_CRYSTAL, 8, EntityDataTypes1_7_6_10.INT, 9, EntityDataTypes1_8.INT);
private static final HashMap<Pair<EntityTypes1_8.EntityType, Integer>, EntityDataIndex1_7_6_10> ENTITY_DATA_REWRITES = new HashMap<>();
static {
for (EntityDataIndex1_7_6_10 index : EntityDataIndex1_7_6_10.values()) {
ENTITY_DATA_REWRITES.put(new Pair<>(index.getClazz(), index.getNewIndex()), index);
}
}
private final EntityTypes1_8.EntityType clazz;
private final int newIndex;
private final EntityDataTypes1_8 newType;
private final EntityDataTypes1_7_6_10 oldType;
private final int index;
EntityDataIndex1_7_6_10(EntityTypes1_8.EntityType type, int index, EntityDataTypes1_7_6_10 oldType, EntityDataTypes1_8 newType) {
this.clazz = type;
this.index = index;
this.newIndex = index;
this.oldType = oldType;
this.newType = newType;
}
EntityDataIndex1_7_6_10(EntityTypes1_8.EntityType type, int index, EntityDataTypes1_7_6_10 oldType, int newIndex, EntityDataTypes1_8 newType) {
this.clazz = type;
this.index = index;
this.oldType = oldType;
this.newIndex = newIndex;
this.newType = newType;
}
private static Optional<EntityDataIndex1_7_6_10> getIndex(EntityType type, int index) {
Pair<EntityType, Integer> pair = new Pair<>(type, index);
if (ENTITY_DATA_REWRITES.containsKey(pair)) {
return Optional.of(ENTITY_DATA_REWRITES.get(pair));
}
return Optional.empty();
}
public EntityTypes1_8.EntityType getClazz() {
return clazz;
}
public int getNewIndex() {
return newIndex;
}
public EntityDataTypes1_8 getNewType() {
return newType;
}
public EntityDataTypes1_7_6_10 getOldType() {
return oldType;
}
public int getIndex() {
return index;
}
public static EntityDataIndex1_7_6_10 searchIndex(EntityType type, int index) {
EntityType currentType = type;
do {
Optional<EntityDataIndex1_7_6_10> optMeta = getIndex(currentType, index);
if (optMeta.isPresent()) {
return optMeta.get();
}
currentType = currentType.getParent();
} while (currentType != null);
return null;
}
}
@@ -15,11 +15,11 @@
* 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.protocol1_7_6_10to1_8.data;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data;
import java.util.HashMap;
public enum ParticleIndex1_7_6_10 {
public enum Particles1_8 {
EXPLOSION_NORMAL("explode"),
EXPLOSION_LARGE("largeexplode"),
EXPLOSION_HUGE("hugeexplosion"),
@@ -65,31 +65,31 @@ public enum ParticleIndex1_7_6_10 {
public final String name;
public final int extra;
private static final HashMap<String, ParticleIndex1_7_6_10> particleMap = new HashMap<>();
private static final HashMap<String, Particles1_8> particleMap = new HashMap<>();
ParticleIndex1_7_6_10(String name) {
Particles1_8(String name) {
this(name, 0);
}
ParticleIndex1_7_6_10(String name, int extra) {
Particles1_8(String name, int extra) {
this.name = name;
this.extra = extra;
}
public static ParticleIndex1_7_6_10 find(String part) {
public static Particles1_8 find(String part) {
return particleMap.get(part);
}
public static ParticleIndex1_7_6_10 find(int id) {
public static Particles1_8 find(int id) {
if (id < 0) return null;
ParticleIndex1_7_6_10[] values = ParticleIndex1_7_6_10.values();
Particles1_8[] values = Particles1_8.values();
return id >= values.length ? null : values[id];
}
static {
ParticleIndex1_7_6_10[] particles = values();
Particles1_8[] particles = values();
for (ParticleIndex1_7_6_10 particle : particles) {
for (Particles1_8 particle : particles) {
particleMap.put(particle.name, particle);
}
}
@@ -0,0 +1,325 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data;
import com.viaversion.viarewind.api.type.version.Types1_7_6_10;
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.api.minecraft.entitydata.EntityDataTypes1_7_6_10;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter.EntityPacketRewriter1_8;
import com.viaversion.viarewind.api.minecraft.math.AABB;
import com.viaversion.viarewind.api.minecraft.math.Vector3d;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.TrackedEntityImpl;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEventImpl;
import java.util.ArrayList;
import java.util.List;
public class VirtualHologramEntity {
private final List<EntityData> entityDataTracker = new ArrayList<>();
private double locX, locY, locZ;
private final UserConnection user;
private final int entityId;
private int[] entityIds = null;
private State currentState = null;
private String name = null;
private float yaw, pitch;
private float headYaw;
private boolean small = false;
private boolean marker = false;
public VirtualHologramEntity(final UserConnection user, final int entityId) {
this.user = user;
this.entityId = entityId;
}
public void setPosition(final double x, final double y, final double z) {
if (x == this.locX && y == this.locY && z == this.locZ) return;
this.locX = x;
this.locY = y;
this.locZ = z;
updateLocation(false);
}
public void setRelativePosition(final double x, final double y, final double z) {
if (x == 0.0 && y == 0.0 && z == 0.0) return;
this.locX += x;
this.locY += y;
this.locZ += z;
updateLocation(false);
}
public void setRotation(final float yaw, final float pitch) {
if (this.yaw == yaw || this.headYaw == yaw || this.pitch == pitch) return;
this.yaw = yaw;
this.headYaw = yaw;
this.pitch = pitch;
updateLocation(false);
}
public void setHeadYaw(float yaw) {
if (this.headYaw == yaw) return;
this.headYaw = yaw;
updateLocation(false);
}
public void syncState(final EntityPacketRewriter1_8 entityRewriter, final List<EntityData> entityDataList) {
// Merge entity data updates into current tracker
for (EntityData entityData : entityDataList) {
entityDataTracker.removeIf(m -> m.id() == entityData.id());
entityDataTracker.add(entityData);
}
// 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();
} else if (entityData.id() == 2 && entityData.dataType() == EntityDataTypes1_8.STRING) {
name = entityData.getValue().toString();
if (name != null && name.isEmpty()) name = null;
} else if (entityData.id() == 10 && entityData.dataType() == EntityDataTypes1_8.BYTE) {
armorStandFlags = ((Number) entityData.getValue()).byteValue();
}
}
final boolean invisible = (flags & 0x20) != 0;
small = (armorStandFlags & 0x01) != 0;
marker = (armorStandFlags & 0x10) != 0;
State prevState = currentState;
if (invisible && name != null) {
currentState = State.HOLOGRAM;
} else {
currentState = State.ZOMBIE;
}
if (currentState != prevState) {
deleteEntity();
sendSpawnPacket(entityRewriter);
} else {
sendEntityDataUpdate(entityRewriter);
updateLocation(false);
}
}
private void updateLocation(final boolean remount) {
if (entityIds == null) {
return;
}
if (currentState == State.ZOMBIE) {
teleportEntity(entityId, locX, locY, locZ, yaw, pitch);
final PacketWrapper entityHeadLook = PacketWrapper.create(ClientboundPackets1_7_2_5.ROTATE_HEAD, user);
entityHeadLook.write(Types.INT, entityId);
entityHeadLook.write(Types.BYTE, (byte) ((headYaw / 360f) * 256));
entityHeadLook.send(Protocol1_8To1_7_6_10.class);
} else if (currentState == State.HOLOGRAM) {
if (remount) {
PacketWrapper detach = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_ENTITY_LINK, user);
detach.write(Types.INT, entityIds[1]);
detach.write(Types.INT, -1);
detach.write(Types.BOOLEAN, false);
detach.send(Protocol1_8To1_7_6_10.class);
}
// Don't ask me where this offset is coming from
teleportEntity(entityIds[0], locX, (locY + (marker ? 54.85 : small ? 56 : 57) - 0.16), locZ, 0, 0); // Skull
if (remount) {
teleportEntity(entityIds[1], locX, locY + 56.75, locZ, 0, 0); // Horse
PacketWrapper attach = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_ENTITY_LINK, null, user);
attach.write(Types.INT, entityIds[1]);
attach.write(Types.INT, entityIds[0]);
attach.write(Types.BOOLEAN, false);
attach.send(Protocol1_8To1_7_6_10.class);
}
}
}
protected void teleportEntity(final int entityId, final double x, final double y, final double z, final float yaw, final float pitch) {
final PacketWrapper entityTeleport = PacketWrapper.create(ClientboundPackets1_7_2_5.TELEPORT_ENTITY, user);
entityTeleport.write(Types.INT, entityId); // entity id
entityTeleport.write(Types.INT, (int) (x * 32.0)); // x
entityTeleport.write(Types.INT, (int) (y * 32.0)); // y
entityTeleport.write(Types.INT, (int) (z * 32.0)); // z
entityTeleport.write(Types.BYTE, (byte) ((yaw / 360f) * 256)); // yaw
entityTeleport.write(Types.BYTE, (byte) ((pitch / 360f) * 256)); // pitch
entityTeleport.send(Protocol1_8To1_7_6_10.class);
}
protected void spawnEntity(final int entityId, final int type, final double locX, final double locY, final double locZ) {
final PacketWrapper addMob = PacketWrapper.create(ClientboundPackets1_7_2_5.ADD_MOB, user);
addMob.write(Types.VAR_INT, entityId); // Entity id
addMob.write(Types.UNSIGNED_BYTE, (short) type); // Entity type
addMob.write(Types.INT, (int) (locX * 32.0)); // X
addMob.write(Types.INT, (int) (locY * 32.0)); // Y
addMob.write(Types.INT, (int) (locZ * 32.0)); // Z
addMob.write(Types.BYTE, (byte) 0); // Yaw
addMob.write(Types.BYTE, (byte) 0); // Pitch
addMob.write(Types.BYTE, (byte) 0); // Head pitch
addMob.write(Types.SHORT, (short) 0); // Velocity x
addMob.write(Types.SHORT, (short) 0); // Velocity y
addMob.write(Types.SHORT, (short) 0); // Velocity z
addMob.write(Types1_7_6_10.ENTITY_DATA_LIST, new ArrayList<>()); // Entity data
addMob.send(Protocol1_8To1_7_6_10.class);
}
public void sendEntityDataUpdate(final EntityPacketRewriter1_8 entityRewriter) {
if (entityIds == null) {
return;
}
final PacketWrapper setEntityData = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_ENTITY_DATA, user);
if (currentState == State.ZOMBIE) {
writeZombieMeta(entityRewriter, setEntityData);
} else if (currentState == State.HOLOGRAM) {
writeHologramMeta(setEntityData);
} else {
return;
}
setEntityData.send(Protocol1_8To1_7_6_10.class);
}
private void writeZombieMeta(final EntityPacketRewriter1_8 entityRewriter, PacketWrapper wrapper) {
wrapper.write(Types.INT, entityIds[0]);
// Filter entity data sent by the server and convert them together with our custom entity data
final List<EntityData> entityDataList = new ArrayList<>();
for (EntityData entityData : entityDataTracker) {
// Remove non existent entityData
if (entityData.id() < 0 || entityData.id() > 9) {
continue;
}
entityDataList.add(new EntityData(entityData.id(), entityData.dataType(), entityData.getValue()));
}
if (small) {
entityDataList.add(new EntityData(12, EntityDataTypes1_8.BYTE, (byte) 1));
}
// Push entity data from the server through entity data conversion 1.7->1.8
for (EntityData entityData : entityDataList.toArray(new EntityData[0])) {
final EntityDataHandlerEvent event = new EntityDataHandlerEventImpl(wrapper.user(), new TrackedEntityImpl(EntityTypes1_8.EntityType.ZOMBIE), -1, entityData, entityDataList);
try {
entityRewriter.handleEntityData(event, entityData);
} catch (Exception e) {
entityDataList.remove(entityData);
break;
}
if (event.cancelled()) {
entityDataList.remove(entityData);
break;
}
}
wrapper.write(Types1_7_6_10.ENTITY_DATA_LIST, entityDataList);
}
private void writeHologramMeta(PacketWrapper wrapper) {
wrapper.write(Types.INT, entityIds[1]);
// Directly write 1.7 entity data here since we are making them up
final List<EntityData> entityDataList = new ArrayList<>();
entityDataList.add(new EntityData(EntityDataIndex1_7_6_10.ABSTRACT_AGEABLE_AGE.getIndex(), EntityDataTypes1_7_6_10.INT, -1700000));
entityDataList.add(new EntityData(EntityDataIndex1_7_6_10.LIVING_ENTITY_BASE_NAME_TAG.getIndex(), EntityDataTypes1_7_6_10.STRING, name));
entityDataList.add(new EntityData(EntityDataIndex1_7_6_10.LIVING_ENTITY_BASE_NAME_TAG_VISIBILITY.getIndex(), EntityDataTypes1_7_6_10.BYTE, (byte) 1));
wrapper.write(Types1_7_6_10.ENTITY_DATA_LIST, entityDataList);
}
public void sendSpawnPacket(final EntityPacketRewriter1_8 entityRewriter) {
if (entityIds != null) {
deleteEntity();
}
if (currentState == State.ZOMBIE) {
spawnEntity(entityId, EntityTypes1_8.EntityType.ZOMBIE.getId(), locX, locY, locZ);
entityIds = new int[]{entityId};
} else if (currentState == State.HOLOGRAM) {
final int[] entityIds = { entityId, additionalEntityId() };
final PacketWrapper spawnSkull = PacketWrapper.create(ClientboundPackets1_7_2_5.ADD_ENTITY, user);
spawnSkull.write(Types.VAR_INT, entityIds[0]);
spawnSkull.write(Types.BYTE, (byte) 66);
spawnSkull.write(Types.INT, (int) (locX * 32.0));
spawnSkull.write(Types.INT, (int) (locY * 32.0));
spawnSkull.write(Types.INT, (int) (locZ * 32.0));
spawnSkull.write(Types.BYTE, (byte) 0);
spawnSkull.write(Types.BYTE, (byte) 0);
spawnSkull.write(Types.INT, 0);
spawnSkull.send(Protocol1_8To1_7_6_10.class);
spawnEntity(entityIds[1], EntityTypes1_8.EntityType.HORSE.getId(), locX, locY, locZ); // Horse
this.entityIds = entityIds;
}
sendEntityDataUpdate(entityRewriter);
updateLocation(true);
}
public AABB getBoundingBox() {
final double width = this.small ? 0.25 : 0.5;
final double height = this.small ? 0.9875 : 1.975;
final Vector3d min = new Vector3d(this.locX - width / 2, this.locY, this.locZ - width / 2);
final Vector3d max = new Vector3d(this.locX + width / 2, this.locY + height, this.locZ + width / 2);
return new AABB(min, max);
}
private int additionalEntityId() {
return Integer.MAX_VALUE - 16000 - entityId;
}
public void deleteEntity() {
if (entityIds == null) {
return;
}
final PacketWrapper despawn = PacketWrapper.create(ClientboundPackets1_7_2_5.REMOVE_ENTITIES, user);
despawn.write(Types.BYTE, (byte) entityIds.length);
for (int id : entityIds) {
despawn.write(Types.INT, id);
}
entityIds = null;
despawn.send(Protocol1_8To1_7_6_10.class);
}
private enum State {
HOLOGRAM, ZOMBIE
}
}
@@ -15,9 +15,9 @@
* 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.protocol1_7_6_10to1_8.provider;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.CompressionStatusTracker;
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;
@@ -15,7 +15,7 @@
* 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.protocol1_7_6_10to1_8.provider;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider;
import com.viaversion.viaversion.api.platform.providers.Provider;
@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
// TODO I believe this should be a storage?
public abstract class TitleRenderProvider implements Provider {
protected Map<UUID, Integer> fadeIn = new HashMap<>();
protected Map<UUID, Integer> stay = new HashMap<>();
@@ -15,9 +15,9 @@
* 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.protocol1_7_6_10to1_8.provider.compression;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.compression;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
@@ -27,7 +27,6 @@ import io.netty.handler.codec.MessageToMessageDecoder;
import java.util.List;
import java.util.zip.Inflater;
// https://github.com/Gerrygames/ClientViaVersion/blob/master/src/main/java/de/gerrygames/the5zig/clientviaversion/netty/CompressionDecoder.java
public class CompressionDecoder extends MessageToMessageDecoder<ByteBuf> {
private final Inflater inflater = new Inflater();
@@ -41,7 +40,7 @@ public class CompressionDecoder extends MessageToMessageDecoder<ByteBuf> {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (!in.isReadable()) return;
int outLength = Type.VAR_INT.readPrimitive(in);
int outLength = Types.VAR_INT.readPrimitive(in);
if (outLength == 0) {
out.add(in.readBytes(in.readableBytes()));
return;
@@ -15,9 +15,9 @@
* 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.protocol1_7_6_10to1_8.provider.compression;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.compression;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
@@ -25,7 +25,6 @@ import io.netty.handler.codec.MessageToByteEncoder;
import java.util.zip.Deflater;
// https://github.com/Gerrygames/ClientViaVersion/blob/master/src/main/java/de/gerrygames/the5zig/clientviaversion/netty/CompressionEncoder.java
public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
private final Deflater deflater = new Deflater();
@@ -44,7 +43,7 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
return;
}
Type.VAR_INT.writePrimitive(out, frameLength);
Types.VAR_INT.writePrimitive(out, frameLength);
ByteBuf temp = in;
if (!in.hasArray()) {
@@ -15,11 +15,11 @@
* 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.protocol1_7_6_10to1_8.provider.compression;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.compression;
import com.viaversion.viarewind.api.netty.EmptyChannelHandler;
import com.viaversion.viarewind.api.netty.ForwardMessageToByteEncoder;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.provider.CompressionHandlerProvider;
import com.viaversion.viarewind.api.minecraft.netty.EmptyChannelHandler;
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;
@@ -15,109 +15,104 @@
* 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.protocol1_7_6_10to1_8.packets;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viarewind.api.rewriter.VRBlockItemRewriter;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ServerboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.EntityTracker1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.GameProfileStorage;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.InventoryTracker;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.PlayerSessionStorage;
import com.viaversion.viarewind.api.type.Types1_7_6_10;
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.storage.EntityTracker1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.GameProfileStorage;
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.api.type.RewindTypes;
import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.*;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.nbt.tag.*;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.UUID;
public class BlockItemPackets1_8 extends VRBlockItemRewriter<ClientboundPackets1_8, ServerboundPackets1_7_2_5, Protocol1_7_6_10To1_8> {
public class BlockItemPacketRewriter1_8 extends VRBlockItemRewriter<ClientboundPackets1_8, ServerboundPackets1_7_2_5, Protocol1_8To1_7_6_10> {
private LegacyEnchantmentRewriter enchantmentRewriter;
public BlockItemPackets1_8(Protocol1_7_6_10To1_8 protocol) {
public BlockItemPacketRewriter1_8(Protocol1_8To1_7_6_10 protocol) {
super(protocol, "1.8");
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_8.OPEN_WINDOW, wrapper -> {
protocol.registerClientbound(ClientboundPackets1_8.OPEN_SCREEN, wrapper -> {
final InventoryTracker windowTracker = wrapper.user().get(InventoryTracker.class);
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE); // window id
final short windowTypeId = InventoryTracker.getInventoryType(wrapper.read(Type.STRING)); // window type
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); // Window id
final short windowTypeId = InventoryTracker.getInventoryType(wrapper.read(Types.STRING)); // Window type
windowTracker.getWindowTypeMap().put(windowId, windowTypeId);
wrapper.write(Type.UNSIGNED_BYTE, windowTypeId); // window type id
wrapper.write(Types.UNSIGNED_BYTE, windowTypeId); // Window type id
final JsonElement titleComponent = wrapper.read(Type.COMPONENT); // Title
final JsonElement titleComponent = wrapper.read(Types.COMPONENT); // Title
String title = ChatUtil.jsonToLegacy(wrapper.user(), titleComponent);
title = ChatUtil.removeUnusedColor(title, '8');
if (title.length() > 32) {
title = title.substring(0, 32);
}
wrapper.write(Type.STRING, title); // window title
wrapper.write(Types.STRING, title); // Window title
wrapper.passthrough(Type.UNSIGNED_BYTE); // slots count
wrapper.write(Type.BOOLEAN, true); // use provided window title
wrapper.passthrough(Types.UNSIGNED_BYTE); // Slots
wrapper.write(Types.BOOLEAN, true); // Use provided window title
if (windowTypeId == 11) { // Horse
wrapper.passthrough(Type.INT); // entity id
wrapper.passthrough(Types.INT); // Entity id
}
});
protocol.registerClientbound(ClientboundPackets1_8.CLOSE_WINDOW, wrapper -> {
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE); // window id
protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_CLOSE, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); // Window id
wrapper.user().get(InventoryTracker.class).remove(windowId);
});
protocol.registerClientbound(ClientboundPackets1_8.SET_SLOT, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // window id
map(Type.SHORT); // slot
map(Types.UNSIGNED_BYTE); // Window id
map(Types.SHORT); // Slot
handler(wrapper -> {
final short windowType = wrapper.user().get(InventoryTracker.class).get(wrapper.get(Type.UNSIGNED_BYTE, 0));
final short slot = wrapper.get(Type.SHORT, 0);
final short windowType = wrapper.user().get(InventoryTracker.class).get(wrapper.get(Types.UNSIGNED_BYTE, 0));
final short slot = wrapper.get(Types.SHORT, 0);
if (windowType == 4) { // Enchantment Table
if (slot == 1) {
wrapper.cancel();
} else if (slot >= 2) {
wrapper.set(Type.SHORT, 0, (short) (slot - 1));
wrapper.set(Types.SHORT, 0, (short) (slot - 1));
}
}
});
map(Type.ITEM1_8, Types1_7_6_10.COMPRESSED_NBT_ITEM); // item
// remap item
handler(wrapper -> {
final Item item = wrapper.get(Types1_7_6_10.COMPRESSED_NBT_ITEM, 0);
handleItemToClient(wrapper.user(), item);
wrapper.set(Types1_7_6_10.COMPRESSED_NBT_ITEM, 0, item);
});
map(Types.ITEM1_8, RewindTypes.COMPRESSED_NBT_ITEM); // item
handler(wrapper -> handleItemToClient(wrapper.user(), wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM, 0)));
handler(wrapper -> {
final short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0);
if (windowId != 0) return;
final short slot = wrapper.get(Type.SHORT, 0);
if (slot < 5 || slot > 8) return;
final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0);
if (windowId != 0) {
return;
}
final short slot = wrapper.get(Types.SHORT, 0);
if (slot < 5 || slot > 8) {
return;
}
final PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
final Item item = wrapper.get(Types1_7_6_10.COMPRESSED_NBT_ITEM, 0);
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_7_6_10To1_8.class);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
if (tracker.isSpectator()) { // Spectator mode didn't exist in 1.7.10
wrapper.cancel();
}
@@ -125,16 +120,16 @@ public class BlockItemPackets1_8 extends VRBlockItemRewriter<ClientboundPackets1
}
});
protocol.registerClientbound(ClientboundPackets1_8.WINDOW_ITEMS, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_CONTENT, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // window id
map(Types.UNSIGNED_BYTE); // Window id
// remap enchantment table items
handler(wrapper -> {
final short windowType = wrapper.user().get(InventoryTracker.class).get(wrapper.get(Type.UNSIGNED_BYTE, 0));
final short windowType = wrapper.user().get(InventoryTracker.class).get(wrapper.get(Types.UNSIGNED_BYTE, 0));
Item[] items = wrapper.read(Type.ITEM1_8_SHORT_ARRAY);
Item[] items = wrapper.read(Types.ITEM1_8_SHORT_ARRAY);
if (windowType == 4) { // Enchantment Table
Item[] old = items;
items = new Item[old.length - 1];
@@ -144,17 +139,18 @@ public class BlockItemPackets1_8 extends VRBlockItemRewriter<ClientboundPackets1
for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(wrapper.user(), items[i]);
}
wrapper.write(Types1_7_6_10.COMPRESSED_NBT_ITEM_ARRAY, items); // items
wrapper.write(RewindTypes.COMPRESSED_NBT_ITEM_ARRAY, items); // Items
});
handler(wrapper -> {
final short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0);
if (windowId != 0) return;
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_7_6_10To1_8.class);
final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0);
if (windowId != 0) {
return;
}
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
final UUID userId = wrapper.user().getProtocolInfo().getUuid();
final Item[] items = wrapper.get(Types1_7_6_10.COMPRESSED_NBT_ITEM_ARRAY, 0);
final Item[] items = wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM_ARRAY, 0);
for (int i = 5; i < 9; i++) {
wrapper.user().get(PlayerSessionStorage.class).setPlayerEquipment(userId, items[i], 8 - i);
if (tracker.isSpectator()) {
@@ -171,21 +167,21 @@ public class BlockItemPackets1_8 extends VRBlockItemRewriter<ClientboundPackets1
}
});
protocol.registerClientbound(ClientboundPackets1_8.WINDOW_PROPERTY, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // window id
map(Type.SHORT); // progress bar id
map(Type.SHORT); // progress bar value
map(Types.UNSIGNED_BYTE); // Window id
map(Types.SHORT); // Progress bar id
map(Types.SHORT); // Progress bar value
handler(wrapper -> {
final InventoryTracker windowTracker = wrapper.user().get(InventoryTracker.class);
final short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0);
final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0);
final short windowType = windowTracker.get(windowId);
final short progressBarId = wrapper.get(Type.SHORT, 0);
short progress = wrapper.get(Type.SHORT, 1);
final short progressBarId = wrapper.get(Types.SHORT, 0);
short progress = wrapper.get(Types.SHORT, 1);
if (windowType == 2) { // Furnace
// TODO | Proper methods (getOrCreate)=
@@ -201,8 +197,8 @@ public class BlockItemPackets1_8 extends VRBlockItemRewriter<ClientboundPackets1
return;
}
progress = (short) (200 * furnace.fuelLeft / furnace.maxFuel);
wrapper.set(Type.SHORT, 0, (short) 1);
wrapper.set(Type.SHORT, 1, progress);
wrapper.set(Types.SHORT, 0, (short) 1);
wrapper.set(Types.SHORT, 1, progress);
} else if (progressBarId == 2 || progressBarId == 3) {
if (progressBarId == 2) {
furnace.progress = progress;
@@ -214,8 +210,8 @@ public class BlockItemPackets1_8 extends VRBlockItemRewriter<ClientboundPackets1
return;
}
progress = (short) (200 * furnace.progress / furnace.maxProgress);
wrapper.set(Type.SHORT, 0, (short) 0);
wrapper.set(Type.SHORT, 1, progress);
wrapper.set(Types.SHORT, 0, (short) 0);
wrapper.set(Types.SHORT, 1, progress);
}
} else if (windowType == 4 && progressBarId > 2) { // Enchanting Table
wrapper.cancel();
@@ -227,49 +223,44 @@ public class BlockItemPackets1_8 extends VRBlockItemRewriter<ClientboundPackets1
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.CLOSE_WINDOW, wrapper -> {
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE);
protocol.registerServerbound(ServerboundPackets1_7_2_5.CONTAINER_CLOSE, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
wrapper.user().get(InventoryTracker.class).remove(windowId);
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.CLICK_WINDOW, new PacketHandlers() {
protocol.registerServerbound(ServerboundPackets1_7_2_5.CONTAINER_CLICK, new PacketHandlers() {
@Override
public void register() {
map(Type.BYTE, Type.UNSIGNED_BYTE); // window id
map(Type.SHORT); // slot
map(Types.BYTE, Types.UNSIGNED_BYTE); // Window id
map(Types.SHORT); // Slot
handler(wrapper -> {
final short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0); //Window Id
final short slot = wrapper.get(Type.SHORT, 0);
final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0); // Window id
final short slot = wrapper.get(Types.SHORT, 0);
final short windowType = wrapper.user().get(InventoryTracker.class).get(windowId);
if (windowType == 4) { // Enchantment Table
if (slot > 0) {
wrapper.set(Type.SHORT, 0, (short) (slot + 1));
wrapper.set(Types.SHORT, 0, (short) (slot + 1));
}
}
});
map(Type.BYTE); // button
map(Type.SHORT); // action number
map(Type.BYTE); // mode
map(Types1_7_6_10.COMPRESSED_NBT_ITEM, Type.ITEM1_8); // clicked item
map(Types.BYTE); // Button
map(Types.SHORT); // Action number
map(Types.BYTE); // Mode
map(RewindTypes.COMPRESSED_NBT_ITEM, Types.ITEM1_8); // Clicked item
// remap item
handler(wrapper -> {
final Item item = wrapper.get(Type.ITEM1_8, 0);
handleItemToServer(wrapper.user(), item);
wrapper.set(Type.ITEM1_8, 0, item);
});
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.CREATIVE_INVENTORY_ACTION, new PacketHandlers() {
protocol.registerServerbound(ServerboundPackets1_7_2_5.SET_CREATIVE_MODE_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Type.SHORT); // slot
map(Types1_7_6_10.COMPRESSED_NBT_ITEM, Type.ITEM1_8); // item
map(Types.SHORT); // Slot
map(RewindTypes.COMPRESSED_NBT_ITEM, Types.ITEM1_8); // Item
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Type.ITEM1_8, 0)));
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
}
});
}
@@ -318,7 +309,7 @@ public class BlockItemPackets1_8 extends VRBlockItemRewriter<ClientboundPackets1
enchantmentRewriter.handleToServer(item);
if (item.identifier() == 387) {
final ListTag<StringTag> oldPages = tag.get(nbtTagName() + "|pages");
final ListTag<StringTag> oldPages = tag.getListTag(nbtTagName() + "|pages", StringTag.class);
if (oldPages != null) {
tag.remove("pages");
tag.put("pages", oldPages);
@@ -0,0 +1,701 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.api.rewriter.VREntityRewriter;
import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viarewind.api.minecraft.entitydata.EntityDataTypes1_7_6_10;
import com.viaversion.viarewind.api.type.version.Types1_7_6_10;
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.data.EntityDataIndex1_7_6_10;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data.VirtualHologramEntity;
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;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.PlayerSessionStorage;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.ScoreboardTracker;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;
import com.viaversion.viaversion.util.IdAndData;
import java.util.List;
import java.util.UUID;
public class EntityPacketRewriter1_8 extends VREntityRewriter<ClientboundPackets1_8, Protocol1_8To1_7_6_10> {
public EntityPacketRewriter1_8(Protocol1_8To1_7_6_10 protocol) {
super(protocol, EntityDataTypes1_7_6_10.STRING, EntityDataTypes1_7_6_10.BYTE);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_8.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Entity id
map(Types.UNSIGNED_BYTE); // Game mode
map(Types.BYTE); // Dimension
map(Types.UNSIGNED_BYTE); // Difficulty
map(Types.UNSIGNED_BYTE); // Max players
map(Types.STRING); // Level type
read(Types.BOOLEAN); // Reduced debug info
handler(playerTrackerHandler());
handler(wrapper -> {
final int entityId = wrapper.get(Types.INT, 0);
if (ViaRewind.getConfig().isReplaceAdventureMode()) {
if (wrapper.get(Types.UNSIGNED_BYTE, 0) == 2) { // adventure
wrapper.set(Types.UNSIGNED_BYTE, 0, (short) 0); // survival
}
}
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
tracker.addPlayer(entityId, wrapper.user().getProtocolInfo().getUuid());
tracker.setClientEntityGameMode(wrapper.get(Types.UNSIGNED_BYTE, 0));
wrapper.user().get(ClientWorld.class).setEnvironment(wrapper.get(Types.BYTE, 0));
// Reset on Velocity server change
wrapper.user().put(new ScoreboardTracker(wrapper.user()));
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.REMOVE_ENTITIES, wrapper -> {
final int[] entities = wrapper.read(Types.VAR_INT_ARRAY_PRIMITIVE);
untrackEntities(wrapper.user(), entities);
wrapper.cancel();
// Split entity destroy packets into smaller packets because 1.8 can handle more entities at once then 1.7 can.
final List<List<Integer>> parts = Lists.partition(Ints.asList(entities), Byte.MAX_VALUE);
for (List<Integer> part : parts) {
final PacketWrapper destroy = PacketWrapper.create(ClientboundPackets1_7_2_5.REMOVE_ENTITIES, wrapper.user());
destroy.write(RewindTypes.INT_ARRAY, part.stream().mapToInt(Integer::intValue).toArray());
destroy.scheduleSend(Protocol1_8To1_7_6_10.class);
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types1_8.ENTITY_DATA_LIST, Types1_7_6_10.ENTITY_DATA_LIST); // Entity data
handler(wrapper -> {
final EntityTracker1_8 tracker = tracker(wrapper.user());
final int entityId = wrapper.get(Types.INT, 0);
final List<EntityData> entityData = wrapper.get(Types1_7_6_10.ENTITY_DATA_LIST, 0);
if (tracker.getHolograms().containsKey(entityId)) {
wrapper.cancel();
tracker.getHolograms().get(entityId).syncState(EntityPacketRewriter1_8.this, entityData);
} else {
handleEntityData(entityId, entityData, wrapper.user());
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.BYTE); // Type id
map(Types.INT); // X
map(Types.INT); // Y
map(Types.INT); // Z
map(Types.BYTE); // Pitch
map(Types.BYTE); // Yaw
map(Types.INT); // Data
// Track entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(EntityTypes1_8.ObjectType::findById));
handler(wrapper -> {
final int entityId = wrapper.get(Types.VAR_INT, 0);
final EntityTypes1_8.EntityType type = EntityTypes1_8.getTypeFromId(wrapper.get(Types.BYTE, 0), true);
int x = wrapper.get(Types.INT, 0);
int y = wrapper.get(Types.INT, 1);
int z = wrapper.get(Types.INT, 2);
byte pitch = wrapper.get(Types.BYTE, 1);
byte yaw = wrapper.get(Types.BYTE, 2);
int data = wrapper.get(Types.INT, 3);
if (type == EntityTypes1_8.ObjectType.ITEM_FRAME.getType()) {
yaw = switch (yaw) {
case -128 -> {
z += 32;
yield 0;
}
case -64 -> {
x -= 32;
yield -64;
}
case 0 -> {
z -= 32;
yield -128;
}
case 64 -> {
x += 32;
yield 64;
}
default -> yaw;
};
} else if (type == EntityTypes1_8.ObjectType.ARMOR_STAND.getType()) {
wrapper.cancel();
final EntityTracker1_8 tracker = tracker(wrapper.user());
final VirtualHologramEntity hologram = tracker.getHolograms().get(entityId);
hologram.setPosition(x / 32.0, y / 32.0, z / 32.0);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
hologram.setHeadYaw(yaw * 360f / 256);
} else if (type != null && type.isOrHasParent(EntityTypes1_8.EntityType.FALLING_BLOCK)) {
int blockId = data & 0xFFF;
int blockData = data >> 12 & 0xF;
final IdAndData replace = protocol.getItemRewriter().handleBlock(blockId, blockData);
if (replace != null) {
blockId = replace.getId();
blockData = replace.getData();
}
wrapper.set(Types.INT, 3, data = (blockId | blockData << 16));
}
wrapper.set(Types.INT, 0, x);
wrapper.set(Types.INT, 1, y);
wrapper.set(Types.INT, 2, z);
wrapper.set(Types.BYTE, 2, yaw);
if (data > 0) {
wrapper.passthrough(Types.SHORT); // Velocity x
wrapper.passthrough(Types.SHORT); // Velocity y
wrapper.passthrough(Types.SHORT); // Velocity z
}
});
}
});
registerTracker(ClientboundPackets1_8.ADD_EXPERIENCE_ORB, EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_8.ADD_GLOBAL_ENTITY, EntityType.LIGHTNING_BOLT);
protocol.registerClientbound(ClientboundPackets1_8.ADD_PAINTING, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.STRING); // Title
map(Types.BLOCK_POSITION1_8, RewindTypes.INT_POSITION); // Position
map(Types.UNSIGNED_BYTE, Types.INT); // Rotation
handler(wrapper -> {
final int entityId = wrapper.get(Types.VAR_INT, 0);
final BlockPosition position = wrapper.get(RewindTypes.INT_POSITION, 0);
final int rotation = wrapper.get(Types.INT, 0);
int modX = 0;
int modZ = 0;
switch (rotation) {
case 0:
modZ = -1;
break;
case 1:
modX = 1;
break;
case 2:
modZ = 1;
break;
case 3:
modX = -1;
break;
}
wrapper.set(RewindTypes.INT_POSITION, 0, new BlockPosition(position.x() + modX, position.y(), position.z() + modZ));
addTrackedEntity(wrapper, entityId, EntityTypes1_8.EntityType.PAINTING);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ADD_MOB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.UNSIGNED_BYTE); // Entity type
map(Types.INT); // X
map(Types.INT); // Y
map(Types.INT); // Z
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
map(Types.BYTE); // Head yaw
map(Types.SHORT); // Velocity x
map(Types.SHORT); // Velocity y
map(Types.SHORT); // Velocity z
map(Types1_8.ENTITY_DATA_LIST, Types1_7_6_10.ENTITY_DATA_LIST); // Entity data
handler(getTrackerHandler(Types.UNSIGNED_BYTE, 0));
// Handle holograms
handler(wrapper -> {
final short typeId = wrapper.get(Types.UNSIGNED_BYTE, 0);
final EntityTypes1_8.EntityType type = EntityTypes1_8.getTypeFromId(typeId, false);
if (type == EntityTypes1_8.EntityType.ARMOR_STAND) {
wrapper.cancel();
final int entityId = wrapper.get(Types.VAR_INT, 0);
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, 0);
final byte headYaw = wrapper.get(Types.BYTE, 2);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(entityId);
hologram.setPosition(x / 32.0, y / 32.0, z / 32.0);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
hologram.setHeadYaw(headYaw * 360f / 256);
hologram.syncState(protocol().getEntityRewriter(), wrapper.get(Types1_7_6_10.ENTITY_DATA_LIST, 0));
}
});
handler(getMobSpawnRewriter(Types1_7_6_10.ENTITY_DATA_LIST));
}
});
protocol.registerClientbound(ClientboundPackets1_8.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
handler(wrapper -> {
final UUID uuid = wrapper.read(Types.UUID);
wrapper.write(Types.STRING, uuid.toString());
final GameProfileStorage gameProfileStorage = wrapper.user().get(GameProfileStorage.class);
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null) {
wrapper.write(Types.STRING, ""); // Name
wrapper.write(Types.VAR_INT, 0); // Properties count
} else {
wrapper.write(Types.STRING, gameProfile.name.length() > 16 ? gameProfile.name.substring(0, 16) : gameProfile.name); // Name
wrapper.write(Types.VAR_INT, gameProfile.properties.size()); // Properties count
for (GameProfileStorage.Property property : gameProfile.properties) {
wrapper.write(Types.STRING, property.name); // Property name
wrapper.write(Types.STRING, property.value); // Property value
wrapper.write(Types.STRING, property.signature == null ? "" : property.signature); // Property signature
}
}
final int entityId = wrapper.get(Types.VAR_INT, 0);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
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());
entityEquipment.write(Types.INT, entityId);
entityEquipment.write(Types.SHORT, i);
entityEquipment.write(RewindTypes.COMPRESSED_NBT_ITEM, i == 4 ? gameProfile.getSkull() : null);
entityEquipment.scheduleSend(Protocol1_8To1_7_6_10.class);
}
}
tracker.addPlayer(entityId, uuid);
});
map(Types.INT); // X
map(Types.INT); // Y
map(Types.INT); // Z
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
map(Types.SHORT); // Current item
map(Types1_8.ENTITY_DATA_LIST, Types1_7_6_10.ENTITY_DATA_LIST); // Entity data
handler(getTrackerAndMetaHandler(Types1_7_6_10.ENTITY_DATA_LIST, EntityTypes1_8.EntityType.PLAYER));
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_EQUIPPED_ITEM, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.SHORT); // Slot
map(Types.ITEM1_8, RewindTypes.COMPRESSED_NBT_ITEM); // Item
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 int id = wrapper.get(Types.INT, 0);
final int limit = tracker.clientEntityId() == id ? 3 : 4;
if (wrapper.get(Types.SHORT, 0) > limit) {
wrapper.cancel();
}
});
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
final short slot = wrapper.get(Types.SHORT, 0);
final UUID uuid = tracker.getPlayerUUID(wrapper.get(Types.INT, 0));
if (uuid == null) {
return;
}
final Item item = wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM, 0);
wrapper.user().get(PlayerSessionStorage.class).setPlayerEquipment(uuid, item, slot);
final GameProfileStorage storage = wrapper.user().get(GameProfileStorage.class);
GameProfileStorage.GameProfile profile = storage.get(uuid);
if (profile != null && profile.gamemode == 3) { // spectator mode didn't exist in 1.7.10
wrapper.cancel();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.PLAYER_SLEEP, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.BLOCK_POSITION1_8, RewindTypes.U_BYTE_POSITION); // Position
}
});
protocol.registerClientbound(ClientboundPackets1_8.TAKE_ITEM_ENTITY, new PacketHandlers() {
@Override
public void register() {
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)));
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_ENTITY_MOTION, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
}
});
protocol.registerClientbound(ClientboundPackets1_8.MOVE_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
}
});
protocol.registerClientbound(ClientboundPackets1_8.MOVE_ENTITY_POS, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.BYTE); // X
map(Types.BYTE); // Y
map(Types.BYTE); // Z
read(Types.BOOLEAN); // On ground
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Types.INT, 0));
if (hologram != null) {
wrapper.cancel();
final int x = wrapper.get(Types.BYTE, 0);
final int y = wrapper.get(Types.BYTE, 1);
final int z = wrapper.get(Types.BYTE, 2);
hologram.setRelativePosition(x / 32.0, y / 32.0, z / 32.0);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.MOVE_ENTITY_ROT, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
read(Types.BOOLEAN); // On ground
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Types.INT, 0));
if (hologram != null) {
wrapper.cancel();
final int yaw = wrapper.get(Types.BYTE, 0);
final int pitch = wrapper.get(Types.BYTE, 1);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.MOVE_ENTITY_POS_ROT, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.BYTE); // X
map(Types.BYTE); // Y
map(Types.BYTE); // Z
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
read(Types.BOOLEAN); // On ground
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Types.INT, 0));
if (hologram != null) {
wrapper.cancel();
final int x = wrapper.get(Types.BYTE, 0);
final int y = wrapper.get(Types.BYTE, 1);
final int z = wrapper.get(Types.BYTE, 2);
final int yaw = wrapper.get(Types.BYTE, 3);
final int pitch = wrapper.get(Types.BYTE, 4);
hologram.setRelativePosition(x / 32.0, y / 32.0, z / 32.0);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.TELEPORT_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.INT); // X
map(Types.INT); // Y
map(Types.INT); // Z
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
read(Types.BOOLEAN); // On ground
handler(wrapper -> {
final int entityId = wrapper.get(Types.INT, 0);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
if (tracker.entityType(entityId) == EntityTypes1_8.EntityType.ABSTRACT_MINECART) { // TODO | Realign all entities?
int y = wrapper.get(Types.INT, 2);
y += 12;
wrapper.set(Types.INT, 2, y);
}
final VirtualHologramEntity hologram = tracker.getHolograms().get(entityId);
if (hologram != null) {
wrapper.cancel();
final int x = wrapper.get(Types.INT, 1);
final int y = wrapper.get(Types.INT, 2);
final int z = wrapper.get(Types.INT, 3);
final int yaw = wrapper.get(Types.BYTE, 0);
final int pitch = wrapper.get(Types.BYTE, 1);
hologram.setPosition(x / 32.0, y / 32.0, z / 32.0);
hologram.setRotation(yaw * 360f / 256, pitch * 360f / 256);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.ROTATE_HEAD, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.BYTE); // Head yaw
handler(wrapper -> {
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
final VirtualHologramEntity hologram = tracker.getHolograms().get(wrapper.get(Types.INT, 0));
if (hologram != null) {
wrapper.cancel();
final int yaw = wrapper.get(Types.BYTE, 0);
hologram.setHeadYaw(yaw * 360f / 256);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_ENTITY_LINK, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Riding Entity id
map(Types.INT); // Vehicle Entity id
map(Types.BOOLEAN); // Leash state
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 int passenger = wrapper.get(Types.INT, 0);
final int vehicle = wrapper.get(Types.INT, 1);
tracker.setPassenger(vehicle, passenger);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.UPDATE_MOB_EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.BYTE); // Effect id
map(Types.BYTE); // Amplifier
map(Types.VAR_INT, Types.SHORT); // Duration
read(Types.BYTE); // Hide particles
}
});
protocol.registerClientbound(ClientboundPackets1_8.REMOVE_MOB_EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT, Types.INT); // Entity id
map(Types.BYTE); // Effect id
}
});
protocol.registerClientbound(ClientboundPackets1_8.UPDATE_ATTRIBUTES, new PacketHandlers() {
@Override
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);
if (tracker.getHolograms().containsKey(wrapper.get(Types.INT, 0))) { // Don't handle properties for hologram emulation
wrapper.cancel();
return;
}
final int amount = wrapper.passthrough(Types.INT);
for (int i = 0; i < amount; i++) {
wrapper.passthrough(Types.STRING); // id
wrapper.passthrough(Types.DOUBLE); // value
int modifierLength = wrapper.read(Types.VAR_INT);
wrapper.write(Types.SHORT, (short) modifierLength);
for (int j = 0; j < modifierLength; j++) {
wrapper.passthrough(Types.UUID); // modifier uuid
wrapper.passthrough(Types.DOUBLE); // modifier amount
wrapper.passthrough(Types.BYTE); // modifier operation
}
}
});
}
});
protocol.cancelClientbound(ClientboundPackets1_8.UPDATE_ENTITY_NBT);
}
@Override
protected void registerRewrites() {
// Handle new entities
mapEntityTypeWithData(EntityType.GUARDIAN, EntityType.SQUID).plainName();
mapEntityTypeWithData(EntityType.ENDERMITE, EntityType.SQUID).plainName();
mapEntityTypeWithData(EntityType.RABBIT, EntityType.CHICKEN).plainName();
// Entity data rewrite
filter().handler(this::handleEntityData);
}
public void handleEntityData(EntityDataHandlerEvent event, EntityData entityData) {
final EntityDataIndex1_7_6_10 metaIndex = EntityDataIndex1_7_6_10.searchIndex(event.entityType(), entityData.id());
if (metaIndex == null) {
// Almost certainly bad data, remove it
event.cancel();
return;
}
if (metaIndex.getOldType() == null) {
event.cancel();
return;
}
final Object value = entityData.getValue();
entityData.setTypeAndValue(metaIndex.getNewType(), value);
entityData.setDataTypeUnsafe(metaIndex.getOldType());
entityData.setId(metaIndex.getIndex());
switch (metaIndex.getOldType()) {
case INT:
if (metaIndex.getNewType() == EntityDataTypes1_8.BYTE) {
entityData.setValue(((Byte) value).intValue());
if (metaIndex == EntityDataIndex1_7_6_10.ABSTRACT_AGEABLE_AGE) {
if ((Integer) entityData.getValue() < 0) {
entityData.setValue(-25000);
}
}
}
if (metaIndex.getNewType() == EntityDataTypes1_8.SHORT) {
entityData.setValue(((Short) value).intValue());
}
if (metaIndex.getNewType() == EntityDataTypes1_8.INT) {
entityData.setValue(value);
}
break;
case BYTE:
if (metaIndex.getNewType() == EntityDataTypes1_8.INT) {
entityData.setValue(((Integer) value).byteValue());
}
if (metaIndex.getNewType() == EntityDataTypes1_8.BYTE) {
if (metaIndex == EntityDataIndex1_7_6_10.ITEM_FRAME_ROTATION) {
entityData.setValue(Integer.valueOf((Byte) value % 4).byteValue());
} else {
entityData.setValue(value);
}
}
if (metaIndex == EntityDataIndex1_7_6_10.PLAYER_SKIN_FLAGS) {
byte flags = (byte) value;
boolean cape = (flags & 0x01) != 0;
flags = (byte) (cape ? 0x00 : 0x02);
entityData.setValue(flags);
}
break;
case ITEM:
entityData.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), (Item) value));
break;
case FLOAT:
case STRING:
case SHORT:
case POSITION:
entityData.setValue(value);
break;
default:
event.cancel();
break;
}
}
@Override
public EntityTypes1_8.EntityType typeFromId(int type) {
return EntityTypes1_8.getTypeFromId(type, false);
}
@Override
public EntityTypes1_8.EntityType objectTypeFromId(int type) {
return EntityTypes1_8.getTypeFromId(type, true);
}
}
@@ -0,0 +1,782 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter;
import com.viaversion.viarewind.ViaRewind;
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_7_6_10to1_7_2_5.packet.ServerboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.TitleRenderProvider;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.*;
import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viarewind.api.minecraft.math.AABB;
import com.viaversion.viarewind.api.minecraft.math.Ray3d;
import com.viaversion.viarewind.api.minecraft.math.RayTracing;
import com.viaversion.viarewind.api.minecraft.math.Vector3d;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.Environment;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
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;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;
public class PlayerPacketRewriter1_8 {
public static void register(Protocol1_8To1_7_6_10 protocol) {
protocol.registerClientbound(ClientboundPackets1_8.CHAT, new PacketHandlers() {
@Override
public void register() {
map(Types.COMPONENT); // Chat message
handler(wrapper -> {
final int position = wrapper.read(Types.BYTE);
if (position == 2) { // Above hotbar
wrapper.cancel();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_DEFAULT_SPAWN_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.INT_POSITION); // Spawn position
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_HEALTH, new PacketHandlers() {
@Override
public void register() {
map(Types.FLOAT); // Health
map(Types.VAR_INT, Types.SHORT); // Food
map(Types.FLOAT); // Food saturation
}
});
protocol.registerClientbound(ClientboundPackets1_8.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Dimension
map(Types.UNSIGNED_BYTE); // Difficulty
map(Types.UNSIGNED_BYTE); // Game mode
handler(wrapper -> {
if (ViaRewind.getConfig().isReplaceAdventureMode()) {
if (wrapper.get(Types.UNSIGNED_BYTE, 1) == 2) {
wrapper.set(Types.UNSIGNED_BYTE, 1, (short) 0);
}
}
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
tracker.setClientEntityGameMode(wrapper.get(Types.UNSIGNED_BYTE, 1));
final Environment dimension = Environment.getEnvironmentById(wrapper.get(Types.INT, 0));
// Clear entities on dimension change and re-track player
final ClientWorld world = wrapper.user().get(ClientWorld.class);
if (world.getEnvironment() != dimension) {
world.setEnvironment(dimension.id());
tracker.clearEntities();
tracker.addEntity(tracker.clientEntityId(), EntityTypes1_8.EntityType.PLAYER);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.PLAYER_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Types.DOUBLE); // X
map(Types.DOUBLE); // Y
map(Types.DOUBLE); // Z
map(Types.FLOAT); // Yaw
map(Types.FLOAT); // Pitch
handler(wrapper -> {
final double x = wrapper.get(Types.DOUBLE, 0);
double y = wrapper.get(Types.DOUBLE, 1);
final double z = wrapper.get(Types.DOUBLE, 2);
final float yaw = wrapper.get(Types.FLOAT, 0);
final float pitch = wrapper.get(Types.FLOAT, 1);
final PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
final int flags = wrapper.read(Types.BYTE);
// x, y, and z
if ((flags & 0x01) == 0x01) wrapper.set(Types.DOUBLE, 0, x + playerSession.getPosX());
if ((flags & 0x02) == 0x02) y += playerSession.getPosY();
playerSession.receivedPosY = y;
wrapper.set(Types.DOUBLE, 1, y + 1.62F);
if ((flags & 0x04) == 0x04) wrapper.set(Types.DOUBLE, 2, z + playerSession.getPosZ());
// yaw and pitch
if ((flags & 0x08) == 0x08) wrapper.set(Types.FLOAT, 0, yaw + playerSession.yaw);
if ((flags & 0x10) == 0x10) wrapper.set(Types.FLOAT, 1, pitch + playerSession.pitch);
wrapper.write(Types.BOOLEAN, playerSession.onGround);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
if (tracker.spectatingClientEntityId != tracker.clientEntityId()) {
wrapper.cancel();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_EXPERIENCE, new PacketHandlers() {
@Override
public void register() {
map(Types.FLOAT); // Experience bar
map(Types.VAR_INT, Types.SHORT); // Level
map(Types.VAR_INT, Types.SHORT); // Total experience
}
});
protocol.registerClientbound(ClientboundPackets1_8.GAME_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Reason
map(Types.FLOAT); // Value
handler(wrapper -> {
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);
if (gameMode == 3 || tracker.isSpectator()) {
UUID myId = wrapper.user().getProtocolInfo().getUuid();
Item[] equipment = new Item[4];
if (gameMode == 3) {
GameProfileStorage.GameProfile profile = wrapper.user().get(GameProfileStorage.class).get(myId);
equipment[3] = profile == null ? null : profile.getSkull();
} else {
for (int i = 0; i < equipment.length; i++) {
equipment[i] = wrapper.user().get(PlayerSessionStorage.class).getPlayerEquipment(myId, i);
}
}
for (int i = 0; i < equipment.length; i++) {
PacketWrapper setSlot = PacketWrapper.create(ClientboundPackets1_7_2_5.CONTAINER_SET_SLOT, wrapper.user());
setSlot.write(Types.BYTE, (byte) 0);
setSlot.write(Types.SHORT, (short) (8 - i));
setSlot.write(RewindTypes.COMPRESSED_NBT_ITEM, equipment[i]);
setSlot.scheduleSend(Protocol1_8To1_7_6_10.class);
}
}
if (gameMode == 2 && ViaRewind.getConfig().isReplaceAdventureMode()) {
gameMode = 0;
wrapper.set(Types.FLOAT, 0, 0.0f);
}
tracker.setClientEntityGameMode(gameMode);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.OPEN_SIGN_EDITOR, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.INT_POSITION); // Position
}
});
protocol.registerClientbound(ClientboundPackets1_8.PLAYER_INFO, wrapper -> {
wrapper.cancel();
final GameProfileStorage gameProfileStorage = wrapper.user().get(GameProfileStorage.class);
final int action = wrapper.read(Types.VAR_INT);
final int count = wrapper.read(Types.VAR_INT);
for (int i = 0; i < count; i++) {
UUID uuid = wrapper.read(Types.UUID);
if (action == 0) {
String name = wrapper.read(Types.STRING);
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null) gameProfile = gameProfileStorage.put(uuid, name);
int propertyCount = wrapper.read(Types.VAR_INT);
while (propertyCount-- > 0) {
String propertyName = wrapper.read(Types.STRING);
String propertyValue = wrapper.read(Types.STRING);
String propertySignature = wrapper.read(Types.OPTIONAL_STRING);
gameProfile.properties.add(new GameProfileStorage.Property(propertyName, propertyValue, propertySignature));
}
int gamemode = wrapper.read(Types.VAR_INT);
int ping = wrapper.read(Types.VAR_INT);
gameProfile.ping = ping;
gameProfile.gamemode = gamemode;
JsonElement displayName = wrapper.read(Types.OPTIONAL_COMPONENT);
if (displayName != null) {
gameProfile.setDisplayName(ChatUtil.jsonToLegacy(wrapper.user(), displayName));
}
final PacketWrapper playerInfo = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, wrapper.user());
playerInfo.write(Types.STRING, gameProfile.getDisplayName());
playerInfo.write(Types.BOOLEAN, true);
playerInfo.write(Types.SHORT, (short) ping);
playerInfo.scheduleSend(Protocol1_8To1_7_6_10.class);
} else if (action == 1) {
final int gamemode = wrapper.read(Types.VAR_INT);
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null || gameProfile.gamemode == gamemode) {
continue;
}
if (gamemode == 3 || gameProfile.gamemode == 3) {
EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
int entityId = tracker.getPlayerEntityId(uuid);
boolean isOwnPlayer = entityId == tracker.clientEntityId();
if (entityId != -1) {
// Weirdly, PlayerEntity has only 4 slots instead of 5
Item[] equipment = new Item[isOwnPlayer ? 4 : 5];
if (gamemode == 3) {
equipment[isOwnPlayer ? 3 : 4] = gameProfile.getSkull();
} else {
for (int j = 0; j < equipment.length; j++) {
equipment[j] = wrapper.user().get(PlayerSessionStorage.class).getPlayerEquipment(uuid, j);
}
}
for (short slot = 0; slot < equipment.length; slot++) {
final PacketWrapper setEquipment = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_EQUIPPED_ITEM, wrapper.user());
setEquipment.write(Types.INT, entityId);
setEquipment.write(Types.SHORT, slot);
setEquipment.write(RewindTypes.COMPRESSED_NBT_ITEM, equipment[slot]);
setEquipment.scheduleSend(Protocol1_8To1_7_6_10.class);
}
}
}
gameProfile.gamemode = gamemode;
} else if (action == 2) {
final int ping = wrapper.read(Types.VAR_INT);
final GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null) {
continue;
}
PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, wrapper.user());
packet.write(Types.STRING, gameProfile.getDisplayName());
packet.write(Types.BOOLEAN, false);
packet.write(Types.SHORT, (short) gameProfile.ping);
packet.scheduleSend(Protocol1_8To1_7_6_10.class);
gameProfile.ping = ping;
packet = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, wrapper.user());
packet.write(Types.STRING, gameProfile.getDisplayName());
packet.write(Types.BOOLEAN, true);
packet.write(Types.SHORT, (short) ping);
packet.scheduleSend(Protocol1_8To1_7_6_10.class);
} else if (action == 3) {
JsonElement displayNameComponent = wrapper.read(Types.OPTIONAL_COMPONENT);
String displayName = displayNameComponent != null ? ChatUtil.jsonToLegacy(wrapper.user(), displayNameComponent) : null;
GameProfileStorage.GameProfile gameProfile = gameProfileStorage.get(uuid);
if (gameProfile == null || gameProfile.displayName == null && displayName == null) continue;
PacketWrapper playerInfo = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, wrapper.user());
playerInfo.write(Types.STRING, gameProfile.getDisplayName());
playerInfo.write(Types.BOOLEAN, false);
playerInfo.write(Types.SHORT, (short) gameProfile.ping);
playerInfo.scheduleSend(Protocol1_8To1_7_6_10.class);
if (gameProfile.displayName == null && displayName != null || gameProfile.displayName != null && displayName == null || !gameProfile.displayName.equals(displayName)) {
gameProfile.setDisplayName(displayName);
}
playerInfo = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, wrapper.user());
playerInfo.write(Types.STRING, gameProfile.getDisplayName());
playerInfo.write(Types.BOOLEAN, true);
playerInfo.write(Types.SHORT, (short) gameProfile.ping);
playerInfo.scheduleSend(Protocol1_8To1_7_6_10.class);
} else if (action == 4) {
final GameProfileStorage.GameProfile gameProfile = gameProfileStorage.remove(uuid);
if (gameProfile == null) {
continue;
}
final PacketWrapper playerInfo = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_INFO, wrapper.user());
playerInfo.write(Types.STRING, gameProfile.getDisplayName());
playerInfo.write(Types.BOOLEAN, false);
playerInfo.write(Types.SHORT, (short) gameProfile.ping);
playerInfo.scheduleSend(Protocol1_8To1_7_6_10.class);
}
}
});
protocol.registerClientbound(ClientboundPackets1_8.PLAYER_ABILITIES, wrapper -> {
final byte flags = wrapper.passthrough(Types.BYTE);
final float flySpeed = wrapper.passthrough(Types.FLOAT);
final float walkSpeed = wrapper.passthrough(Types.FLOAT);
final PlayerSessionStorage abilities = wrapper.user().get(PlayerSessionStorage.class);
abilities.invincible = (flags & 8) == 8;
abilities.allowFly = (flags & 4) == 4;
abilities.flying = (flags & 2) == 2;
abilities.creative = (flags & 1) == 1;
abilities.flySpeed = flySpeed;
abilities.walkSpeed = walkSpeed;
if (abilities.sprinting && abilities.flying) {
wrapper.set(Types.FLOAT, 0, abilities.flySpeed * 2.0f);
}
});
protocol.registerClientbound(ClientboundPackets1_8.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING);
handlerSoftFail(wrapper -> {
wrapper.cancel();
final String channel = wrapper.get(Types.STRING, 0);
if (channel.equals("MC|TrList")) {
wrapper.passthrough(Types.INT); // Window id
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
Item item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8));
wrapper.write(RewindTypes.COMPRESSED_NBT_ITEM, item); // Buy item 1
item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8));
wrapper.write(RewindTypes.COMPRESSED_NBT_ITEM, item); // Buy item 3
boolean has3Items = wrapper.passthrough(Types.BOOLEAN);
if (has3Items) {
item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_8));
wrapper.write(RewindTypes.COMPRESSED_NBT_ITEM, item); // Buy item 2
}
wrapper.passthrough(Types.BOOLEAN); // Unavailable
wrapper.read(Types.INT); // Uses
wrapper.read(Types.INT); // Max uses
}
} else if (channel.equals("MC|Brand")) {
wrapper.write(Types.REMAINING_BYTES, wrapper.read(Types.STRING).getBytes(StandardCharsets.UTF_8));
}
wrapper.setPacketType(null);
final ByteBuf data = Unpooled.buffer();
wrapper.writeToBuffer(data);
// Write new packet to append length
final PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_7_2_5.CUSTOM_PAYLOAD, data, wrapper.user());
packet.passthrough(Types.STRING);
if (data.readableBytes() <= Short.MAX_VALUE) {
packet.write(Types.SHORT, (short) data.readableBytes());
packet.send(Protocol1_8To1_7_6_10.class);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_CAMERA, null, wrapper -> {
wrapper.cancel();
final int entityId = wrapper.read(Types.VAR_INT);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
if (tracker.spectatingClientEntityId != entityId) {
tracker.setSpectating(entityId);
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_TITLES, null, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.cancel();
final int action = wrapper.read(Types.VAR_INT);
final TitleRenderProvider provider = Via.getManager().getProviders().get(TitleRenderProvider.class);
if (provider == null) {
return;
}
final UUID uuid = wrapper.user().getProtocolInfo().getUuid();
switch (action) {
case 0:
provider.setTitle(uuid, wrapper.read(Types.STRING));
break;
case 1:
provider.setSubTitle(uuid, wrapper.read(Types.STRING));
break;
case 2:
provider.setTimings(uuid, wrapper.read(Types.INT), wrapper.read(Types.INT), wrapper.read(Types.INT));
break;
case 3:
provider.clear(uuid);
break;
case 4:
provider.reset(uuid);
break;
}
});
}
});
protocol.cancelClientbound(ClientboundPackets1_8.TAB_LIST);
protocol.registerClientbound(ClientboundPackets1_8.RESOURCE_PACK, ClientboundPackets1_7_2_5.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
create(Types.STRING, "MC|RPack");
handler(wrapper -> {
final ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
try {
// Url
Types.STRING.write(buf, wrapper.read(Types.STRING));
wrapper.write(Types.SHORT_BYTE_ARRAY, Types.REMAINING_BYTES.read(buf));
} finally {
buf.release();
}
});
read(Types.STRING); // Hash
}
});
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);
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);
if (profile != null && profile.uuid != null) {
wrapper.cancel();
final PacketWrapper teleport = PacketWrapper.create(ClientboundPackets1_7_2_5.TELEPORT_ENTITY, wrapper.user());
teleport.write(Types.UUID, profile.uuid);
teleport.send(Protocol1_8To1_7_6_10.class);
}
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.INTERACT, new PacketHandlers() {
@Override
public void register() {
map(Types.INT, Types.VAR_INT); // Entity id
map(Types.BYTE, Types.VAR_INT); // Mode
handler(wrapper -> {
final int mode = wrapper.get(Types.VAR_INT, 1);
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());
double yaw = Math.toRadians(position.yaw);
double pitch = Math.toRadians(position.pitch);
Vector3d dir = new Vector3d(-Math.cos(pitch) * Math.sin(yaw), -Math.sin(pitch), Math.cos(pitch) * Math.cos(yaw));
Ray3d ray = new Ray3d(pos, dir);
Vector3d intersection = RayTracing.trace(ray, boundingBox, 5.0);
if (intersection == null) {
return;
}
intersection.substract(boundingBox.getMin());
wrapper.set(Types.VAR_INT, 1, 2);
wrapper.write(Types.FLOAT, (float) intersection.getX());
wrapper.write(Types.FLOAT, (float) intersection.getY());
wrapper.write(Types.FLOAT, (float) intersection.getZ());
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.MOVE_PLAYER_STATUS_ONLY, new PacketHandlers() {
@Override
public void register() {
map(Types.BOOLEAN); // On ground
handler(wrapper -> wrapper.user().get(PlayerSessionStorage.class).onGround = wrapper.get(Types.BOOLEAN, 0));
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.MOVE_PLAYER_POS, wrapper -> {
final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE);
wrapper.read(Types.DOUBLE); // Head Y
final double z = wrapper.passthrough(Types.DOUBLE);
final PlayerSessionStorage storage = wrapper.user().get(PlayerSessionStorage.class);
storage.onGround = wrapper.passthrough(Types.BOOLEAN);
storage.setPos(x, y, z);
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.MOVE_PLAYER_ROT, wrapper -> {
final PlayerSessionStorage storage = wrapper.user().get(PlayerSessionStorage.class);
storage.yaw = wrapper.passthrough(Types.FLOAT);
storage.pitch = wrapper.passthrough(Types.FLOAT);
storage.onGround = wrapper.passthrough(Types.BOOLEAN);
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.MOVE_PLAYER_POS_ROT, wrapper -> {
final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE);
wrapper.read(Types.DOUBLE); // Head Y
final double z = wrapper.passthrough(Types.DOUBLE);
final PlayerSessionStorage storage = wrapper.user().get(PlayerSessionStorage.class);
storage.setPos(x, y, z);
storage.yaw = wrapper.passthrough(Types.FLOAT);
storage.pitch = wrapper.passthrough(Types.FLOAT);
storage.onGround = wrapper.passthrough(Types.BOOLEAN);
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_ACTION, new PacketHandlers() {
@Override
protected void register() {
map(Types.VAR_INT); // Status
map(RewindTypes.U_BYTE_POSITION, Types.BLOCK_POSITION1_8); // Position
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.USE_ITEM_ON, new PacketHandlers() {
@Override
protected void register() {
map(RewindTypes.U_BYTE_POSITION, Types.BLOCK_POSITION1_8); // Position
map(Types.BYTE); // Direction
map(RewindTypes.COMPRESSED_NBT_ITEM, Types.ITEM1_8); // Item
handler(wrapper -> protocol.getItemRewriter().handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.SWING, wrapper -> {
final int entityId = wrapper.read(Types.INT);
int animation = wrapper.read(Types.BYTE);
if (animation == 1) {
return;
}
wrapper.cancel();
// 1.7 is not sending this packet with animation!=1
switch (animation) {
case 104:
animation = 0;
break;
case 105:
animation = 1;
break;
case 3:
animation = 2;
break;
default:
return;
}
final PacketWrapper animate = PacketWrapper.create(ClientboundPackets1_7_2_5.ANIMATE, wrapper.user());
animate.write(Types.VAR_INT, entityId);
animate.write(Types.VAR_INT, animation);
animate.write(Types.VAR_INT, 0);
animate.send(Protocol1_8To1_7_6_10.class);
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_COMMAND, new PacketHandlers() {
@Override
public void register() {
map(Types.INT, Types.VAR_INT); // Entity id
handler(wrapper -> wrapper.write(Types.VAR_INT, wrapper.read(Types.BYTE) - 1)); // Action id
map(Types.INT, Types.VAR_INT); // Action parameter
handler(wrapper -> {
final int action = wrapper.get(Types.VAR_INT, 1);
if (action == 3 || action == 4) {
final PlayerSessionStorage storage = wrapper.user().get(PlayerSessionStorage.class);
storage.sprinting = action == 3;
final PacketWrapper abilities = PacketWrapper.create(ClientboundPackets1_7_2_5.PLAYER_ABILITIES, wrapper.user());
abilities.write(Types.BYTE, storage.combineAbilities());
abilities.write(Types.FLOAT, storage.sprinting ? storage.flySpeed * 2.0f : storage.flySpeed);
abilities.write(Types.FLOAT, storage.walkSpeed);
abilities.scheduleSend(Protocol1_8To1_7_6_10.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_INPUT, new PacketHandlers() {
@Override
public void register() {
map(Types.FLOAT); // Sideways
map(Types.FLOAT); // Forwards
handler(wrapper -> {
final boolean jump = wrapper.read(Types.BOOLEAN);
final boolean unmount = wrapper.read(Types.BOOLEAN);
short flags = 0;
if (jump) flags += 0x01;
if (unmount) flags += 0x02;
wrapper.write(Types.UNSIGNED_BYTE, flags);
if (!unmount) {
return;
}
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
if (tracker.spectatingClientEntityId != tracker.clientEntityId()) {
PacketWrapper sneakPacket = PacketWrapper.create(ServerboundPackets1_8.PLAYER_COMMAND, wrapper.user());
sneakPacket.write(Types.VAR_INT, tracker.clientEntityId());
sneakPacket.write(Types.VAR_INT, 0); // Start sneaking
sneakPacket.write(Types.VAR_INT, 0); // Action parameter
sneakPacket.scheduleSendToServer(Protocol1_8To1_7_6_10.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.SIGN_UPDATE, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // Position
handler(wrapper -> {
for (int i = 0; i < 4; i++) {
final String line = wrapper.read(Types.STRING);
wrapper.write(Types.COMPONENT, ComponentUtil.legacyToJson(line));
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.PLAYER_ABILITIES, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // Flags
map(Types.FLOAT); // Fly speed
map(Types.FLOAT); // Walk speed
handler(wrapper -> {
final PlayerSessionStorage storage = wrapper.user().get(PlayerSessionStorage.class);
if (storage.allowFly) {
final byte flags = wrapper.get(Types.BYTE, 0);
storage.flying = (flags & 2) == 2;
}
wrapper.set(Types.FLOAT, 0, storage.flySpeed);
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.COMMAND_SUGGESTION, wrapper -> {
final String message = wrapper.passthrough(Types.STRING);
wrapper.write(Types.OPTIONAL_POSITION1_8, null);
if (message.toLowerCase().startsWith("/stp ")) {
wrapper.cancel();
final String[] args = message.split(" ");
if (args.length <= 2) {
final String prefix = args.length == 1 ? "" : args[1];
final GameProfileStorage storage = wrapper.user().get(GameProfileStorage.class);
final List<GameProfileStorage.GameProfile> profiles = storage.getAllWithPrefix(prefix, true);
final PacketWrapper commandSuggestions = PacketWrapper.create(ClientboundPackets1_7_2_5.COMMAND_SUGGESTIONS, wrapper.user());
commandSuggestions.write(Types.VAR_INT, profiles.size());
for (GameProfileStorage.GameProfile profile : profiles) {
commandSuggestions.write(Types.STRING, profile.name);
}
commandSuggestions.scheduleSend(Protocol1_8To1_7_6_10.class);
}
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.CLIENT_INFORMATION, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Locale
map(Types.BYTE); // View distance
map(Types.BYTE); // Chat flags
map(Types.BOOLEAN); // Chat colours
read(Types.BYTE); // Difficulty
handler(wrapper -> {
final boolean showCape = wrapper.read(Types.BOOLEAN);
wrapper.write(Types.UNSIGNED_BYTE, (short) (showCape ? 127 : 126));
});
}
});
protocol.registerServerbound(ServerboundPackets1_7_2_5.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Channel
read(Types.SHORT); // Length
handler(wrapper -> {
final String channel = wrapper.get(Types.STRING, 0);
switch (channel) {
case "MC|TrSel": {
wrapper.passthrough(Types.INT);
wrapper.read(Types.REMAINING_BYTES); // unused data ???
break;
}
case "MC|ItemName": {
final byte[] data = wrapper.read(Types.REMAINING_BYTES);
wrapper.write(Types.STRING, new String(data, StandardCharsets.UTF_8));
final InventoryTracker tracker = wrapper.user().get(InventoryTracker.class);
final PacketWrapper updateCost = PacketWrapper.create(ClientboundPackets1_7_2_5.CONTAINER_SET_DATA, wrapper.user());
updateCost.write(Types.UNSIGNED_BYTE, tracker.anvilId);
updateCost.write(Types.SHORT, (short) 0);
updateCost.write(Types.SHORT, tracker.levelCost);
updateCost.send(Protocol1_8To1_7_6_10.class);
break;
}
case "MC|BEdit":
case "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.write(Types.ITEM1_8, book);
break;
}
case "MC|Brand": {
wrapper.write(Types.STRING, new String(wrapper.read(Types.REMAINING_BYTES), StandardCharsets.UTF_8));
break;
}
}
});
}
});
}
}
@@ -0,0 +1,246 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.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.ScoreboardTracker;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import com.viaversion.viaversion.util.ChatColorUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ScoreboardPacketRewriter1_8 {
public static void register(Protocol1_8To1_7_6_10 protocol) {
protocol.registerClientbound(ClientboundPackets1_8.SET_OBJECTIVE, wrapper -> {
String name = wrapper.passthrough(Types.STRING);
if (name.length() > 16) {
wrapper.set(Types.STRING, 0, name = name.substring(0, 16));
}
final byte mode = wrapper.read(Types.BYTE);
ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
if (mode == 0) {
if (scoreboard.objectiveExists(name)) {
wrapper.cancel();
return;
}
scoreboard.addObjective(name);
} else if (mode == 1) {
if (!scoreboard.objectiveExists(name)) {
wrapper.cancel();
return;
}
if (scoreboard.getColorIndependentSidebar() != null) {
String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent()) {
String sidebar = scoreboard.getColorDependentSidebar().get(color.get());
if (name.equals(sidebar)) {
final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
sidebarPacket.write(Types.BYTE, (byte) 1);
sidebarPacket.write(Types.STRING, scoreboard.getColorIndependentSidebar());
sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class);
}
}
}
scoreboard.removeObjective(name);
} else if (mode == 2) {
if (!scoreboard.objectiveExists(name)) {
wrapper.cancel();
return;
}
}
if (mode == 0 || mode == 2) {
String displayName = wrapper.passthrough(Types.STRING);
if (displayName.length() > 32) {
wrapper.set(Types.STRING, 1, displayName.substring(0, 32));
}
wrapper.read(Types.STRING);
} else {
wrapper.write(Types.STRING, "");
}
wrapper.write(Types.BYTE, mode);
});
protocol.registerClientbound(ClientboundPackets1_8.SET_SCORE, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Name
map(Types.VAR_INT, Types.BYTE); // Mode
handler(wrapper -> {
ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
String name = wrapper.get(Types.STRING, 0);
byte mode = wrapper.get(Types.BYTE, 0);
if (mode == 1) {
name = scoreboard.removeTeamForScore(name);
} else {
name = scoreboard.sendTeamForScore(name);
}
if (name.length() > 16) {
name = ChatColorUtil.stripColor(name);
if (name.length() > 16) {
name = name.substring(0, 16);
}
}
wrapper.set(Types.STRING, 0, name);
String objective = wrapper.read(Types.STRING);
if (objective.length() > 16) {
objective = objective.substring(0, 16);
}
if (mode != 1) {
int score = wrapper.read(Types.VAR_INT);
wrapper.write(Types.STRING, objective);
wrapper.write(Types.INT, score);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_DISPLAY_OBJECTIVE, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // Position
map(Types.STRING); // Score name
handler(wrapper -> {
byte position = wrapper.get(Types.BYTE, 0);
String name = wrapper.get(Types.STRING, 0);
ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
if (position > 2) { // team specific sidebar
byte receiverTeamColor = (byte) (position - 3);
scoreboard.getColorDependentSidebar().put(receiverTeamColor, name);
String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent() && color.get() == receiverTeamColor) {
position = 1;
} else {
position = -1;
}
} else if (position == 1) { // team independent sidebar
scoreboard.setColorIndependentSidebar(name);
String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent() && scoreboard.getColorDependentSidebar().containsKey(color.get())) {
position = -1;
}
}
if (position == -1) {
wrapper.cancel();
return;
}
wrapper.set(Types.BYTE, 0, position);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.SET_PLAYER_TEAM, wrapper -> {
final String team = wrapper.passthrough(Types.STRING);
if (team == null) {
wrapper.cancel();
return;
}
final ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
final byte mode = wrapper.passthrough(Types.BYTE);
if (mode != 0 && !scoreboard.teamExists(team)) {
wrapper.cancel();
return;
} else if (mode == 0 && scoreboard.teamExists(team)) {
scoreboard.removeTeam(team);
final PacketWrapper removeTeam = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, wrapper.user());
removeTeam.write(Types.STRING, team);
removeTeam.write(Types.BYTE, (byte) 1);
removeTeam.send(Protocol1_8To1_7_6_10.class);
}
if (mode == 0) {
scoreboard.addTeam(team);
} else if (mode == 1) {
scoreboard.removeTeam(team);
}
if (mode == 0 || mode == 2) {
wrapper.passthrough(Types.STRING); // Display name
wrapper.passthrough(Types.STRING); // Prefix
wrapper.passthrough(Types.STRING); // Suffix
wrapper.passthrough(Types.BYTE); // Friendly fire
wrapper.read(Types.STRING); // Name tag visibility
byte color = wrapper.read(Types.BYTE);
if (mode == 2 && scoreboard.getTeamColor(team).get() != color) {
final String sidebar = scoreboard.getColorDependentSidebar().get(color);
final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
sidebarPacket.write(Types.BYTE, (byte) 1);
sidebarPacket.write(Types.STRING, sidebar == null ? "" : sidebar);
sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class);
}
scoreboard.setTeamColor(team, color);
}
if (mode == 0 || mode == 3 || mode == 4) {
byte color = scoreboard.getTeamColor(team).get();
String[] entries = wrapper.read(Types.STRING_ARRAY);
List<String> entryList = new ArrayList<>();
for (String entry : entries) {
String username = wrapper.user().getProtocolInfo().getUsername();
if (mode == 4) {
if (!scoreboard.isPlayerInTeam(entry, team)) {
continue;
}
scoreboard.removePlayerFromTeam(entry, team);
if (entry.equals(username)) {
final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
sidebarPacket.write(Types.BYTE, (byte) 1);
sidebarPacket.write(Types.STRING, scoreboard.getColorIndependentSidebar() == null ? "" : scoreboard.getColorIndependentSidebar());
sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class);
}
} else {
scoreboard.addPlayerToTeam(entry, team);
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);
displayObjective.write(Types.STRING, scoreboard.getColorDependentSidebar().get(color));
displayObjective.scheduleSend(Protocol1_8To1_7_6_10.class);
}
}
entryList.add(entry);
}
wrapper.write(Types.SHORT, (short) entryList.size());
for (String entry : entryList) {
wrapper.write(Types.STRING, entry);
}
}
});
}
}
@@ -0,0 +1,288 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter;
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.WorldBorderEmulator;
import com.viaversion.viarewind.api.type.chunk.ChunkType1_7_6;
import com.viaversion.viarewind.api.type.chunk.BulkChunkType1_7_6;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data.Particles1_8;
import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.FixedByteArrayType;
import com.viaversion.viaversion.api.type.types.chunk.BulkChunkType1_8;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_8;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.IdAndData;
public class WorldPacketRewriter1_8 {
public static void register(Protocol1_8To1_7_6_10 protocol) {
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_CHUNK, wrapper -> {
final ClientWorld world = wrapper.user().get(ClientWorld.class);
final Chunk chunk = wrapper.read(ChunkType1_8.forEnvironment(world.getEnvironment()));
protocol.getItemRewriter().handleChunk(chunk);
wrapper.write(ChunkType1_7_6.TYPE, chunk);
});
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_UPDATE, new PacketHandlers() {
@Override
protected void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.U_BYTE_POSITION); // Position
handler(wrapper -> {
int data = wrapper.read(Types.VAR_INT); // Block data
data = protocol.getItemRewriter().handleBlockId(data);
wrapper.write(Types.VAR_INT, IdAndData.getId(data)); // Block id
wrapper.write(Types.UNSIGNED_BYTE, (short) IdAndData.getData(data)); // Block data
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.CHUNK_BLOCKS_UPDATE, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Chunk x
map(Types.INT); // Chunk z
handler(wrapper -> {
final BlockChangeRecord[] records = wrapper.read(Types.BLOCK_CHANGE_ARRAY);
wrapper.write(Types.SHORT, (short) records.length); // Record count
wrapper.write(Types.INT, records.length * 4); // Data array length (position + block id)
for (BlockChangeRecord record : records) {
wrapper.write(Types.SHORT, (short) (record.getSectionX() << 12 | record.getSectionZ() << 8 | record.getY())); // Position
wrapper.write(Types.SHORT, (short) protocol.getItemRewriter().handleBlockId(record.getBlockId())); // Block id
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // Position
map(Types.UNSIGNED_BYTE); // Type
map(Types.UNSIGNED_BYTE); // Data
map(Types.VAR_INT); // Block id
}
});
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_DESTRUCTION, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.BLOCK_POSITION1_8, RewindTypes.INT_POSITION); // Position
map(Types.BYTE); // Progress
}
});
protocol.registerClientbound(ClientboundPackets1_8.MAP_BULK_CHUNK, wrapper -> {
final Chunk[] chunks = wrapper.read(BulkChunkType1_8.TYPE);
for (Chunk chunk : chunks) {
protocol.getItemRewriter().handleChunk(chunk);
}
wrapper.write(BulkChunkType1_7_6.TYPE, chunks);
});
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Effect id
map(Types.BLOCK_POSITION1_8, RewindTypes.BYTE_POSITION); // Position
map(Types.INT); // Data
map(Types.BOOLEAN); // Disable relative volume
}
});
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_PARTICLES, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final int particleId = wrapper.read(Types.INT); // Particle id
Particles1_8 particle = Particles1_8.find(particleId);
if (particle == null) {
particle = Particles1_8.CRIT;
}
wrapper.write(Types.STRING, particle.name); // Particle name
});
read(Types.BOOLEAN); // Long distance
map(Types.FLOAT); // X
map(Types.FLOAT); // Y
map(Types.FLOAT); // Z
map(Types.FLOAT); // Offset x
map(Types.FLOAT); // Offset y
map(Types.FLOAT); // Offset z
map(Types.FLOAT); // Particle data
map(Types.INT); // Particle count
handler(wrapper -> {
String name = wrapper.get(Types.STRING, 0);
Particles1_8 particle = Particles1_8.find(name);
if (particle == Particles1_8.ICON_CRACK || particle == Particles1_8.BLOCK_CRACK || particle == Particles1_8.BLOCK_DUST) {
int id = wrapper.read(Types.VAR_INT);
int data = particle == Particles1_8.ICON_CRACK ? wrapper.read(Types.VAR_INT) : id / 4096;
id %= 4096;
if (id >= 256 && id <= 422 || id >= 2256 && id <= 2267) { //item
particle = Particles1_8.ICON_CRACK;
} else if (id >= 0 && id <= 164 || id >= 170 && id <= 175) {
if (particle == Particles1_8.ICON_CRACK)
particle = Particles1_8.BLOCK_CRACK;
} else {
wrapper.cancel();
return;
}
name = particle.name + "_" + id + "_" + data;
}
wrapper.set(Types.STRING, 0, name);
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.UPDATE_SIGN, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // position
handler(wrapper -> {
for (int i = 0; i < 4; i++) {
String line = wrapper.read(Types.STRING);
line = ChatUtil.jsonToLegacy(wrapper.user(), line);
line = ChatUtil.removeUnusedColor(line, '0');
if (line.length() > 15) {
line = ChatColorUtil.stripColor(line);
if (line.length() > 15) line = line.substring(0, 15);
}
wrapper.write(Types.STRING, line);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper -> {
wrapper.cancel();
final int id = wrapper.read(Types.VAR_INT);
final byte scale = wrapper.read(Types.BYTE);
final int iconCount = wrapper.read(Types.VAR_INT);
byte[] icons = new byte[iconCount * 4];
for (int i = 0; i < iconCount; i++) {
final int directionAndType = wrapper.read(Types.BYTE);
icons[i * 4] = (byte) (directionAndType >> 4 & 0xF);
icons[i * 4 + 1] = wrapper.read(Types.BYTE); // x
icons[i * 4 + 2] = wrapper.read(Types.BYTE); // z
icons[i * 4 + 3] = (byte) (directionAndType & 0xF);
}
final short columns = wrapper.read(Types.UNSIGNED_BYTE);
if (columns > 0) {
final short rows = wrapper.read(Types.UNSIGNED_BYTE);
final short x = wrapper.read(Types.UNSIGNED_BYTE);
final short z = wrapper.read(Types.UNSIGNED_BYTE);
final byte[] data = wrapper.read(Types.BYTE_ARRAY_PRIMITIVE);
for (int column = 0; column < columns; column++) {
byte[] columnData = new byte[rows + 3];
columnData[0] = 0;
columnData[1] = (byte) (x + column);
columnData[2] = (byte) z;
for (int i = 0; i < rows; i++) {
columnData[i + 3] = data[column + i * columns];
}
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user());
mapData.write(Types.VAR_INT, id); // map id
mapData.write(Types.SHORT, (short) columnData.length); // data length
mapData.write(new FixedByteArrayType(columnData.length), columnData); // data
mapData.send(Protocol1_8To1_7_6_10.class);
}
}
if (iconCount > 0) {
final byte[] iconData = new byte[iconCount * 3 + 1];
iconData[0] = 1;
for (int i = 0; i < iconCount; i++) {
iconData[i * 3 + 1] = (byte) (icons[i * 4] << 4 | icons[i * 4 + 3] & 0xF);
iconData[i * 3 + 2] = icons[i * 4 + 1];
iconData[i * 3 + 3] = icons[i * 4 + 2];
}
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user());
mapData.write(Types.VAR_INT, id); // map id
mapData.write(Types.SHORT, (short) iconData.length); // data length
mapData.write(new FixedByteArrayType(iconData.length), iconData); // data
mapData.send(Protocol1_8To1_7_6_10.class);
}
// Update scale
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user());
mapData.write(Types.VAR_INT, id); // map id
mapData.write(Types.SHORT, (short) 2); // data length
mapData.write(new FixedByteArrayType(2), new byte[]{2, scale}); // data
mapData.send(Protocol1_8To1_7_6_10.class);
});
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // position
map(Types.UNSIGNED_BYTE); // action
map(Types.NAMED_COMPOUND_TAG, RewindTypes.COMPRESSED_NBT); // nbt
}
});
protocol.cancelClientbound(ClientboundPackets1_8.CHANGE_DIFFICULTY);
protocol.cancelClientbound(ClientboundPackets1_8.PLAYER_COMBAT);
protocol.registerClientbound(ClientboundPackets1_8.SET_BORDER, null, wrapper -> {
final WorldBorderEmulator emulator = wrapper.user().get(WorldBorderEmulator.class);
wrapper.cancel();
final int action = wrapper.read(Types.VAR_INT);
if (action == 0) { // set size
emulator.setSize(wrapper.read(Types.DOUBLE)); // radius
} else if (action == 1) { // lerp size
emulator.lerpSize(wrapper.read(Types.DOUBLE), wrapper.read(Types.DOUBLE), wrapper.read(Types.VAR_LONG)); // old radius, new radius, speed
} else if (action == 2) { // set center
emulator.setCenter(wrapper.read(Types.DOUBLE), wrapper.read(Types.DOUBLE)); // x, z
} else if (action == 3) { // initialize
emulator.init(
wrapper.read(Types.DOUBLE), wrapper.read(Types.DOUBLE), // x, z
wrapper.read(Types.DOUBLE), wrapper.read(Types.DOUBLE), // old radius, new radius
wrapper.read(Types.VAR_LONG) // speed
);
}
});
}
}
@@ -15,13 +15,13 @@
* 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.protocol1_7_6_10to1_8.storage;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
/**
* @see com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.provider.CompressionHandlerProvider
* @see com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.CompressionHandlerProvider
*/
public class CompressionStatusTracker extends StoredObject {
public boolean removeCompression = false;
@@ -15,17 +15,17 @@
* 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.protocol1_7_6_10to1_8.storage;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ServerboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.data.VirtualHologramEntity;
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.VirtualHologramEntity;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntArrayMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
@@ -33,7 +33,7 @@ import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.Map;
import java.util.UUID;
@@ -50,13 +50,13 @@ public class EntityTracker1_8 extends EntityTrackerBase {
private int clientEntityGameMode;
public EntityTracker1_8(UserConnection connection) {
super(connection, EntityTypes1_10.EntityType.ENTITY_HUMAN);
super(connection, EntityTypes1_8.EntityType.PLAYER);
}
@Override
public void addEntity(int id, EntityType type) {
super.addEntity(id, type);
if (type == EntityTypes1_10.EntityType.ARMOR_STAND) {
if (type == EntityTypes1_8.EntityType.ARMOR_STAND) {
holograms.put(id, new VirtualHologramEntity(user(), id));
}
}
@@ -115,12 +115,12 @@ public class EntityTracker1_8 extends EntityTrackerBase {
protected void startSneaking() {
try {
final PacketWrapper entityAction = PacketWrapper.create(ServerboundPackets1_7_2_5.ENTITY_ACTION, user());
entityAction.write(Type.VAR_INT, this.clientEntityId()); // Entity id
entityAction.write(Type.VAR_INT, 0); // Action id
entityAction.write(Type.VAR_INT, 0); // Jump boost
final PacketWrapper entityAction = PacketWrapper.create(ServerboundPackets1_7_2_5.PLAYER_COMMAND, user());
entityAction.write(Types.VAR_INT, this.clientEntityId()); // Entity id
entityAction.write(Types.VAR_INT, 0); // Action id
entityAction.write(Types.VAR_INT, 0); // Jump boost
entityAction.sendToServer(Protocol1_7_6_10To1_8.class);
entityAction.sendToServer(Protocol1_8To1_7_6_10.class);
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to send sneak packet", e);
}
@@ -143,12 +143,12 @@ public class EntityTracker1_8 extends EntityTrackerBase {
protected void attachEntity(final int target) {
try {
final PacketWrapper attachEntity = PacketWrapper.create(ClientboundPackets1_8.ATTACH_ENTITY, user());
attachEntity.write(Type.INT, this.clientEntityId()); // vehicle id
attachEntity.write(Type.INT, target); // passenger id
attachEntity.write(Type.BOOLEAN, false); // leash
final PacketWrapper attachEntity = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_LINK, user());
attachEntity.write(Types.INT, this.clientEntityId()); // vehicle id
attachEntity.write(Types.INT, target); // passenger id
attachEntity.write(Types.BOOLEAN, false); // leash
attachEntity.scheduleSend(Protocol1_7_6_10To1_8.class);
attachEntity.scheduleSend(Protocol1_8To1_7_6_10.class);
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to send attach packet", e);
}
@@ -15,16 +15,16 @@
* 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.protocol1_7_6_10to1_8.storage;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.util.ChatColorUtil;
import java.util.*;
@@ -15,7 +15,7 @@
* 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.protocol1_7_6_10to1_8.storage;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -15,7 +15,7 @@
* 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.protocol1_7_6_10to1_8.storage;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -15,18 +15,18 @@
* 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.protocol1_7_6_10to1_8.storage;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viarewind.protocol.protocol1_7_2_5to1_7_6_10.ClientboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
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.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import java.util.*;
public class Scoreboard extends StoredObject {
public class ScoreboardTracker extends StoredObject {
private final HashMap<String, List<String>> teams = new HashMap<>();
private final HashSet<String> objectives = new HashSet<>();
private final HashMap<String, ScoreTeam> scoreTeams = new HashMap<>();
@@ -35,7 +35,7 @@ public class Scoreboard extends StoredObject {
private String colorIndependentSidebar;
private final HashMap<Byte, String> colorDependentSidebar = new HashMap<>();
public Scoreboard(UserConnection user) {
public ScoreboardTracker(UserConnection user) {
super(user);
}
@@ -110,7 +110,7 @@ public class Scoreboard extends StoredObject {
return objectives.contains(name);
}
public String sendTeamForScore(String score) throws Exception {
public String sendTeamForScore(String score) {
if (score.length() <= 16) return score;
if (scoreTeams.containsKey(score)) return scoreTeams.get(score).name;
int l = 16;
@@ -132,29 +132,29 @@ public class Scoreboard extends StoredObject {
scoreTeams.put(score, scoreTeam);
scoreTeamNames.add(name);
PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.TEAMS, getUser());
teamPacket.write(Type.STRING, name);
teamPacket.write(Type.BYTE, (byte) 0);
teamPacket.write(Type.STRING, "ViaRewind");
teamPacket.write(Type.STRING, prefix);
teamPacket.write(Type.STRING, suffix);
teamPacket.write(Type.BYTE, (byte) 0);
teamPacket.write(Type.SHORT, (short) 1);
teamPacket.write(Type.STRING, name);
teamPacket.send(Protocol1_7_6_10To1_8.class);
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;
}
public String removeTeamForScore(String score) throws Exception {
public String removeTeamForScore(String score) {
ScoreTeam scoreTeam = scoreTeams.remove(score);
if (scoreTeam == null) return score;
scoreTeamNames.remove(scoreTeam.name);
PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.TEAMS, getUser());
teamPacket.write(Type.STRING, scoreTeam.name);
teamPacket.write(Type.BYTE, (byte) 1);
teamPacket.send(Protocol1_7_6_10To1_8.class);
PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, getUser());
teamPacket.write(Types.STRING, scoreTeam.name);
teamPacket.write(Types.BYTE, (byte) 1);
teamPacket.send(Protocol1_8To1_7_6_10.class);
return scoreTeam.name;
}
@@ -15,7 +15,7 @@
* 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.protocol1_7_6_10to1_8.storage;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -15,17 +15,17 @@
* 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.protocol1_7_6_10to1_8.task;
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.task;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.Protocol1_7_6_10To1_8;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.PlayerSessionStorage;
import com.viaversion.viarewind.protocol.protocol1_7_6_10to1_8.storage.WorldBorderEmulator;
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.PlayerSessionStorage;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.WorldBorderEmulator;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.logging.Level;
@@ -73,19 +73,19 @@ public class WorldBorderUpdateTask implements Runnable {
double particleOffset = 2.5;
final PacketWrapper spawnParticle = PacketWrapper.create(ClientboundPackets1_8.SPAWN_PARTICLE, connection);
spawnParticle.write(Type.STRING, ViaRewind.getConfig().getWorldBorderParticle()); // particle name
spawnParticle.write(Type.FLOAT, (float) (side.modX != 0 ? worldBorderEmulatorTracker.getX() + (radius * side.modX) : centerH)); // x
spawnParticle.write(Type.FLOAT, (float) centerV); // y
spawnParticle.write(Type.FLOAT, (float) (side.modX == 0 ? worldBorderEmulatorTracker.getZ() + (radius * side.modZ) : centerH)); // z
spawnParticle.write(Type.FLOAT, (float) (side.modX != 0 ? 0f : (maxH - minH) / particleOffset)); // offset x
spawnParticle.write(Type.FLOAT, (float) ((maxV - minV) / particleOffset)); // offset y
spawnParticle.write(Type.FLOAT, (float) (side.modX == 0 ? 0f : (maxH - minH) / particleOffset)); // offset z
spawnParticle.write(Type.FLOAT, 0F); // particle data
spawnParticle.write(Type.INT, (int) Math.floor((maxH - minH) * (maxV - minV) * 0.5));
final PacketWrapper spawnParticle = PacketWrapper.create(ClientboundPackets1_8.LEVEL_PARTICLES, connection);
spawnParticle.write(Types.STRING, ViaRewind.getConfig().getWorldBorderParticle()); // particle name
spawnParticle.write(Types.FLOAT, (float) (side.modX != 0 ? worldBorderEmulatorTracker.getX() + (radius * side.modX) : centerH)); // x
spawnParticle.write(Types.FLOAT, (float) centerV); // y
spawnParticle.write(Types.FLOAT, (float) (side.modX == 0 ? worldBorderEmulatorTracker.getZ() + (radius * side.modZ) : centerH)); // z
spawnParticle.write(Types.FLOAT, (float) (side.modX != 0 ? 0f : (maxH - minH) / particleOffset)); // offset x
spawnParticle.write(Types.FLOAT, (float) ((maxV - minV) / particleOffset)); // offset y
spawnParticle.write(Types.FLOAT, (float) (side.modX == 0 ? 0f : (maxH - minH) / particleOffset)); // offset z
spawnParticle.write(Types.FLOAT, 0F); // particle data
spawnParticle.write(Types.INT, (int) Math.floor((maxH - minH) * (maxV - minV) * 0.5));
try {
spawnParticle.send(Protocol1_7_6_10To1_8.class);
spawnParticle.send(Protocol1_8To1_7_6_10.class);
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to send world border particle", e);
}
@@ -15,61 +15,60 @@
* 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.protocol1_8to1_9;
package com.viaversion.viarewind.protocol.v1_9to1_8;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.data.RewindMappings;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.metadata.MetadataRewriter1_8To1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.packets.*;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.*;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.task.CooldownIndicatorTask;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.task.LevitationUpdateTask;
import com.viaversion.viarewind.protocol.v1_9to1_8.data.RewindMappingData1_8;
import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.EntityPacketRewriter1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.*;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.*;
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.UserConnection;
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.protocol1_8.ServerboundPackets1_8;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ServerboundPackets1_9;
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;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_9;
import java.util.concurrent.TimeUnit;
public class Protocol1_8To1_9 extends BackwardsProtocol<ClientboundPackets1_9, ClientboundPackets1_8, ServerboundPackets1_9, ServerboundPackets1_8> {
public class Protocol1_9To1_8 extends BackwardsProtocol<ClientboundPackets1_9, ClientboundPackets1_8, ServerboundPackets1_9, ServerboundPackets1_8> {
public static final ValueTransformer<Double, Integer> DOUBLE_TO_INT_TIMES_32 = new ValueTransformer<Double, Integer>(Type.INT) {
public static final ValueTransformer<Double, Integer> DOUBLE_TO_INT_TIMES_32 = new ValueTransformer<Double, Integer>(Types.INT) {
@Override
public Integer transform(PacketWrapper wrapper, Double inputValue) {
return (int) (inputValue * 32.0D);
}
};
public static final ValueTransformer<Float, Byte> DEGREES_TO_ANGLE = new ValueTransformer<Float, Byte>(Type.BYTE) {
public static final ValueTransformer<Float, Byte> DEGREES_TO_ANGLE = new ValueTransformer<Float, Byte>(Types.BYTE) {
@Override
public Byte transform(PacketWrapper packetWrapper, Float degrees) {
return (byte) ((degrees / 360F) * 256);
}
};
public static final RewindMappings MAPPINGS = new RewindMappings();
public static final RewindMappingData1_8 MAPPINGS = new RewindMappingData1_8();
private final BlockItemPackets1_9 itemRewriter = new BlockItemPackets1_9(this);
private final MetadataRewriter1_8To1_9 metadataRewriter = new MetadataRewriter1_8To1_9(this);
private final BlockItemPacketRewriter1_9 itemRewriter = new BlockItemPacketRewriter1_9(this);
private final EntityPacketRewriter1_9 entityRewriter = new EntityPacketRewriter1_9(this);
public Protocol1_8To1_9() {
public Protocol1_9To1_8() {
super(ClientboundPackets1_9.class, ClientboundPackets1_8.class, ServerboundPackets1_9.class, ServerboundPackets1_8.class);
}
@Override
protected void registerPackets() {
metadataRewriter.register();
entityRewriter.register();
itemRewriter.register();
EntityPackets1_9.register(this);
PlayerPackets1_9.register(this);
WorldPackets1_9.register(this);
PlayerPacketRewriter1_9.register(this);
WorldPacketRewriter1_9.register(this);
}
@Override
@@ -95,18 +94,18 @@ public class Protocol1_8To1_9 extends BackwardsProtocol<ClientboundPackets1_9, C
}
@Override
public RewindMappings getMappingData() {
public RewindMappingData1_8 getMappingData() {
return MAPPINGS;
}
@Override
public BlockItemPackets1_9 getItemRewriter() {
public BlockItemPacketRewriter1_9 getItemRewriter() {
return itemRewriter;
}
@Override
public MetadataRewriter1_8To1_9 getEntityRewriter() {
return metadataRewriter;
public EntityPacketRewriter1_9 getEntityRewriter() {
return entityRewriter;
}
@Override
@@ -15,14 +15,14 @@
* 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.protocol1_8to1_9.emulation;
package com.viaversion.viarewind.protocol.v1_9to1_8.cooldown;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
public class ActionBarVisualization implements CooldownVisualization {
private final UserConnection user;
@@ -41,10 +41,10 @@ public class ActionBarVisualization implements CooldownVisualization {
sendActionBar("§r");
}
private void sendActionBar(String bar) throws Exception {
PacketWrapper actionBarPacket = PacketWrapper.create(ClientboundPackets1_8.CHAT_MESSAGE, user);
actionBarPacket.write(Type.COMPONENT, new JsonPrimitive(bar));
actionBarPacket.write(Type.BYTE, (byte) 2); // Position - above hotbar
actionBarPacket.scheduleSend(Protocol1_8To1_9.class);
private void sendActionBar(final String bar) {
PacketWrapper actionBarPacket = PacketWrapper.create(ClientboundPackets1_8.CHAT, user);
actionBarPacket.write(Types.COMPONENT, new JsonPrimitive(bar));
actionBarPacket.write(Types.BYTE, (byte) 2); // Position - above hotbar
actionBarPacket.scheduleSend(Protocol1_9To1_8.class);
}
}
@@ -15,14 +15,15 @@
* 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.protocol1_8to1_9.emulation;
package com.viaversion.viarewind.protocol.v1_9to1_8.cooldown;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
import java.util.UUID;
public class BossBarVisualization implements CooldownVisualization {
@@ -35,22 +36,22 @@ public class BossBarVisualization implements CooldownVisualization {
@Override
public void show(double progress) throws Exception {
PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_9.BOSSBAR, user);
final PacketWrapper setBossbar = PacketWrapper.create(ClientboundPackets1_9.BOSS_EVENT, user);
if (bossUUID == null) {
bossUUID = UUID.randomUUID();
wrapper.write(Type.UUID, bossUUID);
wrapper.write(Type.VAR_INT, 0); // Action - add
wrapper.write(Type.COMPONENT, new JsonPrimitive(" ")); // Title
wrapper.write(Type.FLOAT, (float) progress); // Health
wrapper.write(Type.VAR_INT, 0); // Color
wrapper.write(Type.VAR_INT, 0); // Division
wrapper.write(Type.UNSIGNED_BYTE, (short) 0); // Flags
setBossbar.write(Types.UUID, bossUUID);
setBossbar.write(Types.VAR_INT, 0); // Action - add
setBossbar.write(Types.COMPONENT, new JsonPrimitive(" ")); // Title
setBossbar.write(Types.FLOAT, (float) progress); // Health
setBossbar.write(Types.VAR_INT, 0); // Color
setBossbar.write(Types.VAR_INT, 0); // Division
setBossbar.write(Types.UNSIGNED_BYTE, (short) 0); // Flags
} else {
wrapper.write(Type.UUID, bossUUID);
wrapper.write(Type.VAR_INT, 2); // Action - update health
wrapper.write(Type.FLOAT, (float) progress); // Health
setBossbar.write(Types.UUID, bossUUID);
setBossbar.write(Types.VAR_INT, 2); // Action - update health
setBossbar.write(Types.FLOAT, (float) progress); // Health
}
wrapper.send(Protocol1_8To1_9.class, false);
setBossbar.send(Protocol1_9To1_8.class, false);
}
@Override
@@ -58,10 +59,10 @@ public class BossBarVisualization implements CooldownVisualization {
if (bossUUID == null) {
return;
}
PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_9.BOSSBAR, null, user);
wrapper.write(Type.UUID, bossUUID);
wrapper.write(Type.VAR_INT, 1); // Action - remove
wrapper.send(Protocol1_8To1_9.class, false);
final PacketWrapper removeBossbar = PacketWrapper.create(ClientboundPackets1_9.BOSS_EVENT, user);
removeBossbar.write(Types.UUID, bossUUID);
removeBossbar.write(Types.VAR_INT, 1); // Action - remove
removeBossbar.send(Protocol1_9To1_8.class, false);
bossUUID = null;
}
}
@@ -15,7 +15,7 @@
* 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.protocol1_8to1_9.emulation;
package com.viaversion.viarewind.protocol.v1_9to1_8.cooldown;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.api.ViaRewindConfig.CooldownIndicator;
@@ -52,18 +52,13 @@ public interface CooldownVisualization {
}
static Factory fromIndicator(CooldownIndicator indicator) {
switch (indicator) {
case TITLE:
return TitleCooldownVisualization::new;
case BOSS_BAR:
return BossBarVisualization::new;
case ACTION_BAR:
return ActionBarVisualization::new;
case DISABLED:
return DISABLED;
default:
throw new IllegalArgumentException("Unexpected: " + indicator);
}
return switch (indicator) {
case TITLE -> TitleCooldownVisualization::new;
case BOSS_BAR -> BossBarVisualization::new;
case ACTION_BAR -> ActionBarVisualization::new;
case DISABLED -> DISABLED;
default -> throw new IllegalArgumentException("Unexpected: " + indicator);
};
}
Factory DISABLED = user -> new DisabledCooldownVisualization();
@@ -15,16 +15,16 @@
* 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.protocol1_8to1_9.emulation;
package com.viaversion.viarewind.protocol.v1_9to1_8.cooldown;
public class DisabledCooldownVisualization implements CooldownVisualization {
@Override
public void show(double progress) {
}
@Override
public void hide() {
}
}
@@ -15,17 +15,24 @@
* 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.protocol1_8to1_9.emulation;
package com.viaversion.viarewind.protocol.v1_9to1_8.cooldown;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
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;
private final UserConnection user;
public TitleCooldownVisualization(UserConnection user) {
@@ -34,8 +41,15 @@ public class TitleCooldownVisualization implements CooldownVisualization {
@Override
public void show(double progress) throws Exception {
String text = CooldownVisualization.buildProgressText("˙", progress);
sendTitle("", text, 0, 2, 5);
final String text = CooldownVisualization.buildProgressText("˙", progress);
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);
});
}
@Override
@@ -43,34 +57,11 @@ public class TitleCooldownVisualization implements CooldownVisualization {
sendTitlePacket(ACTION_HIDE, wrapper -> {});
}
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;
private void sendTitle(String titleText, String subTitleText, int fadeIn, int stay, int fadeOut) throws Exception {
sendTitlePacket(
ACTION_SET_TITLE,
packet -> packet.write(Type.COMPONENT, new JsonPrimitive(titleText))
);
sendTitlePacket(
ACTION_SET_SUBTITLE,
packet -> packet.write(Type.COMPONENT, new JsonPrimitive(subTitleText))
);
sendTitlePacket(
ACTION_SET_TIMES_AND_DISPLAY,
packet -> {
packet.write(Type.INT, fadeIn);
packet.write(Type.INT, stay);
packet.write(Type.INT, fadeOut);
}
);
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 sendTitlePacket(int action, Consumer<PacketWrapper> writer) throws Exception {
PacketWrapper titlePacket = PacketWrapper.create(ClientboundPackets1_8.TITLE, user);
titlePacket.write(Type.VAR_INT, action);
writer.accept(titlePacket);
titlePacket.scheduleSend(Protocol1_8To1_9.class);
}
}
@@ -15,11 +15,11 @@
* 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.protocol1_8to1_9.data;
package com.viaversion.viarewind.protocol.v1_9to1_8.data;
import java.util.HashMap;
public class EffectMappings {
public class EffectIdMappings1_8 {
private static final HashMap<Integer, Integer> effects = new HashMap<>();
@@ -15,39 +15,39 @@
* 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.protocol1_8to1_9.metadata;
package com.viaversion.viarewind.protocol.v1_9to1_8.data;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.metadata.MetaIndex;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.data.EntityDataIndex1_9;
import com.viaversion.viaversion.util.Pair;
import java.util.HashMap;
import java.util.Optional;
public class MetaIndex1_8to1_9 {
public class EntityDataIndex1_8 {
private static final HashMap<Pair<EntityTypes1_10.EntityType, Integer>, MetaIndex> metadataRewrites = new HashMap<>();
private static final HashMap<Pair<EntityTypes1_9.EntityType, Integer>, EntityDataIndex1_9> ENTITY_DATA_REWRITES = new HashMap<>();
static {
for (MetaIndex index : MetaIndex.values()) {
metadataRewrites.put(new Pair<>(index.getClazz(), index.getNewIndex()), index);
for (EntityDataIndex1_9 index : EntityDataIndex1_9.values()) {
ENTITY_DATA_REWRITES.put(new Pair<>(index.getClazz(), index.getNewIndex()), index);
}
}
private static Optional<MetaIndex> getIndex(final EntityType type, final int index) {
private static Optional<EntityDataIndex1_9> getIndex(final EntityType type, final int index) {
final Pair<EntityType, Integer> pair = new Pair<>(type, index);
if (metadataRewrites.containsKey(pair)) {
return Optional.of(metadataRewrites.get(pair));
if (ENTITY_DATA_REWRITES.containsKey(pair)) {
return Optional.of(ENTITY_DATA_REWRITES.get(pair));
} else {
return Optional.empty();
}
}
public static MetaIndex searchIndex(final EntityType type, final int index) {
public static EntityDataIndex1_9 searchIndex(final EntityType type, final int index) {
EntityType currentType = type;
do {
final Optional<MetaIndex> optMeta = getIndex(currentType, index);
final Optional<EntityDataIndex1_9> optMeta = getIndex(currentType, index);
if (optMeta.isPresent()) {
return optMeta.get();
}
@@ -55,4 +55,5 @@ public class MetaIndex1_8to1_9 {
} while (currentType != null);
return null;
}
}
@@ -15,20 +15,20 @@
* 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.protocol1_8to1_9.data;
package com.viaversion.viarewind.protocol.v1_9to1_8.data;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ItemRewriter;
import com.viaversion.viaversion.protocols.v1_8to1_9.data.PotionIdMappings1_9;
import java.util.HashMap;
import java.util.Map;
// TODO | Check if this is correct???
public class PotionMappings {
public class PotionIdMappings1_8 {
public static final Map<String, String> POTION_NAME_INDEX = new HashMap<>();
public static final Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>();
static {
POTION_NAME_TO_ID.putAll(ItemRewriter.POTION_NAME_TO_ID);
POTION_NAME_TO_ID.putAll(PotionIdMappings1_9.POTION_NAME_TO_ID);
POTION_NAME_TO_ID.put("luck", 8203);
POTION_NAME_INDEX.put("water", "§rWater Bottle");
@@ -15,20 +15,20 @@
* 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.protocol1_8to1_9.data;
package com.viaversion.viarewind.protocol.v1_9to1_8.data;
import com.viaversion.viarewind.api.data.VRMappingDataLoader;
import com.viaversion.viarewind.api.data.RewindMappingDataLoader;
import com.viaversion.viaversion.libs.fastutil.objects.ObjectArrayList;
import com.viaversion.viaversion.libs.fastutil.objects.ObjectList;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.nbt.tag.CompoundTag;
public final class RewindMappings extends com.viaversion.viarewind.api.data.RewindMappings {
public final class RewindMappingData1_8 extends com.viaversion.viarewind.api.data.RewindMappingData {
private final ObjectList<String> sounds = new ObjectArrayList<>();
public RewindMappings() {
public RewindMappingData1_8() {
super("1.9.4", "1.8");
}
@@ -36,7 +36,7 @@ public final class RewindMappings extends com.viaversion.viarewind.api.data.Rewi
protected void loadExtras(CompoundTag data) {
super.loadExtras(data);
final JsonArray sounds = VRMappingDataLoader.INSTANCE.loadData("sounds-1.9.json").getAsJsonArray("sounds");
final JsonArray sounds = RewindMappingDataLoader.INSTANCE.loadData("sounds-1.9.json").getAsJsonArray("sounds");
for (final JsonElement sound : sounds) {
this.sounds.add(sound.getAsString());
}
@@ -15,25 +15,25 @@
* 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.protocol1_8to1_9.emulation;
package com.viaversion.viarewind.protocol.v1_9to1_8.data;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ClientboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.legacy.bossbar.BossBar;
import com.viaversion.viaversion.api.legacy.bossbar.BossColor;
import com.viaversion.viaversion.api.legacy.bossbar.BossFlag;
import com.viaversion.viaversion.api.legacy.bossbar.BossStyle;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_8;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_8;
import java.util.*;
import java.util.logging.Level;
public class WitherBossBar implements BossBar {
private static int highestId = Integer.MAX_VALUE - 10000;
private final UUID uuid;
@@ -62,11 +62,7 @@ public class WitherBossBar implements BossBar {
public BossBar setTitle(String title) {
this.title = title;
if (this.visible) {
try {
updateMetadata();
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to update wither boss bar title", e);
}
updateEntityData();
}
return this;
}
@@ -83,11 +79,7 @@ public class WitherBossBar implements BossBar {
this.health = 0.0001f;
}
if (this.visible) {
try {
updateMetadata();
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to update wither boss bar health", e);
}
updateEntityData();
}
return this;
}
@@ -160,12 +152,8 @@ public class WitherBossBar implements BossBar {
@Override
public BossBar show() {
if (!this.visible) {
addWither();
this.visible = true;
try {
spawnWither();
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to spawn wither boss bar", e);
}
}
return this;
}
@@ -173,12 +161,8 @@ public class WitherBossBar implements BossBar {
@Override
public BossBar hide() {
if (this.visible) {
removeWither();
this.visible = false;
try {
despawnWither();
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to despawn wither boss bar", e);
}
}
return this;
}
@@ -193,72 +177,68 @@ public class WitherBossBar implements BossBar {
return this.uuid;
}
public void setLocation(double x, double y, double z) throws Exception {
public void setLocation(double x, double y, double z) {
locX = x;
locY = y;
locZ = z;
updateLocation();
}
private void spawnWither() throws Exception {
PacketWrapper wrapper = PacketWrapper.create(0x0F, null, this.connection);
wrapper.write(Type.VAR_INT, entityId);
wrapper.write(Type.UNSIGNED_BYTE, (short) 64);
wrapper.write(Type.INT, (int) (locX * 32d));
wrapper.write(Type.INT, (int) (locY * 32d));
wrapper.write(Type.INT, (int) (locZ * 32d));
wrapper.write(Type.BYTE, (byte) 0);
wrapper.write(Type.BYTE, (byte) 0);
wrapper.write(Type.BYTE, (byte) 0);
wrapper.write(Type.SHORT, (short) 0);
wrapper.write(Type.SHORT, (short) 0);
wrapper.write(Type.SHORT, (short) 0);
private void addWither() {
final PacketWrapper addMob = PacketWrapper.create(ClientboundPackets1_7_2_5.ADD_MOB, this.connection);
addMob.write(Types.VAR_INT, entityId);
addMob.write(Types.UNSIGNED_BYTE, (short) 64);
addMob.write(Types.INT, (int) (locX * 32D));
addMob.write(Types.INT, (int) (locY * 32D));
addMob.write(Types.INT, (int) (locZ * 32D));
addMob.write(Types.BYTE, (byte) 0);
addMob.write(Types.BYTE, (byte) 0);
addMob.write(Types.BYTE, (byte) 0);
addMob.write(Types.SHORT, (short) 0);
addMob.write(Types.SHORT, (short) 0);
addMob.write(Types.SHORT, (short) 0);
List<Metadata> metadata = new ArrayList<>();
metadata.add(new Metadata(0, MetaType1_8.Byte, (byte) 0x20));
metadata.add(new Metadata(2, MetaType1_8.String, title));
metadata.add(new Metadata(3, MetaType1_8.Byte, (byte) 1));
metadata.add(new Metadata(6, MetaType1_8.Float, health * 300f));
final List<EntityData> entityData = new ArrayList<>();
entityData.add(new EntityData(0, EntityDataTypes1_8.BYTE, (byte) 0x20));
entityData.add(new EntityData(2, EntityDataTypes1_8.STRING, title));
entityData.add(new EntityData(3, EntityDataTypes1_8.BYTE, (byte) 1));
entityData.add(new EntityData(6, EntityDataTypes1_8.FLOAT, health * 300f));
wrapper.write(Types1_8.METADATA_LIST, metadata);
wrapper.scheduleSend(Protocol1_8To1_9.class);
addMob.write(Types1_8.ENTITY_DATA_LIST, entityData);
addMob.scheduleSend(Protocol1_9To1_8.class);
}
private void updateLocation() throws Exception {
PacketWrapper wrapper = PacketWrapper.create(0x18, null, this.connection);
wrapper.write(Type.VAR_INT, entityId);
wrapper.write(Type.INT, (int) (locX * 32d));
wrapper.write(Type.INT, (int) (locY * 32d));
wrapper.write(Type.INT, (int) (locZ * 32d));
wrapper.write(Type.BYTE, (byte) 0);
wrapper.write(Type.BYTE, (byte) 0);
wrapper.write(Type.BOOLEAN, false);
wrapper.scheduleSend(Protocol1_8To1_9.class);
private void updateLocation() {
final PacketWrapper teleportEntity = PacketWrapper.create(ClientboundPackets1_7_2_5.TELEPORT_ENTITY, this.connection);
teleportEntity.write(Types.VAR_INT, entityId);
teleportEntity.write(Types.INT, (int) (locX * 32D));
teleportEntity.write(Types.INT, (int) (locY * 32D));
teleportEntity.write(Types.INT, (int) (locZ * 32D));
teleportEntity.write(Types.BYTE, (byte) 0);
teleportEntity.write(Types.BYTE, (byte) 0);
teleportEntity.write(Types.BOOLEAN, false);
teleportEntity.scheduleSend(Protocol1_9To1_8.class);
}
private void updateMetadata() throws Exception {
PacketWrapper wrapper = PacketWrapper.create(0x1C, null, this.connection);
wrapper.write(Type.VAR_INT, entityId);
private void updateEntityData() {
final PacketWrapper setEntityData = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_ENTITY_DATA, this.connection);
setEntityData.write(Types.VAR_INT, entityId);
List<Metadata> metadata = new ArrayList<>();
metadata.add(new Metadata(2, MetaType1_8.String, title));
metadata.add(new Metadata(6, MetaType1_8.Float, health * 300f));
final List<EntityData> entityData = new ArrayList<>();
entityData.add(new EntityData(2, EntityDataTypes1_8.STRING, title));
entityData.add(new EntityData(6, EntityDataTypes1_8.FLOAT, health * 300f));
wrapper.write(Types1_8.METADATA_LIST, metadata);
wrapper.scheduleSend(Protocol1_8To1_9.class);
setEntityData.write(Types1_8.ENTITY_DATA_LIST, entityData);
setEntityData.scheduleSend(Protocol1_9To1_8.class);
}
private void despawnWither() throws Exception {
PacketWrapper wrapper = PacketWrapper.create(0x13, null, this.connection);
wrapper.write(Type.VAR_INT_ARRAY_PRIMITIVE, new int[]{entityId});
wrapper.scheduleSend(Protocol1_8To1_9.class);
private void removeWither() {
final PacketWrapper removeEntity = PacketWrapper.create(ClientboundPackets1_7_2_5.REMOVE_ENTITIES, this.connection);
removeEntity.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[]{entityId});
removeEntity.scheduleSend(Protocol1_9To1_8.class);
}
public void setPlayerLocation(double posX, double posY, double posZ, float yaw, float pitch) throws Exception {
public void setPlayerLocation(double posX, double posY, double posZ, float yaw, float pitch) {
double yawR = Math.toRadians(yaw);
double pitchR = Math.toRadians(pitch);
@@ -268,4 +248,5 @@ public class WitherBossBar implements BossBar {
setLocation(posX, posY, posZ);
}
}
@@ -15,37 +15,34 @@
* 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.protocol1_8to1_9.packets;
package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viarewind.api.rewriter.VRBlockItemRewriter;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.data.PotionMappings;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.WindowTracker;
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.WindowTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.*;
import com.viaversion.viaversion.protocols.protocol1_8.ServerboundPackets1_8;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ItemRewriter;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.nbt.tag.*;
import com.viaversion.viaversion.protocols.v1_8to1_9.data.EntityIds1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.data.PotionIdMappings1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
import com.viaversion.viaversion.util.Key;
import java.util.HashSet;
import java.util.Set;
import static com.viaversion.viaversion.protocols.protocol1_9to1_8.ItemRewriter.potionNameFromDamage;
public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1_9, ServerboundPackets1_8, Protocol1_8To1_9> {
public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundPackets1_9, ServerboundPackets1_8, Protocol1_9To1_8> {
public final Set<String> VALID_ATTRIBUTES = new HashSet<>();
private LegacyEnchantmentRewriter enchantmentRewriter;
public BlockItemPackets1_9(Protocol1_8To1_9 protocol) {
public BlockItemPacketRewriter1_9(Protocol1_9To1_8 protocol) {
super(protocol, "1.9");
VALID_ATTRIBUTES.add("generic.maxHealth");
@@ -59,12 +56,12 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
@Override
protected void registerPackets() {
registerBlockChange(ClientboundPackets1_9.BLOCK_CHANGE);
registerMultiBlockChange(ClientboundPackets1_9.MULTI_BLOCK_CHANGE);
registerCreativeInvAction(ServerboundPackets1_8.CREATIVE_INVENTORY_ACTION);
registerBlockChange(ClientboundPackets1_9.BLOCK_UPDATE);
registerMultiBlockChange(ClientboundPackets1_9.CHUNK_BLOCKS_UPDATE);
registerSetCreativeModeSlot(ServerboundPackets1_8.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_9.CLOSE_WINDOW, wrapper -> {
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE);
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_CLOSE, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
final WindowTracker tracker = wrapper.user().get(WindowTracker.class);
@@ -75,26 +72,17 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
tracker.remove(windowId);
});
protocol.registerClientbound(ClientboundPackets1_9.OPEN_WINDOW, wrapper -> {
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE);
final String windowType = wrapper.passthrough(Type.STRING);
final JsonElement windowTitle = wrapper.passthrough(Type.COMPONENT);
protocol.registerClientbound(ClientboundPackets1_9.OPEN_SCREEN, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
final String windowType = wrapper.passthrough(Types.STRING);
wrapper.user().get(WindowTracker.class).put(windowId, windowType);
// TODO check
if (windowType.equalsIgnoreCase("minecraft:shulker_box")) {
wrapper.set(Type.STRING, 0, "minecraft:container");
}
if (windowTitle.toString().equalsIgnoreCase("{\"translate\":\"container.shulkerBox\"}")) {
wrapper.set(Type.COMPONENT, 0, JsonParser.parseString("{\"text\":\"Shulker Box\"}"));
}
});
protocol.registerClientbound(ClientboundPackets1_9.WINDOW_ITEMS, wrapper -> {
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE);
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_CONTENT, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
Item[] items = wrapper.read(Type.ITEM1_8_SHORT_ARRAY);
Item[] items = wrapper.read(Types.ITEM1_8_SHORT_ARRAY);
for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(wrapper.user(), items[i]);
}
@@ -115,13 +103,13 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
}
}
wrapper.write(Type.ITEM1_8_SHORT_ARRAY, items);
wrapper.write(Types.ITEM1_8_SHORT_ARRAY, items);
});
protocol.registerClientbound(ClientboundPackets1_9.SET_SLOT, wrapper -> {
final byte windowId = wrapper.passthrough(Type.UNSIGNED_BYTE).byteValue();
final short slot = wrapper.passthrough(Type.SHORT);
final Item item = wrapper.passthrough(Type.ITEM1_8);
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_SLOT, wrapper -> {
final byte windowId = wrapper.passthrough(Types.UNSIGNED_BYTE).byteValue();
final short slot = wrapper.passthrough(Types.SHORT);
final Item item = wrapper.passthrough(Types.ITEM1_8);
handleItemToClient(wrapper.user(), item);
if (windowId == 0 && slot == 45) {
@@ -132,49 +120,49 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
final String windowType = windowTracker.get(windowId);
if (windowType != null && windowType.equalsIgnoreCase("minecraft:brewing_stand")) {
if (slot > 4) {
wrapper.set(Type.SHORT, 0, (short) (slot - 1));
wrapper.set(Types.SHORT, 0, (short) (slot - 1));
} else if (slot == 4) {
wrapper.cancel();
WindowTracker.updateBrewingStand(wrapper.user(), wrapper.get(Type.ITEM1_8, 0), windowId);
WindowTracker.updateBrewingStand(wrapper.user(), wrapper.get(Types.ITEM1_8, 0), windowId);
} else {
windowTracker.getBrewingItems(windowId)[slot] = wrapper.get(Type.ITEM1_8, 0);
windowTracker.getBrewingItems(windowId)[slot] = wrapper.get(Types.ITEM1_8, 0);
}
}
});
protocol.registerServerbound(ServerboundPackets1_8.CLOSE_WINDOW, wrapper -> {
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE);
protocol.registerServerbound(ServerboundPackets1_8.CONTAINER_CLOSE, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
wrapper.user().get(WindowTracker.class).remove(windowId);
});
protocol.registerServerbound(ServerboundPackets1_8.CLICK_WINDOW, new PacketHandlers() {
protocol.registerServerbound(ServerboundPackets1_8.CONTAINER_CLICK, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // Window id
map(Type.SHORT); // Slot
map(Type.BYTE); // Button
map(Type.SHORT); // Action number
map(Type.BYTE, Type.VAR_INT); // Mode
map(Type.ITEM1_8); // Clicked item
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Type.ITEM1_8, 0)));
map(Types.UNSIGNED_BYTE); // Window id
map(Types.SHORT); // Slot
map(Types.BYTE); // Button
map(Types.SHORT); // Action number
map(Types.BYTE, Types.VAR_INT); // Mode
map(Types.ITEM1_8); // Clicked item
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
handler(wrapper -> {
final short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0);
final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0);
final String windowType = wrapper.user().get(WindowTracker.class).get(windowId);
if (windowType != null && windowType.equalsIgnoreCase("minecraft:brewing_stand")) {
final short slot = wrapper.get(Type.SHORT, 0);
final short slot = wrapper.get(Types.SHORT, 0);
if (slot > 3) {
wrapper.set(Type.SHORT, 0, (short) (slot + 1));
wrapper.set(Types.SHORT, 0, (short) (slot + 1));
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.WINDOW_PROPERTY, wrapper -> {
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE);
short key = wrapper.read(Type.SHORT);
short value = wrapper.read(Type.SHORT);
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_DATA, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
short key = wrapper.read(Types.SHORT);
short value = wrapper.read(Types.SHORT);
final WindowTracker tracker = wrapper.user().get(WindowTracker.class);
final String windowType = tracker.get(windowId);
@@ -188,8 +176,8 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
value = (short) (property | (value << 8));
}
}
wrapper.write(Type.SHORT, key);
wrapper.write(Type.SHORT, value);
wrapper.write(Types.SHORT, key);
wrapper.write(Types.SHORT, value);
});
}
@@ -212,16 +200,16 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
enchantmentRewriter.handleToClient(item);
CompoundTag displayTag = tag.get("display");
CompoundTag displayTag = tag.getCompoundTag("display");
if (item.data() != 0 && tag.contains("Unbreakable")) {
final ByteTag unbreakableTag = tag.get("Unbreakable");
final ByteTag unbreakableTag = tag.getByteTag("Unbreakable");
if (unbreakableTag != null && unbreakableTag.asByte() != 0) {
tag.put(nbtTagName() + "|Unbreakable", new ByteTag(unbreakableTag.asByte()));
tag.remove("Unbreakable");
if (displayTag == null) { // Remove the display tag again if it was only added to emulate unbreakable
tag.put("display", displayTag = new CompoundTag());
tag.put(nbtTagName() + "|noDisplay", new ByteTag());
tag.put(nbtTagName() + "|noDisplay", new ByteTag(true));
}
ListTag<StringTag> loreTag = displayTag.getListTag("Lore", StringTag.class);
@@ -239,11 +227,11 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
final StringTag idTag = entityTag.getStringTag("id");
if (idTag != null) {
final String id = idTag.getValue();
if (ItemRewriter.ENTITY_NAME_TO_ID.containsKey(id)) {
data = ItemRewriter.ENTITY_NAME_TO_ID.get(id);
if (EntityIds1_8.ENTITY_NAME_TO_ID.containsKey(id)) {
data = EntityIds1_8.ENTITY_NAME_TO_ID.get(id);
} else if (displayTag == null) {
tag.put("display", displayTag = new CompoundTag());
tag.put(nbtTagName() + "|noDisplay", new ByteTag());
tag.put(nbtTagName() + "|noDisplay", new ByteTag(true));
displayTag.put("Name", new StringTag("§rSpawn " + id));
}
}
@@ -261,8 +249,8 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
final StringTag potionTag = tag.getStringTag("Potion");
if (potionTag != null) {
String potionName = Key.stripMinecraftNamespace(potionTag.getValue());
if (PotionMappings.POTION_NAME_TO_ID.containsKey(potionName)) {
data = PotionMappings.POTION_NAME_TO_ID.get(potionName);
if (PotionIdMappings1_8.POTION_NAME_TO_ID.containsKey(potionName)) {
data = PotionIdMappings1_8.POTION_NAME_TO_ID.get(potionName);
}
if (splashPotion) {
potionName += "_splash";
@@ -270,10 +258,10 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
potionName += "_lingering";
}
// Don't override custom name
if ((displayTag == null || !displayTag.contains("Name")) && PotionMappings.POTION_NAME_INDEX.containsKey(potionName)) {
if ((displayTag == null || !displayTag.contains("Name")) && PotionIdMappings1_8.POTION_NAME_INDEX.containsKey(potionName)) {
tag.put("display", displayTag = new CompoundTag());
tag.put(nbtTagName() + "|noDisplay", new ByteTag());
displayTag.put("Name", new StringTag(PotionMappings.POTION_NAME_INDEX.get(potionName)));
tag.put(nbtTagName() + "|noDisplay", new ByteTag(true));
displayTag.put("Name", new StringTag(PotionIdMappings1_8.POTION_NAME_INDEX.get(potionName)));
}
}
if (splashPotion || lingeringPotion) { // Convert splash and lingering potions to normal potions
@@ -309,9 +297,9 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
enchantmentRewriter.handleToServer(item);
if (item.identifier() == 383 && item.data() != 0) { // Spawn eggs
if (!tag.contains("EntityTag") && ItemRewriter.ENTITY_ID_TO_NAME.containsKey((int) item.data())) {
if (!tag.contains("EntityTag") && EntityIds1_8.ENTITY_ID_TO_NAME.containsKey((int) item.data())) {
final CompoundTag entityTag = new CompoundTag();
entityTag.put("id", new StringTag(ItemRewriter.ENTITY_ID_TO_NAME.get((int) item.data())));
entityTag.put("id", new StringTag(EntityIds1_8.ENTITY_ID_TO_NAME.get((int) item.data())));
tag.put("EntityTag", entityTag);
}
item.setData((short) 0);
@@ -323,7 +311,7 @@ public class BlockItemPackets1_9 extends VRBlockItemRewriter<ClientboundPackets1
item.setData((short) (item.data() - 8192));
}
final String name = item.data() == 8192 ? "water" : potionNameFromDamage(item.data());
final String name = item.data() == 8192 ? "water" : PotionIdMappings1_9.potionNameFromDamage(item.data());
tag.put("Potion", new StringTag("minecraft:" + name));
item.setData((short) 0);
}
@@ -0,0 +1,629 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.api.minecraft.math.RelativeMoveUtil;
import com.viaversion.viarewind.api.rewriter.VREntityRewriter;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viarewind.protocol.v1_9to1_8.data.EntityDataIndex1_8;
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.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.EulerAngle;
import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_8;
import com.viaversion.viaversion.api.type.types.version.Types1_9;
import com.viaversion.viaversion.libs.fastutil.ints.IntArrayList;
import com.viaversion.viaversion.libs.fastutil.ints.IntList;
import com.viaversion.viaversion.protocols.v1_8to1_9.data.EntityDataIndex1_9;
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.rewriter.entitydata.EntityDataHandlerEvent;
import com.viaversion.viaversion.util.IdAndData;
import com.viaversion.viaversion.util.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class EntityPacketRewriter1_9 extends VREntityRewriter<ClientboundPackets1_9, Protocol1_9To1_8> {
private static final byte HAND_ACTIVE_BIT = 0;
private static final byte STATUS_USE_BIT = 4;
public EntityPacketRewriter1_9(Protocol1_9To1_8 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
registerJoinGame1_8(ClientboundPackets1_9.LOGIN);
registerRemoveEntities(ClientboundPackets1_9.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_9.SET_ENTITY_DATA, Types1_9.ENTITY_DATA_LIST, Types1_8.ENTITY_DATA_LIST);
protocol.registerClientbound(ClientboundPackets1_9.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
read(Types.UUID); // Entity uuid
map(Types.BYTE); // Entity type
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // X
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Y
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Z
map(Types.BYTE); // Pitch
map(Types.BYTE); // Yaw
map(Types.INT); // Data
// Track entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(EntityTypes1_9.ObjectType::findById));
handler(wrapper -> {
final int entityId = wrapper.get(Types.VAR_INT, 0);
final int entityType = wrapper.get(Types.BYTE, 0);
final EntityTypes1_9.EntityType type = EntityTypes1_9.getTypeFromId(entityType, true);
// Cancel new entities which can't be handled properly
if (type == EntityTypes1_9.EntityType.AREA_EFFECT_CLOUD || type == EntityTypes1_9.EntityType.SPECTRAL_ARROW || type == EntityTypes1_9.EntityType.DRAGON_FIREBALL) {
wrapper.cancel();
return;
}
if (type.is(EntityTypes1_9.EntityType.BOAT)) {
byte yaw = wrapper.get(Types.BYTE, 1);
yaw -= 64;
wrapper.set(Types.BYTE, 1, yaw);
int y = wrapper.get(Types.INT, 1);
y += 10;
wrapper.set(Types.INT, 1, y);
}
int data = wrapper.get(Types.INT, 3);
if (type.isOrHasParent(EntityTypes1_9.EntityType.ARROW) && data != 0) {
wrapper.set(Types.INT, 3, --data);
}
if (type.is(EntityTypes1_9.EntityType.FALLING_BLOCK)) {
int blockId = data & 0xFFF;
int blockData = data >> 12 & 0xF;
IdAndData replace = protocol.getItemRewriter().handleBlock(blockId, blockData);
if (replace != null) {
wrapper.set(Types.INT, 3, replace.getId() | replace.getData() << 12);
}
}
if (data > 0) {
wrapper.passthrough(Types.SHORT); // Velocity x
wrapper.passthrough(Types.SHORT); // Velocity y
wrapper.passthrough(Types.SHORT); // Velocity z
} else {
final short velocityX = wrapper.read(Types.SHORT);
final short velocityY = wrapper.read(Types.SHORT);
final short velocityZ = wrapper.read(Types.SHORT);
final PacketWrapper setEntityMotion = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_MOTION, wrapper.user());
setEntityMotion.write(Types.VAR_INT, entityId);
setEntityMotion.write(Types.SHORT, velocityX);
setEntityMotion.write(Types.SHORT, velocityY);
setEntityMotion.write(Types.SHORT, velocityZ);
setEntityMotion.scheduleSend(Protocol1_9To1_8.class);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.ADD_EXPERIENCE_ORB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // X
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Y
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Z
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);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.ADD_GLOBAL_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.BYTE); // Type
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // X
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Y
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);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.ADD_MOB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
read(Types.UUID); // Entity uuid
map(Types.UNSIGNED_BYTE); // Entity type
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // X
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Y
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Z
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
map(Types.BYTE); // Head pitch
map(Types.SHORT); // Velocity x
map(Types.SHORT); // Velocity y
map(Types.SHORT); // Velocity z
map(Types1_9.ENTITY_DATA_LIST, Types1_8.ENTITY_DATA_LIST); // Entity data
handler(getTrackerHandler(Types.UNSIGNED_BYTE, 0));
handler(getMobSpawnRewriter(Types1_8.ENTITY_DATA_LIST));
}
});
protocol.registerClientbound(ClientboundPackets1_9.ADD_PAINTING, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
read(Types.UUID); // Entity uuid
map(Types.STRING); // Title
map(Types.BLOCK_POSITION1_8); // Position
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);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.UUID); // Player uuid
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // X
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Y
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Z
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
create(Types.SHORT, (short) 0); // Current item
map(Types1_9.ENTITY_DATA_LIST, Types1_8.ENTITY_DATA_LIST); // Entity data
handler(getTrackerAndMetaHandler(Types1_8.ENTITY_DATA_LIST, EntityTypes1_9.EntityType.PLAYER));
}
});
protocol.registerClientbound(ClientboundPackets1_9.ENTITY_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Entity id
handler(wrapper -> {
final byte status = wrapper.read(Types.BYTE);
if (status > 23) { // Remove op permission level 0-4 (24-28)
wrapper.cancel();
return;
}
wrapper.write(Types.BYTE, status);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.MOVE_ENTITY_POS, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final int deltaX = wrapper.read(Types.SHORT);
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);
wrapper.write(Types.BYTE, (byte) moves[0].blockX());
wrapper.write(Types.BYTE, (byte) moves[0].blockY());
wrapper.write(Types.BYTE, (byte) moves[0].blockZ());
final boolean onGround = wrapper.passthrough(Types.BOOLEAN);
if (moves.length > 1) {
final PacketWrapper secondPacket = PacketWrapper.create(ClientboundPackets1_8.MOVE_ENTITY_POS, wrapper.user());
secondPacket.write(Types.VAR_INT, entityId);
secondPacket.write(Types.BYTE, (byte) moves[1].blockX());
secondPacket.write(Types.BYTE, (byte) moves[1].blockY());
secondPacket.write(Types.BYTE, (byte) moves[1].blockZ());
secondPacket.write(Types.BOOLEAN, onGround);
secondPacket.scheduleSend(Protocol1_9To1_8.class);
}
});
protocol.registerClientbound(ClientboundPackets1_9.MOVE_ENTITY_POS_ROT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final int deltaX = wrapper.read(Types.SHORT);
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);
wrapper.write(Types.BYTE, (byte) moves[0].blockX());
wrapper.write(Types.BYTE, (byte) moves[0].blockY());
wrapper.write(Types.BYTE, (byte) moves[0].blockZ());
byte yaw = wrapper.passthrough(Types.BYTE);
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);
if (type == EntityTypes1_9.EntityType.BOAT) {
yaw -= 64;
wrapper.set(Types.BYTE, 3, yaw);
}
if (moves.length > 1) {
final PacketWrapper secondPacket = PacketWrapper.create(ClientboundPackets1_8.MOVE_ENTITY_POS_ROT, wrapper.user());
secondPacket.write(Types.VAR_INT, entityId);
secondPacket.write(Types.BYTE, (byte) moves[1].blockX());
secondPacket.write(Types.BYTE, (byte) moves[1].blockY());
secondPacket.write(Types.BYTE, (byte) moves[1].blockZ());
secondPacket.write(Types.BYTE, yaw);
secondPacket.write(Types.BYTE, pitch);
secondPacket.write(Types.BOOLEAN, onGround);
secondPacket.scheduleSend(Protocol1_9To1_8.class);
}
});
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);
if (type == EntityTypes1_9.EntityType.BOAT) {
byte yaw = wrapper.read(Types.BYTE);
yaw -= 64;
wrapper.write(Types.BYTE, yaw);
}
});
protocol.registerClientbound(ClientboundPackets1_9.MOVE_VEHICLE, ClientboundPackets1_8.TELEPORT_ENTITY, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
final int vehicle = tracker.getVehicle(tracker.clientEntityId());
if (vehicle == -1) {
wrapper.cancel();
}
wrapper.write(Types.VAR_INT, vehicle);
});
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // X
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Y
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Z
map(Types.FLOAT, Protocol1_9To1_8.DEGREES_TO_ANGLE); // Yaw
map(Types.FLOAT, Protocol1_9To1_8.DEGREES_TO_ANGLE); // Pitch
handler(wrapper -> {
if (wrapper.isCancelled()) {
return;
}
final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class);
double x = wrapper.get(Types.INT, 0) / 32d;
double y = wrapper.get(Types.INT, 1) / 32d;
double z = wrapper.get(Types.INT, 2) / 32d;
storage.setPos(x, y, z);
});
create(Types.BOOLEAN, true);
handler(wrapper -> {
final int entityId = wrapper.get(Types.VAR_INT, 0);
final EntityType type = wrapper.user().getEntityTracker(Protocol1_9To1_8.class).entityType(entityId);
if (type == EntityTypes1_9.EntityType.BOAT) {
byte yaw = wrapper.get(Types.BYTE, 1);
yaw -= 64;
wrapper.set(Types.BYTE, 0, yaw);
int y = wrapper.get(Types.INT, 1);
y += 10;
wrapper.set(Types.INT, 1, y);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.REMOVE_MOB_EFFECT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final int effectId = wrapper.passthrough(Types.BYTE);
if (effectId > 23) { // Throw away new effects
wrapper.cancel();
}
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
if (effectId == 25 && entityId == tracker.clientEntityId()) {
wrapper.user().get(LevitationStorage.class).setActive(false);
}
});
protocol.registerClientbound(ClientboundPackets1_9.SET_ENTITY_LINK, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Attached entity id
map(Types.INT); // Holding entity id
create(Types.BOOLEAN, true); // Leash
}
});
protocol.registerClientbound(ClientboundPackets1_9.SET_EQUIPPED_ITEM, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
handler(wrapper -> {
// todo check if this is correct for the own player
int slot = wrapper.read(Types.VAR_INT);
if (slot == 1) {
wrapper.cancel();
} else if (slot > 1) {
slot -= 1;
}
wrapper.write(Types.SHORT, (short) slot);
});
map(Types.ITEM1_8); // Item
handler(wrapper -> protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
}
});
protocol.registerClientbound(ClientboundPackets1_9.SET_PASSENGERS, null, wrapper -> {
wrapper.cancel();
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
final int vehicle = wrapper.read(Types.VAR_INT);
final IntList oldPassengers = tracker.getPassengers(vehicle);
final int count = wrapper.read(Types.VAR_INT);
final IntList passengers = new IntArrayList();
for (int i = 0; i < count; i++) {
passengers.add(wrapper.read(Types.VAR_INT));
}
tracker.setPassengers(vehicle, passengers);
if (!oldPassengers.isEmpty()) {
for (Integer passenger : oldPassengers) {
final PacketWrapper detach = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_LINK, wrapper.user());
detach.write(Types.INT, passenger); // Attached entity id
detach.write(Types.INT, -1); // Holding entity id
detach.write(Types.BOOLEAN, false); // Leash
detach.scheduleSend(Protocol1_9To1_8.class);
}
}
for (int i = 0; i < count; i++) {
final int attachedEntityId = passengers.getInt(i);
final int holdingEntityId = i == 0 ? vehicle : passengers.getInt(i - 1);
final PacketWrapper attach = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_LINK, wrapper.user());
attach.write(Types.INT, attachedEntityId);
attach.write(Types.INT, holdingEntityId);
attach.write(Types.BOOLEAN, false); // Leash
attach.scheduleSend(Protocol1_9To1_8.class);
}
});
protocol.registerClientbound(ClientboundPackets1_9.TELEPORT_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // X
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Y
map(Types.DOUBLE, Protocol1_9To1_8.DOUBLE_TO_INT_TIMES_32); // Z
map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch
map(Types.BOOLEAN); // On ground
handler(wrapper -> {
final int entityId = wrapper.get(Types.VAR_INT, 0);
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
if (tracker.entityType(entityId) == EntityTypes1_9.EntityType.BOAT) {
byte yaw = wrapper.get(Types.BYTE, 1);
yaw -= 64;
wrapper.set(Types.BYTE, 0, yaw);
int y = wrapper.get(Types.INT, 1);
y += 10;
wrapper.set(Types.INT, 1, y);
}
tracker.resetEntityOffset(entityId);
});
}
});
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 boolean player = entityId == tracker.clientEntityId();
// Throw away new attributes and track attack speed
int removed = 0;
final int size = wrapper.passthrough(Types.INT);
for (int i = 0; i < size; i++) {
final String key = wrapper.read(Types.STRING);
final double value = wrapper.read(Types.DOUBLE);
final int modifierSize = wrapper.read(Types.VAR_INT);
final boolean valid = protocol.getItemRewriter().VALID_ATTRIBUTES.contains(key);
if (valid) {
wrapper.write(Types.STRING, key);
wrapper.write(Types.DOUBLE, value);
wrapper.write(Types.VAR_INT, modifierSize);
}
final List<Pair<Byte, Double>> modifiers = new ArrayList<>();
for (int j = 0; j < modifierSize; j++) {
final UUID modifierId = wrapper.read(Types.UUID); // UUID
final double amount = wrapper.read(Types.DOUBLE); // Amount
final byte operation = wrapper.read(Types.BYTE); // Operation
if (valid) {
wrapper.write(Types.UUID, modifierId);
wrapper.write(Types.DOUBLE, amount);
wrapper.write(Types.BYTE, operation);
}
modifiers.add(new Pair<>(operation, amount));
}
if (!valid) {
if (player && key.equals("generic.attackSpeed")) {
wrapper.user().get(CooldownStorage.class).setAttackSpeed(value, modifiers);
}
removed++;
}
}
wrapper.set(Types.INT, 0, size - removed);
});
protocol.registerClientbound(ClientboundPackets1_9.UPDATE_MOB_EFFECT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
final int effectId = wrapper.passthrough(Types.BYTE);
final byte amplifier = wrapper.passthrough(Types.BYTE);
if (effectId > 23) { // Throw away new effects
wrapper.cancel();
}
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
if (effectId == 25 && entityId == tracker.clientEntityId()) {
final LevitationStorage levitation = wrapper.user().get(LevitationStorage.class);
levitation.setActive(true);
levitation.setAmplifier(amplifier);
}
});
}
@Override
protected void registerRewrites() {
// Handle new entities
mapEntityTypeWithData(EntityTypes1_9.EntityType.SHULKER, EntityTypes1_9.EntityType.MAGMA_CUBE).plainName();
mapEntityTypeWithData(EntityTypes1_9.EntityType.SHULKER_BULLET, EntityTypes1_9.EntityType.WITCH).plainName();
// Entity data rewrite
filter().handler(this::handleEntityData);
}
private void handleEntityData(EntityDataHandlerEvent event, EntityData entityData) {
final EntityTracker1_9 tracker = tracker(event.user());
if (entityData.id() == EntityDataIndex1_9.ENTITY_STATUS.getIndex()) {
tracker.getStatus().put(event.entityId(), (Byte) entityData.value());
}
final EntityDataIndex1_9 metaIndex = EntityDataIndex1_8.searchIndex(event.entityType(), entityData.id());
if (metaIndex == null) {
// Almost certainly bad data, remove it
event.cancel();
return;
}
if (metaIndex.getOldType() == null || metaIndex.getNewType() == null) {
if (metaIndex == EntityDataIndex1_9.PLAYER_HAND) { // Player eating/aiming/drinking
byte status = (byte) tracker.getStatus().getOrDefault(event.entityId(), 0);
if ((((byte) entityData.value()) & 1 << HAND_ACTIVE_BIT) != 0) {
status = (byte) (status | 1 << STATUS_USE_BIT);
} else {
status = (byte) (status & ~(1 << STATUS_USE_BIT));
}
event.createExtraData(new EntityData(EntityDataIndex1_9.ENTITY_STATUS.getIndex(), EntityDataTypes1_8.BYTE, status));
}
event.cancel();
return;
}
entityData.setId(metaIndex.getIndex());
entityData.setDataTypeUnsafe(metaIndex.getOldType());
final Object value = entityData.getValue();
switch (metaIndex.getNewType()) {
case BYTE:
if (metaIndex.getOldType() == EntityDataTypes1_8.BYTE) {
entityData.setValue(value);
}
if (metaIndex.getOldType() == EntityDataTypes1_8.INT) {
entityData.setValue(((Byte) value).intValue());
}
break;
case OPTIONAL_UUID:
if (metaIndex.getOldType() != EntityDataTypes1_8.STRING) {
event.cancel();
break;
}
final UUID owner = (UUID) value;
entityData.setValue(owner != null ? owner.toString() : "");
break;
case OPTIONAL_BLOCK_STATE:
event.cancel();
event.createExtraData(new EntityData(metaIndex.getIndex(), EntityDataTypes1_8.SHORT, ((Integer) value).shortValue()));
break;
case VAR_INT:
if (metaIndex.getOldType() == EntityDataTypes1_8.BYTE) {
entityData.setValue(((Integer) value).byteValue());
}
if (metaIndex.getOldType() == EntityDataTypes1_8.SHORT) {
entityData.setValue(((Integer) value).shortValue());
}
if (metaIndex.getOldType() == EntityDataTypes1_8.INT) {
entityData.setValue(value);
}
break;
case FLOAT:
case STRING:
case COMPONENT:
entityData.setValue(value);
break;
case BOOLEAN:
final boolean bool = (Boolean) value;
if (metaIndex == EntityDataIndex1_9.ABSTRACT_AGEABLE_AGE) {
entityData.setValue((byte) (bool ? -1 : 0));
} else {
entityData.setValue((byte) (bool ? 1 : 0));
}
break;
case ITEM:
entityData.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), (Item) value));
break;
case BLOCK_POSITION:
final BlockPosition position = (BlockPosition) value;
entityData.setValue(position);
break;
case ROTATIONS:
final EulerAngle angle = (EulerAngle) value;
entityData.setValue(angle);
break;
default:
event.cancel();
break;
}
}
@Override
public EntityTypes1_9.EntityType typeFromId(int type) {
return EntityTypes1_9.getTypeFromId(type, false);
}
@Override
public EntityTypes1_9.EntityType objectTypeFromId(int type) {
return EntityTypes1_9.getTypeFromId(type, true);
}
}
@@ -0,0 +1,470 @@
/*
* This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
* Copyright (C) 2018-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.*;
import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_8;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
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;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_9;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class PlayerPacketRewriter1_9 {
public static void register(final Protocol1_9To1_8 protocol) {
protocol.registerClientbound(ClientboundPackets1_9.BOSS_EVENT, null, wrapper -> {
wrapper.cancel();
final BossBarStorage bossbar = wrapper.user().get(BossBarStorage.class);
final UUID uuid = wrapper.read(Types.UUID);
final int action = wrapper.read(Types.VAR_INT);
if (action == 0 /* add */) {
final JsonElement title = wrapper.read(Types.COMPONENT);
final float health = wrapper.read(Types.FLOAT);
wrapper.read(Types.VAR_INT); // Color
wrapper.read(Types.VAR_INT); // Division
wrapper.read(Types.UNSIGNED_BYTE); // Flags
bossbar.add(uuid, ChatUtil.jsonToLegacy(wrapper.user(), title), health);
} else if (action == 1 /* remove */) {
bossbar.remove(uuid);
} else if (action == 2 /* update health */) {
final float health = wrapper.read(Types.FLOAT);
bossbar.updateHealth(uuid, health);
} else if (action == 3 /* update title */) {
final JsonElement title = wrapper.read(Types.COMPONENT);
bossbar.updateTitle(uuid, ChatUtil.jsonToLegacy(wrapper.user(), title));
}
});
protocol.registerClientbound(ClientboundPackets1_9.SET_PLAYER_TEAM, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Team name
map(Types.BYTE); // Mode
handler(wrapper -> {
final byte mode = wrapper.get(Types.BYTE, 0);
if (mode == 0 /* create team */ || mode == 2 /* update team info */) {
wrapper.passthrough(Types.STRING); // Display name
wrapper.passthrough(Types.STRING); // Prefix
wrapper.passthrough(Types.STRING); // Suffix
wrapper.passthrough(Types.BYTE); // Friendly fire
wrapper.passthrough(Types.STRING); // Name tag visibility
wrapper.read(Types.STRING); // Collision rule
}
});
}
});
protocol.cancelClientbound(ClientboundPackets1_9.COOLDOWN);
protocol.registerClientbound(ClientboundPackets1_9.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Channel
handlerSoftFail(wrapper -> {
final String channel = wrapper.get(Types.STRING, 0);
if (channel.equals("MC|BOpen")) {
wrapper.read(Types.VAR_INT);
} else if (channel.equals("MC|TrList")) {
protocol.getItemRewriter().handleTradeList(wrapper);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.PLAYER_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Types.DOUBLE); // X
map(Types.DOUBLE); // Feet y
map(Types.DOUBLE); // Z
map(Types.FLOAT); // Yaw
map(Types.FLOAT); // Pitch
map(Types.BYTE); // Relative arguments
handler(wrapper -> {
final PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
pos.setConfirmId(wrapper.read(Types.VAR_INT));
byte flags = wrapper.get(Types.BYTE, 0);
double x = wrapper.get(Types.DOUBLE, 0);
double y = wrapper.get(Types.DOUBLE, 1);
double z = wrapper.get(Types.DOUBLE, 2);
float yaw = wrapper.get(Types.FLOAT, 0);
float pitch = wrapper.get(Types.FLOAT, 1);
wrapper.set(Types.BYTE, 0, (byte) 0);
if (flags != 0) {
if ((flags & 0x01) != 0) {
x += pos.getPosX();
wrapper.set(Types.DOUBLE, 0, x);
}
if ((flags & 0x02) != 0) {
y += pos.getPosY();
wrapper.set(Types.DOUBLE, 1, y);
}
if ((flags & 0x04) != 0) {
z += pos.getPosZ();
wrapper.set(Types.DOUBLE, 2, z);
}
if ((flags & 0x08) != 0) {
yaw += pos.getYaw();
wrapper.set(Types.FLOAT, 0, yaw);
}
if ((flags & 0x10) != 0) {
pitch += pos.getPitch();
wrapper.set(Types.FLOAT, 1, pitch);
}
}
pos.setPos(x, y, z);
pos.setYaw(yaw);
pos.setPitch(pitch);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Dimension
handler(wrapper -> wrapper.user().get(BossBarStorage.class).reset());
handler(wrapper -> {
final ClientWorld world = wrapper.user().get(ClientWorld.class);
world.setEnvironment(wrapper.get(Types.INT, 0));
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.CHAT, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Message
handler(wrapper -> {
if (!ViaRewind.getConfig().isEnableOffhand()) {
return;
}
final String message = wrapper.get(Types.STRING, 0);
if (message.toLowerCase().trim().startsWith(ViaRewind.getConfig().getOffhandCommand())) {
wrapper.cancel();
final PacketWrapper swapItems = PacketWrapper.create(ServerboundPackets1_9.PLAYER_ACTION, wrapper.user());
swapItems.write(Types.VAR_INT, 6);
swapItems.write(Types.BLOCK_POSITION1_8, new BlockPosition(0, 0, 0));
swapItems.write(Types.UNSIGNED_BYTE, (short) 255);
swapItems.sendToServer(Protocol1_9To1_8.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.INTERACT, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Target
map(Types.VAR_INT); // Type
handler(wrapper -> {
final int type = wrapper.get(Types.VAR_INT, 1);
if (type == 2 /* attack */) {
wrapper.passthrough(Types.FLOAT); // Target x
wrapper.passthrough(Types.FLOAT); // Target y
wrapper.passthrough(Types.FLOAT); // Target z
}
if (type == 2 /* attack */ || type == 0 /* interact */) {
wrapper.write(Types.VAR_INT, 0); // Hand
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_STATUS_ONLY, new PacketHandlers() {
@Override
public void register() {
map(Types.BOOLEAN); // On ground
handler(wrapper -> {
wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
if (tracker.isInsideVehicle(tracker.clientEntityId())) {
wrapper.cancel();
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_POS, new PacketHandlers() {
@Override
public void register() {
map(Types.DOUBLE); // X
map(Types.DOUBLE); // Feet y
map(Types.DOUBLE); // Z
map(Types.BOOLEAN); // On ground
handler(wrapper -> {
wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
final PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
if (pos.getConfirmId() != -1) {
return;
}
pos.setPos(wrapper.get(Types.DOUBLE, 0), wrapper.get(Types.DOUBLE, 1), wrapper.get(Types.DOUBLE, 2));
pos.setOnGround(wrapper.get(Types.BOOLEAN, 0));
});
handler(wrapper -> wrapper.user().get(BossBarStorage.class).updateLocation());
}
});
protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_ROT, new PacketHandlers() {
@Override
public void register() {
map(Types.FLOAT); // Yaw
map(Types.FLOAT); // Pitch
map(Types.BOOLEAN); // On ground
handler(wrapper -> {
wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
if (pos.getConfirmId() != -1) return;
pos.setYaw(wrapper.get(Types.FLOAT, 0));
pos.setPitch(wrapper.get(Types.FLOAT, 1));
pos.setOnGround(wrapper.get(Types.BOOLEAN, 0));
});
handler(wrapper -> wrapper.user().get(BossBarStorage.class).updateLocation());
}
});
protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_POS_ROT, wrapper -> {
final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE);
final double z = wrapper.passthrough(Types.DOUBLE);
final float yaw = wrapper.passthrough(Types.FLOAT);
final float pitch = wrapper.passthrough(Types.FLOAT);
final boolean onGround = wrapper.passthrough(Types.BOOLEAN);
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 PacketWrapper confirmTeleport = PacketWrapper.create(ServerboundPackets1_9.ACCEPT_TELEPORTATION, wrapper.user());
confirmTeleport.write(Types.VAR_INT, storage.getConfirmId());
confirmTeleport.sendToServer(Protocol1_9To1_8.class);
storage.setConfirmId(-1);
}
} else {
storage.setPos(x, y, z);
storage.setYaw(yaw);
storage.setPitch(pitch);
storage.setOnGround(onGround);
wrapper.user().get(BossBarStorage.class).updateLocation();
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_ACTION, wrapper -> {
final int status = wrapper.passthrough(Types.VAR_INT);
final BlockPlaceDestroyTracker tracker = wrapper.user().get(BlockPlaceDestroyTracker.class);
if (status == 0 || status == 1 || status == 2) { // Start, cancel or finish
tracker.setMining();
}
final CooldownStorage cooldown = wrapper.user().get(CooldownStorage.class);
if (status == 1) { // Cancel
tracker.setLastMining(0);
cooldown.hit();
} else if (status == 2) { // Finish
tracker.setLastMining(System.currentTimeMillis() + 100);
cooldown.setLastHit(0);
}
});
protocol.registerServerbound(ServerboundPackets1_8.USE_ITEM_ON, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8); // Position
map(Types.BYTE, Types.VAR_INT); // Face
read(Types.ITEM1_8); // Current item
create(Types.VAR_INT, 0); // Hand - main
map(Types.BYTE, Types.UNSIGNED_BYTE); // Cursor position x
map(Types.BYTE, Types.UNSIGNED_BYTE); // Cursor position y
map(Types.BYTE, Types.UNSIGNED_BYTE); // Cursor position z
handler(wrapper -> {
if (wrapper.get(Types.VAR_INT, 0) == -1) {
wrapper.cancel();
final PacketWrapper useItem = PacketWrapper.create(ServerboundPackets1_9.USE_ITEM, wrapper.user());
useItem.write(Types.VAR_INT, 0);
useItem.sendToServer(Protocol1_9To1_8.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.SET_CARRIED_ITEM, wrapper -> wrapper.user().get(CooldownStorage.class).hit());
// Queue swing packet to be sent after on ground idle packets
protocol.registerServerbound(ServerboundPackets1_8.SWING, wrapper -> {
wrapper.cancel();
final PacketWrapper swing = PacketWrapper.create(ServerboundPackets1_9.SWING, wrapper.user());
swing.write(Types.VAR_INT, 0); // Main Hand
wrapper.user().get(PlayerPositionTracker.class).queueAnimation(swing);
wrapper.user().get(BlockPlaceDestroyTracker.class).updateMining();
wrapper.user().get(CooldownStorage.class).hit();
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_COMMAND, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Entity id
map(Types.VAR_INT); // Action id
map(Types.VAR_INT); // Action parameter
handler(wrapper -> {
final PlayerPositionTracker tracker = wrapper.user().get(PlayerPositionTracker.class);
final int action = wrapper.get(Types.VAR_INT, 1);
if (action == 6) { // Jump with horse
wrapper.set(Types.VAR_INT, 1, 7);
} else if (action == 0 && !tracker.isOnGround()) { // Start sneaking
final PacketWrapper elytra = PacketWrapper.create(ServerboundPackets1_9.PLAYER_COMMAND, wrapper.user());
elytra.write(Types.VAR_INT, wrapper.get(Types.VAR_INT, 0));
elytra.write(Types.VAR_INT, 8);
elytra.write(Types.VAR_INT, 0);
elytra.scheduleSendToServer(Protocol1_9To1_8.class);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_INPUT, wrapper -> {
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 int vehicle = tracker.getVehicle(tracker.clientEntityId());
if (vehicle != -1 && tracker.entityType(vehicle) == EntityTypes1_9.EntityType.BOAT) {
final PacketWrapper paddleBoat = PacketWrapper.create(ServerboundPackets1_9.PADDLE_BOAT, wrapper.user());
paddleBoat.write(Types.BOOLEAN, forward != 0.0f || sideways < 0.0f);
paddleBoat.write(Types.BOOLEAN, forward != 0.0f || sideways > 0.0f);
paddleBoat.scheduleSendToServer(Protocol1_9To1_8.class);
}
});
protocol.registerServerbound(ServerboundPackets1_8.SIGN_UPDATE, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8); // Position
handler(wrapper -> {
for (int i = 0; i < 4; i++) {
wrapper.write(Types.STRING, ChatUtil.jsonToLegacy(wrapper.user(), wrapper.read(Types.COMPONENT)));
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.COMMAND_SUGGESTION, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Message
create(Types.BOOLEAN, false); // Has position
map(Types.OPTIONAL_POSITION1_8); // Looked at block (position)
}
});
protocol.registerServerbound(ServerboundPackets1_8.CLIENT_INFORMATION, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Locale
map(Types.BYTE); // View distance
map(Types.BYTE, Types.VAR_INT); // Chat mode
map(Types.BOOLEAN); // Chat colors
map(Types.UNSIGNED_BYTE); // Displayed skin parts
create(Types.VAR_INT, 1); // Main hand
handler(wrapper -> {
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());
final List<EntityData> entityData = new ArrayList<>();
entityData.add(new EntityData(10, EntityDataTypes1_8.BYTE, (byte) flags));
updateSkin.write(Types1_8.ENTITY_DATA_LIST, entityData);
updateSkin.scheduleSend(Protocol1_9To1_8.class);
});
}
});
protocol.registerServerbound(ServerboundPackets1_8.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Channel
handlerSoftFail(wrapper -> {
final String channel = wrapper.get(Types.STRING, 0);
if (channel.equals("MC|BEdit") || channel.equals("MC|BSign")) {
Item book = wrapper.passthrough(Types.ITEM1_8);
book.setIdentifier(386);
CompoundTag tag = book.tag();
if (tag.contains("pages")) {
ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
if (pages.size() > ViaRewind.getConfig().getMaxBookPages()) {
wrapper.user().disconnect("Too many book pages");
return;
}
for (int i = 0; i < pages.size(); i++) {
StringTag page = pages.get(i);
String value = page.getValue();
if (value.length() > ViaRewind.getConfig().getMaxBookPageSize()) {
wrapper.user().disconnect("Book page too large");
return;
}
value = ChatUtil.jsonToLegacy(wrapper.user(), value);
page.setValue(value);
}
}
} else if (channel.equals("MC|AdvCdm")) {
wrapper.set(Types.STRING, 0, "MC|AdvCmd");
}
});
}
});
}
}
@@ -15,14 +15,15 @@
* 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.protocol1_8to1_9.packets;
package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.data.EffectMappings;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viarewind.protocol.v1_9to1_8.data.EffectIdMappings1_8;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.Environment;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.chunks.BaseChunk;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
@@ -31,33 +32,32 @@ import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_8;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_1;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
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.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
import java.util.ArrayList;
public class WorldPackets1_9 {
public class WorldPacketRewriter1_9 {
public static void register(Protocol1_8To1_9 protocol) {
public static void register(Protocol1_9To1_8 protocol) {
protocol.registerClientbound(ClientboundPackets1_9.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8); // Position
map(Type.UNSIGNED_BYTE); // Action
map(Type.NAMED_COMPOUND_TAG); // Tag
map(Types.BLOCK_POSITION1_8); // Position
map(Types.UNSIGNED_BYTE); // Action
map(Types.NAMED_COMPOUND_TAG); // Tag
handler(wrapper -> {
final CompoundTag tag = wrapper.get(Type.NAMED_COMPOUND_TAG, 0);
final CompoundTag tag = wrapper.get(Types.NAMED_COMPOUND_TAG, 0);
final CompoundTag spawnData = tag.remove("SpawnData");
if (spawnData != null) {
final StringTag id = spawnData.remove("id");
if (id != null) {
if (tag.remove("SpawnData") instanceof CompoundTag spawnData) {
final Tag id = spawnData.remove("id");
if (id instanceof StringTag) {
tag.put("EntityId", id);
}
}
@@ -65,59 +65,59 @@ public class WorldPackets1_9 {
}
});
protocol.registerClientbound(ClientboundPackets1_9.BLOCK_ACTION, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_9.BLOCK_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8);
map(Type.UNSIGNED_BYTE);
map(Type.UNSIGNED_BYTE);
map(Type.VAR_INT);
map(Types.BLOCK_POSITION1_8); // Position
map(Types.UNSIGNED_BYTE); // Byte 1 (depending on block type)
map(Types.UNSIGNED_BYTE); // Byte 2 (depending on block type)
map(Types.VAR_INT); // Block
handler(wrapper -> {
int block = wrapper.get(Type.VAR_INT, 0);
final int block = wrapper.get(Types.VAR_INT, 0);
if (block >= 219 && block <= 234) {
wrapper.set(Type.VAR_INT, 0, 130);
wrapper.set(Types.VAR_INT, 0, 130);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.NAMED_SOUND, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_9.CUSTOM_SOUND, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
map(Types.STRING); // Sound name
handler(wrapper -> {
String name = wrapper.get(Type.STRING, 0);
String name = wrapper.get(Types.STRING, 0);
name = protocol.getMappingData().getMappedNamedSound(name);
if (name == null) {
wrapper.cancel();
} else {
wrapper.set(Type.STRING, 0, name);
wrapper.set(Types.STRING, 0, name);
}
});
read(Type.VAR_INT);
map(Type.INT);
map(Type.INT);
map(Type.INT);
map(Type.FLOAT);
map(Type.UNSIGNED_BYTE);
read(Types.VAR_INT); // Sound category
map(Types.INT); // Effect position x
map(Types.INT); // Effect position y
map(Types.INT); // Effect position z
map(Types.FLOAT); // Volume
map(Types.UNSIGNED_BYTE); // Pitch
}
});
protocol.registerClientbound(ClientboundPackets1_9.UNLOAD_CHUNK, ClientboundPackets1_8.CHUNK_DATA, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_9.FORGET_LEVEL_CHUNK, ClientboundPackets1_8.LEVEL_CHUNK, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final Environment environment = wrapper.user().get(ClientWorld.class).getEnvironment();
final int chunkX = wrapper.read(Type.INT);
final int chunkZ = wrapper.read(Type.INT);
final int chunkX = wrapper.read(Types.INT);
final int chunkZ = wrapper.read(Types.INT);
wrapper.write(ChunkType1_8.forEnvironment(environment), new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], null, new ArrayList<>()));
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.CHUNK_DATA, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_9.LEVEL_CHUNK, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
@@ -135,7 +135,7 @@ public class WorldPackets1_9 {
}
}
if (chunk.isFullChunk() && chunk.getBitmask() == 0) { //This would be an unload packet for 1.8 clients. Just set one air section
if (chunk.isFullChunk() && chunk.getBitmask() == 0) { // This would be an unload packet for 1.8 clients. Just set one air section
boolean skylight = environment == Environment.NORMAL;
ChunkSection[] sections = new ChunkSection[16];
ChunkSection section = new ChunkSectionImpl(true);
@@ -147,11 +147,11 @@ public class WorldPackets1_9 {
wrapper.write(ChunkType1_8.forEnvironment(environment), chunk);
final UserConnection user = wrapper.user();
chunk.getBlockEntities().forEach(nbt -> {
if (!nbt.contains("x") || !nbt.contains("y") || !nbt.contains("z") || !nbt.contains("id"))
if (!nbt.contains("x") || !nbt.contains("y") || !nbt.contains("z") || !nbt.contains("id")) {
return;
Position position = new Position((int) nbt.get("x").getValue(), (int) nbt.get("y").getValue(), (int) nbt.get("z").getValue());
}
BlockPosition position = new BlockPosition((int) nbt.get("x").getValue(), (int) nbt.get("y").getValue(), (int) nbt.get("z").getValue());
String id = (String) nbt.get("id").getValue();
short action;
@@ -178,94 +178,89 @@ public class WorldPackets1_9 {
return;
}
PacketWrapper updateTileEntity = PacketWrapper.create(0x09, null, user);
updateTileEntity.write(Type.POSITION1_8, position);
updateTileEntity.write(Type.UNSIGNED_BYTE, action);
updateTileEntity.write(Type.NBT, nbt);
try {
updateTileEntity.scheduleSend(Protocol1_8To1_9.class, false);
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().warning("Error sending tile entity update packet: " + e.getMessage());
}
final PacketWrapper blockEntityData = PacketWrapper.create(ClientboundPackets1_9.BLOCK_ENTITY_DATA, wrapper.user());
blockEntityData.write(Types.BLOCK_POSITION1_8, position);
blockEntityData.write(Types.UNSIGNED_BYTE, action);
blockEntityData.write(Types.NAMED_COMPOUND_TAG, nbt);
blockEntityData.scheduleSend(Protocol1_9To1_8.class, false);
});
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.EFFECT, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_9.LEVEL_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Type.INT);
map(Type.POSITION1_8);
map(Type.INT);
map(Type.BOOLEAN);
map(Types.INT); // Effect id
map(Types.BLOCK_POSITION1_8); // Position
map(Types.INT); // data
map(Types.BOOLEAN); // disable relative volume
handler(wrapper -> {
int id = wrapper.get(Type.INT, 0);
id = EffectMappings.getOldId(id);
int id = wrapper.get(Types.INT, 0);
id = EffectIdMappings1_8.getOldId(id);
if (id == -1) {
wrapper.cancel();
return;
}
wrapper.set(Type.INT, 0, id);
wrapper.set(Types.INT, 0, id);
if (id == 2001) {
int replacedBlock = protocol.getItemRewriter().handleBlockId(wrapper.get(Type.INT, 1));
wrapper.set(Type.INT, 1, replacedBlock);
int replacedBlock = protocol.getItemRewriter().handleBlockId(wrapper.get(Types.INT, 1));
wrapper.set(Types.INT, 1, replacedBlock);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.SPAWN_PARTICLE, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_9.LEVEL_PARTICLES, new PacketHandlers() {
@Override
public void register() {
map(Type.INT);
map(Types.INT); // Particle id
handler(wrapper -> {
int type = wrapper.get(Type.INT, 0);
if (type > 41 && !ViaRewind.getConfig().isReplaceParticles()) {
int id = wrapper.get(Types.INT, 0);
if (id > 41 && !ViaRewind.getConfig().isReplaceParticles()) {
wrapper.cancel();
return;
}
if (type == 42) { // Dragon Breath
wrapper.set(Type.INT, 0, 24); // Portal
} else if (type == 43) { // End Rod
wrapper.set(Type.INT, 0, 3); // Firework Spark
} else if (type == 44) { // Damage Indicator
wrapper.set(Type.INT, 0, 34); // Heart
} else if (type == 45) { // Sweep Attack
wrapper.set(Type.INT, 0, 1); // Large Explosion
if (id == 42) { // Dragon Breath
wrapper.set(Types.INT, 0, 24); // Portal
} else if (id == 43) { // End Rod
wrapper.set(Types.INT, 0, 3); // Firework Spark
} else if (id == 44) { // Damage Indicator
wrapper.set(Types.INT, 0, 34); // Heart
} else if (id == 45) { // Sweep Attack
wrapper.set(Types.INT, 0, 1); // Large Explosion
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9.MAP_DATA, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_9.MAP_ITEM_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.BYTE);
read(Type.BOOLEAN);
map(Types.VAR_INT); // Item damage
map(Types.BYTE); // Scale
read(Types.BOOLEAN); // Tracking position
}
});
protocol.registerClientbound(ClientboundPackets1_9.SOUND, ClientboundPackets1_8.NAMED_SOUND, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_9.SOUND, ClientboundPackets1_8.CUSTOM_SOUND, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final int soundId = wrapper.read(Type.VAR_INT);
final int soundId = wrapper.read(Types.VAR_INT);
final String soundName = protocol.getMappingData().soundName(soundId);
if (soundName == null) {
wrapper.cancel();
} else {
wrapper.write(Type.STRING, protocol.getMappingData().getMappedNamedSound(soundName));
wrapper.write(Types.STRING, protocol.getMappingData().getMappedNamedSound(soundName));
}
});
read(Type.VAR_INT);
map(Type.INT);
map(Type.INT);
map(Type.INT);
map(Type.FLOAT);
map(Type.UNSIGNED_BYTE);
read(Types.VAR_INT); // Sound category
map(Types.INT); // Effect position x
map(Types.INT); // Effect position y
map(Types.INT); // Effect position z
map(Types.FLOAT); // Volume
map(Types.UNSIGNED_BYTE); // Pitch
}
});
}
@@ -15,7 +15,7 @@
* 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.protocol1_8to1_9.storage;
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
@@ -15,9 +15,9 @@
* 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.protocol1_8to1_9.storage;
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.emulation.WitherBossBar;
import com.viaversion.viarewind.protocol.v1_9to1_8.data.WitherBossBar;
import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -38,7 +38,7 @@ public class BossBarStorage extends StoredObject {
changeWorld();
}
public void add(UUID uuid, String title, float health) throws Exception {
public void add(UUID uuid, String title, float health) {
WitherBossBar bossBar = new WitherBossBar(this.getUser(), uuid, title, health);
PlayerPositionTracker playerPositionTracker = this.getUser().get(PlayerPositionTracker.class);
bossBar.setPlayerLocation(playerPositionTracker.getPosX(), playerPositionTracker.getPosY(), playerPositionTracker.getPosZ(), playerPositionTracker.getYaw(), playerPositionTracker.getPitch());
@@ -15,10 +15,10 @@
* 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.protocol1_8to1_9.storage;
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.emulation.CooldownVisualization;
import com.viaversion.viarewind.protocol.v1_9to1_8.cooldown.CooldownVisualization;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.util.Pair;
@@ -15,11 +15,11 @@
* 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.protocol1_8to1_9.storage;
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.fastutil.ints.*;
@@ -33,7 +33,7 @@ public class EntityTracker1_9 extends EntityTrackerBase {
private final Int2IntMap status = new Int2IntOpenHashMap();
public EntityTracker1_9(UserConnection connection) {
super(connection, EntityTypes1_10.EntityType.ENTITY_HUMAN);
super(connection, EntityTypes1_9.EntityType.PLAYER);
}
@Override
@@ -15,7 +15,7 @@
* 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.protocol1_8to1_9.storage;
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
@@ -15,9 +15,9 @@
* 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.protocol1_8to1_9.storage;
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
@@ -38,10 +38,10 @@ public class PlayerPositionTracker implements StorableObject {
this.posZ = z;
}
public void sendAnimations() throws Exception {
public void sendAnimations() {
PacketWrapper wrapper;
while ((wrapper = animations.poll()) != null) {
wrapper.sendToServer(Protocol1_8To1_9.class);
wrapper.sendToServer(Protocol1_9To1_8.class);
}
}
@@ -15,21 +15,21 @@
* 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.protocol1_8to1_9.storage;
package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.mcstructs.core.TextFormatting;
import com.viaversion.viaversion.libs.mcstructs.text.ATextComponent;
import com.viaversion.viaversion.libs.mcstructs.text.components.StringComponent;
import com.viaversion.viaversion.libs.mcstructs.text.components.TranslationComponent;
import com.viaversion.viaversion.libs.mcstructs.text.serializer.TextComponentSerializer;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.HashMap;
import java.util.Map;
@@ -80,15 +80,15 @@ public class WindowTracker extends StoredObject {
enchantmentProperties.clear();
}
public static void updateBrewingStand(UserConnection user, Item blazePowder, short windowId) throws Exception {
public static void updateBrewingStand(UserConnection user, Item blazePowder, short windowId) {
if (blazePowder != null && blazePowder.identifier() != 377) {
return;
}
int amount = blazePowder == null ? 0 : blazePowder.amount();
PacketWrapper openWindow = PacketWrapper.create(ClientboundPackets1_8.OPEN_WINDOW, user);
openWindow.write(Type.UNSIGNED_BYTE, windowId);
openWindow.write(Type.STRING, "minecraft:brewing_stand");
PacketWrapper openWindow = PacketWrapper.create(ClientboundPackets1_8.OPEN_SCREEN, user);
openWindow.write(Types.UNSIGNED_BYTE, windowId);
openWindow.write(Types.STRING, "minecraft:brewing_stand");
ATextComponent title = new StringComponent().
append(new TranslationComponent("container.brewing")).
@@ -96,17 +96,17 @@ public class WindowTracker extends StoredObject {
append(new StringComponent(amount + " " + TextFormatting.DARK_RED)).
append(new TranslationComponent("item.blazePowder.name", TextFormatting.DARK_RED));
openWindow.write(Type.COMPONENT, TextComponentSerializer.V1_8.serializeJson(title));
openWindow.write(Type.UNSIGNED_BYTE, (short) 420);
openWindow.scheduleSend(Protocol1_8To1_9.class);
openWindow.write(Types.COMPONENT, TextComponentSerializer.V1_8.serializeJson(title));
openWindow.write(Types.UNSIGNED_BYTE, (short) 420);
openWindow.scheduleSend(Protocol1_9To1_8.class);
Item[] items = user.get(WindowTracker.class).getBrewingItems(windowId);
for (int i = 0; i < items.length; i++) {
PacketWrapper setSlot = PacketWrapper.create(ClientboundPackets1_8.SET_SLOT, user);
setSlot.write(Type.UNSIGNED_BYTE, windowId);
setSlot.write(Type.SHORT, (short) i);
setSlot.write(Type.ITEM1_8, items[i]);
setSlot.scheduleSend(Protocol1_8To1_9.class);
PacketWrapper setSlot = PacketWrapper.create(ClientboundPackets1_8.CONTAINER_SET_SLOT, user);
setSlot.write(Types.UNSIGNED_BYTE, windowId);
setSlot.write(Types.SHORT, (short) i);
setSlot.write(Types.ITEM1_8, items[i]);
setSlot.scheduleSend(Protocol1_9To1_8.class);
}
}
}
@@ -15,9 +15,9 @@
* 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.protocol1_8to1_9.task;
package com.viaversion.viarewind.protocol.v1_9to1_8.task;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.CooldownStorage;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CooldownStorage;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -15,16 +15,16 @@
* 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.protocol1_8to1_9.task;
package com.viaversion.viarewind.protocol.v1_9to1_8.task;
import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viarewind.protocol.protocol1_8to1_9.storage.LevitationStorage;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LevitationStorage;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.logging.Level;
@@ -38,13 +38,13 @@ public class LevitationUpdateTask implements Runnable {
continue;
}
final PacketWrapper velocityPacket = PacketWrapper.create(ClientboundPackets1_8.ENTITY_VELOCITY, connection);
velocityPacket.write(Type.VAR_INT, connection.getEntityTracker(Protocol1_8To1_9.class).clientEntityId());
velocityPacket.write(Type.SHORT, (short) 0);
velocityPacket.write(Type.SHORT, (short) ((levitation.getAmplifier() + 1) * 360));
velocityPacket.write(Type.SHORT, (short) 0);
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.SHORT, (short) 0);
velocityPacket.write(Types.SHORT, (short) ((levitation.getAmplifier() + 1) * 360));
velocityPacket.write(Types.SHORT, (short) 0);
try {
velocityPacket.scheduleSend(Protocol1_8To1_9.class);
velocityPacket.scheduleSend(Protocol1_9To1_8.class);
} catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to send levitation packet", e);
}
@@ -23,7 +23,7 @@ import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.util.ComponentUtil;
@@ -36,7 +36,7 @@ public class ChatUtil {
private static final ComponentRewriter<ClientboundPacketType> LEGACY_REWRITER = new ComponentRewriter<ClientboundPacketType>(null, ComponentRewriter.ReadType.JSON) {
@Override
protected void handleTranslate(JsonObject object, String translate) {
String text = Protocol1_13To1_12_2.MAPPINGS.getMojangTranslation().get(translate);
String text = Protocol1_12_2To1_13.MAPPINGS.getMojangTranslation().get(translate);
if (text != null) {
object.addProperty("translate", text);
}
+5 -6
View File
@@ -3,17 +3,16 @@ org.gradle.jvmargs=-Xmx8G
org.gradle.parallel=true
# project
maven_version=3.1.2
maven_version=4.0.0
maven_group=com.viaversion
# libraries
viaversion_version=4.10.0
viabackwards_version=4.10.0
viaversion_version=5.0.0
viabackwards_version=5.0.0
netty_version=4.0.20.Final
guava_version=17.0
# Smile emoji
mcVersions=1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9, 1.8.8
mcVersionRange=1.8-1.20.6
waterfallVersion=1.20
mcVersions=1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9, 1.8.8
mcVersionRange=1.8-1.21
velocityVersion=3.3
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+7 -7
View File
@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -202,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
Loaded 100 of 107 files, more files were not shown because too many files have changed in this diff. Show more