[ci skip] Reformat all classes

This commit is contained in:
FlorianMichael committed 2025-07-25 11:26:09 +02:00
1 parent 5110326a90
commit 1e2fcb9c58
86 files changed
+6374 -6321

No files matched your search

+1 -1
View File
@@ -1,2 +1,2 @@
github: FlorianMichael github: FlorianMichael
custom: ['https://florianmichael.de/donate', 'https://creeper123123321.github.io/#donate'] custom: [ 'https://florianmichael.de/donate', 'https://creeper123123321.github.io/#donate' ]
+1 -1
View File
@@ -1,5 +1,5 @@
name: Build name: Build
on: [pull_request, push, workflow_dispatch] on: [ pull_request, push, workflow_dispatch ]
jobs: jobs:
build: build:
+8 -3
View File
@@ -1,4 +1,5 @@
# ViaRewind # ViaRewind
[![Latest Release](https://img.shields.io/github/v/release/ViaVersion/ViaRewind)](https://github.com/ViaVersion/ViaRewind/releases) [![Latest Release](https://img.shields.io/github/v/release/ViaVersion/ViaRewind)](https://github.com/ViaVersion/ViaRewind/releases)
[![Build Status](https://github.com/ViaVersion/ViaRewind/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/ViaVersion/ViaRewind/actions) [![Build Status](https://github.com/ViaVersion/ViaRewind/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/ViaVersion/ViaRewind/actions)
[![Discord](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://viaversion.com/discord) [![Discord](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://viaversion.com/discord)
@@ -6,13 +7,17 @@
**ViaVersion addon to allow 1.8.x and 1.7.x clients on newer server versions.** <br> **ViaVersion addon to allow 1.8.x and 1.7.x clients on newer server versions.** <br>
Runs on 1.9-latest servers or 1.8 clients and lower. Runs on 1.9-latest servers or 1.8 clients and lower.
**You can override the included version in [ViaFabric](https://modrinth.com/mod/viafabric) or [ViaProxy](https://github.com/ViaVersion/ViaProxy):** **You can override the included version in [ViaFabric](https://modrinth.com/mod/viafabric)
or [ViaProxy](https://github.com/ViaVersion/ViaProxy):**
- in **ViaFabric**, put ViaRewind into the `mods` folder - in **ViaFabric**, put ViaRewind into the `mods` folder
- in **ViaProxy**, put ViaRewind into the `jars` 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. 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..** **Requires [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion)
and [ViaBackwards](https://hangar.papermc.io/ViaVersion/ViaBackwards) to be installed..**
Releases/Dev Builds Releases/Dev Builds
- -
+8 -3
View File
@@ -2,9 +2,14 @@
## Reporting a Vulnerability ## Reporting a Vulnerability
If you discover a **security vulnerability**, please **do not** open a public issue. Instead, use one of the following **confidential contact methods**: If you discover a **security vulnerability**, please **do not** open a public issue. Instead, use one of the following *
*confidential contact methods**:
* **Email:** [security@viaversion.com](mailto:security@viaversion.com) * **Email:** [security@viaversion.com](mailto:security@viaversion.com)
* **Discord:** Join our [Discord server](https://discord.gg/viaversion) and visit the [#exploit-report](https://discord.com/channels/316206679014244363/1388847764137316485) channel for further instructions. * **Discord:** Join our [Discord server](https://discord.gg/viaversion) and visit
the [#exploit-report](https://discord.com/channels/316206679014244363/1388847764137316485) channel for further
instructions.
If your issue is **not security-related** (e.g., bug reports, feature requests, or usage questions), please use the [GitHub Issues page](https://github.com/ViaVersion/ViaRewind/issues) or contact us via the [Discord server](https://discord.gg/viaversion). If your issue is **not security-related** (e.g., bug reports, feature requests, or usage questions), please use
the [GitHub Issues page](https://github.com/ViaVersion/ViaRewind/issues) or contact us via
the [Discord server](https://discord.gg/viaversion).
@@ -19,13 +19,12 @@ package com.viaversion.viarewind;
import com.viaversion.viarewind.api.ViaRewindPlatform; import com.viaversion.viarewind.api.ViaRewindPlatform;
import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.Via;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File; import java.io.File;
import org.bukkit.plugin.java.JavaPlugin;
public class BukkitPlugin extends JavaPlugin implements ViaRewindPlatform { public class BukkitPlugin extends JavaPlugin implements ViaRewindPlatform {
public BukkitPlugin() { public BukkitPlugin() {
Via.getManager().addEnableListener(() -> this.init(new File(getDataFolder(), "config.yml"))); Via.getManager().addEnableListener(() -> this.init(new File(getDataFolder(), "config.yml")));
} }
} }
+2 -2
View File
@@ -1,10 +1,10 @@
name: ViaRewind name: ViaRewind
main: com.viaversion.viarewind.BukkitPlugin main: com.viaversion.viarewind.BukkitPlugin
authors: [FlorianMichael/EnZaXD, Gerrygames, creeper123123321] authors: [ FlorianMichael/EnZaXD, Gerrygames, creeper123123321 ]
version: ${version} version: ${version}
description: ${description} description: ${description}
website: https://viaversion.com/rewind website: https://viaversion.com/rewind
api-version: 1.13 api-version: 1.13
folia-supported: true folia-supported: true
load: STARTUP load: STARTUP
depend: [ViaVersion, ViaBackwards] depend: [ ViaVersion, ViaBackwards ]
+1 -1
View File
@@ -1,4 +1,4 @@
import de.florianmichael.baseproject.* import de.florianmichael.baseproject.latestCommitHash
plugins { plugins {
id("net.raphimc.class-token-replacer") id("net.raphimc.class-token-replacer")
@@ -23,21 +23,21 @@ import com.viaversion.viarewind.api.ViaRewindPlatform;
public class ViaRewind { public class ViaRewind {
private static ViaRewindPlatform platform; private static ViaRewindPlatform platform;
private static ViaRewindConfig config; private static ViaRewindConfig config;
public static void init(ViaRewindPlatform platform, ViaRewindConfig config) { public static void init(ViaRewindPlatform platform, ViaRewindConfig config) {
Preconditions.checkArgument(ViaRewind.platform == null, "ViaRewind is already initialized"); Preconditions.checkArgument(ViaRewind.platform == null, "ViaRewind is already initialized");
ViaRewind.platform = platform; ViaRewind.platform = platform;
ViaRewind.config = config; ViaRewind.config = config;
} }
public static ViaRewindPlatform getPlatform() { public static ViaRewindPlatform getPlatform() {
return ViaRewind.platform; return ViaRewind.platform;
} }
public static ViaRewindConfig getConfig() { public static ViaRewindConfig getConfig() {
return ViaRewind.config; return ViaRewind.config;
} }
} }
@@ -18,7 +18,6 @@
package com.viaversion.viarewind; package com.viaversion.viarewind;
import com.viaversion.viaversion.util.Config; import com.viaversion.viaversion.util.Config;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
@@ -29,105 +28,105 @@ import java.util.logging.Logger;
public class ViaRewindConfig extends Config implements com.viaversion.viarewind.api.ViaRewindConfig { public class ViaRewindConfig extends Config implements com.viaversion.viarewind.api.ViaRewindConfig {
private CooldownIndicator cooldownIndicator; private CooldownIndicator cooldownIndicator;
private boolean replaceAdventureMode; private boolean replaceAdventureMode;
private boolean replaceParticles; private boolean replaceParticles;
private int maxBookPages; private int maxBookPages;
private int maxBookPageSize; private int maxBookPageSize;
private boolean emulateWorldBorder; private boolean emulateWorldBorder;
private boolean alwaysShowOriginalMobName; private boolean alwaysShowOriginalMobName;
private String worldBorderParticle; private String worldBorderParticle;
private boolean enableOffhand; private boolean enableOffhand;
private String offhandCommand; private String offhandCommand;
private boolean emulateLevitationEffect; private boolean emulateLevitationEffect;
private boolean handlePlayerCombatPacket; private boolean handlePlayerCombatPacket;
public ViaRewindConfig(File configFile, Logger logger) { public ViaRewindConfig(File configFile, Logger logger) {
super(configFile, logger); super(configFile, logger);
} }
@Override @Override
public void reload() { public void reload() {
super.reload(); super.reload();
loadFields(); loadFields();
} }
private void loadFields() { private void loadFields() {
cooldownIndicator = CooldownIndicator.valueOf(getString("cooldown-indicator", "TITLE").toUpperCase()); cooldownIndicator = CooldownIndicator.valueOf(getString("cooldown-indicator", "TITLE").toUpperCase());
replaceAdventureMode = getBoolean("replace-adventure", false); replaceAdventureMode = getBoolean("replace-adventure", false);
replaceParticles = getBoolean("replace-particles", false); replaceParticles = getBoolean("replace-particles", false);
maxBookPages = getInt("max-book-pages", 100); maxBookPages = getInt("max-book-pages", 100);
maxBookPageSize = getInt("max-book-page-length", 5000); maxBookPageSize = getInt("max-book-page-length", 5000);
emulateWorldBorder = getBoolean("emulate-world-border", true); emulateWorldBorder = getBoolean("emulate-world-border", true);
alwaysShowOriginalMobName = getBoolean("always-show-original-mob-name", true); alwaysShowOriginalMobName = getBoolean("always-show-original-mob-name", true);
worldBorderParticle = getString("world-border-particle", "fireworksSpark"); worldBorderParticle = getString("world-border-particle", "fireworksSpark");
enableOffhand = getBoolean("enable-offhand", true); enableOffhand = getBoolean("enable-offhand", true);
offhandCommand = getString("offhand-command", "/offhand"); offhandCommand = getString("offhand-command", "/offhand");
emulateLevitationEffect = getBoolean("emulate-levitation-effect", true); emulateLevitationEffect = getBoolean("emulate-levitation-effect", true);
handlePlayerCombatPacket = getBoolean("handle-player-combat-packet", true); handlePlayerCombatPacket = getBoolean("handle-player-combat-packet", true);
} }
@Override @Override
public CooldownIndicator getCooldownIndicator() { public CooldownIndicator getCooldownIndicator() {
return cooldownIndicator; return cooldownIndicator;
} }
@Override @Override
public boolean isReplaceAdventureMode() { public boolean isReplaceAdventureMode() {
return replaceAdventureMode; return replaceAdventureMode;
} }
@Override @Override
public boolean isReplaceParticles() { public boolean isReplaceParticles() {
return replaceParticles; return replaceParticles;
} }
@Override @Override
public int getMaxBookPages() { public int getMaxBookPages() {
return maxBookPages; return maxBookPages;
} }
@Override @Override
public int getMaxBookPageSize() { public int getMaxBookPageSize() {
return maxBookPageSize; return maxBookPageSize;
} }
@Override @Override
public boolean isEmulateWorldBorder() { public boolean isEmulateWorldBorder() {
return emulateWorldBorder; return emulateWorldBorder;
} }
@Override @Override
public boolean alwaysShowOriginalMobName() { public boolean alwaysShowOriginalMobName() {
return alwaysShowOriginalMobName; return alwaysShowOriginalMobName;
} }
@Override @Override
public String getWorldBorderParticle() { public String getWorldBorderParticle() {
return worldBorderParticle; return worldBorderParticle;
} }
@Override @Override
public boolean isEnableOffhand() { public boolean isEnableOffhand() {
return enableOffhand; return enableOffhand;
} }
@Override @Override
public String getOffhandCommand() { public String getOffhandCommand() {
return offhandCommand; return offhandCommand;
} }
@Override @Override
public boolean emulateLevitationEffect() { public boolean emulateLevitationEffect() {
return emulateLevitationEffect; return emulateLevitationEffect;
} }
@Override @Override
public boolean handlePlayerCombatPacket() { public boolean handlePlayerCombatPacket() {
return handlePlayerCombatPacket; return handlePlayerCombatPacket;
} }
@Override @Override
public URL getDefaultConfigURL() { public URL getDefaultConfigURL() {
return getClass().getClassLoader().getResource("assets/viarewind/config.yml"); return getClass().getClassLoader().getResource("assets/viarewind/config.yml");
} }
@@ -24,97 +24,97 @@ import com.viaversion.viaversion.api.configuration.Config;
*/ */
public interface ViaRewindConfig extends Config { public interface ViaRewindConfig extends Config {
enum CooldownIndicator { /**
TITLE, ACTION_BAR, BOSS_BAR, DISABLED * Specifies how 1.8.x clients should see the cooldown indicator
} * You can choose between TITLE, ACTION_BAR, BOSS_BAR and DISABLED
* ONLY DISABLE IF YOU HAVE 1.9 COOLDOWN DISABLED ON YOUR SERVER
* 1.8 PLAYERS MAY ASK WHY PVP IS NOT WORKING OTHERWISE
*
* @return the cooldown indicator
*/
CooldownIndicator getCooldownIndicator();
/** /**
* Specifies how 1.8.x clients should see the cooldown indicator * Replaces Adventure mode with Survival mode for 1.7.x clients
* You can choose between TITLE, ACTION_BAR, BOSS_BAR and DISABLED * Enable this option if your server is using the 'CanDestroy'
* ONLY DISABLE IF YOU HAVE 1.9 COOLDOWN DISABLED ON YOUR SERVER * or 'CanPlaceOn' flags on items
* 1.8 PLAYERS MAY ASK WHY PVP IS NOT WORKING OTHERWISE *
* * @return true if enabled
* @return the cooldown indicator */
*/ boolean isReplaceAdventureMode();
CooldownIndicator getCooldownIndicator();
/** /**
* Replaces Adventure mode with Survival mode for 1.7.x clients * Whether 1.9 particles should be replaced by similar ones in
* Enable this option if your server is using the 'CanDestroy' * 1.8 and lower
* or 'CanPlaceOn' flags on items *
* * @return true if enabled
* @return true if enabled */
*/ boolean isReplaceParticles();
boolean isReplaceAdventureMode();
/** /**
* Whether 1.9 particles should be replaced by similar ones in * Max amount of pages for written books before a client gets kicked
* 1.8 and lower *
* * @return the max amount of pages
* @return true if enabled */
*/ int getMaxBookPages();
boolean isReplaceParticles();
/** /**
* Max amount of pages for written books before a client gets kicked * Max amount of characters in the json (!) string of a book page before a client gets kicked
* *
* @return the max amount of pages * @return the max amount of characters
*/ */
int getMaxBookPages(); int getMaxBookPageSize();
/** /**
* Max amount of characters in the json (!) string of a book page before a client gets kicked * Whether to emulate the 1.8+ world border for 1.7.x clients
* *
* @return the max amount of characters * @return true if enabled
*/ */
int getMaxBookPageSize(); boolean isEmulateWorldBorder();
/** /**
* Whether to emulate the 1.8+ world border for 1.7.x clients * Always shows the original mob's name instead of only when hovering over them with the cursor.
* *
* @return true if enabled * @return true if enabled
*/ */
boolean isEmulateWorldBorder(); boolean alwaysShowOriginalMobName();
/** /**
* Always shows the original mob's name instead of only when hovering over them with the cursor. * The particle to show the world border for the 1.8+ world border for 1.7.x clients
* *
* @return true if enabled * @return the particle name
*/ */
boolean alwaysShowOriginalMobName(); String getWorldBorderParticle();
/** /**
* The particle to show the world border for the 1.8+ world border for 1.7.x clients * If enabled, 1.8 players on 1.9+ servers can use /offhand to switch items between their main hand and offhand.
* *
* @return the particle name * @return true if enabled
*/ */
String getWorldBorderParticle(); boolean isEnableOffhand();
/** /**
* If enabled, 1.8 players on 1.9+ servers can use /offhand to switch items between their main hand and offhand. * Allows to define the offhand command
* *
* @return true if enabled * @return the offhand command
*/ */
boolean isEnableOffhand(); String getOffhandCommand();
/** /**
* Allows to define the offhand command * If enabled, 1.8 players on 1.9+ servers will also experience the levitation effect by sending velocity packets.
* *
* @return the offhand command * @return true if enabled
*/ */
String getOffhandCommand(); boolean emulateLevitationEffect();
/** /**
* If enabled, 1.8 players on 1.9+ servers will also experience the levitation effect by sending velocity packets. * If enabled, 1.8 players will handle the player combat packet added in 1.9 by showing the custom death message above the hotbar.
* *
* @return true if enabled * @return true if enabled
*/ */
boolean emulateLevitationEffect(); boolean handlePlayerCombatPacket();
/** enum CooldownIndicator {
* If enabled, 1.8 players will handle the player combat packet added in 1.9 by showing the custom death message above the hotbar. TITLE, ACTION_BAR, BOSS_BAR, DISABLED
* }
* @return true if enabled
*/
boolean handlePlayerCombatPacket();
} }
@@ -25,7 +25,6 @@ import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.ProtocolManager; import com.viaversion.viaversion.api.protocol.ProtocolManager;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import java.io.File; import java.io.File;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -34,59 +33,59 @@ import java.util.logging.Logger;
*/ */
public interface ViaRewindPlatform { public interface ViaRewindPlatform {
String VERSION = "${version}"; String VERSION = "${version}";
String IMPL_VERSION = "${impl_version}"; String IMPL_VERSION = "${impl_version}";
/** /**
* Initialize ViaRewind * Initialize ViaRewind
*/ */
default void init(final File configFile) { default void init(final File configFile) {
ViaRewindConfig config = new ViaRewindConfig(configFile, getLogger()); ViaRewindConfig config = new ViaRewindConfig(configFile, getLogger());
config.reload(); config.reload();
Via.getManager().getConfigurationProvider().register(config); Via.getManager().getConfigurationProvider().register(config);
ViaRewind.init(this, config); ViaRewind.init(this, config);
Via.getManager().getSubPlatforms().add(IMPL_VERSION); Via.getManager().getSubPlatforms().add(IMPL_VERSION);
getLogger().info("Registering protocols..."); getLogger().info("Registering protocols...");
final ProtocolManager protocolManager = Via.getManager().getProtocolManager(); final ProtocolManager protocolManager = Via.getManager().getProtocolManager();
protocolManager.registerProtocol(new Protocol1_7_6_10To1_7_2_5(), ProtocolVersion.v1_7_2, ProtocolVersion.v1_7_6); 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_7_6_10(), ProtocolVersion.v1_7_6, ProtocolVersion.v1_8);
protocolManager.registerProtocol(new Protocol1_9To1_8(), ProtocolVersion.v1_8, ProtocolVersion.v1_9); protocolManager.registerProtocol(new Protocol1_9To1_8(), ProtocolVersion.v1_8, ProtocolVersion.v1_9);
} }
/** /**
* Get the platform logger * Get the platform logger
* *
* @return the logger * @return the logger
*/ */
Logger getLogger(); Logger getLogger();
/** /**
* Returns ViaRewind's data folder. * Returns ViaRewind's data folder.
* *
* @return data folder * @return data folder
*/ */
File getDataFolder(); File getDataFolder();
/** /**
* Returns the platform's compression handler name. Only used in the 1.8 -> 1.7 protocol. * Returns the platform's compression handler name. Only used in the 1.8 -> 1.7 protocol.
* *
* @return the compression handler name * @return the compression handler name
*/ */
default String compressHandlerName() { default String compressHandlerName() {
return "compress"; return "compress";
} }
/** /**
* Returns the platform's decompression handler name. Only used in the 1.8 -> 1.7 protocol. * Returns the platform's decompression handler name. Only used in the 1.8 -> 1.7 protocol.
* *
* @return the decompression handler name * @return the decompression handler name
*/ */
default String decompressHandlerName() { default String decompressHandlerName() {
return "decompress"; return "decompress";
} }
} }
@@ -17,25 +17,24 @@
*/ */
package com.viaversion.viarewind.api.data; package com.viaversion.viarewind.api.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData; import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viarewind.ViaRewind; import com.viaversion.viarewind.ViaRewind;
import com.viaversion.nbt.tag.CompoundTag;
import java.util.logging.Logger; import java.util.logging.Logger;
public class RewindMappingData extends BackwardsMappingData { public class RewindMappingData extends BackwardsMappingData {
public RewindMappingData(String unmappedVersion, String mappedVersion) { public RewindMappingData(String unmappedVersion, String mappedVersion) {
super(unmappedVersion, mappedVersion); super(unmappedVersion, mappedVersion);
} }
@Override @Override
protected Logger getLogger() { protected Logger getLogger() {
return ViaRewind.getPlatform().getLogger(); return ViaRewind.getPlatform().getLogger();
} }
@Override @Override
protected CompoundTag readMappingsFile(String name) { protected CompoundTag readMappingsFile(String name) {
return RewindMappingDataLoader.INSTANCE.loadNBTFromDir(name); return RewindMappingDataLoader.INSTANCE.loadNBTFromDir(name);
} }
} }
@@ -19,26 +19,25 @@ package com.viaversion.viarewind.api.data;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader; import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viarewind.ViaRewind; import com.viaversion.viarewind.ViaRewind;
import java.io.File; import java.io.File;
import java.util.logging.Logger; import java.util.logging.Logger;
public class RewindMappingDataLoader extends BackwardsMappingDataLoader { public class RewindMappingDataLoader extends BackwardsMappingDataLoader {
public static final RewindMappingDataLoader INSTANCE = new RewindMappingDataLoader(); public static final RewindMappingDataLoader INSTANCE = new RewindMappingDataLoader();
public RewindMappingDataLoader() { public RewindMappingDataLoader() {
super(RewindMappingDataLoader.class, "assets/viarewind/data/"); super(RewindMappingDataLoader.class, "assets/viarewind/data/");
} }
@Override @Override
public Logger getLogger() { public Logger getLogger() {
return ViaRewind.getPlatform().getLogger(); return ViaRewind.getPlatform().getLogger();
} }
@Override @Override
public File getDataFolder() { public File getDataFolder() {
return ViaRewind.getPlatform().getDataFolder(); return ViaRewind.getPlatform().getDataFolder();
} }
} }
@@ -21,57 +21,57 @@ import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.NibbleArray; import com.viaversion.viaversion.api.minecraft.chunks.NibbleArray;
public class ExtendedBlockStorage { public class ExtendedBlockStorage {
private final byte[] blockLSBArray = new byte[ChunkSection.SIZE]; private final byte[] blockLSBArray = new byte[ChunkSection.SIZE];
private final NibbleArray blockMetadataArray = new NibbleArray(this.blockLSBArray.length); private final NibbleArray blockMetadataArray = new NibbleArray(this.blockLSBArray.length);
private final NibbleArray blockLightArray = new NibbleArray(this.blockLSBArray.length); private final NibbleArray blockLightArray = new NibbleArray(this.blockLSBArray.length);
private NibbleArray blockMSBArray; private NibbleArray blockMSBArray;
private NibbleArray skyLightArray; private NibbleArray skyLightArray;
public ExtendedBlockStorage(final boolean skylight) { public ExtendedBlockStorage(final boolean skylight) {
if (skylight) { if (skylight) {
this.skyLightArray = new NibbleArray(this.blockLSBArray.length); this.skyLightArray = new NibbleArray(this.blockLSBArray.length);
} }
} }
public void setBlockId(final int x, final int y, final int z, final int value) { public void setBlockId(final int x, final int y, final int z, final int value) {
this.blockLSBArray[ChunkSection.index(x, y, z)] = (byte) (value & 255); this.blockLSBArray[ChunkSection.index(x, y, z)] = (byte) (value & 255);
if (value > 255) { if (value > 255) {
this.getOrCreateBlockMSBArray().set(x, y, z, (value & 0xF00) >> 8); this.getOrCreateBlockMSBArray().set(x, y, z, (value & 0xF00) >> 8);
} else if (this.blockMSBArray != null) { } else if (this.blockMSBArray != null) {
this.blockMSBArray.set(x, y, z, 0); this.blockMSBArray.set(x, y, z, 0);
} }
} }
public void setBlockMetadata(final int x, final int y, final int z, final int value) { public void setBlockMetadata(final int x, final int y, final int z, final int value) {
this.blockMetadataArray.set(x, y, z, value); this.blockMetadataArray.set(x, y, z, value);
} }
public boolean hasBlockMSBArray() { public boolean hasBlockMSBArray() {
return this.blockMSBArray != null; return this.blockMSBArray != null;
} }
public byte[] getBlockLSBArray() { public byte[] getBlockLSBArray() {
return this.blockLSBArray; return this.blockLSBArray;
} }
public NibbleArray getOrCreateBlockMSBArray() { public NibbleArray getOrCreateBlockMSBArray() {
if (this.blockMSBArray == null) { if (this.blockMSBArray == null) {
return this.blockMSBArray = new NibbleArray(this.blockLSBArray.length); return this.blockMSBArray = new NibbleArray(this.blockLSBArray.length);
} }
return this.blockMSBArray; return this.blockMSBArray;
} }
public NibbleArray getBlockMetadataArray() { public NibbleArray getBlockMetadataArray() {
return this.blockMetadataArray; return this.blockMetadataArray;
} }
public NibbleArray getBlockLightArray() { public NibbleArray getBlockLightArray() {
return this.blockLightArray; return this.blockLightArray;
} }
public NibbleArray getSkyLightArray() { public NibbleArray getSkyLightArray() {
return this.skyLightArray; return this.skyLightArray;
} }
} }
@@ -23,33 +23,33 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
public enum EntityDataTypes1_7_6_10 implements EntityDataType { public enum EntityDataTypes1_7_6_10 implements EntityDataType {
BYTE(0, Types.BYTE), BYTE(0, Types.BYTE),
SHORT(1, Types.SHORT), SHORT(1, Types.SHORT),
INT(2, Types.INT), INT(2, Types.INT),
FLOAT(3, Types.FLOAT), FLOAT(3, Types.FLOAT),
STRING(4, Types.STRING), STRING(4, Types.STRING),
ITEM(5, RewindTypes.COMPRESSED_NBT_ITEM), ITEM(5, RewindTypes.COMPRESSED_NBT_ITEM),
POSITION(6, Types.VECTOR); POSITION(6, Types.VECTOR);
private final int typeID; private final int typeID;
private final Type<?> type; private final Type<?> type;
EntityDataTypes1_7_6_10(int typeID, Type<?> type) { EntityDataTypes1_7_6_10(int typeID, Type<?> type) {
this.typeID = typeID; this.typeID = typeID;
this.type = type; this.type = type;
} }
public static EntityDataTypes1_7_6_10 byId(int id) { public static EntityDataTypes1_7_6_10 byId(int id) {
return values()[id]; return values()[id];
} }
@Override @Override
public int typeId() { public int typeId() {
return this.typeID; return this.typeID;
} }
@Override @Override
public Type<?> type() { public Type<?> type() {
return this.type; return this.type;
} }
} }
@@ -18,19 +18,19 @@
package com.viaversion.viarewind.api.minecraft.math; package com.viaversion.viarewind.api.minecraft.math;
public class AABB { public class AABB {
Vector3d min; Vector3d min;
Vector3d max; Vector3d max;
public AABB(Vector3d min, Vector3d max) { public AABB(Vector3d min, Vector3d max) {
this.min = min; this.min = min;
this.max = max; this.max = max;
} }
public Vector3d getMin() { public Vector3d getMin() {
return this.min; return this.min;
} }
public Vector3d getMax() { public Vector3d getMax() {
return this.max; return this.max;
} }
} }
@@ -18,19 +18,19 @@
package com.viaversion.viarewind.api.minecraft.math; package com.viaversion.viarewind.api.minecraft.math;
public class Ray3d { public class Ray3d {
Vector3d start; Vector3d start;
Vector3d dir; Vector3d dir;
public Ray3d(Vector3d start, Vector3d dir) { public Ray3d(Vector3d start, Vector3d dir) {
this.start = start; this.start = start;
this.dir = dir; this.dir = dir;
} }
public Vector3d getStart() { public Vector3d getStart() {
return this.start; return this.start;
} }
public Vector3d getDir() { public Vector3d getDir() {
return this.dir; return this.dir;
} }
} }
@@ -19,40 +19,40 @@ package com.viaversion.viarewind.api.minecraft.math;
public class RayTracing { public class RayTracing {
public static Vector3d trace(Ray3d ray, AABB aabb, double distance) { public static Vector3d trace(Ray3d ray, AABB aabb, double distance) {
Vector3d invDir = new Vector3d(1f / ray.dir.x, 1f / ray.dir.y, 1f / ray.dir.z); Vector3d invDir = new Vector3d(1f / ray.dir.x, 1f / ray.dir.y, 1f / ray.dir.z);
boolean signDirX = invDir.x < 0; boolean signDirX = invDir.x < 0;
boolean signDirY = invDir.y < 0; boolean signDirY = invDir.y < 0;
boolean signDirZ = invDir.z < 0; boolean signDirZ = invDir.z < 0;
Vector3d bbox = signDirX ? aabb.max : aabb.min; Vector3d bbox = signDirX ? aabb.max : aabb.min;
double tmin = (bbox.x - ray.start.x) * invDir.x; double tmin = (bbox.x - ray.start.x) * invDir.x;
bbox = signDirX ? aabb.min : aabb.max; bbox = signDirX ? aabb.min : aabb.max;
double tmax = (bbox.x - ray.start.x) * invDir.x; double tmax = (bbox.x - ray.start.x) * invDir.x;
bbox = signDirY ? aabb.max : aabb.min; bbox = signDirY ? aabb.max : aabb.min;
double tymin = (bbox.y - ray.start.y) * invDir.y; double tymin = (bbox.y - ray.start.y) * invDir.y;
bbox = signDirY ? aabb.min : aabb.max; bbox = signDirY ? aabb.min : aabb.max;
double tymax = (bbox.y - ray.start.y) * invDir.y; double tymax = (bbox.y - ray.start.y) * invDir.y;
if (tmin > tymax || tymin > tmax) return null; if (tmin > tymax || tymin > tmax) return null;
if (tymin > tmin) tmin = tymin; if (tymin > tmin) tmin = tymin;
if (tymax < tmax) tmax = tymax; if (tymax < tmax) tmax = tymax;
bbox = signDirZ ? aabb.max : aabb.min; bbox = signDirZ ? aabb.max : aabb.min;
double tzmin = (bbox.z - ray.start.z) * invDir.z; double tzmin = (bbox.z - ray.start.z) * invDir.z;
bbox = signDirZ ? aabb.min : aabb.max; bbox = signDirZ ? aabb.min : aabb.max;
double tzmax = (bbox.z - ray.start.z) * invDir.z; double tzmax = (bbox.z - ray.start.z) * invDir.z;
if (tmin > tzmax || tzmin > tmax) return null; if (tmin > tzmax || tzmin > tmax) return null;
if (tzmin > tmin) tmin = tzmin; if (tzmin > tmin) tmin = tzmin;
if (tzmax < tmax) tmax = tzmax; if (tzmax < tmax) tmax = tzmax;
return tmin <= distance && tmax > 0 ? ray.start.clone().add(ray.dir.clone().normalize().multiply(tmin)) : null; return tmin <= distance && tmax > 0 ? ray.start.clone().add(ray.dir.clone().normalize().multiply(tmin)) : null;
} }
} }
@@ -25,79 +25,79 @@ import com.viaversion.viaversion.api.minecraft.Vector;
@Deprecated // ????????? @Deprecated // ?????????
public class RelativeMoveUtil { public class RelativeMoveUtil {
public static Vector[] calculateRelativeMoves(UserConnection user, int entityId, int relX, int relY, int relZ) { public static Vector[] calculateRelativeMoves(UserConnection user, int entityId, int relX, int relY, int relZ) {
EntityTracker1_9 tracker = user.getEntityTracker(Protocol1_9To1_8.class); EntityTracker1_9 tracker = user.getEntityTracker(Protocol1_9To1_8.class);
int x; int x;
int y; int y;
int z; int z;
Vector offset = tracker.getEntityOffset(entityId); Vector offset = tracker.getEntityOffset(entityId);
if (offset != null) { if (offset != null) {
relX += offset.blockX(); relX += offset.blockX();
relY += offset.blockY(); relY += offset.blockY();
relZ += offset.blockZ(); relZ += offset.blockZ();
} }
if (relX > Short.MAX_VALUE) { if (relX > Short.MAX_VALUE) {
x = relX - Short.MAX_VALUE; x = relX - Short.MAX_VALUE;
relX = Short.MAX_VALUE; relX = Short.MAX_VALUE;
} else if (relX < Short.MIN_VALUE) { } else if (relX < Short.MIN_VALUE) {
x = relX - Short.MIN_VALUE; x = relX - Short.MIN_VALUE;
relX = Short.MIN_VALUE; relX = Short.MIN_VALUE;
} else { } else {
x = 0; x = 0;
} }
if (relY > Short.MAX_VALUE) { if (relY > Short.MAX_VALUE) {
y = relY - Short.MAX_VALUE; y = relY - Short.MAX_VALUE;
relY = Short.MAX_VALUE; relY = Short.MAX_VALUE;
} else if (relY < Short.MIN_VALUE) { } else if (relY < Short.MIN_VALUE) {
y = relY - Short.MIN_VALUE; y = relY - Short.MIN_VALUE;
relY = Short.MIN_VALUE; relY = Short.MIN_VALUE;
} else { } else {
y = 0; y = 0;
} }
if (relZ > Short.MAX_VALUE) { if (relZ > Short.MAX_VALUE) {
z = relZ - Short.MAX_VALUE; z = relZ - Short.MAX_VALUE;
relZ = Short.MAX_VALUE; relZ = Short.MAX_VALUE;
} else if (relZ < Short.MIN_VALUE) { } else if (relZ < Short.MIN_VALUE) {
z = relZ - Short.MIN_VALUE; z = relZ - Short.MIN_VALUE;
relZ = Short.MIN_VALUE; relZ = Short.MIN_VALUE;
} else { } else {
z = 0; z = 0;
} }
int sentRelX, sentRelY, sentRelZ; int sentRelX, sentRelY, sentRelZ;
Vector[] moves; Vector[] moves;
if (relX > Byte.MAX_VALUE * 128 || relX < Byte.MIN_VALUE * 128 || relY > Byte.MAX_VALUE * 128 || relY < Byte.MIN_VALUE * 128 || relZ > Byte.MAX_VALUE * 128 || relZ < Byte.MIN_VALUE * 128) { if (relX > Byte.MAX_VALUE * 128 || relX < Byte.MIN_VALUE * 128 || relY > Byte.MAX_VALUE * 128 || relY < Byte.MIN_VALUE * 128 || relZ > Byte.MAX_VALUE * 128 || relZ < Byte.MIN_VALUE * 128) {
byte relX1 = (byte) (relX / 256); byte relX1 = (byte) (relX / 256);
byte relX2 = (byte) (Math.round((relX - relX1 * 128) / 128f)); byte relX2 = (byte) (Math.round((relX - relX1 * 128) / 128f));
byte relY1 = (byte) (relY / 256); byte relY1 = (byte) (relY / 256);
byte relY2 = (byte) (Math.round((relY - relY1 * 128) / 128f)); byte relY2 = (byte) (Math.round((relY - relY1 * 128) / 128f));
byte relZ1 = (byte) (relZ / 256); byte relZ1 = (byte) (relZ / 256);
byte relZ2 = (byte) (Math.round((relZ - relZ1 * 128) / 128f)); byte relZ2 = (byte) (Math.round((relZ - relZ1 * 128) / 128f));
sentRelX = relX1 + relX2; sentRelX = relX1 + relX2;
sentRelY = relY1 + relY2; sentRelY = relY1 + relY2;
sentRelZ = relZ1 + relZ2; sentRelZ = relZ1 + relZ2;
moves = new Vector[]{new Vector(relX1, relY1, relZ1), new Vector(relX2, relY2, relZ2)}; moves = new Vector[]{new Vector(relX1, relY1, relZ1), new Vector(relX2, relY2, relZ2)};
} else { } else {
sentRelX = Math.round(relX / 128f); sentRelX = Math.round(relX / 128f);
sentRelY = Math.round(relY / 128f); sentRelY = Math.round(relY / 128f);
sentRelZ = Math.round(relZ / 128f); sentRelZ = Math.round(relZ / 128f);
moves = new Vector[]{new Vector(sentRelX, sentRelY, sentRelZ)}; moves = new Vector[]{new Vector(sentRelX, sentRelY, sentRelZ)};
} }
x = x + relX - sentRelX * 128; x = x + relX - sentRelX * 128;
y = y + relY - sentRelY * 128; y = y + relY - sentRelY * 128;
z = z + relZ - sentRelZ * 128; z = z + relZ - sentRelZ * 128;
tracker.setEntityOffset(entityId, new Vector(x, y, z)); tracker.setEntityOffset(entityId, new Vector(x, y, z));
return moves; return moves;
} }
} }
@@ -20,109 +20,109 @@ package com.viaversion.viarewind.api.minecraft.math;
import java.util.Objects; import java.util.Objects;
public class Vector3d { public class Vector3d {
double x, y, z; double x, y, z;
public Vector3d(double x, double y, double z) { public Vector3d(double x, double y, double z) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
} }
public Vector3d() { public Vector3d() {
} }
public void set(Vector3d vec) { public void set(Vector3d vec) {
this.x = vec.x; this.x = vec.x;
this.y = vec.y; this.y = vec.y;
this.z = vec.z; this.z = vec.z;
} }
public Vector3d set(double x, double y, double z) { public Vector3d set(double x, double y, double z) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
return this; return this;
} }
public Vector3d multiply(double a) { public Vector3d multiply(double a) {
this.x *= a; this.x *= a;
this.y *= a; this.y *= a;
this.z *= a; this.z *= a;
return this; return this;
} }
public Vector3d add(Vector3d vec) { public Vector3d add(Vector3d vec) {
this.x += vec.x; this.x += vec.x;
this.y += vec.y; this.y += vec.y;
this.z += vec.z; this.z += vec.z;
return this; return this;
} }
public Vector3d substract(Vector3d vec) { public Vector3d substract(Vector3d vec) {
this.x -= vec.x; this.x -= vec.x;
this.y -= vec.y; this.y -= vec.y;
this.z -= vec.z; this.z -= vec.z;
return this; return this;
} }
public double length() { public double length() {
return Math.sqrt(lengthSquared()); return Math.sqrt(lengthSquared());
} }
public double lengthSquared() { public double lengthSquared() {
return this.x * this.x + this.y * this.y + this.z * this.z; return this.x * this.x + this.y * this.y + this.z * this.z;
} }
public Vector3d normalize() { public Vector3d normalize() {
double length = length(); double length = length();
multiply(1.0 / length); multiply(1.0 / length);
return this; return this;
} }
@Override @Override
public Vector3d clone() { public Vector3d clone() {
return new Vector3d(this.x, this.y, this.z); return new Vector3d(this.x, this.y, this.z);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Vector3d vector3d = (Vector3d) o; Vector3d vector3d = (Vector3d) o;
return Double.compare(vector3d.x, x) == 0 && Double.compare(vector3d.y, y) == 0 && Double.compare(vector3d.z, z) == 0; return Double.compare(vector3d.x, x) == 0 && Double.compare(vector3d.y, y) == 0 && Double.compare(vector3d.z, z) == 0;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(x, y, z); return Objects.hash(x, y, z);
} }
@Override @Override
public String toString() { public String toString() {
return "Vector3d{" + "x=" + x + ", y=" + y + ", z=" + z + '}'; return "Vector3d{" + "x=" + x + ", y=" + y + ", z=" + z + '}';
} }
public double getX() { public double getX() {
return this.x; return this.x;
} }
public double getY() { public void setX(double x) {
return this.y; this.x = x;
} }
public double getZ() { public double getY() {
return this.z; return this.y;
} }
public void setX(double x) { public void setY(double y) {
this.x = x; this.y = y;
} }
public void setY(double y) { public double getZ() {
this.y = y; return this.z;
} }
public void setZ(double z) { public void setZ(double z) {
this.z = z; this.z = z;
} }
} }
@@ -23,8 +23,8 @@ import io.netty.handler.codec.MessageToByteEncoder;
public class ForwardMessageToByteEncoder extends MessageToByteEncoder<ByteBuf> { public class ForwardMessageToByteEncoder extends MessageToByteEncoder<ByteBuf> {
@Override @Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) { protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) {
out.writeBytes(msg); out.writeBytes(msg);
} }
} }
@@ -26,17 +26,17 @@ import com.viaversion.viaversion.libs.gson.JsonObject;
public class VRBlockItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType, T extends BackwardsProtocol<C, ?, ?, S>> extends LegacyBlockItemRewriter<C, S, T> { public class VRBlockItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType, T extends BackwardsProtocol<C, ?, ?, S>> extends LegacyBlockItemRewriter<C, S, T> {
protected VRBlockItemRewriter(T protocol, String name) { protected VRBlockItemRewriter(T protocol, String name) {
super(protocol, name); super(protocol, name);
} }
@Override @Override
protected JsonObject readMappingsFile(String name) { protected JsonObject readMappingsFile(String name) {
return RewindMappingDataLoader.INSTANCE.loadFromDataDir(name); return RewindMappingDataLoader.INSTANCE.loadFromDataDir(name);
} }
@Override @Override
public String nbtTagName() { public String nbtTagName() {
return "VR|" + protocol.getClass().getSimpleName(); return "VR|" + protocol.getClass().getSimpleName();
} }
} }
@@ -31,36 +31,36 @@ import com.viaversion.viaversion.data.entity.EntityTrackerBase;
public abstract class VREntityRewriter<C extends ClientboundPacketType, T extends BackwardsProtocol<C, ?, ?, ?>> extends LegacyEntityRewriter<C, T> { public abstract class VREntityRewriter<C extends ClientboundPacketType, T extends BackwardsProtocol<C, ?, ?, ?>> extends LegacyEntityRewriter<C, T> {
public VREntityRewriter(T protocol) { public VREntityRewriter(T protocol) {
super(protocol, EntityDataTypes1_8.STRING, EntityDataTypes1_8.BYTE); super(protocol, EntityDataTypes1_8.STRING, EntityDataTypes1_8.BYTE);
} }
public VREntityRewriter(T protocol, EntityDataType displayType, EntityDataType displayVisibilityType) { public VREntityRewriter(T protocol, EntityDataType displayType, EntityDataType displayVisibilityType) {
super(protocol, displayType, displayVisibilityType); super(protocol, displayType, displayVisibilityType);
} }
protected void removeEntities(final UserConnection connection, final int[] entities) { protected void removeEntities(final UserConnection connection, final int[] entities) {
final EntityTrackerBase tracker = tracker(connection); final EntityTrackerBase tracker = tracker(connection);
for (int entityId : entities) { for (int entityId : entities) {
tracker.removeEntity(entityId); tracker.removeEntity(entityId);
} }
} }
protected PacketHandler getDimensionHandler() { protected PacketHandler getDimensionHandler() {
return wrapper -> { return wrapper -> {
final int dimension = wrapper.get(Types.BYTE, 0); final int dimension = wrapper.get(Types.BYTE, 0);
final ClientWorld clientWorld = wrapper.user().getClientWorld(protocol.getClass()); final ClientWorld clientWorld = wrapper.user().getClientWorld(protocol.getClass());
clientWorld.setEnvironment(dimension); clientWorld.setEnvironment(dimension);
}; };
} }
@Override @Override
protected Object getDisplayVisibilityDataValue() { protected Object getDisplayVisibilityDataValue() {
return (byte) 1; return (byte) 1;
} }
@Override @Override
protected boolean alwaysShowOriginalMobName() { protected boolean alwaysShowOriginalMobName() {
return ViaRewind.getConfig().alwaysShowOriginalMobName(); return ViaRewind.getConfig().alwaysShowOriginalMobName();
} }
} }
@@ -22,23 +22,23 @@ import io.netty.buffer.ByteBuf;
public class IntArrayType extends Type<int[]> { public class IntArrayType extends Type<int[]> {
public IntArrayType() { public IntArrayType() {
super(int[].class); super(int[].class);
} }
@Override @Override
public int[] read(ByteBuf byteBuf) { public int[] read(ByteBuf byteBuf) {
byte size = byteBuf.readByte(); byte size = byteBuf.readByte();
int[] array = new int[size]; int[] array = new int[size];
for (byte i = 0; i < size; i++) { for (byte i = 0; i < size; i++) {
array[i] = byteBuf.readInt(); array[i] = byteBuf.readInt();
} }
return array; return array;
} }
@Override @Override
public void write(ByteBuf byteBuf, int[] array) { public void write(ByteBuf byteBuf, int[] array) {
byteBuf.writeByte(array.length); byteBuf.writeByte(array.length);
for (int i : array) byteBuf.writeInt(i); for (int i : array) byteBuf.writeInt(i);
} }
} }
@@ -20,34 +20,33 @@ package com.viaversion.viarewind.api.type;
import com.viaversion.viaversion.api.minecraft.BlockPosition; import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.util.function.IntFunction; import java.util.function.IntFunction;
public class PositionVarYType<T extends Number> extends Type<BlockPosition> { public class PositionVarYType<T extends Number> extends Type<BlockPosition> {
private final Type<T> yType; private final Type<T> yType;
private final IntFunction<T> toY; private final IntFunction<T> toY;
public PositionVarYType(final Type<T> yType, final IntFunction<T> toY) { public PositionVarYType(final Type<T> yType, final IntFunction<T> toY) {
super(BlockPosition.class); super(BlockPosition.class);
this.yType = yType; this.yType = yType;
this.toY = toY; this.toY = toY;
} }
@Override @Override
public BlockPosition read(ByteBuf buffer) { public BlockPosition read(ByteBuf buffer) {
final int x = buffer.readInt(); final int x = buffer.readInt();
final int y = yType.read(buffer).intValue(); final int y = yType.read(buffer).intValue();
final int z = buffer.readInt(); final int z = buffer.readInt();
return new BlockPosition(x, y, z); return new BlockPosition(x, y, z);
} }
@Override @Override
public void write(ByteBuf buffer, BlockPosition value) { public void write(ByteBuf buffer, BlockPosition value) {
buffer.writeInt(value.x()); buffer.writeInt(value.x());
yType.write(buffer, this.toY.apply(value.y())); yType.write(buffer, this.toY.apply(value.y()));
buffer.writeInt(value.z()); buffer.writeInt(value.z());
} }
} }
@@ -17,19 +17,18 @@
*/ */
package com.viaversion.viarewind.api.type; package com.viaversion.viarewind.api.type;
import com.viaversion.viarewind.api.type.item.NBTType; import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viarewind.api.type.item.ItemArrayType;
import com.viaversion.viarewind.api.type.item.ItemType;
import com.viaversion.viarewind.api.type.entitydata.EntityDataListType; import com.viaversion.viarewind.api.type.entitydata.EntityDataListType;
import com.viaversion.viarewind.api.type.entitydata.EntityDataType; import com.viaversion.viarewind.api.type.entitydata.EntityDataType;
import com.viaversion.viarewind.api.type.item.ItemArrayType;
import com.viaversion.viarewind.api.type.item.ItemType;
import com.viaversion.viarewind.api.type.item.NBTType;
import com.viaversion.viaversion.api.minecraft.BlockPosition; import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.type.types.StringType; import com.viaversion.viaversion.api.type.types.StringType;
import java.util.List; import java.util.List;
/** /**
@@ -38,16 +37,16 @@ import java.util.List;
public class RewindTypes { public class RewindTypes {
public static final Type<String> SIGN_STRING = new StringType(384); public static final Type<String> SIGN_STRING = new StringType(384);
public static final Type<int[]> INT_ARRAY = new IntArrayType(); // Integer array with byte as length indicator public static final Type<int[]> INT_ARRAY = new IntArrayType(); // Integer array with byte as length indicator
public static final Type<BlockPosition> SHORT_POSITION = new PositionVarYType<>(Types.SHORT, value -> (short) value); 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> 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> 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); public static final Type<BlockPosition> U_BYTE_POSITION = new PositionVarYType<>(Types.UNSIGNED_BYTE, value -> (short) value);
public static final Type<CompoundTag> COMPRESSED_NBT = new NBTType(); 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 = new ItemType();
public static final Type<Item[]> COMPRESSED_NBT_ITEM_ARRAY = new ItemArrayType(); public static final Type<Item[]> COMPRESSED_NBT_ITEM_ARRAY = new ItemArrayType();
public static final Type<EntityData> ENTITY_DATA1_7 = new EntityDataType(); public static final Type<EntityData> ENTITY_DATA1_7 = new EntityDataType();
public static final Type<List<EntityData>> ENTITY_DATA_LIST1_7 = new EntityDataListType(ENTITY_DATA1_7); public static final Type<List<EntityData>> ENTITY_DATA_LIST1_7 = new EntityDataListType(ENTITY_DATA1_7);
@@ -22,49 +22,48 @@ import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.Pair; import com.viaversion.viaversion.util.Pair;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.util.zip.Deflater; import java.util.zip.Deflater;
public class BulkChunkType1_7_6 extends Type<Chunk[]> { public class BulkChunkType1_7_6 extends Type<Chunk[]> {
public static final BulkChunkType1_7_6 TYPE = new BulkChunkType1_7_6(); public static final BulkChunkType1_7_6 TYPE = new BulkChunkType1_7_6();
public BulkChunkType1_7_6() { public BulkChunkType1_7_6() {
super(Chunk[].class); super(Chunk[].class);
} }
@Override @Override
public Chunk[] read(ByteBuf byteBuf) { 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 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 @Override
public void write(ByteBuf byteBuf, Chunk[] chunks) { public void write(ByteBuf byteBuf, Chunk[] chunks) {
final int chunkCount = chunks.length; final int chunkCount = chunks.length;
final int[] chunkX = new int[chunkCount]; final int[] chunkX = new int[chunkCount];
final int[] chunkZ = new int[chunkCount]; final int[] chunkZ = new int[chunkCount];
final short[] primaryBitMask = new short[chunkCount]; final short[] primaryBitMask = new short[chunkCount];
final short[] additionalBitMask = new short[chunkCount]; final short[] additionalBitMask = new short[chunkCount];
final byte[][] dataArrays = new byte[chunkCount][]; final byte[][] dataArrays = new byte[chunkCount][];
int dataSize = 0; int dataSize = 0;
for (int i = 0; i < chunkCount; i++) { for (int i = 0; i < chunkCount; i++) {
final Chunk chunk = chunks[i]; final Chunk chunk = chunks[i];
Pair<byte[], Short> chunkData; Pair<byte[], Short> chunkData;
try { try {
chunkData = ChunkType1_7_6.serialize(chunk); chunkData = ChunkType1_7_6.serialize(chunk);
final byte[] data = chunkData.key(); final byte[] data = chunkData.key();
dataArrays[i] = data; dataArrays[i] = data;
dataSize += data.length; dataSize += data.length;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Unable to serialize chunk", e); throw new RuntimeException("Unable to serialize chunk", e);
} }
chunkX[i] = chunk.getX(); chunkX[i] = chunk.getX();
chunkZ[i] = chunk.getZ(); chunkZ[i] = chunk.getZ();
primaryBitMask[i] = (short) chunk.getBitmask(); primaryBitMask[i] = (short) chunk.getBitmask();
additionalBitMask[i] = chunkData.value(); additionalBitMask[i] = chunkData.value();
} }
final byte[] data = new byte[dataSize]; final byte[] data = new byte[dataSize];
int destPos = 0; int destPos = 0;
@@ -73,39 +72,39 @@ public class BulkChunkType1_7_6 extends Type<Chunk[]> {
destPos += array.length; destPos += array.length;
} }
final Deflater deflater = new Deflater(); final Deflater deflater = new Deflater();
byte[] compressedData; byte[] compressedData;
int compressedSize; int compressedSize;
try { try {
deflater.setInput(data, 0, data.length); deflater.setInput(data, 0, data.length);
deflater.finish(); deflater.finish();
compressedData = new byte[data.length]; compressedData = new byte[data.length];
compressedSize = deflater.deflate(compressedData); compressedSize = deflater.deflate(compressedData);
} finally { } finally {
deflater.end(); deflater.end();
} }
byteBuf.writeShort(chunkCount); byteBuf.writeShort(chunkCount);
byteBuf.writeInt(compressedSize); byteBuf.writeInt(compressedSize);
boolean skyLight = false; boolean skyLight = false;
for (Chunk chunk : chunks) { for (Chunk chunk : chunks) {
for (ChunkSection section : chunk.getSections()) { for (ChunkSection section : chunk.getSections()) {
if (section != null && section.getLight().hasSkyLight()) { if (section != null && section.getLight().hasSkyLight()) {
skyLight = true; skyLight = true;
break; break;
} }
} }
} }
byteBuf.writeBoolean(skyLight); // hasSkyLight byteBuf.writeBoolean(skyLight); // hasSkyLight
byteBuf.writeBytes(compressedData, 0, compressedSize); byteBuf.writeBytes(compressedData, 0, compressedSize);
for (int i = 0; i < chunkCount; i++) { for (int i = 0; i < chunkCount; i++) {
byteBuf.writeInt(chunkX[i]); byteBuf.writeInt(chunkX[i]);
byteBuf.writeInt(chunkZ[i]); byteBuf.writeInt(chunkZ[i]);
byteBuf.writeShort(primaryBitMask[i]); byteBuf.writeShort(primaryBitMask[i]);
byteBuf.writeShort(additionalBitMask[i]); byteBuf.writeShort(additionalBitMask[i]);
} }
} }
} }
@@ -18,11 +18,12 @@
package com.viaversion.viarewind.api.type.chunk; package com.viaversion.viarewind.api.type.chunk;
import com.viaversion.viarewind.api.minecraft.ExtendedBlockStorage; import com.viaversion.viarewind.api.minecraft.ExtendedBlockStorage;
import com.viaversion.viaversion.api.minecraft.chunks.*; import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.Pair; import com.viaversion.viaversion.util.Pair;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.io.IOException; import java.io.IOException;
import java.util.zip.Deflater; import java.util.zip.Deflater;
@@ -31,127 +32,90 @@ import static com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionLight.L
public class ChunkType1_7_6 extends Type<Chunk> { public class ChunkType1_7_6 extends Type<Chunk> {
public static final ChunkType1_7_6 TYPE = new ChunkType1_7_6(); public static final ChunkType1_7_6 TYPE = new ChunkType1_7_6();
public ChunkType1_7_6() { public ChunkType1_7_6() {
super(Chunk.class); super(Chunk.class);
} }
@Override public static Pair<byte[], Short> serialize(final Chunk chunk) throws IOException {
public Chunk read(ByteBuf byteBuf) { final ExtendedBlockStorage[] storageArrays = new ExtendedBlockStorage[16];
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 for (int i = 0; i < storageArrays.length; i++) {
} final ChunkSection section = chunk.getSections()[i];
if (section != null) {
@Override final ExtendedBlockStorage storage = storageArrays[i] = new ExtendedBlockStorage(section.getLight().hasSkyLight());
public void write(ByteBuf output, Chunk chunk) { for (int x = 0; x < 16; x++) {
Pair<byte[], Short> chunkData; for (int z = 0; z < 16; z++) {
try { for (int y = 0; y < 16; y++) {
chunkData = serialize(chunk); final int flatBlock = section.palette(PaletteType.BLOCKS).idAt(x, y, z);
} catch (IOException e) { storage.setBlockId(x, y, z, flatBlock >> 4);
throw new RuntimeException("Unable to serialize chunk", e); storage.setBlockMetadata(x, y, z, flatBlock & 15);
} }
final byte[] data = chunkData.key(); }
final short additionalBitMask = chunkData.value(); }
storage.getBlockLightArray().setHandle(section.getLight().getBlockLight());
final Deflater deflater = new Deflater(); if (section.getLight().hasSkyLight()) {
byte[] compressedData; storage.getSkyLightArray().setHandle(section.getLight().getSkyLight());
int compressedSize; }
try { }
deflater.setInput(data, 0, data.length); }
deflater.finish();
compressedData = new byte[data.length];
compressedSize = deflater.deflate(compressedData);
} finally {
deflater.end();
}
output.writeInt(chunk.getX());
output.writeInt(chunk.getZ());
output.writeBoolean(chunk.isFullChunk());
output.writeShort(chunk.getBitmask());
output.writeShort(additionalBitMask);
output.writeInt(compressedSize);
output.writeBytes(compressedData, 0, compressedSize);
}
public static Pair<byte[], Short> serialize(final Chunk chunk) throws IOException {
final ExtendedBlockStorage[] storageArrays = new ExtendedBlockStorage[16];
for (int i = 0; i < storageArrays.length; i++) {
final ChunkSection section = chunk.getSections()[i];
if (section != null) {
final ExtendedBlockStorage storage = storageArrays[i] = new ExtendedBlockStorage(section.getLight().hasSkyLight());
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = 0; y < 16; y++) {
final int flatBlock = section.palette(PaletteType.BLOCKS).idAt(x, y, z);
storage.setBlockId(x, y, z, flatBlock >> 4);
storage.setBlockMetadata(x, y, z, flatBlock & 15);
}
}
}
storage.getBlockLightArray().setHandle(section.getLight().getBlockLight());
if (section.getLight().hasSkyLight()) {
storage.getSkyLightArray().setHandle(section.getLight().getSkyLight());
}
}
}
final boolean biomes = chunk.isFullChunk() && chunk.getBiomeData() != null; final boolean biomes = chunk.isFullChunk() && chunk.getBiomeData() != null;
final int totalSize = calculateSize(storageArrays, chunk.getBitmask(), biomes); final int totalSize = calculateSize(storageArrays, chunk.getBitmask(), biomes);
final byte[] output = new byte[totalSize]; final byte[] output = new byte[totalSize];
int index = 0; int index = 0;
for (int i = 0; i < storageArrays.length; i++) { for (int i = 0; i < storageArrays.length; i++) {
if ((chunk.getBitmask() & 1 << i) != 0) { if ((chunk.getBitmask() & 1 << i) != 0) {
final byte[] blockLSBArray = storageArrays[i].getBlockLSBArray(); final byte[] blockLSBArray = storageArrays[i].getBlockLSBArray();
System.arraycopy(blockLSBArray, 0, output, index, blockLSBArray.length); System.arraycopy(blockLSBArray, 0, output, index, blockLSBArray.length);
index += blockLSBArray.length; index += blockLSBArray.length;
} }
} }
for (int i = 0; i < storageArrays.length; i++) { for (int i = 0; i < storageArrays.length; i++) {
if ((chunk.getBitmask() & 1 << i) != 0) { if ((chunk.getBitmask() & 1 << i) != 0) {
final byte[] blockMetadataArray = storageArrays[i].getBlockMetadataArray().getHandle(); final byte[] blockMetadataArray = storageArrays[i].getBlockMetadataArray().getHandle();
System.arraycopy(blockMetadataArray, 0, output, index, blockMetadataArray.length); System.arraycopy(blockMetadataArray, 0, output, index, blockMetadataArray.length);
index += blockMetadataArray.length; index += blockMetadataArray.length;
} }
} }
for (int i = 0; i < storageArrays.length; i++) { for (int i = 0; i < storageArrays.length; i++) {
if ((chunk.getBitmask() & 1 << i) != 0) { if ((chunk.getBitmask() & 1 << i) != 0) {
final byte[] blockLightArray = storageArrays[i].getBlockLightArray().getHandle(); final byte[] blockLightArray = storageArrays[i].getBlockLightArray().getHandle();
System.arraycopy(blockLightArray, 0, output, index, blockLightArray.length); System.arraycopy(blockLightArray, 0, output, index, blockLightArray.length);
index += blockLightArray.length; index += blockLightArray.length;
} }
} }
for (int i = 0; i < storageArrays.length; i++) { for (int i = 0; i < storageArrays.length; i++) {
if ((chunk.getBitmask() & 1 << i) != 0 && storageArrays[i].getSkyLightArray() != null) { if ((chunk.getBitmask() & 1 << i) != 0 && storageArrays[i].getSkyLightArray() != null) {
final byte[] skyLightArray = storageArrays[i].getSkyLightArray().getHandle(); final byte[] skyLightArray = storageArrays[i].getSkyLightArray().getHandle();
System.arraycopy(skyLightArray, 0, output, index, skyLightArray.length); System.arraycopy(skyLightArray, 0, output, index, skyLightArray.length);
index += skyLightArray.length; index += skyLightArray.length;
} }
} }
short additionalBitMask = 0; short additionalBitMask = 0;
for (int i = 0; i < storageArrays.length; i++) { for (int i = 0; i < storageArrays.length; i++) {
if ((chunk.getBitmask() & 1 << i) != 0 && storageArrays[i].hasBlockMSBArray()) { if ((chunk.getBitmask() & 1 << i) != 0 && storageArrays[i].hasBlockMSBArray()) {
additionalBitMask |= (short) (1 << i); additionalBitMask |= (short) (1 << i);
final byte[] blockMSBArray = storageArrays[i].getOrCreateBlockMSBArray().getHandle(); final byte[] blockMSBArray = storageArrays[i].getOrCreateBlockMSBArray().getHandle();
System.arraycopy(blockMSBArray, 0, output, index, blockMSBArray.length); System.arraycopy(blockMSBArray, 0, output, index, blockMSBArray.length);
index += blockMSBArray.length; index += blockMSBArray.length;
} }
} }
if (biomes) { if (biomes) {
for (int biome : chunk.getBiomeData()) { for (int biome : chunk.getBiomeData()) {
output[index++] = (byte) biome; output[index++] = (byte) biome;
} }
} }
return new Pair<>(output, additionalBitMask); return new Pair<>(output, additionalBitMask);
} }
private static int calculateSize(final ExtendedBlockStorage[] storageArrays, final int bitmask, final boolean biomes) { private static int calculateSize(final ExtendedBlockStorage[] storageArrays, final int bitmask, final boolean biomes) {
int totalSize = 0; int totalSize = 0;
@@ -176,4 +140,41 @@ public class ChunkType1_7_6 extends Type<Chunk> {
return totalSize; return totalSize;
} }
@Override
public Chunk read(ByteBuf byteBuf) {
throw new UnsupportedOperationException(); // Not needed, see https://github.com/ViaVersion/ViaLegacy/blob/main/src/main/java/net/raphimc/vialegacy/protocols/release/protocol1_8to1_7_6_10/types/Chunk1_7_6Type.java
}
@Override
public void write(ByteBuf output, Chunk chunk) {
Pair<byte[], Short> chunkData;
try {
chunkData = serialize(chunk);
} catch (IOException e) {
throw new RuntimeException("Unable to serialize chunk", e);
}
final byte[] data = chunkData.key();
final short additionalBitMask = chunkData.value();
final Deflater deflater = new Deflater();
byte[] compressedData;
int compressedSize;
try {
deflater.setInput(data, 0, data.length);
deflater.finish();
compressedData = new byte[data.length];
compressedSize = deflater.deflate(compressedData);
} finally {
deflater.end();
}
output.writeInt(chunk.getX());
output.writeInt(chunk.getZ());
output.writeBoolean(chunk.isFullChunk());
output.writeShort(chunk.getBitmask());
output.writeShort(additionalBitMask);
output.writeInt(compressedSize);
output.writeBytes(compressedData, 0, compressedSize);
}
} }
@@ -22,41 +22,40 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListTypeTemplate; import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListTypeTemplate;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class EntityDataListType extends EntityDataListTypeTemplate { public class EntityDataListType extends EntityDataListTypeTemplate {
private final Type<EntityData> type; private final Type<EntityData> type;
public EntityDataListType(Type<EntityData> type) { public EntityDataListType(Type<EntityData> type) {
this.type = type; this.type = type;
} }
@Override @Override
public List<EntityData> read(ByteBuf buffer) { public List<EntityData> read(ByteBuf buffer) {
ArrayList<EntityData> entityData = new ArrayList<>(); ArrayList<EntityData> entityData = new ArrayList<>();
EntityData data; EntityData data;
do { do {
data = type.read(buffer); data = type.read(buffer);
if (data != null) { if (data != null) {
entityData.add(data); entityData.add(data);
} }
} while (data != null); } while (data != null);
return entityData; return entityData;
} }
@Override @Override
public void write(ByteBuf buffer, List<EntityData> entityData) { public void write(ByteBuf buffer, List<EntityData> entityData) {
for (EntityData meta : entityData) { for (EntityData meta : entityData) {
type.write(buffer, meta); type.write(buffer, meta);
} }
if (entityData.isEmpty()) { if (entityData.isEmpty()) {
type.write(buffer, new EntityData(0, EntityDataTypes1_7_6_10.BYTE, (byte) 0)); type.write(buffer, new EntityData(0, EntityDataTypes1_7_6_10.BYTE, (byte) 0));
} }
buffer.writeByte(127); buffer.writeByte(127);
} }
} }
@@ -23,23 +23,23 @@ import com.viaversion.viaversion.api.type.types.entitydata.EntityDataTypeTemplat
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
public class EntityDataType extends EntityDataTypeTemplate { public class EntityDataType extends EntityDataTypeTemplate {
@Override @Override
public EntityData read(ByteBuf buffer) { public EntityData read(ByteBuf buffer) {
byte item = buffer.readByte(); byte item = buffer.readByte();
if (item == 127) { if (item == 127) {
return null; return null;
} else { } else {
int typeID = (item & 224) >> 5; int typeID = (item & 224) >> 5;
EntityDataTypes1_7_6_10 type = EntityDataTypes1_7_6_10.byId(typeID); EntityDataTypes1_7_6_10 type = EntityDataTypes1_7_6_10.byId(typeID);
int id = item & 31; int id = item & 31;
return new EntityData(id, type, type.type().read(buffer)); return new EntityData(id, type, type.type().read(buffer));
} }
} }
@Override @Override
public void write(ByteBuf buffer, EntityData meta) { public void write(ByteBuf buffer, EntityData meta) {
int item = (meta.dataType().typeId() << 5 | meta.id() & 31) & 255; int item = (meta.dataType().typeId() << 5 | meta.id() & 31) & 255;
buffer.writeByte(item); buffer.writeByte(item);
meta.dataType().type().write(buffer, meta.getValue()); meta.dataType().type().write(buffer, meta.getValue());
} }
} }
@@ -25,26 +25,26 @@ import io.netty.buffer.ByteBuf;
public class ItemArrayType extends Type<Item[]> { public class ItemArrayType extends Type<Item[]> {
public ItemArrayType() { public ItemArrayType() {
super(Item[].class); super(Item[].class);
} }
@Override @Override
public Item[] read(ByteBuf buffer) { public Item[] read(ByteBuf buffer) {
int amount = Types.SHORT.readPrimitive(buffer); int amount = Types.SHORT.readPrimitive(buffer);
Item[] items = new Item[amount]; Item[] items = new Item[amount];
for (int i = 0; i < amount; ++i) { for (int i = 0; i < amount; ++i) {
items[i] = RewindTypes.COMPRESSED_NBT_ITEM.read(buffer); items[i] = RewindTypes.COMPRESSED_NBT_ITEM.read(buffer);
} }
return items; return items;
} }
@Override @Override
public void write(ByteBuf buffer, Item[] items) { public void write(ByteBuf buffer, Item[] items) {
Types.SHORT.writePrimitive(buffer, (short) items.length); Types.SHORT.writePrimitive(buffer, (short) items.length);
for (Item item : items) { for (Item item : items) {
RewindTypes.COMPRESSED_NBT_ITEM.write(buffer, item); RewindTypes.COMPRESSED_NBT_ITEM.write(buffer, item);
} }
} }
} }
@@ -25,33 +25,33 @@ import io.netty.buffer.ByteBuf;
public class ItemType extends Type<Item> { public class ItemType extends Type<Item> {
public ItemType() { public ItemType() {
super(Item.class); super(Item.class);
} }
@Override @Override
public Item read(ByteBuf buffer) { public Item read(ByteBuf buffer) {
short id = buffer.readShort(); short id = buffer.readShort();
if (id < 0) { if (id < 0) {
return null; return null;
} }
Item item = new DataItem(); Item item = new DataItem();
item.setIdentifier(id); item.setIdentifier(id);
item.setAmount(buffer.readByte()); item.setAmount(buffer.readByte());
item.setData(buffer.readShort()); item.setData(buffer.readShort());
item.setTag(RewindTypes.COMPRESSED_NBT.read(buffer)); item.setTag(RewindTypes.COMPRESSED_NBT.read(buffer));
return item; return item;
} }
@Override @Override
public void write(ByteBuf buffer, Item item) { public void write(ByteBuf buffer, Item item) {
if (item == null) { if (item == null) {
buffer.writeShort(-1); buffer.writeShort(-1);
} else { } else {
buffer.writeShort(item.identifier()); buffer.writeShort(item.identifier());
buffer.writeByte(item.amount()); buffer.writeByte(item.amount());
buffer.writeShort(item.data()); buffer.writeShort(item.data());
RewindTypes.COMPRESSED_NBT.write(buffer, item.tag()); RewindTypes.COMPRESSED_NBT.write(buffer, item.tag());
} }
} }
} }
@@ -17,57 +17,56 @@
*/ */
package com.viaversion.viarewind.api.type.item; package com.viaversion.viarewind.api.type.item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.io.NBTIO; import com.viaversion.nbt.io.NBTIO;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.ByteBufOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
public class NBTType extends Type<CompoundTag> { public class NBTType extends Type<CompoundTag> {
public NBTType() { public NBTType() {
super(CompoundTag.class); super(CompoundTag.class);
} }
@Override @Override
public CompoundTag read(ByteBuf buffer) { public CompoundTag read(ByteBuf buffer) {
short length = buffer.readShort(); short length = buffer.readShort();
if (length <= 0) { if (length <= 0) {
return null; return null;
} }
ByteBuf compressed = buffer.readSlice(length); ByteBuf compressed = buffer.readSlice(length);
try (GZIPInputStream gzipStream = new GZIPInputStream(new ByteBufInputStream(compressed))) { try (GZIPInputStream gzipStream = new GZIPInputStream(new ByteBufInputStream(compressed))) {
return NBTIO.reader(CompoundTag.class).named().read(gzipStream); return NBTIO.reader(CompoundTag.class).named().read(gzipStream);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@Override @Override
public void write(ByteBuf buffer, CompoundTag nbt) { public void write(ByteBuf buffer, CompoundTag nbt) {
if (nbt == null) { if (nbt == null) {
buffer.writeShort(-1); buffer.writeShort(-1);
return; return;
} }
ByteBuf compressedBuf = buffer.alloc().buffer(); ByteBuf compressedBuf = buffer.alloc().buffer();
try { try {
try (GZIPOutputStream gzipStream = new GZIPOutputStream(new ByteBufOutputStream(compressedBuf))) { try (GZIPOutputStream gzipStream = new GZIPOutputStream(new ByteBufOutputStream(compressedBuf))) {
NBTIO.writer().named().write(gzipStream, nbt); NBTIO.writer().named().write(gzipStream, nbt);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
buffer.writeShort(compressedBuf.readableBytes()); buffer.writeShort(compressedBuf.readableBytes());
buffer.writeBytes(compressedBuf); buffer.writeBytes(compressedBuf);
} finally { } finally {
compressedBuf.release(); compressedBuf.release();
} }
} }
} }
@@ -27,90 +27,89 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer; import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets; import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
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 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<>(Types.STRING) { public static final ValueTransformer<String, String> REMOVE_DASHES = new ValueTransformer<>(Types.STRING) {
@Override @Override
public String transform(PacketWrapper wrapper, String s) { public String transform(PacketWrapper wrapper, String s) {
return s.replace("-", ""); return s.replace("-", "");
} }
}; };
public Protocol1_7_6_10To1_7_2_5() { 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); super(ClientboundPackets1_7_2_5.class, ClientboundPackets1_7_2_5.class, ServerboundPackets1_7_2_5.class, ServerboundPackets1_7_2_5.class);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
this.registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, new PacketHandlers() { this.registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING, REMOVE_DASHES); // Uuid map(Types.STRING, REMOVE_DASHES); // Uuid
map(Types.STRING); // Name map(Types.STRING); // Name
} }
}); });
this.registerClientbound(ClientboundPackets1_7_2_5.ADD_PLAYER, new PacketHandlers() { this.registerClientbound(ClientboundPackets1_7_2_5.ADD_PLAYER, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.VAR_INT); // Entity id map(Types.VAR_INT); // Entity id
map(Types.STRING, REMOVE_DASHES); // Uuid map(Types.STRING, REMOVE_DASHES); // Uuid
map(Types.STRING); // Name map(Types.STRING); // Name
handler(wrapper -> { handler(wrapper -> {
final int size = wrapper.read(Types.VAR_INT); // Data count final int size = wrapper.read(Types.VAR_INT); // Data count
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
wrapper.read(Types.STRING); // Data name wrapper.read(Types.STRING); // Data name
wrapper.read(Types.STRING); // Data value wrapper.read(Types.STRING); // Data value
wrapper.read(Types.STRING); // Data signature wrapper.read(Types.STRING); // Data signature
} }
}); });
map(Types.INT); // X map(Types.INT); // X
map(Types.INT); // Y map(Types.INT); // Y
map(Types.INT); // Z map(Types.INT); // Z
map(Types.BYTE); // Yaw map(Types.BYTE); // Yaw
map(Types.BYTE); // Pitch map(Types.BYTE); // Pitch
map(Types.SHORT); // Item in hand map(Types.SHORT); // Item in hand
map(RewindTypes.ENTITY_DATA_LIST1_7); // Entity data map(RewindTypes.ENTITY_DATA_LIST1_7); // Entity data
} }
}); });
this.registerClientbound(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, new PacketHandlers() { this.registerClientbound(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Team name map(Types.STRING); // Team name
map(Types.BYTE); // Mode map(Types.BYTE); // Mode
handler(wrapper -> { handler(wrapper -> {
final byte mode = wrapper.get(Types.BYTE, 0); final byte mode = wrapper.get(Types.BYTE, 0);
if (mode == 0 || mode == 2) { // Team is created or information is updated if (mode == 0 || mode == 2) { // Team is created or information is updated
wrapper.passthrough(Types.STRING); // Team display name wrapper.passthrough(Types.STRING); // Team display name
wrapper.passthrough(Types.STRING); // Team prefix wrapper.passthrough(Types.STRING); // Team prefix
wrapper.passthrough(Types.STRING); // Team suffix wrapper.passthrough(Types.STRING); // Team suffix
wrapper.passthrough(Types.BYTE); // Friendly fire wrapper.passthrough(Types.BYTE); // Friendly fire
} }
if (mode == 0 || mode == 3 || mode == 4) { // Team is created, player is added or player is removed if (mode == 0 || mode == 3 || mode == 4) { // Team is created, player is added or player is removed
List<String> entryList = new ArrayList<>(); List<String> entryList = new ArrayList<>();
final int size = wrapper.read(Types.SHORT); final int size = wrapper.read(Types.SHORT);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
entryList.add(wrapper.read(Types.STRING)); entryList.add(wrapper.read(Types.STRING));
} }
entryList = entryList.stream() entryList = entryList.stream()
.map(it -> it.length() > 16 ? it.substring(0, 16) : it) // trim to 16 characters .map(it -> it.length() > 16 ? it.substring(0, 16) : it) // trim to 16 characters
.distinct() // remove duplicates .distinct() // remove duplicates
.collect(Collectors.toList()); .collect(Collectors.toList());
wrapper.write(Types.SHORT, (short) entryList.size()); wrapper.write(Types.SHORT, (short) entryList.size());
for (String entry : entryList) { for (String entry : entryList) {
wrapper.write(Types.STRING, entry); wrapper.write(Types.STRING, entry);
} }
} }
}); });
} }
}); });
} }
} }
@@ -20,79 +20,79 @@ package com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
public enum ClientboundPackets1_7_2_5 implements ClientboundPacketType { public enum ClientboundPackets1_7_2_5 implements ClientboundPacketType {
KEEP_ALIVE, // 0x00 KEEP_ALIVE, // 0x00
LOGIN, // 0x01 LOGIN, // 0x01
CHAT, // 0x02 CHAT, // 0x02
SET_TIME, // 0x03 SET_TIME, // 0x03
SET_EQUIPPED_ITEM, // 0x04 SET_EQUIPPED_ITEM, // 0x04
SET_DEFAULT_SPAWN_POSITION, // 0x05 SET_DEFAULT_SPAWN_POSITION, // 0x05
SET_HEALTH, // 0x06 SET_HEALTH, // 0x06
RESPAWN, // 0x07 RESPAWN, // 0x07
PLAYER_POSITION, // 0x08 PLAYER_POSITION, // 0x08
SET_CARRIED_ITEM, // 0x09 SET_CARRIED_ITEM, // 0x09
PLAYER_SLEEP, // 0x0A PLAYER_SLEEP, // 0x0A
ANIMATE, // 0x0B ANIMATE, // 0x0B
ADD_PLAYER, // 0x0C ADD_PLAYER, // 0x0C
TAKE_ITEM_ENTITY, // 0x0D TAKE_ITEM_ENTITY, // 0x0D
ADD_ENTITY, // 0x0E ADD_ENTITY, // 0x0E
ADD_MOB, // 0x0F ADD_MOB, // 0x0F
ADD_PAINTING, // 0x10 ADD_PAINTING, // 0x10
ADD_EXPERIENCE_ORB, // 0x11 ADD_EXPERIENCE_ORB, // 0x11
SET_ENTITY_MOTION, // 0x12 SET_ENTITY_MOTION, // 0x12
REMOVE_ENTITIES, // 0x13 REMOVE_ENTITIES, // 0x13
MOVE_ENTITY, // 0x14 MOVE_ENTITY, // 0x14
MOVE_ENTITY_POS, // 0x15 MOVE_ENTITY_POS, // 0x15
MOVE_ENTITY_ROT, // 0x16 MOVE_ENTITY_ROT, // 0x16
MOVE_ENTITY_POS_ROT, // 0x17 MOVE_ENTITY_POS_ROT, // 0x17
TELEPORT_ENTITY, // 0x18 TELEPORT_ENTITY, // 0x18
ROTATE_HEAD, // 0x19 ROTATE_HEAD, // 0x19
ENTITY_EVENT, // 0x1A ENTITY_EVENT, // 0x1A
SET_ENTITY_LINK, // 0x1B SET_ENTITY_LINK, // 0x1B
SET_ENTITY_DATA, // 0x1C SET_ENTITY_DATA, // 0x1C
UPDATE_MOB_EFFECT, // 0x1D UPDATE_MOB_EFFECT, // 0x1D
REMOVE_MOB_EFFECT, // 0x1E REMOVE_MOB_EFFECT, // 0x1E
SET_EXPERIENCE, // 0x1F SET_EXPERIENCE, // 0x1F
UPDATE_ATTRIBUTES, // 0x20 UPDATE_ATTRIBUTES, // 0x20
LEVEL_CHUNK, // 0x21 LEVEL_CHUNK, // 0x21
CHUNK_BLOCKS_UPDATE, // 0x22 CHUNK_BLOCKS_UPDATE, // 0x22
BLOCK_UPDATE, // 0x23 BLOCK_UPDATE, // 0x23
BLOCK_EVENT, // 0x24 BLOCK_EVENT, // 0x24
BLOCK_DESTRUCTION, // 0x25 BLOCK_DESTRUCTION, // 0x25
MAP_BULK_CHUNK, // 0x26 MAP_BULK_CHUNK, // 0x26
EXPLODE, // 0x27 EXPLODE, // 0x27
LEVEL_EVENT, // 0x28 LEVEL_EVENT, // 0x28
CUSTOM_SOUND, // 0x29 CUSTOM_SOUND, // 0x29
LEVEL_PARTICLES, // 0x2A LEVEL_PARTICLES, // 0x2A
GAME_EVENT, // 0x2B GAME_EVENT, // 0x2B
ADD_GLOBAL_ENTITY, // 0x2C ADD_GLOBAL_ENTITY, // 0x2C
OPEN_SCREEN, // 0x2D OPEN_SCREEN, // 0x2D
CONTAINER_CLOSE, // 0x2E CONTAINER_CLOSE, // 0x2E
CONTAINER_SET_SLOT, // 0x2F CONTAINER_SET_SLOT, // 0x2F
CONTAINER_SET_CONTENT, // 0x30 CONTAINER_SET_CONTENT, // 0x30
CONTAINER_SET_DATA, // 0x31 CONTAINER_SET_DATA, // 0x31
CONTAINER_ACK, // 0x32 CONTAINER_ACK, // 0x32
UPDATE_SIGN, // 0x33 UPDATE_SIGN, // 0x33
MAP_ITEM_DATA, // 0x34 MAP_ITEM_DATA, // 0x34
BLOCK_ENTITY_DATA, // 0x35 BLOCK_ENTITY_DATA, // 0x35
OPEN_SIGN_EDITOR, // 0x36 OPEN_SIGN_EDITOR, // 0x36
AWARD_STATS, // 0x37 AWARD_STATS, // 0x37
PLAYER_INFO, // 0x38 PLAYER_INFO, // 0x38
PLAYER_ABILITIES, // 0x39 PLAYER_ABILITIES, // 0x39
COMMAND_SUGGESTIONS, // 0x3A COMMAND_SUGGESTIONS, // 0x3A
SET_OBJECTIVE, // 0x3B SET_OBJECTIVE, // 0x3B
SET_SCORE, // 0x3C SET_SCORE, // 0x3C
SET_DISPLAY_OBJECTIVE, // 0x3D SET_DISPLAY_OBJECTIVE, // 0x3D
SET_PLAYER_TEAM, // 0x3E SET_PLAYER_TEAM, // 0x3E
CUSTOM_PAYLOAD, // 0x3F CUSTOM_PAYLOAD, // 0x3F
DISCONNECT; // 0x40 DISCONNECT; // 0x40
@Override @Override
public int getId() { public int getId() {
return ordinal(); return ordinal();
} }
@Override @Override
public String getName() { public String getName() {
return name(); return name();
} }
} }
@@ -20,38 +20,38 @@ package com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
public enum ServerboundPackets1_7_2_5 implements ServerboundPacketType { public enum ServerboundPackets1_7_2_5 implements ServerboundPacketType {
KEEP_ALIVE, // 0x00 KEEP_ALIVE, // 0x00
CHAT, // 0x01 CHAT, // 0x01
INTERACT, // 0x02 INTERACT, // 0x02
MOVE_PLAYER_STATUS_ONLY, // 0x03 MOVE_PLAYER_STATUS_ONLY, // 0x03
MOVE_PLAYER_POS, // 0x04 MOVE_PLAYER_POS, // 0x04
MOVE_PLAYER_ROT, // 0x05 MOVE_PLAYER_ROT, // 0x05
MOVE_PLAYER_POS_ROT, // 0x06 MOVE_PLAYER_POS_ROT, // 0x06
PLAYER_ACTION, // 0x07 PLAYER_ACTION, // 0x07
USE_ITEM_ON, // 0x08 USE_ITEM_ON, // 0x08
SET_CARRIED_ITEM, // 0x09 SET_CARRIED_ITEM, // 0x09
SWING, // 0x0A SWING, // 0x0A
PLAYER_COMMAND, // 0x0B PLAYER_COMMAND, // 0x0B
PLAYER_INPUT, // 0x0C PLAYER_INPUT, // 0x0C
CONTAINER_CLOSE, // 0x0D CONTAINER_CLOSE, // 0x0D
CONTAINER_CLICK, // 0x0E CONTAINER_CLICK, // 0x0E
CONTAINER_ACK, // 0x0F CONTAINER_ACK, // 0x0F
SET_CREATIVE_MODE_SLOT, // 0x10 SET_CREATIVE_MODE_SLOT, // 0x10
CONTAINER_BUTTON_CLICK, // 0x11 CONTAINER_BUTTON_CLICK, // 0x11
SIGN_UPDATE, // 0x12 SIGN_UPDATE, // 0x12
PLAYER_ABILITIES, // 0x13 PLAYER_ABILITIES, // 0x13
COMMAND_SUGGESTION, // 0x14 COMMAND_SUGGESTION, // 0x14
CLIENT_INFORMATION, // 0x15 CLIENT_INFORMATION, // 0x15
CLIENT_COMMAND, // 0x16 CLIENT_COMMAND, // 0x16
CUSTOM_PAYLOAD; // 0x17 CUSTOM_PAYLOAD; // 0x17
@Override @Override
public int getId() { public int getId() {
return ordinal(); return ordinal();
} }
@Override @Override
public String getName() { public String getName() {
return name(); return name();
} }
} }
@@ -22,11 +22,20 @@ import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.api.data.RewindMappingData; 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.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_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.CompressionHandlerProvider;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.compression.TrackingCompressionHandlerProvider; 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.rewriter.BlockItemPacketRewriter1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter.EntityPacketRewriter1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter.PlayerPacketRewriter1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter.ScoreboardPacketRewriter1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter.WorldPacketRewriter1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.CompressionStatusTracker;
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.protocol.v1_8to1_7_6_10.storage.ScoreboardTracker;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.WorldBorderEmulator;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.task.WorldBorderUpdateTask; import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.task.WorldBorderUpdateTask;
import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
@@ -42,118 +51,117 @@ import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets; import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; 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.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class Protocol1_8To1_7_6_10 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 RewindMappingData MAPPINGS = new RewindMappingData("1.8", "1.7.10"); public static final RewindMappingData MAPPINGS = new RewindMappingData("1.8", "1.7.10");
private final BlockItemPacketRewriter1_8 itemRewriter = new BlockItemPacketRewriter1_8(this); private final BlockItemPacketRewriter1_8 itemRewriter = new BlockItemPacketRewriter1_8(this);
private final EntityPacketRewriter1_8 entityRewriter = new EntityPacketRewriter1_8(this); private final EntityPacketRewriter1_8 entityRewriter = new EntityPacketRewriter1_8(this);
public Protocol1_8To1_7_6_10() { public Protocol1_8To1_7_6_10() {
super(ClientboundPackets1_8.class, ClientboundPackets1_7_2_5.class, ServerboundPackets1_8.class, ServerboundPackets1_7_2_5.class); super(ClientboundPackets1_8.class, ClientboundPackets1_7_2_5.class, ServerboundPackets1_8.class, ServerboundPackets1_7_2_5.class);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
itemRewriter.register(); itemRewriter.register();
entityRewriter.register(); entityRewriter.register();
new PlayerPacketRewriter1_8(this).register(); new PlayerPacketRewriter1_8(this).register();
new ScoreboardPacketRewriter1_8(this).register(); new ScoreboardPacketRewriter1_8(this).register();
new WorldPacketRewriter1_8(this).register(); new WorldPacketRewriter1_8(this).register();
this.registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, new PacketHandlers() { this.registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // server hash 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); // public key
map(Types.BYTE_ARRAY_PRIMITIVE, Types.SHORT_BYTE_ARRAY); // verification token map(Types.BYTE_ARRAY_PRIMITIVE, Types.SHORT_BYTE_ARRAY); // verification token
} }
}); });
this.registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_COMPRESSION, new PacketHandlers() { this.registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_COMPRESSION, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
handler(wrapper -> { handler(wrapper -> {
final int threshold = wrapper.read(Types.VAR_INT); final int threshold = wrapper.read(Types.VAR_INT);
Via.getManager().getProviders().get(CompressionHandlerProvider.class).onHandleLoginCompressionPacket(wrapper.user(), threshold); Via.getManager().getProviders().get(CompressionHandlerProvider.class).onHandleLoginCompressionPacket(wrapper.user(), threshold);
wrapper.cancel(); wrapper.cancel();
}); });
} }
}); });
this.cancelClientbound(ClientboundPackets1_8.SET_COMPRESSION); // unused this.cancelClientbound(ClientboundPackets1_8.SET_COMPRESSION); // unused
this.registerClientbound(ClientboundPackets1_8.KEEP_ALIVE, new PacketHandlers() { this.registerClientbound(ClientboundPackets1_8.KEEP_ALIVE, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.VAR_INT, Types.INT); // id map(Types.VAR_INT, Types.INT); // id
} }
}); });
this.registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY, new PacketHandlers() { this.registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.SHORT_BYTE_ARRAY, Types.BYTE_ARRAY_PRIMITIVE); // shared secret map(Types.SHORT_BYTE_ARRAY, Types.BYTE_ARRAY_PRIMITIVE); // shared secret
map(Types.SHORT_BYTE_ARRAY, Types.BYTE_ARRAY_PRIMITIVE); // verification token map(Types.SHORT_BYTE_ARRAY, Types.BYTE_ARRAY_PRIMITIVE); // verification token
} }
}); });
this.registerServerbound(ServerboundPackets1_7_2_5.KEEP_ALIVE, new PacketHandlers() { this.registerServerbound(ServerboundPackets1_7_2_5.KEEP_ALIVE, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.INT, Types.VAR_INT); // id map(Types.INT, Types.VAR_INT); // id
} }
}); });
} }
@Override @Override
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws CancelException { public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws CancelException {
Via.getManager().getProviders().get(CompressionHandlerProvider.class).onTransformPacket(packetWrapper.user()); Via.getManager().getProviders().get(CompressionHandlerProvider.class).onTransformPacket(packetWrapper.user());
super.transform(direction, state, packetWrapper); super.transform(direction, state, packetWrapper);
} }
@Override @Override
public void init(UserConnection connection) { public void init(UserConnection connection) {
connection.addEntityTracker(this.getClass(), new EntityTracker1_8(connection)); connection.addEntityTracker(this.getClass(), new EntityTracker1_8(connection));
connection.addClientWorld(this.getClass(), new ClientWorld()); connection.addClientWorld(this.getClass(), new ClientWorld());
connection.put(new InventoryTracker(connection)); connection.put(new InventoryTracker(connection));
connection.put(new PlayerSessionStorage(connection)); connection.put(new PlayerSessionStorage(connection));
connection.put(new GameProfileStorage(connection)); connection.put(new GameProfileStorage(connection));
connection.put(new ScoreboardTracker(connection)); connection.put(new ScoreboardTracker(connection));
connection.put(new CompressionStatusTracker(connection)); connection.put(new CompressionStatusTracker(connection));
connection.put(new WorldBorderEmulator(connection)); connection.put(new WorldBorderEmulator(connection));
} }
@Override @Override
public void register(ViaProviders providers) { public void register(ViaProviders providers) {
providers.register(CompressionHandlerProvider.class, new TrackingCompressionHandlerProvider()); providers.register(CompressionHandlerProvider.class, new TrackingCompressionHandlerProvider());
if (ViaRewind.getConfig().isEmulateWorldBorder()) { if (ViaRewind.getConfig().isEmulateWorldBorder()) {
Via.getManager().getScheduler().scheduleRepeating(new WorldBorderUpdateTask(), 0L, 50L, TimeUnit.MILLISECONDS); Via.getManager().getScheduler().scheduleRepeating(new WorldBorderUpdateTask(), 0L, 50L, TimeUnit.MILLISECONDS);
} }
} }
@Override @Override
public RewindMappingData getMappingData() { public RewindMappingData getMappingData() {
return MAPPINGS; return MAPPINGS;
} }
@Override @Override
public BlockItemPacketRewriter1_8 getItemRewriter() { public BlockItemPacketRewriter1_8 getItemRewriter() {
return itemRewriter; return itemRewriter;
} }
@Override @Override
public EntityPacketRewriter1_8 getEntityRewriter() { public EntityPacketRewriter1_8 getEntityRewriter() {
return entityRewriter; return entityRewriter;
} }
@Override @Override
public boolean hasMappingDataToLoad() { public boolean hasMappingDataToLoad() {
return true; return true;
} }
} }
@@ -22,194 +22,226 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8; import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.util.Pair; import com.viaversion.viaversion.util.Pair;
import java.util.HashMap; import java.util.HashMap;
import java.util.Optional; import java.util.Optional;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.*; import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ABSTRACT_AGEABLE;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ABSTRACT_MINECART;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ARMOR_STAND;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ARROW;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.BAT;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.BLAZE;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.BOAT;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.CREEPER;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ENDERMAN;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.END_CRYSTAL;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ENTITY;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.FIREWORK_ROCKET;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.FURNACE_MINECART;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.GHAST;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.GUARDIAN;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.HORSE;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.IRON_GOLEM;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ITEM;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ITEM_FRAME;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.LIVING_ENTITY;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.LIVING_ENTITY_BASE;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.OCELOT;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.PIG;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.PLAYER;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.SHEEP;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.SKELETON;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.SLIME;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.SPIDER;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.TAMABLE_ANIMAL;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.VILLAGER;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.WITCH;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.WITHER;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.WOLF;
import static com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_8.EntityType.ZOMBIE;
public enum EntityDataIndex1_7_6_10 { public enum EntityDataIndex1_7_6_10 {
ENTITY_FLAGS(ENTITY, 0, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE), 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_AIR(ENTITY, 1, EntityDataTypes1_7_6_10.SHORT, EntityDataTypes1_8.SHORT),
ENTITY_NAME_TAG(ENTITY, -1, null, 2, EntityDataTypes1_8.STRING), ENTITY_NAME_TAG(ENTITY, -1, null, 2, EntityDataTypes1_8.STRING),
ENTITY_NAME_TAG_VISIBILITY(ENTITY, -1, null, 3, EntityDataTypes1_8.BYTE), ENTITY_NAME_TAG_VISIBILITY(ENTITY, -1, null, 3, EntityDataTypes1_8.BYTE),
ENTITY_SILENT(ENTITY, -1, null, 4, 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_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_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_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_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(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_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), 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), 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_FLAGS(ARMOR_STAND, -1, null, 10, EntityDataTypes1_8.BYTE),
ARMOR_STAND_HEAD_POSITION(ARMOR_STAND, -1, null, 11, EntityDataTypes1_8.ROTATIONS), 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_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_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_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_LEFT_LEG_POSITION(ARMOR_STAND, -1, null, 15, EntityDataTypes1_8.ROTATIONS),
ARMOR_STAND_RIGHT_LEG_POSITION(ARMOR_STAND, -1, null, 16, 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_SKIN_FLAGS(PLAYER, 16, EntityDataTypes1_7_6_10.BYTE, 10, EntityDataTypes1_8.BYTE),
PLAYER_UNUSED(PLAYER, -1, null, 16, 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_ABSORPTION_HEATS(PLAYER, 17, EntityDataTypes1_7_6_10.FLOAT, EntityDataTypes1_8.FLOAT),
PLAYER_SCORE(PLAYER, 18, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT), 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_FLAGS(HORSE, 16, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
HORSE_TYPE(HORSE, 19, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE), 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_COLOR(HORSE, 20, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
HORSE_OWNER(HORSE, 21, EntityDataTypes1_7_6_10.STRING, EntityDataTypes1_8.STRING), HORSE_OWNER(HORSE, 21, EntityDataTypes1_7_6_10.STRING, EntityDataTypes1_8.STRING),
HORSE_ARMOR(HORSE, 22, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT), HORSE_ARMOR(HORSE, 22, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
BAT_HANGING(BAT, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE), 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_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), 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), 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_FLAGS(WOLF, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
WOLF_HEALTH(WOLF, 18, EntityDataTypes1_7_6_10.FLOAT, EntityDataTypes1_8.FLOAT), 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_BEGGING(WOLF, 19, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
WOLF_COLLAR_COLOR(WOLF, 20, 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), 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), 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), VILLAGER_TYPE(VILLAGER, 16, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
ENDERMAN_CARRIED_BLOCK(ENDERMAN, 16, null, EntityDataTypes1_8.SHORT), ENDERMAN_CARRIED_BLOCK(ENDERMAN, 16, null, EntityDataTypes1_8.SHORT),
ENDERMAN_CARRIED_BLOCK_DATA(ENDERMAN, 17, null, EntityDataTypes1_8.BYTE), ENDERMAN_CARRIED_BLOCK_DATA(ENDERMAN, 17, null, EntityDataTypes1_8.BYTE),
ENDERMAN_IS_SCREAMING(ENDERMAN, 18, EntityDataTypes1_7_6_10.BYTE, 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_CHILD(ZOMBIE, 12, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
ZOMBIE_VILLAGER(ZOMBIE, 13, 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), 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), 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), 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_STATE(CREEPER, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
CREEPER_POWERED(CREEPER, 17, 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), 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_STATE(GHAST, 16, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
GHAST_IS_POWERED(GHAST, 17, null, EntityDataTypes1_8.BYTE), GHAST_IS_POWERED(GHAST, 17, null, EntityDataTypes1_8.BYTE),
SLIME_SIZE(SLIME, 16, EntityDataTypes1_7_6_10.BYTE, 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), SKELETON_TYPE(SKELETON, 13, EntityDataTypes1_7_6_10.BYTE, EntityDataTypes1_8.BYTE),
WITCH_AGGRESSIVE(WITCH, 21, 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), 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_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_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_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), WITHER_INVULNERABLE_TIME(WITHER, 20, EntityDataTypes1_7_6_10.INT, EntityDataTypes1_8.INT),
GUARDIAN_FLAGS(GUARDIAN, 16, null, EntityDataTypes1_8.BYTE), GUARDIAN_FLAGS(GUARDIAN, 16, null, EntityDataTypes1_8.BYTE),
GUARDIAN_TARGET(GUARDIAN, 17, null, EntityDataTypes1_8.INT), GUARDIAN_TARGET(GUARDIAN, 17, null, EntityDataTypes1_8.INT),
BOAT_TIME_SINCE_HIT(BOAT, 17, EntityDataTypes1_7_6_10.INT, 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_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), 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_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_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_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_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_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), 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), 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), 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), 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), 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_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), 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); 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<>(); private static final HashMap<Pair<EntityTypes1_8.EntityType, Integer>, EntityDataIndex1_7_6_10> ENTITY_DATA_REWRITES = new HashMap<>();
static { static {
for (EntityDataIndex1_7_6_10 index : EntityDataIndex1_7_6_10.values()) { for (EntityDataIndex1_7_6_10 index : EntityDataIndex1_7_6_10.values()) {
ENTITY_DATA_REWRITES.put(new Pair<>(index.getClazz(), index.getNewIndex()), index); ENTITY_DATA_REWRITES.put(new Pair<>(index.getClazz(), index.getNewIndex()), index);
} }
} }
private final EntityTypes1_8.EntityType clazz; private final EntityTypes1_8.EntityType clazz;
private final int newIndex; private final int newIndex;
private final EntityDataTypes1_8 newType; private final EntityDataTypes1_8 newType;
private final EntityDataTypes1_7_6_10 oldType; private final EntityDataTypes1_7_6_10 oldType;
private final int index; private final int index;
EntityDataIndex1_7_6_10(EntityTypes1_8.EntityType type, int index, EntityDataTypes1_7_6_10 oldType, EntityDataTypes1_8 newType) { EntityDataIndex1_7_6_10(EntityTypes1_8.EntityType type, int index, EntityDataTypes1_7_6_10 oldType, EntityDataTypes1_8 newType) {
this.clazz = type; this.clazz = type;
this.index = index; this.index = index;
this.newIndex = index; this.newIndex = index;
this.oldType = oldType; this.oldType = oldType;
this.newType = newType; this.newType = newType;
} }
EntityDataIndex1_7_6_10(EntityTypes1_8.EntityType type, int index, EntityDataTypes1_7_6_10 oldType, int newIndex, EntityDataTypes1_8 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.clazz = type;
this.index = index; this.index = index;
this.oldType = oldType; this.oldType = oldType;
this.newIndex = newIndex; this.newIndex = newIndex;
this.newType = newType; this.newType = newType;
} }
private static Optional<EntityDataIndex1_7_6_10> getIndex(EntityType type, int index) { private static Optional<EntityDataIndex1_7_6_10> getIndex(EntityType type, int index) {
final Pair<EntityType, Integer> pair = new Pair<>(type, index); final Pair<EntityType, Integer> pair = new Pair<>(type, index);
return Optional.ofNullable(ENTITY_DATA_REWRITES.get(pair)); return Optional.ofNullable(ENTITY_DATA_REWRITES.get(pair));
} }
public EntityTypes1_8.EntityType getClazz() { public static EntityDataIndex1_7_6_10 searchIndex(EntityType type, int index) {
return clazz; EntityType currentType = type;
} do {
Optional<EntityDataIndex1_7_6_10> optMeta = getIndex(currentType, index);
public int getNewIndex() { if (optMeta.isPresent()) {
return newIndex; return optMeta.get();
} }
public EntityDataTypes1_8 getNewType() { currentType = currentType.getParent();
return newType; } while (currentType != null);
}
public EntityDataTypes1_7_6_10 getOldType() { return null;
return oldType; }
}
public int getIndex() { public EntityTypes1_8.EntityType getClazz() {
return index; return clazz;
} }
public static EntityDataIndex1_7_6_10 searchIndex(EntityType type, int index) { public int getNewIndex() {
EntityType currentType = type; return newIndex;
do { }
Optional<EntityDataIndex1_7_6_10> optMeta = getIndex(currentType, index);
if (optMeta.isPresent()) { public EntityDataTypes1_8 getNewType() {
return optMeta.get(); return newType;
} }
currentType = currentType.getParent(); public EntityDataTypes1_7_6_10 getOldType() {
} while (currentType != null); return oldType;
}
return null; public int getIndex() {
} return index;
} }
}
@@ -20,77 +20,78 @@ package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data;
import java.util.HashMap; import java.util.HashMap;
public enum Particles1_8 { public enum Particles1_8 {
EXPLOSION_NORMAL("explode"), EXPLOSION_NORMAL("explode"),
EXPLOSION_LARGE("largeexplode"), EXPLOSION_LARGE("largeexplode"),
EXPLOSION_HUGE("hugeexplosion"), EXPLOSION_HUGE("hugeexplosion"),
FIREWORKS_SPARK("fireworksSpark"), FIREWORKS_SPARK("fireworksSpark"),
WATER_BUBBLE("bubble"), WATER_BUBBLE("bubble"),
WATER_SPLASH("splash"), WATER_SPLASH("splash"),
WATER_WAKE("wake"), WATER_WAKE("wake"),
SUSPENDED("suspended"), SUSPENDED("suspended"),
SUSPENDED_DEPTH("depthsuspend"), SUSPENDED_DEPTH("depthsuspend"),
CRIT("crit"), CRIT("crit"),
CRIT_MAGIC("magicCrit"), CRIT_MAGIC("magicCrit"),
SMOKE_NORMAL("smoke"), SMOKE_NORMAL("smoke"),
SMOKE_LARGE("largesmoke"), SMOKE_LARGE("largesmoke"),
SPELL("spell"), SPELL("spell"),
SPELL_INSTANT("instantSpell"), SPELL_INSTANT("instantSpell"),
SPELL_MOB("mobSpell"), SPELL_MOB("mobSpell"),
SPELL_MOB_AMBIENT("mobSpellAmbient"), SPELL_MOB_AMBIENT("mobSpellAmbient"),
SPELL_WITCH("witchMagic"), SPELL_WITCH("witchMagic"),
DRIP_WATER("dripWater"), DRIP_WATER("dripWater"),
DRIP_LAVA("dripLava"), DRIP_LAVA("dripLava"),
VILLAGER_ANGRY("angryVillager"), VILLAGER_ANGRY("angryVillager"),
VILLAGER_HAPPY("happyVillager"), VILLAGER_HAPPY("happyVillager"),
TOWN_AURA("townaura"), TOWN_AURA("townaura"),
NOTE("note"), NOTE("note"),
PORTAL("portal"), PORTAL("portal"),
ENCHANTMENT_TABLE("enchantmenttable"), ENCHANTMENT_TABLE("enchantmenttable"),
FLAME("flame"), FLAME("flame"),
LAVA("lava"), LAVA("lava"),
FOOTSTEP("footstep"), FOOTSTEP("footstep"),
CLOUD("cloud"), CLOUD("cloud"),
REDSTONE("reddust"), REDSTONE("reddust"),
SNOWBALL("snowballpoof"), SNOWBALL("snowballpoof"),
SNOW_SHOVEL("snowshovel"), SNOW_SHOVEL("snowshovel"),
SLIME("slime"), SLIME("slime"),
HEART("heart"), HEART("heart"),
BARRIER("barrier"), BARRIER("barrier"),
ICON_CRACK("iconcrack", 2), ICON_CRACK("iconcrack", 2),
BLOCK_CRACK("blockcrack", 1), BLOCK_CRACK("blockcrack", 1),
BLOCK_DUST("blockdust", 1), BLOCK_DUST("blockdust", 1),
WATER_DROP("droplet"), WATER_DROP("droplet"),
ITEM_TAKE("take"), ITEM_TAKE("take"),
MOB_APPEARANCE("mobappearance"); MOB_APPEARANCE("mobappearance");
public final String name; private static final HashMap<String, Particles1_8> particleMap = new HashMap<>();
public final int extra;
private static final HashMap<String, Particles1_8> particleMap = new HashMap<>();
Particles1_8(String name) { static {
this(name, 0); Particles1_8[] particles = values();
}
Particles1_8(String name, int extra) { for (Particles1_8 particle : particles) {
this.name = name; particleMap.put(particle.name, particle);
this.extra = extra; }
} }
public static Particles1_8 find(String part) { public final String name;
return particleMap.get(part); public final int extra;
}
public static Particles1_8 find(int id) { Particles1_8(String name) {
if (id < 0) return null; this(name, 0);
Particles1_8[] values = Particles1_8.values(); }
return id >= values.length ? null : values[id];
}
static { Particles1_8(String name, int extra) {
Particles1_8[] particles = values(); this.name = name;
this.extra = extra;
}
for (Particles1_8 particle : particles) { public static Particles1_8 find(String part) {
particleMap.put(particle.name, particle); return particleMap.get(part);
} }
}
} public static Particles1_8 find(int id) {
if (id < 0) return null;
Particles1_8[] values = Particles1_8.values();
return id >= values.length ? null : values[id];
}
}
@@ -24,17 +24,19 @@ import io.netty.channel.ChannelHandler;
public abstract class CompressionHandlerProvider implements Provider { public abstract class CompressionHandlerProvider implements Provider {
public abstract void onHandleLoginCompressionPacket(UserConnection user, int threshold); public abstract void onHandleLoginCompressionPacket(UserConnection user, int threshold);
public abstract void onTransformPacket(UserConnection user);
public abstract ChannelHandler getEncoder(int threshold); public abstract void onTransformPacket(UserConnection user);
public abstract ChannelHandler getDecoder(int threshold);
public boolean isCompressionEnabled(UserConnection user) { public abstract ChannelHandler getEncoder(int threshold);
return user.get(CompressionStatusTracker.class).removeCompression;
}
public void setCompressionEnabled(UserConnection user, boolean enabled) { public abstract ChannelHandler getDecoder(int threshold);
user.get(CompressionStatusTracker.class).removeCompression = enabled;
} public boolean isCompressionEnabled(UserConnection user) {
return user.get(CompressionStatusTracker.class).removeCompression;
}
public void setCompressionEnabled(UserConnection user, boolean enabled) {
user.get(CompressionStatusTracker.class).removeCompression = enabled;
}
} }
@@ -18,7 +18,6 @@
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider; package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider;
import com.viaversion.viaversion.api.platform.providers.Provider; import com.viaversion.viaversion.api.platform.providers.Provider;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@@ -26,74 +25,74 @@ import java.util.concurrent.atomic.AtomicInteger;
// TODO I believe this should be a storage? // TODO I believe this should be a storage?
public abstract class TitleRenderProvider implements Provider { public abstract class TitleRenderProvider implements Provider {
protected Map<UUID, Integer> fadeIn = new HashMap<>(); protected Map<UUID, Integer> fadeIn = new HashMap<>();
protected Map<UUID, Integer> stay = new HashMap<>(); protected Map<UUID, Integer> stay = new HashMap<>();
protected Map<UUID, Integer> fadeOut = new HashMap<>(); protected Map<UUID, Integer> fadeOut = new HashMap<>();
protected Map<UUID, String> titles = new HashMap<>(); protected Map<UUID, String> titles = new HashMap<>();
protected Map<UUID, String> subTitles = new HashMap<>(); protected Map<UUID, String> subTitles = new HashMap<>();
protected Map<UUID, AtomicInteger> times = new HashMap<>(); protected Map<UUID, AtomicInteger> times = new HashMap<>();
public void setTimings(UUID uuid, int fadeIn, int stay, int fadeOut) { public void setTimings(UUID uuid, int fadeIn, int stay, int fadeOut) {
setFadeIn(uuid, fadeIn); setFadeIn(uuid, fadeIn);
setStay(uuid, stay); setStay(uuid, stay);
setFadeOut(uuid, fadeOut); setFadeOut(uuid, fadeOut);
AtomicInteger time = getTime(uuid); AtomicInteger time = getTime(uuid);
if (time.get() > 0) time.set(getFadeIn(uuid) + getStay(uuid) + getFadeOut(uuid)); if (time.get() > 0) time.set(getFadeIn(uuid) + getStay(uuid) + getFadeOut(uuid));
} }
public void reset(UUID uuid) { public void reset(UUID uuid) {
this.titles.remove(uuid); this.titles.remove(uuid);
this.subTitles.remove(uuid); this.subTitles.remove(uuid);
getTime(uuid).set(0); getTime(uuid).set(0);
fadeIn.remove(uuid); fadeIn.remove(uuid);
stay.remove(uuid); stay.remove(uuid);
fadeOut.remove(uuid); fadeOut.remove(uuid);
} }
public void setTitle(UUID uuid, String title) { public void setTitle(UUID uuid, String title) {
this.titles.put(uuid, title); this.titles.put(uuid, title);
getTime(uuid).set(getFadeIn(uuid) + getStay(uuid) + getFadeOut(uuid)); getTime(uuid).set(getFadeIn(uuid) + getStay(uuid) + getFadeOut(uuid));
} }
public void setSubTitle(UUID uuid, String subTitle) { public void setSubTitle(UUID uuid, String subTitle) {
this.subTitles.put(uuid, subTitle); this.subTitles.put(uuid, subTitle);
} }
public void clear(UUID uuid) { public void clear(UUID uuid) {
this.titles.remove(uuid); this.titles.remove(uuid);
this.subTitles.remove(uuid); this.subTitles.remove(uuid);
getTime(uuid).set(0); getTime(uuid).set(0);
} }
public AtomicInteger getTime(UUID uuid) { public AtomicInteger getTime(UUID uuid) {
return times.computeIfAbsent(uuid, key -> new AtomicInteger(0)); return times.computeIfAbsent(uuid, key -> new AtomicInteger(0));
} }
public int getFadeIn(UUID uuid) { public int getFadeIn(UUID uuid) {
return fadeIn.getOrDefault(uuid, 10); return fadeIn.getOrDefault(uuid, 10);
} }
public int getStay(UUID uuid) { public int getStay(UUID uuid) {
return stay.getOrDefault(uuid, 70); return stay.getOrDefault(uuid, 70);
} }
public int getFadeOut(UUID uuid) { public int getFadeOut(UUID uuid) {
return fadeOut.getOrDefault(uuid, 20); return fadeOut.getOrDefault(uuid, 20);
} }
public void setFadeIn(UUID uuid, int fadeIn) { public void setFadeIn(UUID uuid, int fadeIn) {
if (fadeIn >= 0) this.fadeIn.put(uuid, fadeIn); if (fadeIn >= 0) this.fadeIn.put(uuid, fadeIn);
else this.fadeIn.remove(uuid); else this.fadeIn.remove(uuid);
} }
public void setStay(UUID uuid, int stay) { public void setStay(UUID uuid, int stay) {
if (stay >= 0) this.stay.put(uuid, stay); if (stay >= 0) this.stay.put(uuid, stay);
else this.stay.remove(uuid); else this.stay.remove(uuid);
} }
public void setFadeOut(UUID uuid, int fadeOut) { public void setFadeOut(UUID uuid, int fadeOut) {
if (fadeOut >= 0) this.fadeOut.put(uuid, fadeOut); if (fadeOut >= 0) this.fadeOut.put(uuid, fadeOut);
else this.fadeOut.remove(uuid); else this.fadeOut.remove(uuid);
} }
} }
@@ -23,50 +23,49 @@ import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageDecoder;
import java.util.List; import java.util.List;
import java.util.zip.Inflater; import java.util.zip.Inflater;
public class CompressionDecoder extends MessageToMessageDecoder<ByteBuf> { public class CompressionDecoder extends MessageToMessageDecoder<ByteBuf> {
private final Inflater inflater = new Inflater(); private final Inflater inflater = new Inflater();
private final int threshold; private final int threshold;
public CompressionDecoder(final int threshold) { public CompressionDecoder(final int threshold) {
this.threshold = threshold; this.threshold = threshold;
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (!in.isReadable()) return; if (!in.isReadable()) return;
int outLength = Types.VAR_INT.readPrimitive(in); int outLength = Types.VAR_INT.readPrimitive(in);
if (outLength == 0) { if (outLength == 0) {
out.add(in.readBytes(in.readableBytes())); out.add(in.readBytes(in.readableBytes()));
return; return;
} }
if (outLength < this.threshold) { if (outLength < this.threshold) {
throw new DecoderException("Badly compressed packet - size of " + outLength + " is below server threshold of " + this.threshold); throw new DecoderException("Badly compressed packet - size of " + outLength + " is below server threshold of " + this.threshold);
} else if (outLength > 2097152) { } else if (outLength > 2097152) {
throw new DecoderException("Badly compressed packet - size of " + outLength + " is larger than protocol maximum of " + 2097152); throw new DecoderException("Badly compressed packet - size of " + outLength + " is larger than protocol maximum of " + 2097152);
} }
ByteBuf temp = in; ByteBuf temp = in;
if (!in.hasArray()) { if (!in.hasArray()) {
temp = ByteBufAllocator.DEFAULT.heapBuffer().writeBytes(in); temp = ByteBufAllocator.DEFAULT.heapBuffer().writeBytes(in);
} else { } else {
in.retain(); in.retain();
} }
ByteBuf output = ByteBufAllocator.DEFAULT.heapBuffer(outLength, outLength); ByteBuf output = ByteBufAllocator.DEFAULT.heapBuffer(outLength, outLength);
try { try {
this.inflater.setInput(temp.array(), temp.arrayOffset() + temp.readerIndex(), temp.readableBytes()); this.inflater.setInput(temp.array(), temp.arrayOffset() + temp.readerIndex(), temp.readableBytes());
output.writerIndex(output.writerIndex() + this.inflater.inflate(output.array(), output.arrayOffset(), outLength)); output.writerIndex(output.writerIndex() + this.inflater.inflate(output.array(), output.arrayOffset(), outLength));
out.add(output.retain()); out.add(output.retain());
} finally { } finally {
output.release(); output.release();
temp.release(); temp.release();
this.inflater.reset(); this.inflater.reset();
} }
} }
} }
@@ -22,49 +22,48 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
import java.util.zip.Deflater; import java.util.zip.Deflater;
public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> { public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
private final Deflater deflater = new Deflater(); private final Deflater deflater = new Deflater();
private final int threshold; private final int threshold;
public CompressionEncoder(final int threshold) { public CompressionEncoder(final int threshold) {
this.threshold = threshold; this.threshold = threshold;
} }
@Override @Override
protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
int frameLength = in.readableBytes(); int frameLength = in.readableBytes();
if (frameLength < this.threshold) { if (frameLength < this.threshold) {
out.writeByte(0); // VarInt out.writeByte(0); // VarInt
out.writeBytes(in); out.writeBytes(in);
return; return;
} }
Types.VAR_INT.writePrimitive(out, frameLength); Types.VAR_INT.writePrimitive(out, frameLength);
ByteBuf temp = in; ByteBuf temp = in;
if (!in.hasArray()) { if (!in.hasArray()) {
temp = ByteBufAllocator.DEFAULT.heapBuffer().writeBytes(in); temp = ByteBufAllocator.DEFAULT.heapBuffer().writeBytes(in);
} else { } else {
in.retain(); in.retain();
} }
ByteBuf output = ByteBufAllocator.DEFAULT.heapBuffer(); ByteBuf output = ByteBufAllocator.DEFAULT.heapBuffer();
try { try {
this.deflater.setInput(temp.array(), temp.arrayOffset() + temp.readerIndex(), temp.readableBytes()); this.deflater.setInput(temp.array(), temp.arrayOffset() + temp.readerIndex(), temp.readableBytes());
deflater.finish(); deflater.finish();
while (!deflater.finished()) { while (!deflater.finished()) {
output.ensureWritable(4096); output.ensureWritable(4096);
output.writerIndex(output.writerIndex() + this.deflater.deflate(output.array(), output.arrayOffset() + output.writerIndex(), output.writableBytes())); output.writerIndex(output.writerIndex() + this.deflater.deflate(output.array(), output.arrayOffset() + output.writerIndex(), output.writableBytes()));
} }
out.writeBytes(output); out.writeBytes(output);
} finally { } finally {
output.release(); output.release();
temp.release(); temp.release();
this.deflater.reset(); this.deflater.reset();
} }
} }
} }
@@ -28,47 +28,47 @@ import io.netty.channel.ChannelPipeline;
public class TrackingCompressionHandlerProvider extends CompressionHandlerProvider { public class TrackingCompressionHandlerProvider extends CompressionHandlerProvider {
@Override @Override
public void onHandleLoginCompressionPacket(UserConnection user, int threshold) { public void onHandleLoginCompressionPacket(UserConnection user, int threshold) {
final ChannelPipeline pipeline = user.getChannel().pipeline(); final ChannelPipeline pipeline = user.getChannel().pipeline();
if (user.isClientSide()) { if (user.isClientSide()) {
pipeline.addBefore(Via.getManager().getInjector().getEncoderName(), ViaRewind.getPlatform().compressHandlerName(), getEncoder(threshold)); pipeline.addBefore(Via.getManager().getInjector().getEncoderName(), ViaRewind.getPlatform().compressHandlerName(), getEncoder(threshold));
pipeline.addBefore(Via.getManager().getInjector().getDecoderName(), ViaRewind.getPlatform().decompressHandlerName(), getDecoder(threshold)); pipeline.addBefore(Via.getManager().getInjector().getDecoderName(), ViaRewind.getPlatform().decompressHandlerName(), getDecoder(threshold));
} else { } else {
setCompressionEnabled(user, true); // We need to remove compression for 1.7 clients setCompressionEnabled(user, true); // We need to remove compression for 1.7 clients
} }
} }
@Override @Override
public void onTransformPacket(UserConnection user) { public void onTransformPacket(UserConnection user) {
if (isCompressionEnabled(user)) { if (isCompressionEnabled(user)) {
final ChannelPipeline pipeline = user.getChannel().pipeline(); final ChannelPipeline pipeline = user.getChannel().pipeline();
String compressor = null; String compressor = null;
String decompressor = null; String decompressor = null;
if (pipeline.get(ViaRewind.getPlatform().compressHandlerName()) != null) { if (pipeline.get(ViaRewind.getPlatform().compressHandlerName()) != null) {
compressor = ViaRewind.getPlatform().compressHandlerName(); compressor = ViaRewind.getPlatform().compressHandlerName();
decompressor = ViaRewind.getPlatform().decompressHandlerName(); decompressor = ViaRewind.getPlatform().decompressHandlerName();
} }
if (compressor != null) { // We can neutralize the effect of compressor to the client if (compressor != null) { // We can neutralize the effect of compressor to the client
pipeline.replace(decompressor, decompressor, new EmptyChannelHandler()); pipeline.replace(decompressor, decompressor, new EmptyChannelHandler());
pipeline.replace(compressor, compressor, new ForwardMessageToByteEncoder()); pipeline.replace(compressor, compressor, new ForwardMessageToByteEncoder());
} else { } else {
throw new IllegalStateException("Couldn't remove compression for 1.7!"); throw new IllegalStateException("Couldn't remove compression for 1.7!");
} }
setCompressionEnabled(user, false); setCompressionEnabled(user, false);
} }
} }
@Override @Override
public ChannelHandler getEncoder(int threshold) { public ChannelHandler getEncoder(int threshold) {
return new CompressionEncoder(threshold); return new CompressionEncoder(threshold);
} }
@Override @Override
public ChannelHandler getDecoder(int threshold) { public ChannelHandler getDecoder(int threshold) {
return new CompressionDecoder(threshold); return new CompressionDecoder(threshold);
} }
} }
@@ -17,304 +17,305 @@
*/ */
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter; package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter; import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viarewind.api.rewriter.VRBlockItemRewriter; import com.viaversion.viarewind.api.rewriter.VRBlockItemRewriter;
import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ServerboundPackets1_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.Protocol1_8To1_7_6_10; 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.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.GameProfileStorage;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.InventoryTracker; 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.protocol.v1_8to1_7_6_10.storage.PlayerSessionStorage;
import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viarewind.utils.ChatUtil; import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement; import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.nbt.tag.*;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.UUID; import java.util.UUID;
public class BlockItemPacketRewriter1_8 extends VRBlockItemRewriter<ClientboundPackets1_8, ServerboundPackets1_7_2_5, Protocol1_8To1_7_6_10> { public class BlockItemPacketRewriter1_8 extends VRBlockItemRewriter<ClientboundPackets1_8, ServerboundPackets1_7_2_5, Protocol1_8To1_7_6_10> {
private LegacyEnchantmentRewriter enchantmentRewriter; private LegacyEnchantmentRewriter enchantmentRewriter;
public BlockItemPacketRewriter1_8(Protocol1_8To1_7_6_10 protocol) { public BlockItemPacketRewriter1_8(Protocol1_8To1_7_6_10 protocol) {
super(protocol, "1.8"); super(protocol, "1.8");
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_8.OPEN_SCREEN, wrapper -> { protocol.registerClientbound(ClientboundPackets1_8.OPEN_SCREEN, wrapper -> {
final InventoryTracker windowTracker = wrapper.user().get(InventoryTracker.class); final InventoryTracker windowTracker = wrapper.user().get(InventoryTracker.class);
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); // Window id final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); // Window id
final short windowTypeId = InventoryTracker.getInventoryType(wrapper.read(Types.STRING)); // Window type final short windowTypeId = InventoryTracker.getInventoryType(wrapper.read(Types.STRING)); // Window type
windowTracker.getWindowTypeMap().put(windowId, windowTypeId); windowTracker.getWindowTypeMap().put(windowId, windowTypeId);
wrapper.write(Types.UNSIGNED_BYTE, windowTypeId); // Window type id wrapper.write(Types.UNSIGNED_BYTE, windowTypeId); // Window type id
final JsonElement titleComponent = wrapper.read(Types.COMPONENT); // Title final JsonElement titleComponent = wrapper.read(Types.COMPONENT); // Title
String title = ChatUtil.jsonToLegacy(titleComponent); String title = ChatUtil.jsonToLegacy(titleComponent);
title = ChatUtil.removeUnusedColor(title, '8'); title = ChatUtil.removeUnusedColor(title, '8');
if (title.length() > 32) { if (title.length() > 32) {
title = title.substring(0, 32); title = title.substring(0, 32);
} }
wrapper.write(Types.STRING, title); // Window title wrapper.write(Types.STRING, title); // Window title
wrapper.passthrough(Types.UNSIGNED_BYTE); // Slots wrapper.passthrough(Types.UNSIGNED_BYTE); // Slots
wrapper.write(Types.BOOLEAN, true); // Use provided window title wrapper.write(Types.BOOLEAN, true); // Use provided window title
if (windowTypeId == 11) { // Horse if (windowTypeId == 11) { // Horse
wrapper.passthrough(Types.INT); // Entity id wrapper.passthrough(Types.INT); // Entity id
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_CLOSE, wrapper -> { protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_CLOSE, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); // Window id final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); // Window id
wrapper.user().get(InventoryTracker.class).remove(windowId); wrapper.user().get(InventoryTracker.class).remove(windowId);
}); });
protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_SLOT, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_SLOT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BYTE); // Window id map(Types.BYTE); // Window id
map(Types.SHORT); // Slot map(Types.SHORT); // Slot
handler(wrapper -> { handler(wrapper -> {
final short windowType = wrapper.user().get(InventoryTracker.class).get(wrapper.get(Types.BYTE, 0)); final short windowType = wrapper.user().get(InventoryTracker.class).get(wrapper.get(Types.BYTE, 0));
final short slot = wrapper.get(Types.SHORT, 0); final short slot = wrapper.get(Types.SHORT, 0);
if (windowType == 4) { // Enchantment Table if (windowType == 4) { // Enchantment Table
if (slot == 1) { if (slot == 1) {
wrapper.cancel(); wrapper.cancel();
} else if (slot >= 2) { } else if (slot >= 2) {
wrapper.set(Types.SHORT, 0, (short) (slot - 1)); wrapper.set(Types.SHORT, 0, (short) (slot - 1));
} }
} }
}); });
map(Types.ITEM1_8, RewindTypes.COMPRESSED_NBT_ITEM); // item map(Types.ITEM1_8, RewindTypes.COMPRESSED_NBT_ITEM); // item
handler(wrapper -> handleItemToClient(wrapper.user(), wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM, 0))); handler(wrapper -> handleItemToClient(wrapper.user(), wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM, 0)));
handler(wrapper -> { handler(wrapper -> {
final byte windowId = wrapper.get(Types.BYTE, 0); final byte windowId = wrapper.get(Types.BYTE, 0);
if (windowId != 0) { if (windowId != 0) {
return; return;
} }
final short slot = wrapper.get(Types.SHORT, 0); final short slot = wrapper.get(Types.SHORT, 0);
if (slot < 5 || slot > 8) { if (slot < 5 || slot > 8) {
return; return;
} }
final PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class); final PlayerSessionStorage playerSession = wrapper.user().get(PlayerSessionStorage.class);
final Item item = wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM, 0); final Item item = wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM, 0);
playerSession.setPlayerEquipment(wrapper.user().getProtocolInfo().getUuid(), item, 8 - slot); playerSession.setPlayerEquipment(wrapper.user().getProtocolInfo().getUuid(), item, 8 - slot);
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class); final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
if (tracker.isSpectator()) { // Spectator mode didn't exist in 1.7.10 if (tracker.isSpectator()) { // Spectator mode didn't exist in 1.7.10
wrapper.cancel(); wrapper.cancel();
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_CONTENT, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_CONTENT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.UNSIGNED_BYTE); // Window id map(Types.UNSIGNED_BYTE); // Window id
// remap enchantment table items // remap enchantment table items
handler(wrapper -> { handler(wrapper -> {
final short windowType = wrapper.user().get(InventoryTracker.class).get(wrapper.get(Types.UNSIGNED_BYTE, 0)); final short windowType = wrapper.user().get(InventoryTracker.class).get(wrapper.get(Types.UNSIGNED_BYTE, 0));
Item[] items = wrapper.read(Types.ITEM1_8_SHORT_ARRAY); Item[] items = wrapper.read(Types.ITEM1_8_SHORT_ARRAY);
if (windowType == 4) { // Enchantment Table if (windowType == 4) { // Enchantment Table
Item[] old = items; Item[] old = items;
items = new Item[old.length - 1]; items = new Item[old.length - 1];
items[0] = old[0]; items[0] = old[0];
System.arraycopy(old, 2, items, 1, old.length - 2); System.arraycopy(old, 2, items, 1, old.length - 2);
} }
for (int i = 0; i < items.length; i++) { for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(wrapper.user(), items[i]); items[i] = handleItemToClient(wrapper.user(), items[i]);
} }
wrapper.write(RewindTypes.COMPRESSED_NBT_ITEM_ARRAY, items); // Items wrapper.write(RewindTypes.COMPRESSED_NBT_ITEM_ARRAY, items); // Items
}); });
handler(wrapper -> { handler(wrapper -> {
final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0); final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0);
if (windowId != 0) { if (windowId != 0) {
return; return;
} }
final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class); final EntityTracker1_8 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_7_6_10.class);
final UUID userId = wrapper.user().getProtocolInfo().getUuid(); final UUID userId = wrapper.user().getProtocolInfo().getUuid();
final Item[] items = wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM_ARRAY, 0); final Item[] items = wrapper.get(RewindTypes.COMPRESSED_NBT_ITEM_ARRAY, 0);
for (int i = 5; i < 9; i++) { for (int i = 5; i < 9; i++) {
wrapper.user().get(PlayerSessionStorage.class).setPlayerEquipment(userId, items[i], 8 - i); wrapper.user().get(PlayerSessionStorage.class).setPlayerEquipment(userId, items[i], 8 - i);
if (tracker.isSpectator()) { if (tracker.isSpectator()) {
items[i] = null; items[i] = null;
} }
} }
if (tracker.isSpectator()) { if (tracker.isSpectator()) {
final GameProfileStorage.GameProfile profile = wrapper.user().get(GameProfileStorage.class).get(userId); final GameProfileStorage.GameProfile profile = wrapper.user().get(GameProfileStorage.class).get(userId);
if (profile != null) { if (profile != null) {
items[5] = profile.getSkull(); items[5] = profile.getSkull();
} }
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_DATA, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.CONTAINER_SET_DATA, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.UNSIGNED_BYTE); // Window id map(Types.UNSIGNED_BYTE); // Window id
map(Types.SHORT); // Progress bar id map(Types.SHORT); // Progress bar id
map(Types.SHORT); // Progress bar value map(Types.SHORT); // Progress bar value
handler(wrapper -> { handler(wrapper -> {
final InventoryTracker windowTracker = wrapper.user().get(InventoryTracker.class); final InventoryTracker windowTracker = wrapper.user().get(InventoryTracker.class);
final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0); final short windowId = wrapper.get(Types.UNSIGNED_BYTE, 0);
final short windowType = windowTracker.get(windowId); final short windowType = windowTracker.get(windowId);
final short progressBarId = wrapper.get(Types.SHORT, 0); final short progressBarId = wrapper.get(Types.SHORT, 0);
short progress = wrapper.get(Types.SHORT, 1); short progress = wrapper.get(Types.SHORT, 1);
if (windowType == 2) { // Furnace if (windowType == 2) { // Furnace
// TODO | Proper methods (getOrCreate)= // TODO | Proper methods (getOrCreate)=
final InventoryTracker.FurnaceData furnace = windowTracker.getFurnaceData().computeIfAbsent(windowId, x -> new InventoryTracker.FurnaceData()); final InventoryTracker.FurnaceData furnace = windowTracker.getFurnaceData().computeIfAbsent(windowId, x -> new InventoryTracker.FurnaceData());
if (progressBarId == 0 || progressBarId == 1) { if (progressBarId == 0 || progressBarId == 1) {
if (progressBarId == 0) { if (progressBarId == 0) {
furnace.fuelLeft = progress; furnace.fuelLeft = progress;
} else { } else {
furnace.maxFuel = progress; furnace.maxFuel = progress;
} }
if (furnace.maxFuel == 0) { if (furnace.maxFuel == 0) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
progress = (short) (200 * furnace.fuelLeft / furnace.maxFuel); progress = (short) (200 * furnace.fuelLeft / furnace.maxFuel);
wrapper.set(Types.SHORT, 0, (short) 1); wrapper.set(Types.SHORT, 0, (short) 1);
wrapper.set(Types.SHORT, 1, progress); wrapper.set(Types.SHORT, 1, progress);
} else if (progressBarId == 2 || progressBarId == 3) { } else if (progressBarId == 2 || progressBarId == 3) {
if (progressBarId == 2) { if (progressBarId == 2) {
furnace.progress = progress; furnace.progress = progress;
} else { } else {
furnace.maxProgress = progress; furnace.maxProgress = progress;
} }
if (furnace.maxProgress == 0) { if (furnace.maxProgress == 0) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
progress = (short) (200 * furnace.progress / furnace.maxProgress); progress = (short) (200 * furnace.progress / furnace.maxProgress);
wrapper.set(Types.SHORT, 0, (short) 0); wrapper.set(Types.SHORT, 0, (short) 0);
wrapper.set(Types.SHORT, 1, progress); wrapper.set(Types.SHORT, 1, progress);
} }
} else if (windowType == 4 && progressBarId > 2) { // Enchanting Table } else if (windowType == 4 && progressBarId > 2) { // Enchanting Table
wrapper.cancel(); wrapper.cancel();
} else if (windowType == 8) { // Anvil } else if (windowType == 8) { // Anvil
windowTracker.levelCost = progress; windowTracker.levelCost = progress;
windowTracker.anvilId = windowId; windowTracker.anvilId = windowId;
} }
}); });
} }
}); });
protocol.registerServerbound(ServerboundPackets1_7_2_5.CONTAINER_CLOSE, wrapper -> { protocol.registerServerbound(ServerboundPackets1_7_2_5.CONTAINER_CLOSE, wrapper -> {
final byte windowId = wrapper.passthrough(Types.BYTE); final byte windowId = wrapper.passthrough(Types.BYTE);
wrapper.user().get(InventoryTracker.class).remove(windowId); wrapper.user().get(InventoryTracker.class).remove(windowId);
}); });
protocol.registerServerbound(ServerboundPackets1_7_2_5.CONTAINER_CLICK, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_7_2_5.CONTAINER_CLICK, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BYTE); // Window id map(Types.BYTE); // Window id
map(Types.SHORT); // Slot map(Types.SHORT); // Slot
handler(wrapper -> { handler(wrapper -> {
final byte windowId = wrapper.get(Types.BYTE, 0); // Window id final byte windowId = wrapper.get(Types.BYTE, 0); // Window id
final short slot = wrapper.get(Types.SHORT, 0); final short slot = wrapper.get(Types.SHORT, 0);
final short windowType = wrapper.user().get(InventoryTracker.class).get(windowId); final short windowType = wrapper.user().get(InventoryTracker.class).get(windowId);
if (windowType == 4) { // Enchantment Table if (windowType == 4) { // Enchantment Table
if (slot > 0) { if (slot > 0) {
wrapper.set(Types.SHORT, 0, (short) (slot + 1)); wrapper.set(Types.SHORT, 0, (short) (slot + 1));
} }
} }
}); });
map(Types.BYTE); // Button map(Types.BYTE); // Button
map(Types.SHORT); // Action number map(Types.SHORT); // Action number
map(Types.BYTE); // Mode map(Types.BYTE); // Mode
map(RewindTypes.COMPRESSED_NBT_ITEM, Types.ITEM1_8); // Clicked item map(RewindTypes.COMPRESSED_NBT_ITEM, Types.ITEM1_8); // Clicked item
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0))); handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
} }
}); });
protocol.registerServerbound(ServerboundPackets1_7_2_5.SET_CREATIVE_MODE_SLOT, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_7_2_5.SET_CREATIVE_MODE_SLOT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.SHORT); // Slot map(Types.SHORT); // Slot
map(RewindTypes.COMPRESSED_NBT_ITEM, Types.ITEM1_8); // Item map(RewindTypes.COMPRESSED_NBT_ITEM, Types.ITEM1_8); // Item
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0))); handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
} }
}); });
} }
@Override @Override
protected void registerRewrites() { protected void registerRewrites() {
enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName(), false); enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName(), false);
enchantmentRewriter.registerEnchantment(8, "§7Depth Strider"); enchantmentRewriter.registerEnchantment(8, "§7Depth Strider");
} }
@Override @Override
public Item handleItemToClient(UserConnection connection, Item item) { public Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null; if (item == null) return null;
super.handleItemToClient(connection, item); super.handleItemToClient(connection, item);
CompoundTag tag = item.tag(); CompoundTag tag = item.tag();
if (tag == null) return item; if (tag == null) return item;
enchantmentRewriter.handleToClient(item); enchantmentRewriter.handleToClient(item);
if (item.identifier() == 387) { if (item.identifier() == 387) {
final ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class); final ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
if (pages == null) return item; if (pages == null) return item;
final ListTag<StringTag> oldPages = new ListTag<>(StringTag.class); final ListTag<StringTag> oldPages = new ListTag<>(StringTag.class);
tag.put(nbtTagName() + "|pages", oldPages); tag.put(nbtTagName() + "|pages", oldPages);
for (StringTag page : pages) { for (StringTag page : pages) {
final String value = page.getValue(); final String value = page.getValue();
oldPages.add(new StringTag(value)); oldPages.add(new StringTag(value));
page.setValue(ChatUtil.jsonToLegacy(value)); page.setValue(ChatUtil.jsonToLegacy(value));
} }
} }
return item; return item;
} }
@Override @Override
public Item handleItemToServer(UserConnection connection, Item item) { public Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null; if (item == null) return null;
super.handleItemToServer(connection, item); super.handleItemToServer(connection, item);
final CompoundTag tag = item.tag(); final CompoundTag tag = item.tag();
if (tag == null) return item; if (tag == null) return item;
enchantmentRewriter.handleToServer(item); enchantmentRewriter.handleToServer(item);
if (item.identifier() == 387) { if (item.identifier() == 387) {
final ListTag<StringTag> oldPages = tag.getListTag(nbtTagName() + "|pages", StringTag.class); final ListTag<StringTag> oldPages = tag.getListTag(nbtTagName() + "|pages", StringTag.class);
if (oldPages != null) { if (oldPages != null) {
tag.remove("pages"); tag.remove("pages");
tag.put("pages", oldPages); tag.put("pages", oldPages);
} }
} }
return item; return item;
} }
} }
@@ -26,227 +26,226 @@ import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import com.viaversion.viaversion.util.ChatColorUtil; import com.viaversion.viaversion.util.ChatColorUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
public class ScoreboardPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10> { public class ScoreboardPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10> {
public ScoreboardPacketRewriter1_8(Protocol1_8To1_7_6_10 protocol) { public ScoreboardPacketRewriter1_8(Protocol1_8To1_7_6_10 protocol) {
super(protocol); super(protocol);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_8.SET_OBJECTIVE, wrapper -> { protocol.registerClientbound(ClientboundPackets1_8.SET_OBJECTIVE, wrapper -> {
String name = wrapper.passthrough(Types.STRING); String name = wrapper.passthrough(Types.STRING);
if (name.length() > 16) { if (name.length() > 16) {
wrapper.set(Types.STRING, 0, name = name.substring(0, 16)); wrapper.set(Types.STRING, 0, name = name.substring(0, 16));
} }
final byte mode = wrapper.read(Types.BYTE); final byte mode = wrapper.read(Types.BYTE);
ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class); ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
if (mode == 0) { if (mode == 0) {
if (scoreboard.objectiveExists(name)) { if (scoreboard.objectiveExists(name)) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
scoreboard.addObjective(name); scoreboard.addObjective(name);
} else if (mode == 1) { } else if (mode == 1) {
if (!scoreboard.objectiveExists(name)) { if (!scoreboard.objectiveExists(name)) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
if (scoreboard.getColorIndependentSidebar() != null) { if (scoreboard.getColorIndependentSidebar() != null) {
String username = wrapper.user().getProtocolInfo().getUsername(); String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username); Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent()) { if (color.isPresent()) {
String sidebar = scoreboard.getColorDependentSidebar().get(color.get()); String sidebar = scoreboard.getColorDependentSidebar().get(color.get());
if (name.equals(sidebar)) { if (name.equals(sidebar)) {
final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user()); final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
sidebarPacket.write(Types.BYTE, (byte) 1); sidebarPacket.write(Types.BYTE, (byte) 1);
sidebarPacket.write(Types.STRING, scoreboard.getColorIndependentSidebar()); sidebarPacket.write(Types.STRING, scoreboard.getColorIndependentSidebar());
sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class); sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class);
} }
} }
} }
scoreboard.removeObjective(name); scoreboard.removeObjective(name);
} else if (mode == 2) { } else if (mode == 2) {
if (!scoreboard.objectiveExists(name)) { if (!scoreboard.objectiveExists(name)) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
} }
if (mode == 0 || mode == 2) { if (mode == 0 || mode == 2) {
String displayName = wrapper.passthrough(Types.STRING); String displayName = wrapper.passthrough(Types.STRING);
if (displayName.length() > 32) { if (displayName.length() > 32) {
wrapper.set(Types.STRING, 1, displayName.substring(0, 32)); wrapper.set(Types.STRING, 1, displayName.substring(0, 32));
} }
wrapper.read(Types.STRING); wrapper.read(Types.STRING);
} else { } else {
wrapper.write(Types.STRING, ""); wrapper.write(Types.STRING, "");
} }
wrapper.write(Types.BYTE, mode); wrapper.write(Types.BYTE, mode);
}); });
protocol.registerClientbound(ClientboundPackets1_8.SET_SCORE, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.SET_SCORE, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Name map(Types.STRING); // Name
map(Types.VAR_INT, Types.BYTE); // Mode map(Types.VAR_INT, Types.BYTE); // Mode
handler(wrapper -> { handler(wrapper -> {
ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class); ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
String name = wrapper.get(Types.STRING, 0); String name = wrapper.get(Types.STRING, 0);
byte mode = wrapper.get(Types.BYTE, 0); byte mode = wrapper.get(Types.BYTE, 0);
if (mode == 1) { if (mode == 1) {
name = scoreboard.removeTeamForScore(name); name = scoreboard.removeTeamForScore(name);
} else { } else {
name = scoreboard.sendTeamForScore(name); name = scoreboard.sendTeamForScore(name);
} }
if (name.length() > 16) { if (name.length() > 16) {
name = ChatColorUtil.stripColor(name); name = ChatColorUtil.stripColor(name);
if (name.length() > 16) { if (name.length() > 16) {
name = name.substring(0, 16); name = name.substring(0, 16);
} }
} }
wrapper.set(Types.STRING, 0, name); wrapper.set(Types.STRING, 0, name);
String objective = wrapper.read(Types.STRING); String objective = wrapper.read(Types.STRING);
if (objective.length() > 16) { if (objective.length() > 16) {
objective = objective.substring(0, 16); objective = objective.substring(0, 16);
} }
if (mode != 1) { if (mode != 1) {
int score = wrapper.read(Types.VAR_INT); int score = wrapper.read(Types.VAR_INT);
wrapper.write(Types.STRING, objective); wrapper.write(Types.STRING, objective);
wrapper.write(Types.INT, score); wrapper.write(Types.INT, score);
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.SET_DISPLAY_OBJECTIVE, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.SET_DISPLAY_OBJECTIVE, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BYTE); // Position map(Types.BYTE); // Position
map(Types.STRING); // Score name map(Types.STRING); // Score name
handler(wrapper -> { handler(wrapper -> {
byte position = wrapper.get(Types.BYTE, 0); byte position = wrapper.get(Types.BYTE, 0);
String name = wrapper.get(Types.STRING, 0); String name = wrapper.get(Types.STRING, 0);
ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class); ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
if (position > 2) { // team specific sidebar if (position > 2) { // team specific sidebar
byte receiverTeamColor = (byte) (position - 3); byte receiverTeamColor = (byte) (position - 3);
scoreboard.getColorDependentSidebar().put(receiverTeamColor, name); scoreboard.getColorDependentSidebar().put(receiverTeamColor, name);
String username = wrapper.user().getProtocolInfo().getUsername(); String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username); Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent() && color.get() == receiverTeamColor) { if (color.isPresent() && color.get() == receiverTeamColor) {
position = 1; position = 1;
} else { } else {
position = -1; position = -1;
} }
} else if (position == 1) { // team independent sidebar } else if (position == 1) { // team independent sidebar
scoreboard.setColorIndependentSidebar(name); scoreboard.setColorIndependentSidebar(name);
String username = wrapper.user().getProtocolInfo().getUsername(); String username = wrapper.user().getProtocolInfo().getUsername();
Optional<Byte> color = scoreboard.getPlayerTeamColor(username); Optional<Byte> color = scoreboard.getPlayerTeamColor(username);
if (color.isPresent() && scoreboard.getColorDependentSidebar().containsKey(color.get())) { if (color.isPresent() && scoreboard.getColorDependentSidebar().containsKey(color.get())) {
position = -1; position = -1;
} }
} }
if (position == -1) { if (position == -1) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
wrapper.set(Types.BYTE, 0, position); wrapper.set(Types.BYTE, 0, position);
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.SET_PLAYER_TEAM, wrapper -> { protocol.registerClientbound(ClientboundPackets1_8.SET_PLAYER_TEAM, wrapper -> {
final String team = wrapper.passthrough(Types.STRING); final String team = wrapper.passthrough(Types.STRING);
if (team == null) { if (team == null) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
final ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class); final ScoreboardTracker scoreboard = wrapper.user().get(ScoreboardTracker.class);
final byte mode = wrapper.passthrough(Types.BYTE); final byte mode = wrapper.passthrough(Types.BYTE);
if (mode != 0 && !scoreboard.teamExists(team)) { if (mode != 0 && !scoreboard.teamExists(team)) {
wrapper.cancel(); wrapper.cancel();
return; return;
} else if (mode == 0 && scoreboard.teamExists(team)) { } else if (mode == 0 && scoreboard.teamExists(team)) {
scoreboard.removeTeam(team); scoreboard.removeTeam(team);
final PacketWrapper removeTeam = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, wrapper.user()); final PacketWrapper removeTeam = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, wrapper.user());
removeTeam.write(Types.STRING, team); removeTeam.write(Types.STRING, team);
removeTeam.write(Types.BYTE, (byte) 1); removeTeam.write(Types.BYTE, (byte) 1);
removeTeam.send(Protocol1_8To1_7_6_10.class); removeTeam.send(Protocol1_8To1_7_6_10.class);
} }
if (mode == 0) { if (mode == 0) {
scoreboard.addTeam(team); scoreboard.addTeam(team);
} else if (mode == 1) { } else if (mode == 1) {
scoreboard.removeTeam(team); scoreboard.removeTeam(team);
} }
if (mode == 0 || mode == 2) { if (mode == 0 || mode == 2) {
wrapper.passthrough(Types.STRING); // Display name wrapper.passthrough(Types.STRING); // Display name
wrapper.passthrough(Types.STRING); // Prefix wrapper.passthrough(Types.STRING); // Prefix
wrapper.passthrough(Types.STRING); // Suffix wrapper.passthrough(Types.STRING); // Suffix
wrapper.passthrough(Types.BYTE); // Friendly fire wrapper.passthrough(Types.BYTE); // Friendly fire
wrapper.read(Types.STRING); // Name tag visibility wrapper.read(Types.STRING); // Name tag visibility
byte color = wrapper.read(Types.BYTE); byte color = wrapper.read(Types.BYTE);
if (mode == 2 && scoreboard.getTeamColor(team).get() != color) { if (mode == 2 && scoreboard.getTeamColor(team).get() != color) {
final String sidebar = scoreboard.getColorDependentSidebar().get(color); final String sidebar = scoreboard.getColorDependentSidebar().get(color);
final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user()); final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
sidebarPacket.write(Types.BYTE, (byte) 1); sidebarPacket.write(Types.BYTE, (byte) 1);
sidebarPacket.write(Types.STRING, sidebar == null ? "" : sidebar); sidebarPacket.write(Types.STRING, sidebar == null ? "" : sidebar);
sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class); sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class);
} }
scoreboard.setTeamColor(team, color); scoreboard.setTeamColor(team, color);
} }
if (mode == 0 || mode == 3 || mode == 4) { if (mode == 0 || mode == 3 || mode == 4) {
byte color = scoreboard.getTeamColor(team).get(); byte color = scoreboard.getTeamColor(team).get();
String[] entries = wrapper.read(Types.STRING_ARRAY); String[] entries = wrapper.read(Types.STRING_ARRAY);
List<String> entryList = new ArrayList<>(); List<String> entryList = new ArrayList<>();
for (String entry : entries) { for (String entry : entries) {
String username = wrapper.user().getProtocolInfo().getUsername(); String username = wrapper.user().getProtocolInfo().getUsername();
if (mode == 4) { if (mode == 4) {
if (!scoreboard.isPlayerInTeam(entry, team)) { if (!scoreboard.isPlayerInTeam(entry, team)) {
continue; continue;
} }
scoreboard.removePlayerFromTeam(entry, team); scoreboard.removePlayerFromTeam(entry, team);
if (entry.equals(username)) { if (entry.equals(username)) {
final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user()); final PacketWrapper sidebarPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
sidebarPacket.write(Types.BYTE, (byte) 1); sidebarPacket.write(Types.BYTE, (byte) 1);
sidebarPacket.write(Types.STRING, scoreboard.getColorIndependentSidebar() == null ? "" : scoreboard.getColorIndependentSidebar()); sidebarPacket.write(Types.STRING, scoreboard.getColorIndependentSidebar() == null ? "" : scoreboard.getColorIndependentSidebar());
sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class); sidebarPacket.scheduleSend(Protocol1_8To1_7_6_10.class);
} }
} else { } else {
scoreboard.addPlayerToTeam(entry, team); scoreboard.addPlayerToTeam(entry, team);
if (entry.equals(username) && scoreboard.getColorDependentSidebar().containsKey(color)) { if (entry.equals(username) && scoreboard.getColorDependentSidebar().containsKey(color)) {
final PacketWrapper displayObjective = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user()); final PacketWrapper displayObjective = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_DISPLAY_OBJECTIVE, wrapper.user());
displayObjective.write(Types.BYTE, (byte) 1); displayObjective.write(Types.BYTE, (byte) 1);
displayObjective.write(Types.STRING, scoreboard.getColorDependentSidebar().get(color)); displayObjective.write(Types.STRING, scoreboard.getColorDependentSidebar().get(color));
displayObjective.scheduleSend(Protocol1_8To1_7_6_10.class); displayObjective.scheduleSend(Protocol1_8To1_7_6_10.class);
} }
} }
entryList.add(entry); entryList.add(entry);
} }
wrapper.write(Types.SHORT, (short) entryList.size()); wrapper.write(Types.SHORT, (short) entryList.size());
for (String entry : entryList) { for (String entry : entryList) {
wrapper.write(Types.STRING, entry); wrapper.write(Types.STRING, entry);
} }
} }
}); });
} }
} }
@@ -17,14 +17,15 @@
*/ */
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.rewriter; 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.api.type.RewindTypes;
import com.viaversion.viarewind.api.type.chunk.BulkChunkType1_7_6;
import com.viaversion.viarewind.api.type.chunk.ChunkType1_7_6;
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.Particles1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.WorldBorderEmulator;
import com.viaversion.viarewind.utils.ChatUtil; import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord; import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk; import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
@@ -33,261 +34,260 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.FixedByteArrayType; 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.BulkChunkType1_8;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_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.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import com.viaversion.viaversion.util.ChatColorUtil; import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.IdAndData; import com.viaversion.viaversion.util.IdAndData;
public class WorldPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10> { public class WorldPacketRewriter1_8 extends RewriterBase<Protocol1_8To1_7_6_10> {
public WorldPacketRewriter1_8(Protocol1_8To1_7_6_10 protocol) { public WorldPacketRewriter1_8(Protocol1_8To1_7_6_10 protocol) {
super(protocol); super(protocol);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_CHUNK, wrapper -> { protocol.registerClientbound(ClientboundPackets1_8.LEVEL_CHUNK, wrapper -> {
final ClientWorld world = wrapper.user().getClientWorld(Protocol1_8To1_7_6_10.class); final ClientWorld world = wrapper.user().getClientWorld(Protocol1_8To1_7_6_10.class);
final Chunk chunk = wrapper.read(ChunkType1_8.forEnvironment(world.getEnvironment())); final Chunk chunk = wrapper.read(ChunkType1_8.forEnvironment(world.getEnvironment()));
protocol.getItemRewriter().handleChunk(chunk); protocol.getItemRewriter().handleChunk(chunk);
wrapper.write(ChunkType1_7_6.TYPE, chunk); wrapper.write(ChunkType1_7_6.TYPE, chunk);
}); });
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_UPDATE, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.BLOCK_UPDATE, new PacketHandlers() {
@Override @Override
protected void register() { protected void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.U_BYTE_POSITION); // Position map(Types.BLOCK_POSITION1_8, RewindTypes.U_BYTE_POSITION); // Position
handler(wrapper -> { handler(wrapper -> {
int data = wrapper.read(Types.VAR_INT); // Block data int data = wrapper.read(Types.VAR_INT); // Block data
data = protocol.getItemRewriter().handleBlockId(data); data = protocol.getItemRewriter().handleBlockId(data);
wrapper.write(Types.VAR_INT, IdAndData.getId(data)); // Block id wrapper.write(Types.VAR_INT, IdAndData.getId(data)); // Block id
wrapper.write(Types.UNSIGNED_BYTE, (short) IdAndData.getData(data)); // Block data wrapper.write(Types.UNSIGNED_BYTE, (short) IdAndData.getData(data)); // Block data
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.CHUNK_BLOCKS_UPDATE, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.CHUNK_BLOCKS_UPDATE, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.INT); // Chunk x map(Types.INT); // Chunk x
map(Types.INT); // Chunk z map(Types.INT); // Chunk z
handler(wrapper -> { handler(wrapper -> {
final BlockChangeRecord[] records = wrapper.read(Types.BLOCK_CHANGE_ARRAY); final BlockChangeRecord[] records = wrapper.read(Types.BLOCK_CHANGE_ARRAY);
wrapper.write(Types.SHORT, (short) records.length); // Record count wrapper.write(Types.SHORT, (short) records.length); // Record count
wrapper.write(Types.INT, records.length * 4); // Data array length (position + block id) wrapper.write(Types.INT, records.length * 4); // Data array length (position + block id)
for (BlockChangeRecord record : records) { for (BlockChangeRecord record : records) {
wrapper.write(Types.SHORT, (short) (record.getSectionX() << 12 | record.getSectionZ() << 8 | record.getY())); // Position 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 wrapper.write(Types.SHORT, (short) protocol.getItemRewriter().handleBlockId(record.getBlockId())); // Block id
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_EVENT, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.BLOCK_EVENT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // Position map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // Position
map(Types.UNSIGNED_BYTE); // Type map(Types.UNSIGNED_BYTE); // Type
map(Types.UNSIGNED_BYTE); // Data map(Types.UNSIGNED_BYTE); // Data
map(Types.VAR_INT); // Block id map(Types.VAR_INT); // Block id
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_DESTRUCTION, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.BLOCK_DESTRUCTION, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.VAR_INT); // Entity id map(Types.VAR_INT); // Entity id
map(Types.BLOCK_POSITION1_8, RewindTypes.INT_POSITION); // Position map(Types.BLOCK_POSITION1_8, RewindTypes.INT_POSITION); // Position
map(Types.BYTE); // Progress map(Types.BYTE); // Progress
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.MAP_BULK_CHUNK, wrapper -> { protocol.registerClientbound(ClientboundPackets1_8.MAP_BULK_CHUNK, wrapper -> {
final Chunk[] chunks = wrapper.read(BulkChunkType1_8.TYPE); final Chunk[] chunks = wrapper.read(BulkChunkType1_8.TYPE);
for (Chunk chunk : chunks) { for (Chunk chunk : chunks) {
protocol.getItemRewriter().handleChunk(chunk); protocol.getItemRewriter().handleChunk(chunk);
} }
wrapper.write(BulkChunkType1_7_6.TYPE, chunks); wrapper.write(BulkChunkType1_7_6.TYPE, chunks);
}); });
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_EVENT, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.LEVEL_EVENT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.INT); // Effect id map(Types.INT); // Effect id
map(Types.BLOCK_POSITION1_8, RewindTypes.BYTE_POSITION); // Position map(Types.BLOCK_POSITION1_8, RewindTypes.BYTE_POSITION); // Position
map(Types.INT); // Data map(Types.INT); // Data
map(Types.BOOLEAN); // Disable relative volume map(Types.BOOLEAN); // Disable relative volume
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_PARTICLES, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.LEVEL_PARTICLES, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
handler(wrapper -> { handler(wrapper -> {
final int particleId = wrapper.read(Types.INT); // Particle id final int particleId = wrapper.read(Types.INT); // Particle id
Particles1_8 particle = Particles1_8.find(particleId); Particles1_8 particle = Particles1_8.find(particleId);
if (particle == null) { if (particle == null) {
particle = Particles1_8.CRIT; particle = Particles1_8.CRIT;
} }
wrapper.write(Types.STRING, particle.name); // Particle name wrapper.write(Types.STRING, particle.name); // Particle name
}); });
read(Types.BOOLEAN); // Long distance read(Types.BOOLEAN); // Long distance
map(Types.FLOAT); // X map(Types.FLOAT); // X
map(Types.FLOAT); // Y map(Types.FLOAT); // Y
map(Types.FLOAT); // Z map(Types.FLOAT); // Z
map(Types.FLOAT); // Offset x map(Types.FLOAT); // Offset x
map(Types.FLOAT); // Offset y map(Types.FLOAT); // Offset y
map(Types.FLOAT); // Offset z map(Types.FLOAT); // Offset z
map(Types.FLOAT); // Particle data map(Types.FLOAT); // Particle data
map(Types.INT); // Particle count map(Types.INT); // Particle count
handler(wrapper -> { handler(wrapper -> {
String name = wrapper.get(Types.STRING, 0); String name = wrapper.get(Types.STRING, 0);
Particles1_8 particle = Particles1_8.find(name); Particles1_8 particle = Particles1_8.find(name);
if (particle == Particles1_8.ICON_CRACK || particle == Particles1_8.BLOCK_CRACK || particle == Particles1_8.BLOCK_DUST) { if (particle == Particles1_8.ICON_CRACK || particle == Particles1_8.BLOCK_CRACK || particle == Particles1_8.BLOCK_DUST) {
int id = wrapper.read(Types.VAR_INT); int id = wrapper.read(Types.VAR_INT);
int data = particle == Particles1_8.ICON_CRACK ? wrapper.read(Types.VAR_INT) : id / 4096; int data = particle == Particles1_8.ICON_CRACK ? wrapper.read(Types.VAR_INT) : id / 4096;
id %= 4096; id %= 4096;
if (id >= 256 && id <= 422 || id >= 2256 && id <= 2267) { //item if (id >= 256 && id <= 422 || id >= 2256 && id <= 2267) { //item
particle = Particles1_8.ICON_CRACK; particle = Particles1_8.ICON_CRACK;
} else if (id >= 0 && id <= 164 || id >= 170 && id <= 175) { } else if (id >= 0 && id <= 164 || id >= 170 && id <= 175) {
if (particle == Particles1_8.ICON_CRACK) if (particle == Particles1_8.ICON_CRACK)
particle = Particles1_8.BLOCK_CRACK; particle = Particles1_8.BLOCK_CRACK;
} else { } else {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
name = particle.name + "_" + id + "_" + data; name = particle.name + "_" + id + "_" + data;
} }
wrapper.set(Types.STRING, 0, name); wrapper.set(Types.STRING, 0, name);
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.UPDATE_SIGN, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.UPDATE_SIGN, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // position map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // position
handler(wrapper -> { handler(wrapper -> {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
String line = wrapper.read(Types.STRING); String line = wrapper.read(Types.STRING);
line = ChatUtil.jsonToLegacy(line); line = ChatUtil.jsonToLegacy(line);
line = ChatUtil.removeUnusedColor(line, '0'); line = ChatUtil.removeUnusedColor(line, '0');
if (line.length() > 15) { if (line.length() > 15) {
line = ChatColorUtil.stripColor(line); line = ChatColorUtil.stripColor(line);
if (line.length() > 15) line = line.substring(0, 15); if (line.length() > 15) line = line.substring(0, 15);
} }
wrapper.write(Types.STRING, line); wrapper.write(Types.STRING, line);
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper -> { protocol.registerClientbound(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper -> {
wrapper.cancel(); wrapper.cancel();
final int id = wrapper.read(Types.VAR_INT); final int id = wrapper.read(Types.VAR_INT);
final byte scale = wrapper.read(Types.BYTE); final byte scale = wrapper.read(Types.BYTE);
final int iconCount = wrapper.read(Types.VAR_INT); final int iconCount = wrapper.read(Types.VAR_INT);
byte[] icons = new byte[iconCount * 4]; byte[] icons = new byte[iconCount * 4];
for (int i = 0; i < iconCount; i++) { for (int i = 0; i < iconCount; i++) {
final int directionAndType = wrapper.read(Types.BYTE); final int directionAndType = wrapper.read(Types.BYTE);
icons[i * 4] = (byte) (directionAndType >> 4 & 0xF); icons[i * 4] = (byte) (directionAndType >> 4 & 0xF);
icons[i * 4 + 1] = wrapper.read(Types.BYTE); // x icons[i * 4 + 1] = wrapper.read(Types.BYTE); // x
icons[i * 4 + 2] = wrapper.read(Types.BYTE); // z icons[i * 4 + 2] = wrapper.read(Types.BYTE); // z
icons[i * 4 + 3] = (byte) (directionAndType & 0xF); icons[i * 4 + 3] = (byte) (directionAndType & 0xF);
} }
final short columns = wrapper.read(Types.UNSIGNED_BYTE); final short columns = wrapper.read(Types.UNSIGNED_BYTE);
if (columns > 0) { if (columns > 0) {
final short rows = wrapper.read(Types.UNSIGNED_BYTE); final short rows = wrapper.read(Types.UNSIGNED_BYTE);
final short x = wrapper.read(Types.UNSIGNED_BYTE); final short x = wrapper.read(Types.UNSIGNED_BYTE);
final short z = wrapper.read(Types.UNSIGNED_BYTE); final short z = wrapper.read(Types.UNSIGNED_BYTE);
final byte[] data = wrapper.read(Types.BYTE_ARRAY_PRIMITIVE); final byte[] data = wrapper.read(Types.BYTE_ARRAY_PRIMITIVE);
for (int column = 0; column < columns; column++) { for (int column = 0; column < columns; column++) {
byte[] columnData = new byte[rows + 3]; byte[] columnData = new byte[rows + 3];
columnData[0] = 0; columnData[0] = 0;
columnData[1] = (byte) (x + column); columnData[1] = (byte) (x + column);
columnData[2] = (byte) z; columnData[2] = (byte) z;
for (int i = 0; i < rows; i++) { for (int i = 0; i < rows; i++) {
columnData[i + 3] = data[column + i * columns]; columnData[i + 3] = data[column + i * columns];
} }
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user()); final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user());
mapData.write(Types.VAR_INT, id); // map id mapData.write(Types.VAR_INT, id); // map id
mapData.write(Types.SHORT, (short) columnData.length); // data length mapData.write(Types.SHORT, (short) columnData.length); // data length
mapData.write(new FixedByteArrayType(columnData.length), columnData); // data mapData.write(new FixedByteArrayType(columnData.length), columnData); // data
mapData.send(Protocol1_8To1_7_6_10.class); mapData.send(Protocol1_8To1_7_6_10.class);
} }
} }
if (iconCount > 0) { if (iconCount > 0) {
final byte[] iconData = new byte[iconCount * 3 + 1]; final byte[] iconData = new byte[iconCount * 3 + 1];
iconData[0] = 1; iconData[0] = 1;
for (int i = 0; i < iconCount; i++) { for (int i = 0; i < iconCount; i++) {
iconData[i * 3 + 1] = (byte) (icons[i * 4] << 4 | icons[i * 4 + 3] & 0xF); 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 + 2] = icons[i * 4 + 1];
iconData[i * 3 + 3] = icons[i * 4 + 2]; iconData[i * 3 + 3] = icons[i * 4 + 2];
} }
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user()); final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user());
mapData.write(Types.VAR_INT, id); // map id mapData.write(Types.VAR_INT, id); // map id
mapData.write(Types.SHORT, (short) iconData.length); // data length mapData.write(Types.SHORT, (short) iconData.length); // data length
mapData.write(new FixedByteArrayType(iconData.length), iconData); // data mapData.write(new FixedByteArrayType(iconData.length), iconData); // data
mapData.send(Protocol1_8To1_7_6_10.class); mapData.send(Protocol1_8To1_7_6_10.class);
} }
// Update scale // Update scale
final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user()); final PacketWrapper mapData = PacketWrapper.create(ClientboundPackets1_8.MAP_ITEM_DATA, wrapper.user());
mapData.write(Types.VAR_INT, id); // map id mapData.write(Types.VAR_INT, id); // map id
mapData.write(Types.SHORT, (short) 2); // data length mapData.write(Types.SHORT, (short) 2); // data length
mapData.write(new FixedByteArrayType(2), new byte[]{2, scale}); // data mapData.write(new FixedByteArrayType(2), new byte[]{2, scale}); // data
mapData.send(Protocol1_8To1_7_6_10.class); mapData.send(Protocol1_8To1_7_6_10.class);
}); });
protocol.registerClientbound(ClientboundPackets1_8.BLOCK_ENTITY_DATA, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_8.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // position map(Types.BLOCK_POSITION1_8, RewindTypes.SHORT_POSITION); // position
map(Types.UNSIGNED_BYTE); // action map(Types.UNSIGNED_BYTE); // action
map(Types.NAMED_COMPOUND_TAG, RewindTypes.COMPRESSED_NBT); // nbt map(Types.NAMED_COMPOUND_TAG, RewindTypes.COMPRESSED_NBT); // nbt
} }
}); });
protocol.cancelClientbound(ClientboundPackets1_8.CHANGE_DIFFICULTY); protocol.cancelClientbound(ClientboundPackets1_8.CHANGE_DIFFICULTY);
protocol.registerClientbound(ClientboundPackets1_8.SET_BORDER, null, wrapper -> { protocol.registerClientbound(ClientboundPackets1_8.SET_BORDER, null, wrapper -> {
final WorldBorderEmulator emulator = wrapper.user().get(WorldBorderEmulator.class); final WorldBorderEmulator emulator = wrapper.user().get(WorldBorderEmulator.class);
wrapper.cancel(); wrapper.cancel();
final int action = wrapper.read(Types.VAR_INT); final int action = wrapper.read(Types.VAR_INT);
if (action == 0) { // set size if (action == 0) { // set size
emulator.setSize(wrapper.read(Types.DOUBLE)); // radius emulator.setSize(wrapper.read(Types.DOUBLE)); // radius
} else if (action == 1) { // lerp size } 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 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 } else if (action == 2) { // set center
emulator.setCenter(wrapper.read(Types.DOUBLE), wrapper.read(Types.DOUBLE)); // x, z emulator.setCenter(wrapper.read(Types.DOUBLE), wrapper.read(Types.DOUBLE)); // x, z
} else if (action == 3) { // initialize } else if (action == 3) { // initialize
emulator.init( emulator.init(
wrapper.read(Types.DOUBLE), wrapper.read(Types.DOUBLE), // x, z 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.DOUBLE), wrapper.read(Types.DOUBLE), // old radius, new radius
wrapper.read(Types.VAR_LONG) // speed wrapper.read(Types.VAR_LONG) // speed
); );
} }
}); });
} }
} }
@@ -24,9 +24,9 @@ import com.viaversion.viaversion.api.connection.UserConnection;
* @see com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.CompressionHandlerProvider * @see com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.CompressionHandlerProvider
*/ */
public class CompressionStatusTracker extends StoredObject { public class CompressionStatusTracker extends StoredObject {
public boolean removeCompression = false; public boolean removeCompression = false;
public CompressionStatusTracker(UserConnection user) { public CompressionStatusTracker(UserConnection user) {
super(user); super(user);
} }
} }
@@ -36,8 +36,11 @@ import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap; import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap; import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.ArrayList;
import java.util.*; import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
public class EntityTracker1_8 extends EntityTrackerBase { public class EntityTracker1_8 extends EntityTrackerBase {
@@ -17,129 +17,132 @@
*/ */
package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage; package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viarewind.utils.ChatUtil; import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.connection.StoredObject; import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.DataItem; import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.util.ChatColorUtil; import com.viaversion.viaversion.util.ChatColorUtil;
import java.util.ArrayList;
import java.util.*; import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class GameProfileStorage extends StoredObject { public class GameProfileStorage extends StoredObject {
private final Map<UUID, GameProfile> properties = new HashMap<>(); private final Map<UUID, GameProfile> properties = new HashMap<>();
public GameProfileStorage(UserConnection user) { public GameProfileStorage(UserConnection user) {
super(user); super(user);
} }
public GameProfile put(UUID uuid, String name) { public GameProfile put(UUID uuid, String name) {
GameProfile gameProfile = new GameProfile(uuid, name); GameProfile gameProfile = new GameProfile(uuid, name);
properties.put(uuid, gameProfile); properties.put(uuid, gameProfile);
return gameProfile; return gameProfile;
} }
public GameProfile get(UUID uuid) { public GameProfile get(UUID uuid) {
return properties.get(uuid); return properties.get(uuid);
} }
public GameProfile get(String name, boolean ignoreCase) { public GameProfile get(String name, boolean ignoreCase) {
if (ignoreCase) name = name.toLowerCase(); if (ignoreCase) name = name.toLowerCase();
for (GameProfile profile : properties.values()) { for (GameProfile profile : properties.values()) {
if (profile.name == null) continue; if (profile.name == null) continue;
String n = ignoreCase ? profile.name.toLowerCase() : profile.name; String n = ignoreCase ? profile.name.toLowerCase() : profile.name;
if (n.equals(name)) { if (n.equals(name)) {
return profile; return profile;
} }
} }
return null; return null;
} }
public List<GameProfile> getAllWithPrefix(String prefix, boolean ignoreCase) { public List<GameProfile> getAllWithPrefix(String prefix, boolean ignoreCase) {
if (ignoreCase) prefix = prefix.toLowerCase(); if (ignoreCase) prefix = prefix.toLowerCase();
ArrayList<GameProfile> profiles = new ArrayList<>(); ArrayList<GameProfile> profiles = new ArrayList<>();
for (GameProfile profile : properties.values()) { for (GameProfile profile : properties.values()) {
if (profile.name == null) continue; if (profile.name == null) continue;
String n = ignoreCase ? profile.name.toLowerCase() : profile.name; String n = ignoreCase ? profile.name.toLowerCase() : profile.name;
if (n.startsWith(prefix)) profiles.add(profile); if (n.startsWith(prefix)) profiles.add(profile);
} }
return profiles; return profiles;
} }
public GameProfile remove(UUID uuid) { public GameProfile remove(UUID uuid) {
return properties.remove(uuid); return properties.remove(uuid);
} }
public static class GameProfile { public static class GameProfile {
public final String name; public final String name;
public final UUID uuid; public final UUID uuid;
public String displayName; public String displayName;
public int ping; public int ping;
public List<Property> properties = new ArrayList<>(); public List<Property> properties = new ArrayList<>();
public int gamemode = 0; public int gamemode = 0;
public GameProfile(UUID uuid, String name) { public GameProfile(UUID uuid, String name) {
this.name = name; this.name = name;
this.uuid = uuid; this.uuid = uuid;
} }
public Item getSkull() { public Item getSkull() {
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();
CompoundTag ownerTag = new CompoundTag(); CompoundTag ownerTag = new CompoundTag();
tag.put("SkullOwner", ownerTag); tag.put("SkullOwner", ownerTag);
ownerTag.put("Id", new StringTag(uuid.toString())); ownerTag.put("Id", new StringTag(uuid.toString()));
CompoundTag properties = new CompoundTag(); CompoundTag properties = new CompoundTag();
ownerTag.put("Properties", properties); ownerTag.put("Properties", properties);
ListTag textures = new ListTag(CompoundTag.class); ListTag textures = new ListTag(CompoundTag.class);
properties.put("textures", textures); properties.put("textures", textures);
for (Property property : this.properties) { for (Property property : this.properties) {
if (property.name.equals("textures")) { if (property.name.equals("textures")) {
CompoundTag textureTag = new CompoundTag(); CompoundTag textureTag = new CompoundTag();
textureTag.put("Value", new StringTag(property.value)); textureTag.put("Value", new StringTag(property.value));
if (property.signature != null) { if (property.signature != null) {
textureTag.put("Signature", new StringTag(property.signature)); textureTag.put("Signature", new StringTag(property.signature));
} }
textures.add(textureTag); textures.add(textureTag);
} }
} }
return new DataItem(397, (byte) 1, (short) 3, tag); return new DataItem(397, (byte) 1, (short) 3, tag);
} }
public String getDisplayName() { public String getDisplayName() {
String displayName = this.displayName == null ? name : this.displayName; String displayName = this.displayName == null ? name : this.displayName;
if (displayName.length() > 16) displayName = ChatUtil.removeUnusedColor(displayName, 'f'); if (displayName.length() > 16) displayName = ChatUtil.removeUnusedColor(displayName, 'f');
if (displayName.length() > 16) displayName = ChatColorUtil.stripColor(displayName); if (displayName.length() > 16) displayName = ChatColorUtil.stripColor(displayName);
if (displayName.length() > 16) displayName = displayName.substring(0, 16); if (displayName.length() > 16) displayName = displayName.substring(0, 16);
return displayName; return displayName;
} }
public void setDisplayName(String displayName) { public void setDisplayName(String displayName) {
this.displayName = displayName; this.displayName = displayName;
} }
} }
public static class Property { public static class Property {
public final String name; public final String name;
public final String value; public final String value;
public final String signature; public final String signature;
public Property(String name, String value, String signature) { public Property(String name, String value, String signature) {
this.name = name; this.name = name;
this.value = value; this.value = value;
this.signature = signature; this.signature = signature;
} }
} }
} }
@@ -19,66 +19,65 @@ package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viaversion.api.connection.StoredObject; import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class InventoryTracker extends StoredObject { public class InventoryTracker extends StoredObject {
public static final Map<String, Integer> WINDOW_TYPE_REGISTRY = new HashMap<>(); public static final Map<String, Integer> WINDOW_TYPE_REGISTRY = new HashMap<>();
static { static {
WINDOW_TYPE_REGISTRY.put("minecraft:container", 0); WINDOW_TYPE_REGISTRY.put("minecraft:container", 0);
WINDOW_TYPE_REGISTRY.put("minecraft:chest", 0); WINDOW_TYPE_REGISTRY.put("minecraft:chest", 0);
WINDOW_TYPE_REGISTRY.put("minecraft:crafting_table", 1); WINDOW_TYPE_REGISTRY.put("minecraft:crafting_table", 1);
WINDOW_TYPE_REGISTRY.put("minecraft:furnace", 2); WINDOW_TYPE_REGISTRY.put("minecraft:furnace", 2);
WINDOW_TYPE_REGISTRY.put("minecraft:dispenser", 3); WINDOW_TYPE_REGISTRY.put("minecraft:dispenser", 3);
WINDOW_TYPE_REGISTRY.put("minecraft:enchanting_table", 4); WINDOW_TYPE_REGISTRY.put("minecraft:enchanting_table", 4);
WINDOW_TYPE_REGISTRY.put("minecraft:brewing_stand", 5); WINDOW_TYPE_REGISTRY.put("minecraft:brewing_stand", 5);
WINDOW_TYPE_REGISTRY.put("minecraft:villager", 6); WINDOW_TYPE_REGISTRY.put("minecraft:villager", 6);
WINDOW_TYPE_REGISTRY.put("minecraft:beacon", 7); WINDOW_TYPE_REGISTRY.put("minecraft:beacon", 7);
WINDOW_TYPE_REGISTRY.put("minecraft:anvil", 8); WINDOW_TYPE_REGISTRY.put("minecraft:anvil", 8);
WINDOW_TYPE_REGISTRY.put("minecraft:hopper", 9); WINDOW_TYPE_REGISTRY.put("minecraft:hopper", 9);
WINDOW_TYPE_REGISTRY.put("minecraft:dropper", 10); WINDOW_TYPE_REGISTRY.put("minecraft:dropper", 10);
WINDOW_TYPE_REGISTRY.put("EntityHorse", 11); WINDOW_TYPE_REGISTRY.put("EntityHorse", 11);
} }
private final HashMap<Short, Short> windowTypeMap = new HashMap<>(); private final HashMap<Short, Short> windowTypeMap = new HashMap<>();
private final HashMap<Short, FurnaceData> furnaceData = new HashMap<>(); private final HashMap<Short, FurnaceData> furnaceData = new HashMap<>();
public short levelCost = 0; public short levelCost = 0;
public short anvilId = -1; public short anvilId = -1;
public InventoryTracker(UserConnection user) { public InventoryTracker(UserConnection user) {
super(user); super(user);
} }
public short get(short windowId) { public static short getInventoryType(String name) {
return windowTypeMap.getOrDefault(windowId, (short) -1); return WINDOW_TYPE_REGISTRY.getOrDefault(name, -1).shortValue();
} }
public void remove(short windowId) { public short get(short windowId) {
windowTypeMap.remove(windowId); return windowTypeMap.getOrDefault(windowId, (short) -1);
furnaceData.remove(windowId); }
}
public static short getInventoryType(String name) { public void remove(short windowId) {
return WINDOW_TYPE_REGISTRY.getOrDefault(name, -1).shortValue(); windowTypeMap.remove(windowId);
} furnaceData.remove(windowId);
}
public HashMap<Short, Short> getWindowTypeMap() { public HashMap<Short, Short> getWindowTypeMap() {
return windowTypeMap; return windowTypeMap;
} }
public HashMap<Short, FurnaceData> getFurnaceData() { public HashMap<Short, FurnaceData> getFurnaceData() {
return furnaceData; return furnaceData;
} }
public static class FurnaceData { public static class FurnaceData {
public short fuelLeft = 0; public short fuelLeft = 0;
public short maxFuel = 0; public short maxFuel = 0;
public short progress = 0; public short progress = 0;
public short maxProgress = 200; public short maxProgress = 200;
} }
} }
@@ -20,78 +20,77 @@ package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage;
import com.viaversion.viaversion.api.connection.StoredObject; import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.item.Item;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
public class PlayerSessionStorage extends StoredObject { public class PlayerSessionStorage extends StoredObject {
// Player abilities // Player inventory
public boolean sprinting, allowFly, flying, invincible, creative; private final Map<UUID, Item[]> playerEquipment = new HashMap<>();
public float flySpeed, walkSpeed;
// Player position, rotation and data // Player abilities
private double posX, posY, posZ; public boolean sprinting, allowFly, flying, invincible, creative;
public double receivedPosY; public float flySpeed, walkSpeed;
public float yaw, pitch; public double receivedPosY;
public boolean onGround; public float yaw, pitch;
public boolean onGround;
// Player inventory // Player position, rotation and data
private final Map<UUID, Item[]> playerEquipment = new HashMap<>(); private double posX, posY, posZ;
public PlayerSessionStorage(UserConnection user) { public PlayerSessionStorage(UserConnection user) {
super(user); super(user);
} }
public byte combineAbilities() { public byte combineAbilities() {
byte flags = 0; byte flags = 0;
if (invincible) flags |= 8; if (invincible) flags |= 8;
if (allowFly) flags |= 4; if (allowFly) flags |= 4;
if (flying) flags |= 2; if (flying) flags |= 2;
if (creative) flags |= 1; if (creative) flags |= 1;
return flags; return flags;
} }
public double getPosX() { public double getPosX() {
return posX; return posX;
} }
public double getPosY() { public double getPosY() {
return posY; return posY;
} }
public double getPosZ() { public double getPosZ() {
return posZ; return posZ;
} }
public void setPos(double x, double y, double z) { public void setPos(double x, double y, double z) {
posX = x; posX = x;
posY = y; posY = y;
posZ = z; posZ = z;
} }
public Item getPlayerEquipment(final UUID uuid, final int slot) { public Item getPlayerEquipment(final UUID uuid, final int slot) {
final Item[] items = playerEquipment.get(uuid); final Item[] items = playerEquipment.get(uuid);
if (items == null || slot < 0 || slot >= items.length) { if (items == null || slot < 0 || slot >= items.length) {
return null; return null;
} }
return items[slot]; return items[slot];
} }
public void setPlayerEquipment(final UUID uuid, final Item equipment, final int slot) { public void setPlayerEquipment(final UUID uuid, final Item equipment, final int slot) {
final Item[] items = playerEquipment.computeIfAbsent(uuid, it -> new Item[5]); final Item[] items = playerEquipment.computeIfAbsent(uuid, it -> new Item[5]);
if (slot < 0 || slot >= items.length) { if (slot < 0 || slot >= items.length) {
return; return;
} }
items[slot] = equipment; items[slot] = equipment;
} }
public Map<UUID, Item[]> getPlayerEquipment() { public Map<UUID, Item[]> getPlayerEquipment() {
return playerEquipment; return playerEquipment;
} }
} }
@@ -23,163 +23,167 @@ import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import java.util.ArrayList;
import java.util.*; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class ScoreboardTracker extends StoredObject { public class ScoreboardTracker extends StoredObject {
private final HashMap<String, List<String>> teams = new HashMap<>(); private final HashMap<String, List<String>> teams = new HashMap<>();
private final HashSet<String> objectives = new HashSet<>(); private final HashSet<String> objectives = new HashSet<>();
private final HashMap<String, ScoreTeam> scoreTeams = new HashMap<>(); private final HashMap<String, ScoreTeam> scoreTeams = new HashMap<>();
private final HashMap<String, Byte> teamColors = new HashMap<>(); private final HashMap<String, Byte> teamColors = new HashMap<>();
private final HashSet<String> scoreTeamNames = new HashSet<>(); private final HashSet<String> scoreTeamNames = new HashSet<>();
private String colorIndependentSidebar; private final HashMap<Byte, String> colorDependentSidebar = new HashMap<>();
private final HashMap<Byte, String> colorDependentSidebar = new HashMap<>(); private String colorIndependentSidebar;
public ScoreboardTracker(UserConnection user) { public ScoreboardTracker(UserConnection user) {
super(user); super(user);
} }
public void addPlayerToTeam(String player, String team) { public void addPlayerToTeam(String player, String team) {
teams.computeIfAbsent(team, key -> new ArrayList<>()).add(player); teams.computeIfAbsent(team, key -> new ArrayList<>()).add(player);
} }
public void setTeamColor(String team, Byte color) { public void setTeamColor(String team, Byte color) {
teamColors.put(team, color); teamColors.put(team, color);
} }
public Optional<Byte> getTeamColor(String team) { public Optional<Byte> getTeamColor(String team) {
return Optional.ofNullable(teamColors.get(team)); return Optional.ofNullable(teamColors.get(team));
} }
public void addTeam(String team) { public void addTeam(String team) {
teams.computeIfAbsent(team, key -> new ArrayList<>()); teams.computeIfAbsent(team, key -> new ArrayList<>());
} }
public void removeTeam(String team) { public void removeTeam(String team) {
teams.remove(team); teams.remove(team);
scoreTeams.remove(team); scoreTeams.remove(team);
teamColors.remove(team); teamColors.remove(team);
} }
public boolean teamExists(String team) { public boolean teamExists(String team) {
return teams.containsKey(team); return teams.containsKey(team);
} }
public void removePlayerFromTeam(String player, String team) { public void removePlayerFromTeam(String player, String team) {
List<String> teamPlayers = teams.get(team); List<String> teamPlayers = teams.get(team);
if (teamPlayers != null) teamPlayers.remove(player); if (teamPlayers != null) teamPlayers.remove(player);
} }
public boolean isPlayerInTeam(String player, String team) { public boolean isPlayerInTeam(String player, String team) {
List<String> teamPlayers = teams.get(team); List<String> teamPlayers = teams.get(team);
return teamPlayers != null && teamPlayers.contains(player); return teamPlayers != null && teamPlayers.contains(player);
} }
public boolean isPlayerInTeam(String player) { public boolean isPlayerInTeam(String player) {
for (List<String> teamPlayers : teams.values()) { for (List<String> teamPlayers : teams.values()) {
if (teamPlayers.contains(player)) return true; if (teamPlayers.contains(player)) return true;
} }
return false; return false;
} }
public Optional<Byte> getPlayerTeamColor(String player) { public Optional<Byte> getPlayerTeamColor(String player) {
Optional<String> team = getTeam(player); Optional<String> team = getTeam(player);
return team.isPresent() ? getTeamColor(team.get()) : Optional.empty(); return team.isPresent() ? getTeamColor(team.get()) : Optional.empty();
} }
public Optional<String> getTeam(String player) { public Optional<String> getTeam(String player) {
for (Map.Entry<String, List<String>> entry : teams.entrySet()) for (Map.Entry<String, List<String>> entry : teams.entrySet())
if (entry.getValue().contains(player)) if (entry.getValue().contains(player))
return Optional.of(entry.getKey()); return Optional.of(entry.getKey());
return Optional.empty(); return Optional.empty();
} }
public void addObjective(String name) { public void addObjective(String name) {
objectives.add(name); objectives.add(name);
} }
public void removeObjective(String name) { public void removeObjective(String name) {
objectives.remove(name); objectives.remove(name);
colorDependentSidebar.values().remove(name); colorDependentSidebar.values().remove(name);
if (name.equals(colorIndependentSidebar)) { if (name.equals(colorIndependentSidebar)) {
colorIndependentSidebar = null; colorIndependentSidebar = null;
} }
} }
public boolean objectiveExists(String name) { public boolean objectiveExists(String name) {
return objectives.contains(name); return objectives.contains(name);
} }
public String sendTeamForScore(String score) { public String sendTeamForScore(String score) {
if (score.length() <= 16) return score; if (score.length() <= 16) return score;
if (scoreTeams.containsKey(score)) return scoreTeams.get(score).name; if (scoreTeams.containsKey(score)) return scoreTeams.get(score).name;
int l = 16; int l = 16;
int i = Math.min(16, score.length() - 16); int i = Math.min(16, score.length() - 16);
String name = score.substring(i, i + l); String name = score.substring(i, i + l);
while (scoreTeamNames.contains(name) || teams.containsKey(name)) { while (scoreTeamNames.contains(name) || teams.containsKey(name)) {
i--; i--;
while (score.length() - l - i > 16) { while (score.length() - l - i > 16) {
l--; l--;
if (l < 1) return score; if (l < 1) return score;
i = Math.min(16, score.length() - l); i = Math.min(16, score.length() - l);
} }
name = score.substring(i, i + l); name = score.substring(i, i + l);
} }
String prefix = score.substring(0, i); String prefix = score.substring(0, i);
String suffix = i + l >= score.length() ? "" : score.substring(i + l); String suffix = i + l >= score.length() ? "" : score.substring(i + l);
ScoreTeam scoreTeam = new ScoreTeam(name, prefix, suffix); ScoreTeam scoreTeam = new ScoreTeam(name, prefix, suffix);
scoreTeams.put(score, scoreTeam); scoreTeams.put(score, scoreTeam);
scoreTeamNames.add(name); scoreTeamNames.add(name);
PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, getUser()); PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, getUser());
teamPacket.write(Types.STRING, name); teamPacket.write(Types.STRING, name);
teamPacket.write(Types.BYTE, (byte) 0); teamPacket.write(Types.BYTE, (byte) 0);
teamPacket.write(Types.STRING, "ViaRewind"); teamPacket.write(Types.STRING, "ViaRewind");
teamPacket.write(Types.STRING, prefix); teamPacket.write(Types.STRING, prefix);
teamPacket.write(Types.STRING, suffix); teamPacket.write(Types.STRING, suffix);
teamPacket.write(Types.BYTE, (byte) 0); teamPacket.write(Types.BYTE, (byte) 0);
teamPacket.write(Types.SHORT, (short) 1); teamPacket.write(Types.SHORT, (short) 1);
teamPacket.write(Types.STRING, name); teamPacket.write(Types.STRING, name);
teamPacket.send(Protocol1_8To1_7_6_10.class); teamPacket.send(Protocol1_8To1_7_6_10.class);
return name; return name;
} }
public String removeTeamForScore(String score) { public String removeTeamForScore(String score) {
ScoreTeam scoreTeam = scoreTeams.remove(score); ScoreTeam scoreTeam = scoreTeams.remove(score);
if (scoreTeam == null) return score; if (scoreTeam == null) return score;
scoreTeamNames.remove(scoreTeam.name); scoreTeamNames.remove(scoreTeam.name);
PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, getUser()); PacketWrapper teamPacket = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_PLAYER_TEAM, getUser());
teamPacket.write(Types.STRING, scoreTeam.name); teamPacket.write(Types.STRING, scoreTeam.name);
teamPacket.write(Types.BYTE, (byte) 1); teamPacket.write(Types.BYTE, (byte) 1);
teamPacket.send(Protocol1_8To1_7_6_10.class); teamPacket.send(Protocol1_8To1_7_6_10.class);
return scoreTeam.name; return scoreTeam.name;
} }
public String getColorIndependentSidebar() { public String getColorIndependentSidebar() {
return this.colorIndependentSidebar; return this.colorIndependentSidebar;
} }
public HashMap<Byte, String> getColorDependentSidebar() { public void setColorIndependentSidebar(String colorIndependentSidebar) {
return this.colorDependentSidebar; this.colorIndependentSidebar = colorIndependentSidebar;
} }
public void setColorIndependentSidebar(String colorIndependentSidebar) { public HashMap<Byte, String> getColorDependentSidebar() {
this.colorIndependentSidebar = colorIndependentSidebar; return this.colorDependentSidebar;
} }
private static class ScoreTeam { private static class ScoreTeam {
private final String prefix; private final String prefix;
private final String suffix; private final String suffix;
private final String name; private final String name;
public ScoreTeam(String name, String prefix, String suffix) { public ScoreTeam(String name, String prefix, String suffix) {
this.prefix = prefix; this.prefix = prefix;
this.suffix = suffix; this.suffix = suffix;
this.name = name; this.name = name;
} }
} }
} }
@@ -21,87 +21,87 @@ import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
public class WorldBorderEmulator extends StoredObject { public class WorldBorderEmulator extends StoredObject {
private double x, z; private double x, z;
private double oldDiameter, newDiameter; private double oldDiameter, newDiameter;
private long lerpTime; private long lerpTime;
private long lerpStartTime; private long lerpStartTime;
private boolean init = false; private boolean init = false;
public WorldBorderEmulator(UserConnection user) { public WorldBorderEmulator(UserConnection user) {
super(user); super(user);
} }
public void init(double x, double z, double oldDiameter, double newDiameter, long lerpTime) { public void init(double x, double z, double oldDiameter, double newDiameter, long lerpTime) {
this.x = x; this.x = x;
this.z = z; this.z = z;
this.oldDiameter = oldDiameter; this.oldDiameter = oldDiameter;
this.newDiameter = newDiameter; this.newDiameter = newDiameter;
this.lerpTime = lerpTime; this.lerpTime = lerpTime;
init = true; init = true;
} }
public void setCenter(double x, double z) { public void setCenter(double x, double z) {
this.x = x; this.x = x;
this.z = z; this.z = z;
} }
public void lerpSize(double oldDiameter, double newDiameter, long lerpTime) { public void lerpSize(double oldDiameter, double newDiameter, long lerpTime) {
this.oldDiameter = oldDiameter; this.oldDiameter = oldDiameter;
this.newDiameter = newDiameter; this.newDiameter = newDiameter;
this.lerpTime = lerpTime; this.lerpTime = lerpTime;
this.lerpStartTime = System.currentTimeMillis(); this.lerpStartTime = System.currentTimeMillis();
} }
public void setSize(double size) { public double getSize() {
this.oldDiameter = size; if (lerpTime == 0) {
this.newDiameter = size; return newDiameter;
}
this.lerpTime = 0; double percent = ((double) (System.currentTimeMillis() - lerpStartTime) / (double) (lerpTime));
}
public double getSize() { // Clamp value
if (lerpTime == 0) { if (percent > 1.0D) percent = 1.0d;
return newDiameter; else if (percent < 0.0D) percent = 0.0d;
}
double percent = ((double) (System.currentTimeMillis() - lerpStartTime) / (double) (lerpTime)); return oldDiameter + (newDiameter - oldDiameter) * percent;
}
// Clamp value public void setSize(double size) {
if (percent > 1.0D) percent = 1.0d; this.oldDiameter = size;
else if (percent < 0.0D) percent = 0.0d; this.newDiameter = size;
return oldDiameter + (newDiameter - oldDiameter) * percent; this.lerpTime = 0;
} }
public double getX() { public double getX() {
return x; return x;
} }
public double getZ() { public double getZ() {
return z; return z;
} }
public boolean isInit() { public boolean isInit() {
return init; return init;
} }
public enum Side { public enum Side {
NORTH(0, -1), NORTH(0, -1),
EAST(1, 0), EAST(1, 0),
SOUTH(0, 1), SOUTH(0, 1),
WEST(-1, 0); WEST(-1, 0);
public final int modX; public final int modX;
public final int modZ; public final int modZ;
Side(int modX, int modZ) { Side(int modX, int modZ) {
this.modX = modX; this.modX = modX;
this.modZ = modZ; this.modZ = modZ;
} }
} }
} }
@@ -26,70 +26,69 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.logging.Level; import java.util.logging.Level;
public class WorldBorderUpdateTask implements Runnable { public class WorldBorderUpdateTask implements Runnable {
public static final int VIEW_DISTANCE = 16; public static final int VIEW_DISTANCE = 16;
@Override @Override
public void run() { public void run() {
for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) { for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) {
final WorldBorderEmulator worldBorderEmulatorTracker = connection.get(WorldBorderEmulator.class); final WorldBorderEmulator worldBorderEmulatorTracker = connection.get(WorldBorderEmulator.class);
if (!worldBorderEmulatorTracker.isInit()) continue; if (!worldBorderEmulatorTracker.isInit()) continue;
final PlayerSessionStorage playerSession = connection.get(PlayerSessionStorage.class); final PlayerSessionStorage playerSession = connection.get(PlayerSessionStorage.class);
double radius = worldBorderEmulatorTracker.getSize() / 2.0; double radius = worldBorderEmulatorTracker.getSize() / 2.0;
for (WorldBorderEmulator.Side side : WorldBorderEmulator.Side.values()) { for (WorldBorderEmulator.Side side : WorldBorderEmulator.Side.values()) {
double d; double d;
double pos; double pos;
double center; double center;
if (side.modX != 0) { if (side.modX != 0) {
pos = playerSession.getPosZ(); pos = playerSession.getPosZ();
center = worldBorderEmulatorTracker.getZ(); center = worldBorderEmulatorTracker.getZ();
d = Math.abs(worldBorderEmulatorTracker.getX() + radius * side.modX - playerSession.getPosX()); d = Math.abs(worldBorderEmulatorTracker.getX() + radius * side.modX - playerSession.getPosX());
} else { } else {
center = worldBorderEmulatorTracker.getX(); center = worldBorderEmulatorTracker.getX();
pos = playerSession.getPosX(); pos = playerSession.getPosX();
d = Math.abs(worldBorderEmulatorTracker.getZ() + radius * side.modZ - playerSession.getPosZ()); d = Math.abs(worldBorderEmulatorTracker.getZ() + radius * side.modZ - playerSession.getPosZ());
} }
if (d >= VIEW_DISTANCE) continue; if (d >= VIEW_DISTANCE) continue;
double r = Math.sqrt(VIEW_DISTANCE * VIEW_DISTANCE - d * d); double r = Math.sqrt(VIEW_DISTANCE * VIEW_DISTANCE - d * d);
double minH = Math.ceil(pos - r); double minH = Math.ceil(pos - r);
double maxH = Math.floor(pos + r); double maxH = Math.floor(pos + r);
double minV = Math.ceil(playerSession.getPosY() - r); double minV = Math.ceil(playerSession.getPosY() - r);
double maxV = Math.floor(playerSession.getPosY() + r); double maxV = Math.floor(playerSession.getPosY() + r);
if (minH < center - radius) minH = Math.ceil(center - radius); if (minH < center - radius) minH = Math.ceil(center - radius);
if (maxH > center + radius) maxH = Math.floor(center + radius); if (maxH > center + radius) maxH = Math.floor(center + radius);
if (minV < 0.0) minV = 0.0; if (minV < 0.0) minV = 0.0;
double centerH = (minH + maxH) / 2.0; double centerH = (minH + maxH) / 2.0;
double centerV = (minV + maxV) / 2.0; double centerV = (minV + maxV) / 2.0;
double particleOffset = 2.5; double particleOffset = 2.5;
final PacketWrapper spawnParticle = PacketWrapper.create(ClientboundPackets1_8.LEVEL_PARTICLES, connection); final PacketWrapper spawnParticle = PacketWrapper.create(ClientboundPackets1_8.LEVEL_PARTICLES, connection);
spawnParticle.write(Types.STRING, ViaRewind.getConfig().getWorldBorderParticle()); // particle name 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) (side.modX != 0 ? worldBorderEmulatorTracker.getX() + (radius * side.modX) : centerH)); // x
spawnParticle.write(Types.FLOAT, (float) centerV); // y 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 ? 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) (side.modX != 0 ? 0f : (maxH - minH) / particleOffset)); // offset x
spawnParticle.write(Types.FLOAT, (float) ((maxV - minV) / particleOffset)); // offset y 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, (float) (side.modX == 0 ? 0f : (maxH - minH) / particleOffset)); // offset z
spawnParticle.write(Types.FLOAT, 0F); // particle data spawnParticle.write(Types.FLOAT, 0F); // particle data
spawnParticle.write(Types.INT, (int) Math.floor((maxH - minH) * (maxV - minV) * 0.5)); spawnParticle.write(Types.INT, (int) Math.floor((maxH - minH) * (maxV - minV) * 0.5));
try { try {
spawnParticle.send(Protocol1_8To1_7_6_10.class); spawnParticle.send(Protocol1_8To1_7_6_10.class);
} catch (Exception e) { } catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to send world border particle", e); ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to send world border particle", e);
} }
} }
} }
} }
} }
@@ -19,93 +19,100 @@ package com.viaversion.viarewind.protocol.v1_9to1_8;
import com.viaversion.viabackwards.api.BackwardsProtocol; import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viarewind.protocol.v1_9to1_8.data.RewindMappingData1_8; import com.viaversion.viarewind.protocol.v1_9to1_8.data.RewindMappingData1_8;
import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.BlockItemPacketRewriter1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.EntityPacketRewriter1_9; 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.rewriter.PlayerPacketRewriter1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.*; import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.WorldPacketRewriter1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BlockPlaceDestroyTracker;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BossBarStorage;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CooldownStorage;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.EntityTracker1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LevitationStorage;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.PlayerPositionTracker;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.WindowTracker;
import com.viaversion.viarewind.protocol.v1_9to1_8.task.CooldownIndicatorTask; import com.viaversion.viarewind.protocol.v1_9to1_8.task.CooldownIndicatorTask;
import com.viaversion.viarewind.protocol.v1_9to1_8.task.LevitationUpdateTask; import com.viaversion.viarewind.protocol.v1_9to1_8.task.LevitationUpdateTask;
import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer; import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
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_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_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.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_9; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_9;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class Protocol1_9To1_8 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<>(Types.INT) { public static final ValueTransformer<Double, Integer> DOUBLE_TO_INT_TIMES_32 = new ValueTransformer<>(Types.INT) {
@Override @Override
public Integer transform(PacketWrapper wrapper, Double inputValue) { public Integer transform(PacketWrapper wrapper, Double inputValue) {
return (int) (inputValue * 32.0D); return (int) (inputValue * 32.0D);
} }
}; };
public static final ValueTransformer<Float, Byte> DEGREES_TO_ANGLE = new ValueTransformer<>(Types.BYTE) { public static final ValueTransformer<Float, Byte> DEGREES_TO_ANGLE = new ValueTransformer<>(Types.BYTE) {
@Override @Override
public Byte transform(PacketWrapper packetWrapper, Float degrees) { public Byte transform(PacketWrapper packetWrapper, Float degrees) {
return (byte) ((degrees / 360F) * 256); return (byte) ((degrees / 360F) * 256);
} }
}; };
public static final RewindMappingData1_8 MAPPINGS = new RewindMappingData1_8(); public static final RewindMappingData1_8 MAPPINGS = new RewindMappingData1_8();
private final BlockItemPacketRewriter1_9 itemRewriter = new BlockItemPacketRewriter1_9(this); private final BlockItemPacketRewriter1_9 itemRewriter = new BlockItemPacketRewriter1_9(this);
private final EntityPacketRewriter1_9 entityRewriter = new EntityPacketRewriter1_9(this); private final EntityPacketRewriter1_9 entityRewriter = new EntityPacketRewriter1_9(this);
public Protocol1_9To1_8() { public Protocol1_9To1_8() {
super(ClientboundPackets1_9.class, ClientboundPackets1_8.class, ServerboundPackets1_9.class, ServerboundPackets1_8.class); super(ClientboundPackets1_9.class, ClientboundPackets1_8.class, ServerboundPackets1_9.class, ServerboundPackets1_8.class);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
entityRewriter.register(); entityRewriter.register();
itemRewriter.register(); itemRewriter.register();
new PlayerPacketRewriter1_9(this).register(); new PlayerPacketRewriter1_9(this).register();
new WorldPacketRewriter1_9(this).register(); new WorldPacketRewriter1_9(this).register();
} }
@Override @Override
public void init(UserConnection connection) { public void init(UserConnection connection) {
connection.addEntityTracker(this.getClass(), new EntityTracker1_9(connection)); connection.addEntityTracker(this.getClass(), new EntityTracker1_9(connection));
connection.addClientWorld(this.getClass(), new ClientWorld()); connection.addClientWorld(this.getClass(), new ClientWorld());
connection.put(new WindowTracker(connection)); connection.put(new WindowTracker(connection));
connection.put(new LevitationStorage()); connection.put(new LevitationStorage());
connection.put(new PlayerPositionTracker()); connection.put(new PlayerPositionTracker());
connection.put(new CooldownStorage()); connection.put(new CooldownStorage());
connection.put(new BlockPlaceDestroyTracker()); connection.put(new BlockPlaceDestroyTracker());
connection.put(new BossBarStorage(connection)); connection.put(new BossBarStorage(connection));
} }
@Override @Override
public void register(ViaProviders providers) { public void register(ViaProviders providers) {
Via.getManager().getScheduler().scheduleRepeating(new LevitationUpdateTask(), 0L, 50L, TimeUnit.MILLISECONDS); Via.getManager().getScheduler().scheduleRepeating(new LevitationUpdateTask(), 0L, 50L, TimeUnit.MILLISECONDS);
Via.getManager().getScheduler().scheduleRepeating(new CooldownIndicatorTask(), 0L, 50L, TimeUnit.MILLISECONDS); Via.getManager().getScheduler().scheduleRepeating(new CooldownIndicatorTask(), 0L, 50L, TimeUnit.MILLISECONDS);
} }
@Override @Override
public RewindMappingData1_8 getMappingData() { public RewindMappingData1_8 getMappingData() {
return MAPPINGS; return MAPPINGS;
} }
@Override @Override
public BlockItemPacketRewriter1_9 getItemRewriter() { public BlockItemPacketRewriter1_9 getItemRewriter() {
return itemRewriter; return itemRewriter;
} }
@Override @Override
public EntityPacketRewriter1_9 getEntityRewriter() { public EntityPacketRewriter1_9 getEntityRewriter() {
return entityRewriter; return entityRewriter;
} }
@Override @Override
public boolean hasMappingDataToLoad() { public boolean hasMappingDataToLoad() {
return true; return true;
} }
} }
@@ -25,26 +25,26 @@ import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
public class ActionBarVisualization implements CooldownVisualization { public class ActionBarVisualization implements CooldownVisualization {
private final UserConnection user; private final UserConnection user;
public ActionBarVisualization(UserConnection user) { public ActionBarVisualization(UserConnection user) {
this.user = user; this.user = user;
} }
@Override @Override
public void show(double progress) throws Exception { public void show(double progress) throws Exception {
sendActionBar(CooldownVisualization.buildProgressText("■", progress)); sendActionBar(CooldownVisualization.buildProgressText("■", progress));
} }
@Override @Override
public void hide() throws Exception { public void hide() throws Exception {
sendActionBar("§r"); sendActionBar("§r");
} }
private void sendActionBar(final String bar) { private void sendActionBar(final String bar) {
PacketWrapper actionBarPacket = PacketWrapper.create(ClientboundPackets1_8.CHAT, user); PacketWrapper actionBarPacket = PacketWrapper.create(ClientboundPackets1_8.CHAT, user);
actionBarPacket.write(Types.COMPONENT, new JsonPrimitive(bar)); actionBarPacket.write(Types.COMPONENT, new JsonPrimitive(bar));
actionBarPacket.write(Types.BYTE, (byte) 2); // Position - above hotbar actionBarPacket.write(Types.BYTE, (byte) 2); // Position - above hotbar
actionBarPacket.scheduleSend(Protocol1_9To1_8.class); actionBarPacket.scheduleSend(Protocol1_9To1_8.class);
} }
} }
@@ -23,46 +23,45 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonPrimitive; import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
import java.util.UUID; import java.util.UUID;
public class BossBarVisualization implements CooldownVisualization { public class BossBarVisualization implements CooldownVisualization {
private final UserConnection user; private final UserConnection user;
private UUID bossUUID; private UUID bossUUID;
public BossBarVisualization(UserConnection user) { public BossBarVisualization(UserConnection user) {
this.user = user; this.user = user;
} }
@Override @Override
public void show(double progress) throws Exception { public void show(double progress) throws Exception {
final PacketWrapper setBossbar = PacketWrapper.create(ClientboundPackets1_9.BOSS_EVENT, user); final PacketWrapper setBossbar = PacketWrapper.create(ClientboundPackets1_9.BOSS_EVENT, user);
if (bossUUID == null) { if (bossUUID == null) {
bossUUID = UUID.randomUUID(); bossUUID = UUID.randomUUID();
setBossbar.write(Types.UUID, bossUUID); setBossbar.write(Types.UUID, bossUUID);
setBossbar.write(Types.VAR_INT, 0); // Action - add setBossbar.write(Types.VAR_INT, 0); // Action - add
setBossbar.write(Types.COMPONENT, new JsonPrimitive(" ")); // Title setBossbar.write(Types.COMPONENT, new JsonPrimitive(" ")); // Title
setBossbar.write(Types.FLOAT, (float) progress); // Health setBossbar.write(Types.FLOAT, (float) progress); // Health
setBossbar.write(Types.VAR_INT, 0); // Color setBossbar.write(Types.VAR_INT, 0); // Color
setBossbar.write(Types.VAR_INT, 0); // Division setBossbar.write(Types.VAR_INT, 0); // Division
setBossbar.write(Types.UNSIGNED_BYTE, (short) 0); // Flags setBossbar.write(Types.UNSIGNED_BYTE, (short) 0); // Flags
} else { } else {
setBossbar.write(Types.UUID, bossUUID); setBossbar.write(Types.UUID, bossUUID);
setBossbar.write(Types.VAR_INT, 2); // Action - update health setBossbar.write(Types.VAR_INT, 2); // Action - update health
setBossbar.write(Types.FLOAT, (float) progress); // Health setBossbar.write(Types.FLOAT, (float) progress); // Health
} }
setBossbar.send(Protocol1_9To1_8.class, false); setBossbar.send(Protocol1_9To1_8.class, false);
} }
@Override @Override
public void hide() throws Exception { public void hide() throws Exception {
if (bossUUID == null) { if (bossUUID == null) {
return; return;
} }
final PacketWrapper removeBossbar = PacketWrapper.create(ClientboundPackets1_9.BOSS_EVENT, user); final PacketWrapper removeBossbar = PacketWrapper.create(ClientboundPackets1_9.BOSS_EVENT, user);
removeBossbar.write(Types.UUID, bossUUID); removeBossbar.write(Types.UUID, bossUUID);
removeBossbar.write(Types.VAR_INT, 1); // Action - remove removeBossbar.write(Types.VAR_INT, 1); // Action - remove
removeBossbar.send(Protocol1_9To1_8.class, false); removeBossbar.send(Protocol1_9To1_8.class, false);
bossUUID = null; bossUUID = null;
} }
} }
@@ -22,44 +22,43 @@ import com.viaversion.viarewind.api.ViaRewindConfig.CooldownIndicator;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
public interface CooldownVisualization { public interface CooldownVisualization {
void show(double progress) throws Exception; int MAX_PROGRESS_TEXT_LENGTH = 10;
void hide() throws Exception; static String buildProgressText(String symbol, double cooldown) {
int green = (int) Math.floor(((double) MAX_PROGRESS_TEXT_LENGTH) * cooldown);
int grey = MAX_PROGRESS_TEXT_LENGTH - green;
StringBuilder builder = new StringBuilder("§8");
while (green-- > 0) builder.append(symbol);
builder.append("§7");
while (grey-- > 0) builder.append(symbol);
return builder.toString();
}
void show(double progress) throws Exception;
int MAX_PROGRESS_TEXT_LENGTH = 10; void hide() throws Exception;
static String buildProgressText(String symbol, double cooldown) { interface Factory {
int green = (int) Math.floor(((double) MAX_PROGRESS_TEXT_LENGTH) * cooldown); Factory DISABLED = user -> new DisabledCooldownVisualization();
int grey = MAX_PROGRESS_TEXT_LENGTH - green;
StringBuilder builder = new StringBuilder("§8");
while (green-- > 0) builder.append(symbol);
builder.append("§7");
while (grey-- > 0) builder.append(symbol);
return builder.toString();
}
interface Factory { static Factory fromConfiguration() {
CooldownVisualization create(UserConnection user); try {
return fromIndicator(ViaRewind.getConfig().getCooldownIndicator());
} catch (IllegalArgumentException e) {
ViaRewind.getPlatform().getLogger().warning("Invalid cooldown-indicator setting");
return DISABLED;
}
}
static Factory fromConfiguration() { static Factory fromIndicator(CooldownIndicator indicator) {
try { return switch (indicator) {
return fromIndicator(ViaRewind.getConfig().getCooldownIndicator()); case TITLE -> TitleCooldownVisualization::new;
} catch (IllegalArgumentException e) { case BOSS_BAR -> BossBarVisualization::new;
ViaRewind.getPlatform().getLogger().warning("Invalid cooldown-indicator setting"); case ACTION_BAR -> ActionBarVisualization::new;
return DISABLED; case DISABLED -> DISABLED;
} };
} }
static Factory fromIndicator(CooldownIndicator indicator) { CooldownVisualization create(UserConnection user);
return switch (indicator) { }
case TITLE -> TitleCooldownVisualization::new;
case BOSS_BAR -> BossBarVisualization::new;
case ACTION_BAR -> ActionBarVisualization::new;
case DISABLED -> DISABLED;
};
}
Factory DISABLED = user -> new DisabledCooldownVisualization();
}
} }
@@ -19,12 +19,12 @@ package com.viaversion.viarewind.protocol.v1_9to1_8.cooldown;
public class DisabledCooldownVisualization implements CooldownVisualization { public class DisabledCooldownVisualization implements CooldownVisualization {
@Override @Override
public void show(double progress) { public void show(double progress) {
} }
@Override @Override
public void hide() { public void hide() {
} }
} }
@@ -23,45 +23,45 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonPrimitive; import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.function.Consumer; import java.util.function.Consumer;
public class TitleCooldownVisualization implements CooldownVisualization { public class TitleCooldownVisualization implements CooldownVisualization {
private static final int ACTION_SET_TITLE = 0; private static final int ACTION_SET_TITLE = 0;
private static final int ACTION_SET_SUBTITLE = 1; private static final int ACTION_SET_SUBTITLE = 1;
private static final int ACTION_SET_TIMES_AND_DISPLAY = 2; private static final int ACTION_SET_TIMES_AND_DISPLAY = 2;
private static final int ACTION_HIDE = 3; private static final int ACTION_HIDE = 3;
private final UserConnection user; private final UserConnection user;
public TitleCooldownVisualization(UserConnection user) { public TitleCooldownVisualization(UserConnection user) {
this.user = user; this.user = user;
} }
@Override @Override
public void show(double progress) throws Exception { public void show(double progress) throws Exception {
final String text = CooldownVisualization.buildProgressText("˙", progress); final String text = CooldownVisualization.buildProgressText("˙", progress);
sendTitlePacket(ACTION_SET_TITLE, wrapper -> wrapper.write(Types.COMPONENT, new JsonPrimitive(""))); 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_SUBTITLE, wrapper -> wrapper.write(Types.COMPONENT, new JsonPrimitive(text)));
sendTitlePacket(ACTION_SET_TIMES_AND_DISPLAY, wrapper -> { sendTitlePacket(ACTION_SET_TIMES_AND_DISPLAY, wrapper -> {
wrapper.write(Types.INT, 0); wrapper.write(Types.INT, 0);
wrapper.write(Types.INT, 2); wrapper.write(Types.INT, 2);
wrapper.write(Types.INT, 5); wrapper.write(Types.INT, 5);
}); });
} }
@Override @Override
public void hide() throws Exception { public void hide() throws Exception {
sendTitlePacket(ACTION_HIDE, wrapper -> {}); sendTitlePacket(ACTION_HIDE, wrapper -> {
} });
}
private void sendTitlePacket(int action, Consumer<PacketWrapper> writer) { private void sendTitlePacket(int action, Consumer<PacketWrapper> writer) {
final PacketWrapper title = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user); final PacketWrapper title = PacketWrapper.create(ClientboundPackets1_8.SET_TITLES, user);
title.write(Types.VAR_INT, action); title.write(Types.VAR_INT, action);
writer.accept(title); writer.accept(title);
title.scheduleSend(Protocol1_9To1_8.class); title.scheduleSend(Protocol1_9To1_8.class);
} }
} }
@@ -21,49 +21,49 @@ import java.util.HashMap;
public class EffectIdMappings1_8 { public class EffectIdMappings1_8 {
private static final HashMap<Integer, Integer> effects = new HashMap<>(); private static final HashMap<Integer, Integer> effects = new HashMap<>();
static { static {
effects.put(1003, 1002); effects.put(1003, 1002);
effects.put(1005, 1003); effects.put(1005, 1003);
effects.put(1006, 1003); effects.put(1006, 1003);
effects.put(1007, 1003); effects.put(1007, 1003);
effects.put(1008, 1003); effects.put(1008, 1003);
effects.put(1009, 1004); effects.put(1009, 1004);
effects.put(1010, 1005); effects.put(1010, 1005);
effects.put(1011, 1006); effects.put(1011, 1006);
effects.put(1012, 1006); effects.put(1012, 1006);
effects.put(1013, 1006); effects.put(1013, 1006);
effects.put(1014, 1006); effects.put(1014, 1006);
effects.put(1015, 1007); effects.put(1015, 1007);
effects.put(1016, 1008); effects.put(1016, 1008);
effects.put(1017, 1008); effects.put(1017, 1008);
effects.put(1018, 1009); effects.put(1018, 1009);
effects.put(1019, 1010); effects.put(1019, 1010);
effects.put(1020, 1011); effects.put(1020, 1011);
effects.put(1021, 1012); effects.put(1021, 1012);
effects.put(1022, 1012); effects.put(1022, 1012);
effects.put(1023, 1013); effects.put(1023, 1013);
effects.put(1024, 1014); effects.put(1024, 1014);
effects.put(1025, 1015); effects.put(1025, 1015);
effects.put(1026, 1016); effects.put(1026, 1016);
effects.put(1027, 1017); effects.put(1027, 1017);
effects.put(1028, 1018); effects.put(1028, 1018);
effects.put(1029, 1020); effects.put(1029, 1020);
effects.put(1030, 1021); effects.put(1030, 1021);
effects.put(1031, 1022); effects.put(1031, 1022);
effects.put(1032, -1); effects.put(1032, -1);
effects.put(1033, -1); effects.put(1033, -1);
effects.put(1034, -1); effects.put(1034, -1);
effects.put(1035, -1); effects.put(1035, -1);
effects.put(1036, 1003); effects.put(1036, 1003);
effects.put(1037, 1006); effects.put(1037, 1006);
effects.put(3000, -1); effects.put(3000, -1);
effects.put(3001, -1); effects.put(3001, -1);
} }
public static int getOldId(int id) { public static int getOldId(int id) {
return effects.getOrDefault(id, id); return effects.getOrDefault(id, id);
} }
} }
@@ -21,35 +21,34 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.data.EntityDataIndex1_9; import com.viaversion.viaversion.protocols.v1_8to1_9.data.EntityDataIndex1_9;
import com.viaversion.viaversion.util.Pair; import com.viaversion.viaversion.util.Pair;
import java.util.HashMap; import java.util.HashMap;
import java.util.Optional; import java.util.Optional;
public class EntityDataIndex1_8 { public class EntityDataIndex1_8 {
private static final HashMap<Pair<EntityTypes1_9.EntityType, Integer>, EntityDataIndex1_9> ENTITY_DATA_REWRITES = new HashMap<>(); private static final HashMap<Pair<EntityTypes1_9.EntityType, Integer>, EntityDataIndex1_9> ENTITY_DATA_REWRITES = new HashMap<>();
static { static {
for (EntityDataIndex1_9 index : EntityDataIndex1_9.values()) { for (EntityDataIndex1_9 index : EntityDataIndex1_9.values()) {
ENTITY_DATA_REWRITES.put(new Pair<>(index.getClazz(), index.getNewIndex()), index); ENTITY_DATA_REWRITES.put(new Pair<>(index.getClazz(), index.getNewIndex()), index);
} }
} }
private static Optional<EntityDataIndex1_9> 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); final Pair<EntityType, Integer> pair = new Pair<>(type, index);
return Optional.ofNullable(ENTITY_DATA_REWRITES.get(pair)); return Optional.ofNullable(ENTITY_DATA_REWRITES.get(pair));
} }
public static EntityDataIndex1_9 searchIndex(final EntityType type, final int index) { public static EntityDataIndex1_9 searchIndex(final EntityType type, final int index) {
EntityType currentType = type; EntityType currentType = type;
do { do {
final Optional<EntityDataIndex1_9> optMeta = getIndex(currentType, index); final Optional<EntityDataIndex1_9> optMeta = getIndex(currentType, index);
if (optMeta.isPresent()) { if (optMeta.isPresent()) {
return optMeta.get(); return optMeta.get();
} }
currentType = currentType.getParent(); currentType = currentType.getParent();
} while (currentType != null); } while (currentType != null);
return null; return null;
} }
} }
@@ -18,63 +18,62 @@
package com.viaversion.viarewind.protocol.v1_9to1_8.data; package com.viaversion.viarewind.protocol.v1_9to1_8.data;
import com.viaversion.viaversion.protocols.v1_8to1_9.data.PotionIdMappings1_9; import com.viaversion.viaversion.protocols.v1_8to1_9.data.PotionIdMappings1_9;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class PotionIdMappings1_8 { public class PotionIdMappings1_8 {
public static final Map<String, String> POTION_NAME_INDEX = new HashMap<>(); public static final Map<String, String> POTION_NAME_INDEX = new HashMap<>();
public static final Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>(); public static final Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>();
static { static {
POTION_NAME_TO_ID.putAll(PotionIdMappings1_9.POTION_NAME_TO_ID); POTION_NAME_TO_ID.putAll(PotionIdMappings1_9.POTION_NAME_TO_ID);
POTION_NAME_TO_ID.put("luck", 8203); // Map new potion to similar one (luck->leaping) POTION_NAME_TO_ID.put("luck", 8203); // Map new potion to similar one (luck->leaping)
POTION_NAME_INDEX.put("water", "§rWater Bottle"); POTION_NAME_INDEX.put("water", "§rWater Bottle");
POTION_NAME_INDEX.put("mundane", "§rMundane Potion"); POTION_NAME_INDEX.put("mundane", "§rMundane Potion");
POTION_NAME_INDEX.put("thick", "§rThick Potion"); POTION_NAME_INDEX.put("thick", "§rThick Potion");
POTION_NAME_INDEX.put("awkward", "§rAwkward Potion"); POTION_NAME_INDEX.put("awkward", "§rAwkward Potion");
POTION_NAME_INDEX.put("water_splash", "§rSplash Water Bottle"); POTION_NAME_INDEX.put("water_splash", "§rSplash Water Bottle");
POTION_NAME_INDEX.put("mundane_splash", "§rMundane Splash Potion"); POTION_NAME_INDEX.put("mundane_splash", "§rMundane Splash Potion");
POTION_NAME_INDEX.put("thick_splash", "§rThick Splash Potion"); POTION_NAME_INDEX.put("thick_splash", "§rThick Splash Potion");
POTION_NAME_INDEX.put("awkward_splash", "§rAwkward Splash Potion"); POTION_NAME_INDEX.put("awkward_splash", "§rAwkward Splash Potion");
POTION_NAME_INDEX.put("water_lingering", "§rLingering Water Bottle"); POTION_NAME_INDEX.put("water_lingering", "§rLingering Water Bottle");
POTION_NAME_INDEX.put("mundane_lingering", "§rMundane Lingering Potion"); POTION_NAME_INDEX.put("mundane_lingering", "§rMundane Lingering Potion");
POTION_NAME_INDEX.put("thick_lingering", "§rThick Lingering Potion"); POTION_NAME_INDEX.put("thick_lingering", "§rThick Lingering Potion");
POTION_NAME_INDEX.put("awkward_lingering", "§rAwkward Lingering Potion"); POTION_NAME_INDEX.put("awkward_lingering", "§rAwkward Lingering Potion");
POTION_NAME_INDEX.put("night_vision_lingering", "§rLingering Potion of Night Vision"); POTION_NAME_INDEX.put("night_vision_lingering", "§rLingering Potion of Night Vision");
POTION_NAME_INDEX.put("long_night_vision_lingering", "§rLingering Potion of Night Vision"); POTION_NAME_INDEX.put("long_night_vision_lingering", "§rLingering Potion of Night Vision");
POTION_NAME_INDEX.put("invisibility_lingering", "§rLingering Potion of Invisibility"); POTION_NAME_INDEX.put("invisibility_lingering", "§rLingering Potion of Invisibility");
POTION_NAME_INDEX.put("long_invisibility_lingering", "§rLingering Potion of Invisibility"); POTION_NAME_INDEX.put("long_invisibility_lingering", "§rLingering Potion of Invisibility");
POTION_NAME_INDEX.put("leaping_lingering", "§rLingering Potion of Leaping"); POTION_NAME_INDEX.put("leaping_lingering", "§rLingering Potion of Leaping");
POTION_NAME_INDEX.put("long_leaping_lingering", "§rLingering Potion of Leaping"); POTION_NAME_INDEX.put("long_leaping_lingering", "§rLingering Potion of Leaping");
POTION_NAME_INDEX.put("strong_leaping_lingering", "§rLingering Potion of Leaping"); POTION_NAME_INDEX.put("strong_leaping_lingering", "§rLingering Potion of Leaping");
POTION_NAME_INDEX.put("fire_resistance_lingering", "§rLingering Potion of Fire Resistance"); POTION_NAME_INDEX.put("fire_resistance_lingering", "§rLingering Potion of Fire Resistance");
POTION_NAME_INDEX.put("long_fire_resistance_lingering", "§rLingering Potion of Fire Resistance"); POTION_NAME_INDEX.put("long_fire_resistance_lingering", "§rLingering Potion of Fire Resistance");
POTION_NAME_INDEX.put("swiftness_lingering", "§rLingering Potion of Swiftness"); POTION_NAME_INDEX.put("swiftness_lingering", "§rLingering Potion of Swiftness");
POTION_NAME_INDEX.put("long_swiftness_lingering", "§rLingering Potion of Swiftness"); POTION_NAME_INDEX.put("long_swiftness_lingering", "§rLingering Potion of Swiftness");
POTION_NAME_INDEX.put("strong_swiftness_lingering", "§rLingering Potion of Swiftness"); POTION_NAME_INDEX.put("strong_swiftness_lingering", "§rLingering Potion of Swiftness");
POTION_NAME_INDEX.put("slowness_lingering", "§rLingering Potion of Slowness"); POTION_NAME_INDEX.put("slowness_lingering", "§rLingering Potion of Slowness");
POTION_NAME_INDEX.put("long_slowness_lingering", "§rLingering Potion of Slowness"); POTION_NAME_INDEX.put("long_slowness_lingering", "§rLingering Potion of Slowness");
POTION_NAME_INDEX.put("water_breathing_lingering", "§rLingering Potion of Water Breathing"); POTION_NAME_INDEX.put("water_breathing_lingering", "§rLingering Potion of Water Breathing");
POTION_NAME_INDEX.put("long_water_breathing_lingering", "§rLingering Potion of Water Breathing"); POTION_NAME_INDEX.put("long_water_breathing_lingering", "§rLingering Potion of Water Breathing");
POTION_NAME_INDEX.put("healing_lingering", "§rLingering Potion of Healing"); POTION_NAME_INDEX.put("healing_lingering", "§rLingering Potion of Healing");
POTION_NAME_INDEX.put("strong_healing_lingering", "§rLingering Potion of Healing"); POTION_NAME_INDEX.put("strong_healing_lingering", "§rLingering Potion of Healing");
POTION_NAME_INDEX.put("harming_lingering", "§rLingering Potion of Harming"); POTION_NAME_INDEX.put("harming_lingering", "§rLingering Potion of Harming");
POTION_NAME_INDEX.put("strong_harming_lingering", "§rLingering Potion of Harming"); POTION_NAME_INDEX.put("strong_harming_lingering", "§rLingering Potion of Harming");
POTION_NAME_INDEX.put("poison_lingering", "§rLingering Potion of Poisen"); POTION_NAME_INDEX.put("poison_lingering", "§rLingering Potion of Poisen");
POTION_NAME_INDEX.put("long_poison_lingering", "§rLingering Potion of Poisen"); POTION_NAME_INDEX.put("long_poison_lingering", "§rLingering Potion of Poisen");
POTION_NAME_INDEX.put("strong_poison_lingering", "§rLingering Potion of Poisen"); POTION_NAME_INDEX.put("strong_poison_lingering", "§rLingering Potion of Poisen");
POTION_NAME_INDEX.put("regeneration_lingering", "§rLingering Potion of Regeneration"); POTION_NAME_INDEX.put("regeneration_lingering", "§rLingering Potion of Regeneration");
POTION_NAME_INDEX.put("long_regeneration_lingering", "§rLingering Potion of Regeneration"); POTION_NAME_INDEX.put("long_regeneration_lingering", "§rLingering Potion of Regeneration");
POTION_NAME_INDEX.put("strong_regeneration_lingering", "§rLingering Potion of Regeneration"); POTION_NAME_INDEX.put("strong_regeneration_lingering", "§rLingering Potion of Regeneration");
POTION_NAME_INDEX.put("strength_lingering", "§rLingering Potion of Strength"); POTION_NAME_INDEX.put("strength_lingering", "§rLingering Potion of Strength");
POTION_NAME_INDEX.put("long_strength_lingering", "§rLingering Potion of Strength"); POTION_NAME_INDEX.put("long_strength_lingering", "§rLingering Potion of Strength");
POTION_NAME_INDEX.put("strong_strength_lingering", "§rLingering Potion of Strength"); POTION_NAME_INDEX.put("strong_strength_lingering", "§rLingering Potion of Strength");
POTION_NAME_INDEX.put("weakness_lingering", "§rLingering Potion of Weakness"); POTION_NAME_INDEX.put("weakness_lingering", "§rLingering Potion of Weakness");
POTION_NAME_INDEX.put("long_weakness_lingering", "§rLingering Potion of Weakness"); POTION_NAME_INDEX.put("long_weakness_lingering", "§rLingering Potion of Weakness");
POTION_NAME_INDEX.put("luck_lingering", "§rLingering Potion of Luck"); POTION_NAME_INDEX.put("luck_lingering", "§rLingering Potion of Luck");
POTION_NAME_INDEX.put("luck", "§rPotion of Luck"); POTION_NAME_INDEX.put("luck", "§rPotion of Luck");
POTION_NAME_INDEX.put("luck_splash", "§rSplash Potion of Luck"); POTION_NAME_INDEX.put("luck_splash", "§rSplash Potion of Luck");
} }
} }
@@ -17,32 +17,32 @@
*/ */
package com.viaversion.viarewind.protocol.v1_9to1_8.data; package com.viaversion.viarewind.protocol.v1_9to1_8.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viarewind.api.data.RewindMappingDataLoader; import com.viaversion.viarewind.api.data.RewindMappingDataLoader;
import com.viaversion.viaversion.libs.fastutil.objects.ObjectArrayList; import com.viaversion.viaversion.libs.fastutil.objects.ObjectArrayList;
import com.viaversion.viaversion.libs.fastutil.objects.ObjectList; import com.viaversion.viaversion.libs.fastutil.objects.ObjectList;
import com.viaversion.viaversion.libs.gson.JsonArray; import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonElement; import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
public final class RewindMappingData1_8 extends com.viaversion.viarewind.api.data.RewindMappingData { public final class RewindMappingData1_8 extends com.viaversion.viarewind.api.data.RewindMappingData {
private final ObjectList<String> sounds = new ObjectArrayList<>(); private final ObjectList<String> sounds = new ObjectArrayList<>();
public RewindMappingData1_8() { public RewindMappingData1_8() {
super("1.9.4", "1.8"); super("1.9.4", "1.8");
} }
@Override @Override
protected void loadExtras(CompoundTag data) { protected void loadExtras(CompoundTag data) {
super.loadExtras(data); super.loadExtras(data);
final JsonArray sounds = RewindMappingDataLoader.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) { for (final JsonElement sound : sounds) {
this.sounds.add(sound.getAsString()); this.sounds.add(sound.getAsString());
} }
} }
public String soundName(final int soundId) { public String soundName(final int soundId) {
return sounds.get(soundId); return sounds.get(soundId);
} }
} }
@@ -28,224 +28,225 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8; import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import java.util.ArrayList;
import java.util.*; import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class WitherBossBar implements BossBar { public class WitherBossBar implements BossBar {
private static int highestId = Integer.MAX_VALUE - 10000; private static int highestId = Integer.MAX_VALUE - 10000;
private final UUID uuid; private final UUID uuid;
private String title; private final UserConnection connection;
private float health; private final int entityId = highestId++;
private boolean visible = false; private String title;
private float health;
private boolean visible = false;
private double locX, locY, locZ;
private final UserConnection connection; public WitherBossBar(UserConnection connection, UUID uuid, String title, float health) {
this.connection = connection;
this.uuid = uuid;
this.title = title;
this.health = health;
}
private final int entityId = highestId++; @Override
private double locX, locY, locZ; public String getTitle() {
return title;
}
public WitherBossBar(UserConnection connection, UUID uuid, String title, float health) { @Override
this.connection = connection; public BossBar setTitle(String title) {
this.uuid = uuid; this.title = title;
this.title = title; if (this.visible) {
this.health = health; updateEntityData();
} }
return this;
}
@Override @Override
public String getTitle() { public float getHealth() {
return title; return health;
} }
@Override @Override
public BossBar setTitle(String title) { public BossBar setHealth(float health) {
this.title = title; this.health = health;
if (this.visible) { if (this.health <= 0) {
updateEntityData(); this.health = 0.0001f;
} }
return this; if (this.visible) {
} updateEntityData();
}
return this;
}
@Override @Override
public float getHealth() { public BossColor getColor() {
return health; return null;
} }
@Override @Override
public BossBar setHealth(float health) { public BossBar setColor(BossColor bossColor) {
this.health = health; throw new UnsupportedOperationException(this.getClass().getName() + " does not support color");
if (this.health <= 0) { }
this.health = 0.0001f;
}
if (this.visible) {
updateEntityData();
}
return this;
}
@Override @Override
public BossColor getColor() { public BossStyle getStyle() {
return null; return null;
} }
@Override @Override
public BossBar setColor(BossColor bossColor) { public BossBar setStyle(BossStyle bossStyle) {
throw new UnsupportedOperationException(this.getClass().getName() + " does not support color"); throw new UnsupportedOperationException(this.getClass().getName() + " does not support styles");
} }
@Override @Override
public BossStyle getStyle() { public BossBar addPlayer(UUID uuid) {
return null; throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!");
} }
@Override @Override
public BossBar setStyle(BossStyle bossStyle) { public BossBar addConnection(UserConnection userConnection) {
throw new UnsupportedOperationException(this.getClass().getName() + " does not support styles"); throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!");
} }
@Override @Override
public BossBar addPlayer(UUID uuid) { public BossBar removePlayer(UUID uuid) {
throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!"); throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!");
} }
@Override @Override
public BossBar addConnection(UserConnection userConnection) { public BossBar removeConnection(UserConnection userConnection) {
throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!"); throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!");
} }
@Override @Override
public BossBar removePlayer(UUID uuid) { public BossBar addFlag(BossFlag bossFlag) {
throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!"); throw new UnsupportedOperationException(this.getClass().getName() + " does not support flags");
} }
@Override @Override
public BossBar removeConnection(UserConnection userConnection) { public BossBar removeFlag(BossFlag bossFlag) {
throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!"); throw new UnsupportedOperationException(this.getClass().getName() + " does not support flags");
} }
@Override @Override
public BossBar addFlag(BossFlag bossFlag) { public boolean hasFlag(BossFlag bossFlag) {
throw new UnsupportedOperationException(this.getClass().getName() + " does not support flags"); return false;
} }
@Override @Override
public BossBar removeFlag(BossFlag bossFlag) { public Set<UUID> getPlayers() {
throw new UnsupportedOperationException(this.getClass().getName() + " does not support flags"); return Collections.singleton(connection.getProtocolInfo().getUuid());
} }
@Override @Override
public boolean hasFlag(BossFlag bossFlag) { public Set<UserConnection> getConnections() {
return false; throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!");
} }
@Override @Override
public Set<UUID> getPlayers() { public BossBar show() {
return Collections.singleton(connection.getProtocolInfo().getUuid()); if (!this.visible) {
} addWither();
this.visible = true;
}
return this;
}
@Override @Override
public Set<UserConnection> getConnections() { public BossBar hide() {
throw new UnsupportedOperationException(this.getClass().getName() + " is only for one UserConnection!"); if (this.visible) {
} removeWither();
this.visible = false;
}
return this;
}
@Override @Override
public BossBar show() { public boolean isVisible() {
if (!this.visible) { return visible;
addWither(); }
this.visible = true;
}
return this;
}
@Override @Override
public BossBar hide() { public UUID getId() {
if (this.visible) { return this.uuid;
removeWither(); }
this.visible = false;
}
return this;
}
@Override public void setLocation(double x, double y, double z) {
public boolean isVisible() { locX = x;
return visible; locY = y;
} locZ = z;
updateLocation();
}
@Override private void addWither() {
public UUID getId() { final PacketWrapper addMob = PacketWrapper.create(ClientboundPackets1_7_2_5.ADD_MOB, this.connection);
return this.uuid; 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);
public void setLocation(double x, double y, double z) { final List<EntityData> entityData = new ArrayList<>();
locX = x; entityData.add(new EntityData(0, EntityDataTypes1_8.BYTE, (byte) 0x20));
locY = y; entityData.add(new EntityData(2, EntityDataTypes1_8.STRING, title));
locZ = z; entityData.add(new EntityData(3, EntityDataTypes1_8.BYTE, (byte) 1));
updateLocation(); entityData.add(new EntityData(6, EntityDataTypes1_8.FLOAT, health * 300f));
}
private void addWither() { addMob.write(Types.ENTITY_DATA_LIST1_8, entityData);
final PacketWrapper addMob = PacketWrapper.create(ClientboundPackets1_7_2_5.ADD_MOB, this.connection); addMob.scheduleSend(Protocol1_9To1_8.class);
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);
final List<EntityData> entityData = new ArrayList<>(); private void updateLocation() {
entityData.add(new EntityData(0, EntityDataTypes1_8.BYTE, (byte) 0x20)); final PacketWrapper teleportEntity = PacketWrapper.create(ClientboundPackets1_7_2_5.TELEPORT_ENTITY, this.connection);
entityData.add(new EntityData(2, EntityDataTypes1_8.STRING, title)); teleportEntity.write(Types.VAR_INT, entityId);
entityData.add(new EntityData(3, EntityDataTypes1_8.BYTE, (byte) 1)); teleportEntity.write(Types.INT, (int) (locX * 32D));
entityData.add(new EntityData(6, EntityDataTypes1_8.FLOAT, health * 300f)); 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);
}
addMob.write(Types.ENTITY_DATA_LIST1_8, entityData); private void updateEntityData() {
addMob.scheduleSend(Protocol1_9To1_8.class); final PacketWrapper setEntityData = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_ENTITY_DATA, this.connection);
} setEntityData.write(Types.VAR_INT, entityId);
private void updateLocation() { final List<EntityData> entityData = new ArrayList<>();
final PacketWrapper teleportEntity = PacketWrapper.create(ClientboundPackets1_7_2_5.TELEPORT_ENTITY, this.connection); entityData.add(new EntityData(2, EntityDataTypes1_8.STRING, title));
teleportEntity.write(Types.VAR_INT, entityId); entityData.add(new EntityData(6, EntityDataTypes1_8.FLOAT, health * 300f));
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 updateEntityData() { setEntityData.write(Types.ENTITY_DATA_LIST1_8, entityData);
final PacketWrapper setEntityData = PacketWrapper.create(ClientboundPackets1_7_2_5.SET_ENTITY_DATA, this.connection); setEntityData.scheduleSend(Protocol1_9To1_8.class);
setEntityData.write(Types.VAR_INT, entityId); }
final List<EntityData> entityData = new ArrayList<>(); private void removeWither() {
entityData.add(new EntityData(2, EntityDataTypes1_8.STRING, title)); final PacketWrapper removeEntity = PacketWrapper.create(ClientboundPackets1_7_2_5.REMOVE_ENTITIES, this.connection);
entityData.add(new EntityData(6, EntityDataTypes1_8.FLOAT, health * 300f)); removeEntity.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[]{entityId});
removeEntity.scheduleSend(Protocol1_9To1_8.class);
}
setEntityData.write(Types.ENTITY_DATA_LIST1_8, entityData); public void setPlayerLocation(double posX, double posY, double posZ, float yaw, float pitch) {
setEntityData.scheduleSend(Protocol1_9To1_8.class); double yawR = Math.toRadians(yaw);
} double pitchR = Math.toRadians(pitch);
private void removeWither() { posX -= Math.cos(pitchR) * Math.sin(yawR) * 48;
final PacketWrapper removeEntity = PacketWrapper.create(ClientboundPackets1_7_2_5.REMOVE_ENTITIES, this.connection); posY -= Math.sin(pitchR) * 48;
removeEntity.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[]{entityId}); posZ += Math.cos(pitchR) * Math.cos(yawR) * 48;
removeEntity.scheduleSend(Protocol1_9To1_8.class);
}
public void setPlayerLocation(double posX, double posY, double posZ, float yaw, float pitch) { setLocation(posX, posY, posZ);
double yawR = Math.toRadians(yaw); }
double pitchR = Math.toRadians(pitch);
posX -= Math.cos(pitchR) * Math.sin(yawR) * 48;
posY -= Math.sin(pitchR) * 48;
posZ += Math.cos(pitchR) * Math.cos(yawR) * 48;
setLocation(posX, posY, posZ);
}
} }
@@ -17,6 +17,11 @@
*/ */
package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter; package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter; import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viarewind.api.rewriter.VRBlockItemRewriter; import com.viaversion.viarewind.api.rewriter.VRBlockItemRewriter;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8; import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
@@ -26,315 +31,313 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types; 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.EntityIds1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.data.PotionIdMappings1_9; 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.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
import com.viaversion.viaversion.util.Key; import com.viaversion.viaversion.util.Key;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundPackets1_9, ServerboundPackets1_8, Protocol1_9To1_8> { public class BlockItemPacketRewriter1_9 extends VRBlockItemRewriter<ClientboundPackets1_9, ServerboundPackets1_8, Protocol1_9To1_8> {
public final Set<String> VALID_ATTRIBUTES = new HashSet<>(); public final Set<String> VALID_ATTRIBUTES = new HashSet<>();
private LegacyEnchantmentRewriter enchantmentRewriter; private LegacyEnchantmentRewriter enchantmentRewriter;
public BlockItemPacketRewriter1_9(Protocol1_9To1_8 protocol) { public BlockItemPacketRewriter1_9(Protocol1_9To1_8 protocol) {
super(protocol, "1.9"); super(protocol, "1.9");
VALID_ATTRIBUTES.add("generic.maxHealth"); VALID_ATTRIBUTES.add("generic.maxHealth");
VALID_ATTRIBUTES.add("generic.followRange"); VALID_ATTRIBUTES.add("generic.followRange");
VALID_ATTRIBUTES.add("generic.knockbackResistance"); VALID_ATTRIBUTES.add("generic.knockbackResistance");
VALID_ATTRIBUTES.add("generic.movementSpeed"); VALID_ATTRIBUTES.add("generic.movementSpeed");
VALID_ATTRIBUTES.add("generic.attackDamage"); VALID_ATTRIBUTES.add("generic.attackDamage");
VALID_ATTRIBUTES.add("horse.jumpStrength"); VALID_ATTRIBUTES.add("horse.jumpStrength");
VALID_ATTRIBUTES.add("zombie.spawnReinforcements"); VALID_ATTRIBUTES.add("zombie.spawnReinforcements");
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
registerBlockChange(ClientboundPackets1_9.BLOCK_UPDATE); registerBlockChange(ClientboundPackets1_9.BLOCK_UPDATE);
registerMultiBlockChange(ClientboundPackets1_9.CHUNK_BLOCKS_UPDATE); registerMultiBlockChange(ClientboundPackets1_9.CHUNK_BLOCKS_UPDATE);
registerSetCreativeModeSlot(ServerboundPackets1_8.SET_CREATIVE_MODE_SLOT); registerSetCreativeModeSlot(ServerboundPackets1_8.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_CLOSE, wrapper -> { protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_CLOSE, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
final WindowTracker tracker = wrapper.user().get(WindowTracker.class); final WindowTracker tracker = wrapper.user().get(WindowTracker.class);
final String windowType = tracker.get(windowId); final String windowType = tracker.get(windowId);
if (windowType != null && windowType.equalsIgnoreCase("minecraft:enchanting_table")) { if (windowType != null && windowType.equalsIgnoreCase("minecraft:enchanting_table")) {
tracker.clearEnchantmentProperties(); tracker.clearEnchantmentProperties();
} }
tracker.remove(windowId); tracker.remove(windowId);
}); });
protocol.registerClientbound(ClientboundPackets1_9.OPEN_SCREEN, wrapper -> { protocol.registerClientbound(ClientboundPackets1_9.OPEN_SCREEN, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
final String windowType = wrapper.passthrough(Types.STRING); final String windowType = wrapper.passthrough(Types.STRING);
wrapper.user().get(WindowTracker.class).put(windowId, windowType); wrapper.user().get(WindowTracker.class).put(windowId, windowType);
}); });
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_CONTENT, wrapper -> { protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_CONTENT, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
Item[] items = wrapper.read(Types.ITEM1_8_SHORT_ARRAY); Item[] items = wrapper.read(Types.ITEM1_8_SHORT_ARRAY);
for (int i = 0; i < items.length; i++) { for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(wrapper.user(), items[i]); items[i] = handleItemToClient(wrapper.user(), items[i]);
} }
if (windowId == 0 && items.length == 46) { if (windowId == 0 && items.length == 46) {
Item[] old = items; Item[] old = items;
items = new Item[45]; items = new Item[45];
System.arraycopy(old, 0, items, 0, 45); System.arraycopy(old, 0, items, 0, 45);
} else { } else {
final String type = wrapper.user().get(WindowTracker.class).get(windowId); final String type = wrapper.user().get(WindowTracker.class).get(windowId);
if (type != null && type.equalsIgnoreCase("minecraft:brewing_stand")) { if (type != null && type.equalsIgnoreCase("minecraft:brewing_stand")) {
System.arraycopy(items, 0, wrapper.user().get(WindowTracker.class).getBrewingItems(windowId), 0, 4); System.arraycopy(items, 0, wrapper.user().get(WindowTracker.class).getBrewingItems(windowId), 0, 4);
WindowTracker.updateBrewingStand(wrapper.user(), items[4], windowId); WindowTracker.updateBrewingStand(wrapper.user(), items[4], windowId);
Item[] old = items; Item[] old = items;
items = new Item[old.length - 1]; items = new Item[old.length - 1];
System.arraycopy(old, 0, items, 0, 4); System.arraycopy(old, 0, items, 0, 4);
System.arraycopy(old, 5, items, 4, old.length - 5); System.arraycopy(old, 5, items, 4, old.length - 5);
} }
} }
wrapper.write(Types.ITEM1_8_SHORT_ARRAY, items); wrapper.write(Types.ITEM1_8_SHORT_ARRAY, items);
}); });
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_SLOT, wrapper -> { protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_SLOT, wrapper -> {
final byte windowId = wrapper.passthrough(Types.BYTE); final byte windowId = wrapper.passthrough(Types.BYTE);
final short slot = wrapper.passthrough(Types.SHORT); final short slot = wrapper.passthrough(Types.SHORT);
final Item item = wrapper.passthrough(Types.ITEM1_8); final Item item = wrapper.passthrough(Types.ITEM1_8);
handleItemToClient(wrapper.user(), item); handleItemToClient(wrapper.user(), item);
if (windowId == 0 && slot == 45) { if (windowId == 0 && slot == 45) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
final WindowTracker windowTracker = wrapper.user().get(WindowTracker.class); final WindowTracker windowTracker = wrapper.user().get(WindowTracker.class);
final String windowType = windowTracker.get(windowId); final String windowType = windowTracker.get(windowId);
if (windowType != null && windowType.equalsIgnoreCase("minecraft:brewing_stand")) { if (windowType != null && windowType.equalsIgnoreCase("minecraft:brewing_stand")) {
if (slot > 4) { if (slot > 4) {
wrapper.set(Types.SHORT, 0, (short) (slot - 1)); wrapper.set(Types.SHORT, 0, (short) (slot - 1));
} else if (slot == 4) { } else if (slot == 4) {
wrapper.cancel(); wrapper.cancel();
WindowTracker.updateBrewingStand(wrapper.user(), wrapper.get(Types.ITEM1_8, 0), windowId); WindowTracker.updateBrewingStand(wrapper.user(), wrapper.get(Types.ITEM1_8, 0), windowId);
} else { } else {
windowTracker.getBrewingItems(windowId)[slot] = wrapper.get(Types.ITEM1_8, 0); windowTracker.getBrewingItems(windowId)[slot] = wrapper.get(Types.ITEM1_8, 0);
} }
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.CONTAINER_CLOSE, wrapper -> { protocol.registerServerbound(ServerboundPackets1_8.CONTAINER_CLOSE, wrapper -> {
final byte windowId = wrapper.passthrough(Types.BYTE); final byte windowId = wrapper.passthrough(Types.BYTE);
wrapper.user().get(WindowTracker.class).remove(windowId); wrapper.user().get(WindowTracker.class).remove(windowId);
}); });
protocol.registerServerbound(ServerboundPackets1_8.CONTAINER_CLICK, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.CONTAINER_CLICK, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BYTE); // Window id map(Types.BYTE); // Window id
map(Types.SHORT); // Slot map(Types.SHORT); // Slot
map(Types.BYTE); // Button map(Types.BYTE); // Button
map(Types.SHORT); // Action number map(Types.SHORT); // Action number
map(Types.BYTE, Types.VAR_INT); // Mode map(Types.BYTE, Types.VAR_INT); // Mode
map(Types.ITEM1_8); // Clicked item map(Types.ITEM1_8); // Clicked item
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0))); handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
handler(wrapper -> { handler(wrapper -> {
final byte windowId = wrapper.get(Types.BYTE, 0); final byte windowId = wrapper.get(Types.BYTE, 0);
final String windowType = wrapper.user().get(WindowTracker.class).get(windowId); final String windowType = wrapper.user().get(WindowTracker.class).get(windowId);
if (windowType != null && windowType.equalsIgnoreCase("minecraft:brewing_stand")) { if (windowType != null && windowType.equalsIgnoreCase("minecraft:brewing_stand")) {
final short slot = wrapper.get(Types.SHORT, 0); final short slot = wrapper.get(Types.SHORT, 0);
if (slot > 3) { if (slot > 3) {
wrapper.set(Types.SHORT, 0, (short) (slot + 1)); wrapper.set(Types.SHORT, 0, (short) (slot + 1));
} }
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_DATA, wrapper -> { protocol.registerClientbound(ClientboundPackets1_9.CONTAINER_SET_DATA, wrapper -> {
final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE); final short windowId = wrapper.passthrough(Types.UNSIGNED_BYTE);
short key = wrapper.read(Types.SHORT); short key = wrapper.read(Types.SHORT);
short value = wrapper.read(Types.SHORT); short value = wrapper.read(Types.SHORT);
final WindowTracker tracker = wrapper.user().get(WindowTracker.class); final WindowTracker tracker = wrapper.user().get(WindowTracker.class);
final String windowType = tracker.get(windowId); final String windowType = tracker.get(windowId);
if (windowType != null && windowType.equalsIgnoreCase("minecraft:enchanting_table")) { if (windowType != null && windowType.equalsIgnoreCase("minecraft:enchanting_table")) {
if (key >= 4 && key <= 6) { // Store enchantment ids if (key >= 4 && key <= 6) { // Store enchantment ids
tracker.putEnchantmentProperty(key, value); tracker.putEnchantmentProperty(key, value);
wrapper.cancel(); wrapper.cancel();
} else if (key >= 7 && key <= 9) { // Mix levels with tracked ids } else if (key >= 7 && key <= 9) { // Mix levels with tracked ids
key -= 3; key -= 3;
final short property = tracker.getEnchantmentValue(key); final short property = tracker.getEnchantmentValue(key);
value = (short) (property | (value << 8)); value = (short) (property | (value << 8));
} }
} }
wrapper.write(Types.SHORT, key); wrapper.write(Types.SHORT, key);
wrapper.write(Types.SHORT, value); wrapper.write(Types.SHORT, value);
}); });
} }
@Override @Override
protected void registerRewrites() { protected void registerRewrites() {
enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName()); enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName());
enchantmentRewriter.registerEnchantment(9, "§7Frost Walker"); enchantmentRewriter.registerEnchantment(9, "§7Frost Walker");
enchantmentRewriter.registerEnchantment(70, "§7Mending"); enchantmentRewriter.registerEnchantment(70, "§7Mending");
} }
@Override @Override
public Item handleItemToClient(UserConnection connection, Item item) { public Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null; if (item == null) return null;
super.handleItemToClient(connection, item); super.handleItemToClient(connection, item);
CompoundTag tag = item.tag(); CompoundTag tag = item.tag();
enchantmentRewriter.handleToClient(item); enchantmentRewriter.handleToClient(item);
CompoundTag displayTag = tag == null ? null : tag.getCompoundTag("display"); CompoundTag displayTag = tag == null ? null : tag.getCompoundTag("display");
if (item.data() != 0) { if (item.data() != 0) {
final ByteTag unbreakableTag = tag == null ? null : tag.getByteTag("Unbreakable"); final ByteTag unbreakableTag = tag == null ? null : tag.getByteTag("Unbreakable");
if (unbreakableTag != null && unbreakableTag.asByte() != 0) { if (unbreakableTag != null && unbreakableTag.asByte() != 0) {
tag.put(nbtTagName() + "|Unbreakable", new ByteTag(unbreakableTag.asByte())); tag.put(nbtTagName() + "|Unbreakable", new ByteTag(unbreakableTag.asByte()));
tag.remove("Unbreakable"); tag.remove("Unbreakable");
if (displayTag == null) { // Remove the display tag again if it was only added to emulate 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("display", displayTag = new CompoundTag());
tag.put(nbtTagName() + "|noDisplay", new ByteTag(true)); tag.put(nbtTagName() + "|noDisplay", new ByteTag(true));
} }
ListTag<StringTag> loreTag = displayTag.getListTag("Lore", StringTag.class); ListTag<StringTag> loreTag = displayTag.getListTag("Lore", StringTag.class);
if (loreTag == null) { if (loreTag == null) {
displayTag.put("Lore", loreTag = new ListTag<>(StringTag.class)); displayTag.put("Lore", loreTag = new ListTag<>(StringTag.class));
} }
loreTag.add(new StringTag("§9Unbreakable")); loreTag.add(new StringTag("§9Unbreakable"));
} }
} }
if (item.identifier() == 383 && item.data() == 0) { // Spawn eggs if (item.identifier() == 383 && item.data() == 0) { // Spawn eggs
int data = 0; int data = 0;
final CompoundTag entityTag = tag == null ? null : tag.getCompoundTag("EntityTag"); final CompoundTag entityTag = tag == null ? null : tag.getCompoundTag("EntityTag");
if (entityTag != null) { if (entityTag != null) {
final StringTag idTag = entityTag.getStringTag("id"); final StringTag idTag = entityTag.getStringTag("id");
if (idTag != null) { if (idTag != null) {
final String id = idTag.getValue(); final String id = idTag.getValue();
if (EntityIds1_8.ENTITY_NAME_TO_ID.containsKey(id)) { if (EntityIds1_8.ENTITY_NAME_TO_ID.containsKey(id)) {
data = EntityIds1_8.ENTITY_NAME_TO_ID.get(id); data = EntityIds1_8.ENTITY_NAME_TO_ID.get(id);
} else if (displayTag == null) { } else if (displayTag == null) {
tag.put("display", displayTag = new CompoundTag()); tag.put("display", displayTag = new CompoundTag());
tag.put(nbtTagName() + "|noDisplay", new ByteTag(true)); tag.put(nbtTagName() + "|noDisplay", new ByteTag(true));
displayTag.put("Name", new StringTag("§rSpawn " + id)); displayTag.put("Name", new StringTag("§rSpawn " + id));
} }
} }
} }
item.setData((short) data); item.setData((short) data);
} }
// Potion, splash potion, lingering potion // Potion, splash potion, lingering potion
final boolean potion = item.identifier() == 373; final boolean potion = item.identifier() == 373;
final boolean splashPotion = item.identifier() == 438; final boolean splashPotion = item.identifier() == 438;
final boolean lingeringPotion = item.identifier() == 441; final boolean lingeringPotion = item.identifier() == 441;
if (potion || splashPotion || lingeringPotion) { if (potion || splashPotion || lingeringPotion) {
int data = 0; int data = 0;
final StringTag potionTag = tag == null ? null : tag.getStringTag("Potion"); final StringTag potionTag = tag == null ? null : tag.getStringTag("Potion");
if (potionTag != null) { if (potionTag != null) {
String potionName = Key.stripMinecraftNamespace(potionTag.getValue()); String potionName = Key.stripMinecraftNamespace(potionTag.getValue());
if (PotionIdMappings1_8.POTION_NAME_TO_ID.containsKey(potionName)) { if (PotionIdMappings1_8.POTION_NAME_TO_ID.containsKey(potionName)) {
data = PotionIdMappings1_8.POTION_NAME_TO_ID.get(potionName); data = PotionIdMappings1_8.POTION_NAME_TO_ID.get(potionName);
} }
if (splashPotion) { if (splashPotion) {
potionName += "_splash"; potionName += "_splash";
} else if (lingeringPotion) { } else if (lingeringPotion) {
potionName += "_lingering"; potionName += "_lingering";
} }
// Don't override custom name // Don't override custom name
if ((displayTag == null || !displayTag.contains("Name")) && PotionIdMappings1_8.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("display", displayTag = new CompoundTag());
tag.put(nbtTagName() + "|noDisplay", new ByteTag(true)); tag.put(nbtTagName() + "|noDisplay", new ByteTag(true));
displayTag.put("Name", new StringTag(PotionIdMappings1_8.POTION_NAME_INDEX.get(potionName))); displayTag.put("Name", new StringTag(PotionIdMappings1_8.POTION_NAME_INDEX.get(potionName)));
} }
} }
if (splashPotion || lingeringPotion) { // Convert splash and lingering potions to normal potions if (splashPotion || lingeringPotion) { // Convert splash and lingering potions to normal potions
item.setIdentifier(373); item.setIdentifier(373);
data += 8192; data += 8192;
} }
item.setData((short) data); item.setData((short) data);
} }
final ListTag<CompoundTag> attributeModifiers = tag == null ? null : tag.getListTag("AttributeModifiers", CompoundTag.class); final ListTag<CompoundTag> attributeModifiers = tag == null ? null : tag.getListTag("AttributeModifiers", CompoundTag.class);
if (attributeModifiers != null) { if (attributeModifiers != null) {
tag.put(nbtTagName() + "|AttributeModifiers", attributeModifiers.copy()); tag.put(nbtTagName() + "|AttributeModifiers", attributeModifiers.copy());
attributeModifiers.getValue().removeIf(entries -> { attributeModifiers.getValue().removeIf(entries -> {
final StringTag nameTag = entries.getStringTag("AttributeName"); final StringTag nameTag = entries.getStringTag("AttributeName");
return nameTag != null && !VALID_ATTRIBUTES.contains(nameTag.getValue()); return nameTag != null && !VALID_ATTRIBUTES.contains(nameTag.getValue());
}); });
} }
return item; return item;
} }
@Override @Override
public Item handleItemToServer(UserConnection connection, Item item) { public Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null; if (item == null) return null;
super.handleItemToServer(connection, item); super.handleItemToServer(connection, item);
CompoundTag tag = item.tag(); CompoundTag tag = item.tag();
enchantmentRewriter.handleToServer(item); enchantmentRewriter.handleToServer(item);
if (item.identifier() == 383 && item.data() != 0) { // Spawn eggs if (item.identifier() == 383 && item.data() != 0) { // Spawn eggs
if ((tag == null || !tag.contains("EntityTag")) && EntityIds1_8.ENTITY_ID_TO_NAME.containsKey((int) item.data())) { if ((tag == null || !tag.contains("EntityTag")) && EntityIds1_8.ENTITY_ID_TO_NAME.containsKey((int) item.data())) {
if (tag == null) { if (tag == null) {
item.setTag(tag = new CompoundTag()); item.setTag(tag = new CompoundTag());
} }
final CompoundTag entityTag = new CompoundTag(); final CompoundTag entityTag = new CompoundTag();
entityTag.put("id", new StringTag(EntityIds1_8.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); tag.put("EntityTag", entityTag);
} }
item.setData((short) 0); item.setData((short) 0);
} }
if (item.identifier() == 373 && (tag == null || !tag.contains("Potion"))) { // Potions if (item.identifier() == 373 && (tag == null || !tag.contains("Potion"))) { // Potions
if (item.data() >= 16384) { if (item.data() >= 16384) {
item.setIdentifier(438); item.setIdentifier(438);
item.setData((short) (item.data() - 8192)); item.setData((short) (item.data() - 8192));
} }
if (tag == null) { if (tag == null) {
item.setTag(tag = new CompoundTag()); item.setTag(tag = new CompoundTag());
final String name = item.data() == 8192 ? "water" : PotionIdMappings1_9.potionNameFromDamage(item.data()); final String name = item.data() == 8192 ? "water" : PotionIdMappings1_9.potionNameFromDamage(item.data());
tag.put("Potion", new StringTag("minecraft:" + name)); tag.put("Potion", new StringTag("minecraft:" + name));
} }
item.setData((short) 0); item.setData((short) 0);
} }
if (tag == null) { if (tag == null) {
return item; return item;
} }
final Tag noDisplayTag = tag.remove(nbtTagName() + "|noDisplay"); final Tag noDisplayTag = tag.remove(nbtTagName() + "|noDisplay");
if (noDisplayTag != null) { if (noDisplayTag != null) {
tag.remove("display"); tag.remove("display");
if (tag.isEmpty()) { if (tag.isEmpty()) {
item.setTag(null); item.setTag(null);
} }
} }
final Tag unbreakableTag = tag.remove(nbtTagName() + "|Unbreakable"); final Tag unbreakableTag = tag.remove(nbtTagName() + "|Unbreakable");
if (unbreakableTag != null) { if (unbreakableTag != null) {
tag.put("Unbreakable", unbreakableTag); tag.put("Unbreakable", unbreakableTag);
} }
final Tag attributeModifiersTag = tag.remove(nbtTagName() + "|AttributeModifiers"); final Tag attributeModifiersTag = tag.remove(nbtTagName() + "|AttributeModifiers");
if (attributeModifiersTag != null) { if (attributeModifiersTag != null) {
tag.put("AttributeModifiers", attributeModifiersTag); tag.put("AttributeModifiers", attributeModifiersTag);
} }
return item; return item;
} }
} }
@@ -17,512 +17,515 @@
*/ */
package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter; package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viarewind.ViaRewind; import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.api.type.RewindTypes; import com.viaversion.viarewind.api.type.RewindTypes;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8; import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.*; import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BlockPlaceDestroyTracker;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BossBarStorage;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CooldownStorage;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.EntityTracker1_9;
import com.viaversion.viarewind.protocol.v1_9to1_8.storage.PlayerPositionTracker;
import com.viaversion.viarewind.utils.ChatUtil; import com.viaversion.viarewind.utils.ChatUtil;
import com.viaversion.viaversion.api.data.entity.EntityTracker; import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.BlockPosition; import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9; 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.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8; import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.rewriter.RewriterBase; import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement; 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.libs.gson.JsonParser; import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_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.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_9; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_9;
import com.viaversion.viaversion.util.StringUtil; import com.viaversion.viaversion.util.StringUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> { public class PlayerPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
public PlayerPacketRewriter1_9(Protocol1_9To1_8 protocol) { public PlayerPacketRewriter1_9(Protocol1_9To1_8 protocol) {
super(protocol); super(protocol);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9.BOSS_EVENT, null, wrapper -> { protocol.registerClientbound(ClientboundPackets1_9.BOSS_EVENT, null, wrapper -> {
wrapper.cancel(); wrapper.cancel();
final BossBarStorage bossbar = wrapper.user().get(BossBarStorage.class); final BossBarStorage bossbar = wrapper.user().get(BossBarStorage.class);
final UUID uuid = wrapper.read(Types.UUID); final UUID uuid = wrapper.read(Types.UUID);
final int action = wrapper.read(Types.VAR_INT); final int action = wrapper.read(Types.VAR_INT);
if (action == 0 /* add */) { if (action == 0 /* add */) {
final JsonElement title = wrapper.read(Types.COMPONENT); final JsonElement title = wrapper.read(Types.COMPONENT);
final float health = wrapper.read(Types.FLOAT); final float health = wrapper.read(Types.FLOAT);
wrapper.read(Types.VAR_INT); // Color wrapper.read(Types.VAR_INT); // Color
wrapper.read(Types.VAR_INT); // Division wrapper.read(Types.VAR_INT); // Division
wrapper.read(Types.UNSIGNED_BYTE); // Flags wrapper.read(Types.UNSIGNED_BYTE); // Flags
bossbar.add(uuid, ChatUtil.jsonToLegacy(title), health); bossbar.add(uuid, ChatUtil.jsonToLegacy(title), health);
} else if (action == 1 /* remove */) { } else if (action == 1 /* remove */) {
bossbar.remove(uuid); bossbar.remove(uuid);
} else if (action == 2 /* update health */) { } else if (action == 2 /* update health */) {
final float health = wrapper.read(Types.FLOAT); final float health = wrapper.read(Types.FLOAT);
bossbar.updateHealth(uuid, health); bossbar.updateHealth(uuid, health);
} else if (action == 3 /* update title */) { } else if (action == 3 /* update title */) {
final JsonElement title = wrapper.read(Types.COMPONENT); final JsonElement title = wrapper.read(Types.COMPONENT);
bossbar.updateTitle(uuid, ChatUtil.jsonToLegacy(title)); bossbar.updateTitle(uuid, ChatUtil.jsonToLegacy(title));
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.SET_PLAYER_TEAM, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.SET_PLAYER_TEAM, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Team name map(Types.STRING); // Team name
map(Types.BYTE); // Mode map(Types.BYTE); // Mode
handler(wrapper -> { handler(wrapper -> {
final byte mode = wrapper.get(Types.BYTE, 0); final byte mode = wrapper.get(Types.BYTE, 0);
if (mode == 0 /* create team */ || mode == 2 /* update team info */) { if (mode == 0 /* create team */ || mode == 2 /* update team info */) {
wrapper.passthrough(Types.STRING); // Display name wrapper.passthrough(Types.STRING); // Display name
wrapper.passthrough(Types.STRING); // Prefix wrapper.passthrough(Types.STRING); // Prefix
wrapper.passthrough(Types.STRING); // Suffix wrapper.passthrough(Types.STRING); // Suffix
wrapper.passthrough(Types.BYTE); // Friendly fire wrapper.passthrough(Types.BYTE); // Friendly fire
wrapper.passthrough(Types.STRING); // Name tag visibility wrapper.passthrough(Types.STRING); // Name tag visibility
wrapper.read(Types.STRING); // Collision rule wrapper.read(Types.STRING); // Collision rule
} }
}); });
} }
}); });
protocol.cancelClientbound(ClientboundPackets1_9.COOLDOWN); protocol.cancelClientbound(ClientboundPackets1_9.COOLDOWN);
protocol.registerClientbound(ClientboundPackets1_9.CUSTOM_PAYLOAD, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Channel map(Types.STRING); // Channel
handlerSoftFail(wrapper -> { handlerSoftFail(wrapper -> {
final String channel = wrapper.get(Types.STRING, 0); final String channel = wrapper.get(Types.STRING, 0);
if (channel.equals("MC|BOpen")) { if (channel.equals("MC|BOpen")) {
wrapper.read(Types.VAR_INT); wrapper.read(Types.VAR_INT);
} else if (channel.equals("MC|TrList")) { } else if (channel.equals("MC|TrList")) {
protocol.getItemRewriter().handleTradeList(wrapper); protocol.getItemRewriter().handleTradeList(wrapper);
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.PLAYER_POSITION, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.PLAYER_POSITION, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.DOUBLE); // X map(Types.DOUBLE); // X
map(Types.DOUBLE); // Feet y map(Types.DOUBLE); // Feet y
map(Types.DOUBLE); // Z map(Types.DOUBLE); // Z
map(Types.FLOAT); // Yaw map(Types.FLOAT); // Yaw
map(Types.FLOAT); // Pitch map(Types.FLOAT); // Pitch
map(Types.BYTE); // Relative arguments map(Types.BYTE); // Relative arguments
handler(wrapper -> { handler(wrapper -> {
final PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class); final PlayerPositionTracker pos = wrapper.user().get(PlayerPositionTracker.class);
pos.setConfirmId(wrapper.read(Types.VAR_INT)); pos.setConfirmId(wrapper.read(Types.VAR_INT));
byte flags = wrapper.get(Types.BYTE, 0); byte flags = wrapper.get(Types.BYTE, 0);
double x = wrapper.get(Types.DOUBLE, 0); double x = wrapper.get(Types.DOUBLE, 0);
double y = wrapper.get(Types.DOUBLE, 1); double y = wrapper.get(Types.DOUBLE, 1);
double z = wrapper.get(Types.DOUBLE, 2); double z = wrapper.get(Types.DOUBLE, 2);
float yaw = wrapper.get(Types.FLOAT, 0); float yaw = wrapper.get(Types.FLOAT, 0);
float pitch = wrapper.get(Types.FLOAT, 1); float pitch = wrapper.get(Types.FLOAT, 1);
wrapper.set(Types.BYTE, 0, (byte) 0); wrapper.set(Types.BYTE, 0, (byte) 0);
if (flags != 0) { if (flags != 0) {
if ((flags & 0x01) != 0) { if ((flags & 0x01) != 0) {
x += pos.getPosX(); x += pos.getPosX();
wrapper.set(Types.DOUBLE, 0, x); wrapper.set(Types.DOUBLE, 0, x);
} }
if ((flags & 0x02) != 0) { if ((flags & 0x02) != 0) {
y += pos.getPosY(); y += pos.getPosY();
wrapper.set(Types.DOUBLE, 1, y); wrapper.set(Types.DOUBLE, 1, y);
} }
if ((flags & 0x04) != 0) { if ((flags & 0x04) != 0) {
z += pos.getPosZ(); z += pos.getPosZ();
wrapper.set(Types.DOUBLE, 2, z); wrapper.set(Types.DOUBLE, 2, z);
} }
if ((flags & 0x08) != 0) { if ((flags & 0x08) != 0) {
yaw += pos.getYaw(); yaw += pos.getYaw();
wrapper.set(Types.FLOAT, 0, yaw); wrapper.set(Types.FLOAT, 0, yaw);
} }
if ((flags & 0x10) != 0) { if ((flags & 0x10) != 0) {
pitch += pos.getPitch(); pitch += pos.getPitch();
wrapper.set(Types.FLOAT, 1, pitch); wrapper.set(Types.FLOAT, 1, pitch);
} }
} }
pos.setPos(x, y, z); pos.setPos(x, y, z);
pos.setYaw(yaw); pos.setYaw(yaw);
pos.setPitch(pitch); pos.setPitch(pitch);
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.RESPAWN, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.RESPAWN, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.INT); // Dimension map(Types.INT); // Dimension
handler(wrapper -> { handler(wrapper -> {
final ClientWorld world = wrapper.user().getClientWorld(Protocol1_9To1_8.class); final ClientWorld world = wrapper.user().getClientWorld(Protocol1_9To1_8.class);
final int dimension = wrapper.get(Types.INT, 0); final int dimension = wrapper.get(Types.INT, 0);
if (world.setEnvironment(dimension)) { if (world.setEnvironment(dimension)) {
final EntityTracker tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class); final EntityTracker tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
tracker.clearEntities(); tracker.clearEntities();
wrapper.user().get(BossBarStorage.class).reset(); wrapper.user().get(BossBarStorage.class).reset();
} }
}); });
} }
}); });
// Packet implementation doesn't do anything until 1.9 // Packet implementation doesn't do anything until 1.9
protocol.registerClientbound(ClientboundPackets1_9.PLAYER_COMBAT, wrapper -> { protocol.registerClientbound(ClientboundPackets1_9.PLAYER_COMBAT, wrapper -> {
if (!ViaRewind.getConfig().handlePlayerCombatPacket()) { if (!ViaRewind.getConfig().handlePlayerCombatPacket()) {
return; return;
} }
final int action = wrapper.passthrough(Types.VAR_INT); final int action = wrapper.passthrough(Types.VAR_INT);
if (action != 2) { if (action != 2) {
return; return;
} }
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class); final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
final int entityId = wrapper.passthrough(Types.VAR_INT); final int entityId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.INT); // Killer id wrapper.passthrough(Types.INT); // Killer id
if (entityId != tracker.clientEntityId()) { if (entityId != tracker.clientEntityId()) {
return; return;
} }
final JsonElement message = wrapper.passthrough(Types.COMPONENT); final JsonElement message = wrapper.passthrough(Types.COMPONENT);
final PacketWrapper killPlayer = wrapper.create(ClientboundPackets1_8.SET_HEALTH); final PacketWrapper killPlayer = wrapper.create(ClientboundPackets1_8.SET_HEALTH);
killPlayer.write(Types.FLOAT, 0F); // Health killPlayer.write(Types.FLOAT, 0F); // Health
killPlayer.write(Types.VAR_INT, 0); // Food killPlayer.write(Types.VAR_INT, 0); // Food
killPlayer.write(Types.FLOAT, 0F); // Food Saturation killPlayer.write(Types.FLOAT, 0F); // Food Saturation
killPlayer.scheduleSend(Protocol1_9To1_8.class); killPlayer.scheduleSend(Protocol1_9To1_8.class);
final PacketWrapper chatMessage = wrapper.create(ClientboundPackets1_8.CHAT); final PacketWrapper chatMessage = wrapper.create(ClientboundPackets1_8.CHAT);
chatMessage.write(Types.COMPONENT, message); chatMessage.write(Types.COMPONENT, message);
chatMessage.write(Types.BYTE, (byte) 2); // Position - above hotbar chatMessage.write(Types.BYTE, (byte) 2); // Position - above hotbar
chatMessage.scheduleSend(Protocol1_9To1_8.class); chatMessage.scheduleSend(Protocol1_9To1_8.class);
}); });
protocol.registerServerbound(ServerboundPackets1_8.CHAT, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.CHAT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Message map(Types.STRING); // Message
handler(wrapper -> { handler(wrapper -> {
if (!ViaRewind.getConfig().isEnableOffhand()) { if (!ViaRewind.getConfig().isEnableOffhand()) {
return; return;
} }
final String message = wrapper.get(Types.STRING, 0); final String message = wrapper.get(Types.STRING, 0);
if (message.toLowerCase().trim().startsWith(ViaRewind.getConfig().getOffhandCommand())) { if (message.toLowerCase().trim().startsWith(ViaRewind.getConfig().getOffhandCommand())) {
wrapper.cancel(); wrapper.cancel();
final PacketWrapper swapItems = PacketWrapper.create(ServerboundPackets1_9.PLAYER_ACTION, wrapper.user()); final PacketWrapper swapItems = PacketWrapper.create(ServerboundPackets1_9.PLAYER_ACTION, wrapper.user());
swapItems.write(Types.VAR_INT, 6); swapItems.write(Types.VAR_INT, 6);
swapItems.write(Types.BLOCK_POSITION1_8, new BlockPosition(0, 0, 0)); swapItems.write(Types.BLOCK_POSITION1_8, new BlockPosition(0, 0, 0));
swapItems.write(Types.UNSIGNED_BYTE, (short) 255); swapItems.write(Types.UNSIGNED_BYTE, (short) 255);
swapItems.sendToServer(Protocol1_9To1_8.class); swapItems.sendToServer(Protocol1_9To1_8.class);
} }
}); });
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.INTERACT, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.INTERACT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.VAR_INT); // Target map(Types.VAR_INT); // Target
map(Types.VAR_INT); // Type map(Types.VAR_INT); // Type
handler(wrapper -> { handler(wrapper -> {
final int type = wrapper.get(Types.VAR_INT, 1); final int type = wrapper.get(Types.VAR_INT, 1);
if (type == 2 /* attack */) { if (type == 2 /* attack */) {
wrapper.passthrough(Types.FLOAT); // Target x wrapper.passthrough(Types.FLOAT); // Target x
wrapper.passthrough(Types.FLOAT); // Target y wrapper.passthrough(Types.FLOAT); // Target y
wrapper.passthrough(Types.FLOAT); // Target z wrapper.passthrough(Types.FLOAT); // Target z
} }
if (type == 2 /* attack */ || type == 0 /* interact */) { if (type == 2 /* attack */ || type == 0 /* interact */) {
wrapper.write(Types.VAR_INT, 0); // Hand wrapper.write(Types.VAR_INT, 0); // Hand
} }
}); });
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_STATUS_ONLY, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_STATUS_ONLY, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BOOLEAN); // On ground map(Types.BOOLEAN); // On ground
handler(wrapper -> { handler(wrapper -> {
wrapper.user().get(PlayerPositionTracker.class).sendAnimations(); wrapper.user().get(PlayerPositionTracker.class).sendAnimations();
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class); final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
if (tracker.isInsideVehicle(tracker.clientEntityId())) { if (tracker.isInsideVehicle(tracker.clientEntityId())) {
wrapper.cancel(); wrapper.cancel();
} }
}); });
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_POS, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_POS, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.DOUBLE); // X map(Types.DOUBLE); // X
map(Types.DOUBLE); // Feet y map(Types.DOUBLE); // Feet y
map(Types.DOUBLE); // Z map(Types.DOUBLE); // Z
map(Types.BOOLEAN); // On ground map(Types.BOOLEAN); // On ground
handler(wrapper -> { handler(wrapper -> {
final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class); final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class);
storage.sendAnimations(); storage.sendAnimations();
if (storage.getConfirmId() != -1) { if (storage.getConfirmId() != -1) {
return; return;
} }
storage.setPos(wrapper.get(Types.DOUBLE, 0), wrapper.get(Types.DOUBLE, 1), wrapper.get(Types.DOUBLE, 2)); storage.setPos(wrapper.get(Types.DOUBLE, 0), wrapper.get(Types.DOUBLE, 1), wrapper.get(Types.DOUBLE, 2));
storage.setOnGround(wrapper.get(Types.BOOLEAN, 0)); storage.setOnGround(wrapper.get(Types.BOOLEAN, 0));
}); });
handler(wrapper -> wrapper.user().get(BossBarStorage.class).updateLocation()); handler(wrapper -> wrapper.user().get(BossBarStorage.class).updateLocation());
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_ROT, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_ROT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.FLOAT); // Yaw map(Types.FLOAT); // Yaw
map(Types.FLOAT); // Pitch map(Types.FLOAT); // Pitch
map(Types.BOOLEAN); // On ground map(Types.BOOLEAN); // On ground
handler(wrapper -> { handler(wrapper -> {
final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class); final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class);
storage.sendAnimations(); storage.sendAnimations();
if (storage.getConfirmId() != -1) { if (storage.getConfirmId() != -1) {
return; return;
} }
storage.setYaw(wrapper.get(Types.FLOAT, 0)); storage.setYaw(wrapper.get(Types.FLOAT, 0));
storage.setPitch(wrapper.get(Types.FLOAT, 1)); storage.setPitch(wrapper.get(Types.FLOAT, 1));
storage.setOnGround(wrapper.get(Types.BOOLEAN, 0)); storage.setOnGround(wrapper.get(Types.BOOLEAN, 0));
}); });
handler(wrapper -> wrapper.user().get(BossBarStorage.class).updateLocation()); handler(wrapper -> wrapper.user().get(BossBarStorage.class).updateLocation());
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_POS_ROT, wrapper -> { protocol.registerServerbound(ServerboundPackets1_8.MOVE_PLAYER_POS_ROT, wrapper -> {
final double x = wrapper.passthrough(Types.DOUBLE); final double x = wrapper.passthrough(Types.DOUBLE);
final double y = wrapper.passthrough(Types.DOUBLE); final double y = wrapper.passthrough(Types.DOUBLE);
final double z = wrapper.passthrough(Types.DOUBLE); final double z = wrapper.passthrough(Types.DOUBLE);
final float yaw = wrapper.passthrough(Types.FLOAT); final float yaw = wrapper.passthrough(Types.FLOAT);
final float pitch = wrapper.passthrough(Types.FLOAT); final float pitch = wrapper.passthrough(Types.FLOAT);
final boolean onGround = wrapper.passthrough(Types.BOOLEAN); final boolean onGround = wrapper.passthrough(Types.BOOLEAN);
final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class); final PlayerPositionTracker storage = wrapper.user().get(PlayerPositionTracker.class);
storage.sendAnimations(); storage.sendAnimations();
if (storage.getConfirmId() != -1) { if (storage.getConfirmId() != -1) {
if (storage.getPosX() == x && storage.getPosY() == y && storage.getPosZ() == z && storage.getYaw() == yaw && storage.getPitch() == pitch) { 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()); final PacketWrapper confirmTeleport = PacketWrapper.create(ServerboundPackets1_9.ACCEPT_TELEPORTATION, wrapper.user());
confirmTeleport.write(Types.VAR_INT, storage.getConfirmId()); confirmTeleport.write(Types.VAR_INT, storage.getConfirmId());
confirmTeleport.sendToServer(Protocol1_9To1_8.class); confirmTeleport.sendToServer(Protocol1_9To1_8.class);
storage.setConfirmId(-1); storage.setConfirmId(-1);
} }
} else { } else {
storage.setPos(x, y, z); storage.setPos(x, y, z);
storage.setYaw(yaw); storage.setYaw(yaw);
storage.setPitch(pitch); storage.setPitch(pitch);
storage.setOnGround(onGround); storage.setOnGround(onGround);
wrapper.user().get(BossBarStorage.class).updateLocation(); wrapper.user().get(BossBarStorage.class).updateLocation();
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_ACTION, wrapper -> { protocol.registerServerbound(ServerboundPackets1_8.PLAYER_ACTION, wrapper -> {
final int status = wrapper.passthrough(Types.VAR_INT); final int status = wrapper.passthrough(Types.VAR_INT);
final BlockPlaceDestroyTracker tracker = wrapper.user().get(BlockPlaceDestroyTracker.class); final BlockPlaceDestroyTracker tracker = wrapper.user().get(BlockPlaceDestroyTracker.class);
if (status == 0 || status == 1 || status == 2) { // Start, cancel or finish if (status == 0 || status == 1 || status == 2) { // Start, cancel or finish
tracker.setMining(); tracker.setMining();
} }
final CooldownStorage cooldown = wrapper.user().get(CooldownStorage.class); final CooldownStorage cooldown = wrapper.user().get(CooldownStorage.class);
if (status == 1) { // Cancel if (status == 1) { // Cancel
tracker.setLastMining(0); tracker.setLastMining(0);
cooldown.hit(); cooldown.hit();
} else if (status == 2) { // Finish } else if (status == 2) { // Finish
tracker.setLastMining(System.currentTimeMillis() + 100); tracker.setLastMining(System.currentTimeMillis() + 100);
cooldown.setLastHit(0); cooldown.setLastHit(0);
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.USE_ITEM_ON, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.USE_ITEM_ON, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BLOCK_POSITION1_8); // Position map(Types.BLOCK_POSITION1_8); // Position
map(Types.BYTE, Types.VAR_INT); // Face map(Types.BYTE, Types.VAR_INT); // Face
read(Types.ITEM1_8); // Current item read(Types.ITEM1_8); // Current item
create(Types.VAR_INT, 0); // Hand - main create(Types.VAR_INT, 0); // Hand - main
map(Types.BYTE, Types.UNSIGNED_BYTE); // Cursor position x 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 y
map(Types.BYTE, Types.UNSIGNED_BYTE); // Cursor position z map(Types.BYTE, Types.UNSIGNED_BYTE); // Cursor position z
handler(wrapper -> { handler(wrapper -> {
if (wrapper.get(Types.VAR_INT, 0) == -1) { if (wrapper.get(Types.VAR_INT, 0) == -1) {
wrapper.cancel(); wrapper.cancel();
final PacketWrapper useItem = PacketWrapper.create(ServerboundPackets1_9.USE_ITEM, wrapper.user()); final PacketWrapper useItem = PacketWrapper.create(ServerboundPackets1_9.USE_ITEM, wrapper.user());
useItem.write(Types.VAR_INT, 0); useItem.write(Types.VAR_INT, 0);
useItem.sendToServer(Protocol1_9To1_8.class); useItem.sendToServer(Protocol1_9To1_8.class);
} }
}); });
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.SET_CARRIED_ITEM, wrapper -> wrapper.user().get(CooldownStorage.class).hit()); 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 // Queue swing packet to be sent after on ground idle packets
protocol.registerServerbound(ServerboundPackets1_8.SWING, wrapper -> { protocol.registerServerbound(ServerboundPackets1_8.SWING, wrapper -> {
wrapper.cancel(); wrapper.cancel();
final PacketWrapper swing = PacketWrapper.create(ServerboundPackets1_9.SWING, wrapper.user()); final PacketWrapper swing = PacketWrapper.create(ServerboundPackets1_9.SWING, wrapper.user());
swing.write(Types.VAR_INT, 0); // Main Hand swing.write(Types.VAR_INT, 0); // Main Hand
wrapper.user().get(PlayerPositionTracker.class).queueAnimation(swing); wrapper.user().get(PlayerPositionTracker.class).queueAnimation(swing);
wrapper.user().get(BlockPlaceDestroyTracker.class).updateMining(); wrapper.user().get(BlockPlaceDestroyTracker.class).updateMining();
wrapper.user().get(CooldownStorage.class).hit(); wrapper.user().get(CooldownStorage.class).hit();
}); });
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_COMMAND, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.PLAYER_COMMAND, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.VAR_INT); // Entity id map(Types.VAR_INT); // Entity id
map(Types.VAR_INT); // Action id map(Types.VAR_INT); // Action id
map(Types.VAR_INT); // Action parameter map(Types.VAR_INT); // Action parameter
handler(wrapper -> { handler(wrapper -> {
final PlayerPositionTracker tracker = wrapper.user().get(PlayerPositionTracker.class); final PlayerPositionTracker tracker = wrapper.user().get(PlayerPositionTracker.class);
final int action = wrapper.get(Types.VAR_INT, 1); final int action = wrapper.get(Types.VAR_INT, 1);
if (action == 6) { // Jump with horse if (action == 6) { // Jump with horse
wrapper.set(Types.VAR_INT, 1, 7); wrapper.set(Types.VAR_INT, 1, 7);
} else if (action == 0 && !tracker.isOnGround()) { // Start sneaking } else if (action == 0 && !tracker.isOnGround()) { // Start sneaking
final PacketWrapper elytra = PacketWrapper.create(ServerboundPackets1_9.PLAYER_COMMAND, wrapper.user()); 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, wrapper.get(Types.VAR_INT, 0));
elytra.write(Types.VAR_INT, 8); elytra.write(Types.VAR_INT, 8);
elytra.write(Types.VAR_INT, 0); elytra.write(Types.VAR_INT, 0);
elytra.scheduleSendToServer(Protocol1_9To1_8.class); elytra.scheduleSendToServer(Protocol1_9To1_8.class);
} }
}); });
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.PLAYER_INPUT, wrapper -> { protocol.registerServerbound(ServerboundPackets1_8.PLAYER_INPUT, wrapper -> {
final float sideways = wrapper.passthrough(Types.FLOAT); final float sideways = wrapper.passthrough(Types.FLOAT);
final float forward = wrapper.passthrough(Types.FLOAT); final float forward = wrapper.passthrough(Types.FLOAT);
final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class); final EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
final Integer vehicle = tracker.getVehicle(tracker.clientEntityId()); final Integer vehicle = tracker.getVehicle(tracker.clientEntityId());
if (vehicle != null && tracker.entityType(vehicle) == EntityTypes1_9.EntityType.BOAT) { if (vehicle != null && tracker.entityType(vehicle) == EntityTypes1_9.EntityType.BOAT) {
final PacketWrapper paddleBoat = PacketWrapper.create(ServerboundPackets1_9.PADDLE_BOAT, wrapper.user()); 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.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); paddleBoat.scheduleSendToServer(Protocol1_9To1_8.class);
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.SIGN_UPDATE, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.SIGN_UPDATE, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BLOCK_POSITION1_8); // Position map(Types.BLOCK_POSITION1_8); // Position
handler(wrapper -> { handler(wrapper -> {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
final JsonElement json = JsonParser.parseString(wrapper.read(RewindTypes.SIGN_STRING)); final JsonElement json = JsonParser.parseString(wrapper.read(RewindTypes.SIGN_STRING));
if (!json.isJsonPrimitive()) { if (!json.isJsonPrimitive()) {
throw new IllegalStateException("Invalid sign text: " + StringUtil.forLogging(json)); throw new IllegalStateException("Invalid sign text: " + StringUtil.forLogging(json));
} }
wrapper.write(Types.STRING, ChatUtil.jsonToLegacy(json)); wrapper.write(Types.STRING, ChatUtil.jsonToLegacy(json));
} }
}); });
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.COMMAND_SUGGESTION, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.COMMAND_SUGGESTION, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Message map(Types.STRING); // Message
create(Types.BOOLEAN, false); // Has position create(Types.BOOLEAN, false); // Has position
map(Types.OPTIONAL_POSITION1_8); // Looked at block (position) map(Types.OPTIONAL_POSITION1_8); // Looked at block (position)
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.CLIENT_INFORMATION, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.CLIENT_INFORMATION, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Locale map(Types.STRING); // Locale
map(Types.BYTE); // View distance map(Types.BYTE); // View distance
map(Types.BYTE, Types.VAR_INT); // Chat mode map(Types.BYTE, Types.VAR_INT); // Chat mode
map(Types.BOOLEAN); // Chat colors map(Types.BOOLEAN); // Chat colors
map(Types.UNSIGNED_BYTE); // Displayed skin parts map(Types.UNSIGNED_BYTE); // Displayed skin parts
create(Types.VAR_INT, 1); // Main hand create(Types.VAR_INT, 1); // Main hand
handler(wrapper -> { handler(wrapper -> {
final short flags = wrapper.get(Types.UNSIGNED_BYTE, 0); final short flags = wrapper.get(Types.UNSIGNED_BYTE, 0);
final PacketWrapper updateSkin = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_DATA, wrapper.user()); final PacketWrapper updateSkin = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_DATA, wrapper.user());
updateSkin.write(Types.VAR_INT, wrapper.user().getEntityTracker(Protocol1_9To1_8.class).clientEntityId()); updateSkin.write(Types.VAR_INT, wrapper.user().getEntityTracker(Protocol1_9To1_8.class).clientEntityId());
final List<EntityData> entityData = new ArrayList<>(); final List<EntityData> entityData = new ArrayList<>();
entityData.add(new EntityData(10, EntityDataTypes1_8.BYTE, (byte) flags)); entityData.add(new EntityData(10, EntityDataTypes1_8.BYTE, (byte) flags));
updateSkin.write(Types.ENTITY_DATA_LIST1_8, entityData); updateSkin.write(Types.ENTITY_DATA_LIST1_8, entityData);
updateSkin.scheduleSend(Protocol1_9To1_8.class); updateSkin.scheduleSend(Protocol1_9To1_8.class);
}); });
} }
}); });
protocol.registerServerbound(ServerboundPackets1_8.CUSTOM_PAYLOAD, new PacketHandlers() { protocol.registerServerbound(ServerboundPackets1_8.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Channel map(Types.STRING); // Channel
handlerSoftFail(wrapper -> { handlerSoftFail(wrapper -> {
final String channel = wrapper.get(Types.STRING, 0); final String channel = wrapper.get(Types.STRING, 0);
if (channel.equals("MC|BEdit") || channel.equals("MC|BSign")) { if (channel.equals("MC|BEdit") || channel.equals("MC|BSign")) {
final Item book = wrapper.passthrough(Types.ITEM1_8); final Item book = wrapper.passthrough(Types.ITEM1_8);
book.setIdentifier(386); book.setIdentifier(386);
final CompoundTag tag = book.tag(); final CompoundTag tag = book.tag();
if (tag == null) { if (tag == null) {
return; return;
} }
final ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class); final ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
if (pages == null) { if (pages == null) {
return; return;
} }
if (pages.size() > ViaRewind.getConfig().getMaxBookPages()) { if (pages.size() > ViaRewind.getConfig().getMaxBookPages()) {
wrapper.user().disconnect("Too many book pages"); wrapper.user().disconnect("Too many book pages");
return; return;
} }
for (int i = 0; i < pages.size(); i++) { for (int i = 0; i < pages.size(); i++) {
final StringTag pageTag = pages.get(i); final StringTag pageTag = pages.get(i);
final String value = pageTag.getValue(); final String value = pageTag.getValue();
if (value.length() > ViaRewind.getConfig().getMaxBookPageSize()) { if (value.length() > ViaRewind.getConfig().getMaxBookPageSize()) {
wrapper.user().disconnect("Book page too large"); wrapper.user().disconnect("Book page too large");
return; return;
} }
pageTag.setValue(ChatUtil.jsonToLegacy(value)); pageTag.setValue(ChatUtil.jsonToLegacy(value));
} }
} else if (channel.equals("MC|AdvCdm")) { } else if (channel.equals("MC|AdvCdm")) {
wrapper.set(Types.STRING, 0, "MC|AdvCmd"); wrapper.set(Types.STRING, 0, "MC|AdvCmd");
} }
}); });
} }
}); });
} }
} }
@@ -17,6 +17,8 @@
*/ */
package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter; package com.viaversion.viarewind.protocol.v1_9to1_8.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag; import com.viaversion.nbt.tag.Tag;
import com.viaversion.viarewind.ViaRewind; import com.viaversion.viarewind.ViaRewind;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8; import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
@@ -37,235 +39,232 @@ 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.api.type.types.chunk.ChunkType1_9_1;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.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.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import java.util.ArrayList; import java.util.ArrayList;
public class WorldPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> { public class WorldPacketRewriter1_9 extends RewriterBase<Protocol1_9To1_8> {
public WorldPacketRewriter1_9(Protocol1_9To1_8 protocol) { public WorldPacketRewriter1_9(Protocol1_9To1_8 protocol) {
super(protocol); super(protocol);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9.BLOCK_ENTITY_DATA, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BLOCK_POSITION1_8); // Position map(Types.BLOCK_POSITION1_8); // Position
map(Types.UNSIGNED_BYTE); // Action map(Types.UNSIGNED_BYTE); // Action
map(Types.NAMED_COMPOUND_TAG); // Tag map(Types.NAMED_COMPOUND_TAG); // Tag
handler(wrapper -> { handler(wrapper -> {
final CompoundTag tag = wrapper.get(Types.NAMED_COMPOUND_TAG, 0); final CompoundTag tag = wrapper.get(Types.NAMED_COMPOUND_TAG, 0);
if (tag.remove("SpawnData") instanceof CompoundTag spawnData) { if (tag.remove("SpawnData") instanceof CompoundTag spawnData) {
final Tag id = spawnData.remove("id"); final Tag id = spawnData.remove("id");
if (id instanceof StringTag) { if (id instanceof StringTag) {
tag.put("EntityId", id); tag.put("EntityId", id);
} }
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.BLOCK_EVENT, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.BLOCK_EVENT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.BLOCK_POSITION1_8); // Position map(Types.BLOCK_POSITION1_8); // Position
map(Types.UNSIGNED_BYTE); // Byte 1 (depending on block type) map(Types.UNSIGNED_BYTE); // Byte 1 (depending on block type)
map(Types.UNSIGNED_BYTE); // Byte 2 (depending on block type) map(Types.UNSIGNED_BYTE); // Byte 2 (depending on block type)
map(Types.VAR_INT); // Block map(Types.VAR_INT); // Block
handler(wrapper -> { handler(wrapper -> {
final int block = wrapper.get(Types.VAR_INT, 0); final int block = wrapper.get(Types.VAR_INT, 0);
if (block >= 219 && block <= 234) { if (block >= 219 && block <= 234) {
wrapper.set(Types.VAR_INT, 0, 130); wrapper.set(Types.VAR_INT, 0, 130);
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.CUSTOM_SOUND, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.CUSTOM_SOUND, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.STRING); // Sound name map(Types.STRING); // Sound name
handler(wrapper -> { handler(wrapper -> {
String name = wrapper.get(Types.STRING, 0); String name = wrapper.get(Types.STRING, 0);
name = protocol.getMappingData().getMappedNamedSound(name); name = protocol.getMappingData().getMappedNamedSound(name);
if (name == null) { if (name == null) {
wrapper.cancel(); wrapper.cancel();
} else { } else {
wrapper.set(Types.STRING, 0, name); wrapper.set(Types.STRING, 0, name);
} }
}); });
read(Types.VAR_INT); // Sound category read(Types.VAR_INT); // Sound category
map(Types.INT); // Effect position x map(Types.INT); // Effect position x
map(Types.INT); // Effect position y map(Types.INT); // Effect position y
map(Types.INT); // Effect position z map(Types.INT); // Effect position z
map(Types.FLOAT); // Volume map(Types.FLOAT); // Volume
map(Types.UNSIGNED_BYTE); // Pitch map(Types.UNSIGNED_BYTE); // Pitch
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.FORGET_LEVEL_CHUNK, ClientboundPackets1_8.LEVEL_CHUNK, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.FORGET_LEVEL_CHUNK, ClientboundPackets1_8.LEVEL_CHUNK, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
handler(wrapper -> { handler(wrapper -> {
final Environment environment = wrapper.user().getClientWorld(Protocol1_9To1_8.class).getEnvironment(); final Environment environment = wrapper.user().getClientWorld(Protocol1_9To1_8.class).getEnvironment();
final int chunkX = wrapper.read(Types.INT); final int chunkX = wrapper.read(Types.INT);
final int chunkZ = 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<>())); wrapper.write(ChunkType1_8.forEnvironment(environment), new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], null, new ArrayList<>()));
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.LEVEL_CHUNK, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.LEVEL_CHUNK, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
handler(wrapper -> { handler(wrapper -> {
final Environment environment = wrapper.user().getClientWorld(Protocol1_9To1_8.class).getEnvironment(); final Environment environment = wrapper.user().getClientWorld(Protocol1_9To1_8.class).getEnvironment();
Chunk chunk = wrapper.read(ChunkType1_9_1.forEnvironment(environment)); Chunk chunk = wrapper.read(ChunkType1_9_1.forEnvironment(environment));
for (ChunkSection section : chunk.getSections()) { for (ChunkSection section : chunk.getSections()) {
if (section == null) continue; if (section == null) continue;
DataPalette palette = section.palette(PaletteType.BLOCKS); DataPalette palette = section.palette(PaletteType.BLOCKS);
for (int i = 0; i < palette.size(); i++) { for (int i = 0; i < palette.size(); i++) {
int block = palette.idByIndex(i); int block = palette.idByIndex(i);
int replacedBlock = protocol.getItemRewriter().handleBlockId(block); int replacedBlock = protocol.getItemRewriter().handleBlockId(block);
palette.setIdByIndex(i, replacedBlock); palette.setIdByIndex(i, replacedBlock);
} }
} }
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; boolean skylight = environment == Environment.NORMAL;
ChunkSection[] sections = new ChunkSection[16]; ChunkSection[] sections = new ChunkSection[16];
ChunkSection section = new ChunkSectionImpl(true); ChunkSection section = new ChunkSectionImpl(true);
sections[0] = section; sections[0] = section;
section.palette(PaletteType.BLOCKS).addId(0); section.palette(PaletteType.BLOCKS).addId(0);
if (skylight) section.getLight().setSkyLight(new byte[2048]); if (skylight) section.getLight().setSkyLight(new byte[2048]);
chunk = new BaseChunk(chunk.getX(), chunk.getZ(), true, false, 1, sections, chunk.getBiomeData(), chunk.getBlockEntities()); chunk = new BaseChunk(chunk.getX(), chunk.getZ(), true, false, 1, sections, chunk.getBiomeData(), chunk.getBlockEntities());
} }
wrapper.write(ChunkType1_8.forEnvironment(environment), chunk); wrapper.write(ChunkType1_8.forEnvironment(environment), chunk);
chunk.getBlockEntities().forEach(nbt -> { 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; return;
} }
BlockPosition position = new BlockPosition((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(); String id = (String) nbt.get("id").getValue();
short action; short action;
switch (id) { switch (id) {
case "minecraft:mob_spawner": case "minecraft:mob_spawner":
action = 1; action = 1;
break; break;
case "minecraft:command_block": case "minecraft:command_block":
action = 2; action = 2;
break; break;
case "minecraft:beacon": case "minecraft:beacon":
action = 3; action = 3;
break; break;
case "minecraft:skull": case "minecraft:skull":
action = 4; action = 4;
break; break;
case "minecraft:flower_pot": case "minecraft:flower_pot":
action = 5; action = 5;
break; break;
case "minecraft:banner": case "minecraft:banner":
action = 6; action = 6;
break; break;
default: default:
return; return;
} }
final PacketWrapper blockEntityData = PacketWrapper.create(ClientboundPackets1_9.BLOCK_ENTITY_DATA, wrapper.user()); final PacketWrapper blockEntityData = PacketWrapper.create(ClientboundPackets1_9.BLOCK_ENTITY_DATA, wrapper.user());
blockEntityData.write(Types.BLOCK_POSITION1_8, position); blockEntityData.write(Types.BLOCK_POSITION1_8, position);
blockEntityData.write(Types.UNSIGNED_BYTE, action); blockEntityData.write(Types.UNSIGNED_BYTE, action);
blockEntityData.write(Types.NAMED_COMPOUND_TAG, nbt); blockEntityData.write(Types.NAMED_COMPOUND_TAG, nbt);
blockEntityData.scheduleSend(Protocol1_9To1_8.class, false); blockEntityData.scheduleSend(Protocol1_9To1_8.class, false);
}); });
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.LEVEL_EVENT, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.LEVEL_EVENT, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.INT); // Effect id map(Types.INT); // Effect id
map(Types.BLOCK_POSITION1_8); // Position map(Types.BLOCK_POSITION1_8); // Position
map(Types.INT); // data map(Types.INT); // data
map(Types.BOOLEAN); // disable relative volume map(Types.BOOLEAN); // disable relative volume
handler(wrapper -> { handler(wrapper -> {
int id = wrapper.get(Types.INT, 0); int id = wrapper.get(Types.INT, 0);
id = EffectIdMappings1_8.getOldId(id); id = EffectIdMappings1_8.getOldId(id);
if (id == -1) { if (id == -1) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
wrapper.set(Types.INT, 0, id); wrapper.set(Types.INT, 0, id);
if (id == 2001) { if (id == 2001) {
int replacedBlock = protocol.getItemRewriter().handleBlockId(wrapper.get(Types.INT, 1)); int replacedBlock = protocol.getItemRewriter().handleBlockId(wrapper.get(Types.INT, 1));
wrapper.set(Types.INT, 1, replacedBlock); wrapper.set(Types.INT, 1, replacedBlock);
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.LEVEL_PARTICLES, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.LEVEL_PARTICLES, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.INT); // Particle id map(Types.INT); // Particle id
handler(wrapper -> { handler(wrapper -> {
int id = wrapper.get(Types.INT, 0); int id = wrapper.get(Types.INT, 0);
if (id > 41 && !ViaRewind.getConfig().isReplaceParticles()) { if (id > 41 && !ViaRewind.getConfig().isReplaceParticles()) {
wrapper.cancel(); wrapper.cancel();
return; return;
} }
if (id == 42) { // Dragon Breath if (id == 42) { // Dragon Breath
wrapper.set(Types.INT, 0, 24); // Portal wrapper.set(Types.INT, 0, 24); // Portal
} else if (id == 43) { // End Rod } else if (id == 43) { // End Rod
wrapper.set(Types.INT, 0, 3); // Firework Spark wrapper.set(Types.INT, 0, 3); // Firework Spark
} else if (id == 44) { // Damage Indicator } else if (id == 44) { // Damage Indicator
wrapper.set(Types.INT, 0, 34); // Heart wrapper.set(Types.INT, 0, 34); // Heart
} else if (id == 45) { // Sweep Attack } else if (id == 45) { // Sweep Attack
wrapper.set(Types.INT, 0, 1); // Large Explosion wrapper.set(Types.INT, 0, 1); // Large Explosion
} }
}); });
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.MAP_ITEM_DATA, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.MAP_ITEM_DATA, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
map(Types.VAR_INT); // Item damage map(Types.VAR_INT); // Item damage
map(Types.BYTE); // Scale map(Types.BYTE); // Scale
read(Types.BOOLEAN); // Tracking position read(Types.BOOLEAN); // Tracking position
} }
}); });
protocol.registerClientbound(ClientboundPackets1_9.SOUND, ClientboundPackets1_8.CUSTOM_SOUND, new PacketHandlers() { protocol.registerClientbound(ClientboundPackets1_9.SOUND, ClientboundPackets1_8.CUSTOM_SOUND, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
handler(wrapper -> { handler(wrapper -> {
final int soundId = wrapper.read(Types.VAR_INT); final int soundId = wrapper.read(Types.VAR_INT);
final String soundName = protocol.getMappingData().soundName(soundId); final String soundName = protocol.getMappingData().soundName(soundId);
if (soundName == null) { if (soundName == null) {
wrapper.cancel(); wrapper.cancel();
} else { } else {
wrapper.write(Types.STRING, protocol.getMappingData().getMappedNamedSound(soundName)); wrapper.write(Types.STRING, protocol.getMappingData().getMappedNamedSound(soundName));
} }
}); });
read(Types.VAR_INT); // Sound category read(Types.VAR_INT); // Sound category
map(Types.INT); // Effect position x map(Types.INT); // Effect position x
map(Types.INT); // Effect position y map(Types.INT); // Effect position y
map(Types.INT); // Effect position z map(Types.INT); // Effect position z
map(Types.FLOAT); // Volume map(Types.FLOAT); // Volume
map(Types.UNSIGNED_BYTE); // Pitch map(Types.UNSIGNED_BYTE); // Pitch
} }
}); });
} }
} }
@@ -20,24 +20,24 @@ package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viaversion.api.connection.StorableObject; import com.viaversion.viaversion.api.connection.StorableObject;
public class BlockPlaceDestroyTracker implements StorableObject { public class BlockPlaceDestroyTracker implements StorableObject {
private long lastMining; private long lastMining;
public boolean isMining() { public boolean isMining() {
long time = System.currentTimeMillis() - lastMining; long time = System.currentTimeMillis() - lastMining;
return time < 75; return time < 75;
} }
public void setMining() { public void setMining() {
lastMining = System.currentTimeMillis(); lastMining = System.currentTimeMillis();
} }
public void updateMining() { public void updateMining() {
if (this.isMining()) { if (this.isMining()) {
lastMining = System.currentTimeMillis(); lastMining = System.currentTimeMillis();
} }
} }
public void setLastMining(long lastMining) { public void setLastMining(long lastMining) {
this.lastMining = lastMining; this.lastMining = lastMining;
} }
} }
@@ -20,65 +20,64 @@ package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viarewind.protocol.v1_9to1_8.data.WitherBossBar; import com.viaversion.viarewind.protocol.v1_9to1_8.data.WitherBossBar;
import com.viaversion.viaversion.api.connection.StoredObject; import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
public class BossBarStorage extends StoredObject { public class BossBarStorage extends StoredObject {
private final Map<UUID, WitherBossBar> bossBars = new HashMap<>(); private final Map<UUID, WitherBossBar> bossBars = new HashMap<>();
public BossBarStorage(UserConnection user) { public BossBarStorage(UserConnection user) {
super(user); super(user);
} }
public void reset() { public void reset() {
updateLocation(); updateLocation();
changeWorld(); changeWorld();
} }
public void add(UUID uuid, String title, float health) { public void add(UUID uuid, String title, float health) {
WitherBossBar bossBar = new WitherBossBar(this.getUser(), uuid, title, health); WitherBossBar bossBar = new WitherBossBar(this.getUser(), uuid, title, health);
PlayerPositionTracker playerPositionTracker = this.getUser().get(PlayerPositionTracker.class); PlayerPositionTracker playerPositionTracker = this.getUser().get(PlayerPositionTracker.class);
bossBar.setPlayerLocation(playerPositionTracker.getPosX(), playerPositionTracker.getPosY(), playerPositionTracker.getPosZ(), playerPositionTracker.getYaw(), playerPositionTracker.getPitch()); bossBar.setPlayerLocation(playerPositionTracker.getPosX(), playerPositionTracker.getPosY(), playerPositionTracker.getPosZ(), playerPositionTracker.getYaw(), playerPositionTracker.getPitch());
bossBar.show(); bossBar.show();
bossBars.put(uuid, bossBar); bossBars.put(uuid, bossBar);
} }
public void remove(UUID uuid) { public void remove(UUID uuid) {
WitherBossBar bossBar = bossBars.remove(uuid); WitherBossBar bossBar = bossBars.remove(uuid);
if (bossBar == null) return; if (bossBar == null) return;
bossBar.hide(); bossBar.hide();
} }
public void updateLocation() { public void updateLocation() {
PlayerPositionTracker playerPositionTracker = this.getUser().get(PlayerPositionTracker.class); PlayerPositionTracker playerPositionTracker = this.getUser().get(PlayerPositionTracker.class);
bossBars.values().forEach(bossBar -> { bossBars.values().forEach(bossBar -> {
try { try {
bossBar.setPlayerLocation(playerPositionTracker.getPosX(), playerPositionTracker.getPosY(), playerPositionTracker.getPosZ(), playerPositionTracker.getYaw(), playerPositionTracker.getPitch()); bossBar.setPlayerLocation(playerPositionTracker.getPosX(), playerPositionTracker.getPosY(), playerPositionTracker.getPosZ(), playerPositionTracker.getYaw(), playerPositionTracker.getPitch());
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}); });
} }
public void changeWorld() { public void changeWorld() {
bossBars.values().forEach(bossBar -> { bossBars.values().forEach(bossBar -> {
bossBar.hide(); bossBar.hide();
bossBar.show(); bossBar.show();
}); });
} }
public void updateHealth(UUID uuid, float health) { public void updateHealth(UUID uuid, float health) {
WitherBossBar bossBar = bossBars.get(uuid); WitherBossBar bossBar = bossBars.get(uuid);
if (bossBar == null) return; if (bossBar == null) return;
bossBar.setHealth(health); bossBar.setHealth(health);
} }
public void updateTitle(UUID uuid, String title) { public void updateTitle(UUID uuid, String title) {
WitherBossBar bossBar = bossBars.get(uuid); WitherBossBar bossBar = bossBars.get(uuid);
if (bossBar == null) return; if (bossBar == null) return;
bossBar.setTitle(title); bossBar.setTitle(title);
} }
} }
@@ -22,101 +22,100 @@ import com.viaversion.viarewind.protocol.v1_9to1_8.cooldown.CooldownVisualizatio
import com.viaversion.viaversion.api.connection.StorableObject; import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.util.Pair; import com.viaversion.viaversion.util.Pair;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
public class CooldownStorage implements StorableObject { public class CooldownStorage implements StorableObject {
private CooldownVisualization.Factory visualizationFactory = CooldownVisualization.Factory.fromConfiguration(); private CooldownVisualization.Factory visualizationFactory = CooldownVisualization.Factory.fromConfiguration();
private CooldownVisualization current; private CooldownVisualization current;
private double attackSpeed = 4.0; private double attackSpeed = 4.0;
private long lastHit = 0; private long lastHit = 0;
public void tick(final UserConnection connection) { public void tick(final UserConnection connection) {
if (!hasCooldown()) { if (!hasCooldown()) {
endCurrentVisualization(); endCurrentVisualization();
return; return;
} }
BlockPlaceDestroyTracker tracker = connection.get(BlockPlaceDestroyTracker.class); BlockPlaceDestroyTracker tracker = connection.get(BlockPlaceDestroyTracker.class);
if (tracker.isMining()) { if (tracker.isMining()) {
lastHit = 0; lastHit = 0;
endCurrentVisualization(); endCurrentVisualization();
return; return;
} }
if (current == null) { if (current == null) {
current = visualizationFactory.create(connection); current = visualizationFactory.create(connection);
} }
try { try {
current.show(getCooldown()); current.show(getCooldown());
} catch (Exception exception) { } catch (Exception exception) {
ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Unable to show cooldown visualization", exception); ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Unable to show cooldown visualization", exception);
} }
} }
private void endCurrentVisualization() { private void endCurrentVisualization() {
if (current != null) { if (current != null) {
try { try {
current.hide(); current.hide();
} catch (Exception exception) { } catch (Exception exception) {
ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Unable to hide cooldown visualization", exception); ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Unable to hide cooldown visualization", exception);
} }
current = null; current = null;
} }
} }
public boolean hasCooldown() { public boolean hasCooldown() {
long time = System.currentTimeMillis() - lastHit; long time = System.currentTimeMillis() - lastHit;
double cooldown = restrain(((double) time) * attackSpeed / 1000d, 1.5); double cooldown = restrain(((double) time) * attackSpeed / 1000d, 1.5);
return cooldown > 0.1 && cooldown < 1.1; return cooldown > 0.1 && cooldown < 1.1;
} }
public double getCooldown() { public double getCooldown() {
long time = System.currentTimeMillis() - lastHit; long time = System.currentTimeMillis() - lastHit;
return restrain(((double) time) * attackSpeed / 1000d, 1); return restrain(((double) time) * attackSpeed / 1000d, 1);
} }
private double restrain(double x, double b) { private double restrain(double x, double b) {
if (x < 0) return 0; if (x < 0) return 0;
return Math.min(x, b); return Math.min(x, b);
} }
public void setAttackSpeed(double base, List<Pair<Byte, Double>> modifiers) { public void setAttackSpeed(double base, List<Pair<Byte, Double>> modifiers) {
attackSpeed = base; attackSpeed = base;
for (int j = 0; j < modifiers.size(); j++) { for (int j = 0; j < modifiers.size(); j++) {
if (modifiers.get(j).key() == 0) { if (modifiers.get(j).key() == 0) {
attackSpeed += modifiers.get(j).value(); attackSpeed += modifiers.get(j).value();
modifiers.remove(j--); modifiers.remove(j--);
} }
} }
for (int j = 0; j < modifiers.size(); j++) { for (int j = 0; j < modifiers.size(); j++) {
if (modifiers.get(j).key() == 1) { if (modifiers.get(j).key() == 1) {
attackSpeed += base * modifiers.get(j).value(); attackSpeed += base * modifiers.get(j).value();
modifiers.remove(j--); modifiers.remove(j--);
} }
} }
for (int j = 0; j < modifiers.size(); j++) { for (int j = 0; j < modifiers.size(); j++) {
if (modifiers.get(j).key() == 2) { if (modifiers.get(j).key() == 2) {
attackSpeed *= (1.0 + modifiers.get(j).value()); attackSpeed *= (1.0 + modifiers.get(j).value());
modifiers.remove(j--); modifiers.remove(j--);
} }
} }
} }
public void hit() { public void hit() {
lastHit = System.currentTimeMillis(); lastHit = System.currentTimeMillis();
} }
public void setLastHit(long lastHit) { public void setLastHit(long lastHit) {
this.lastHit = lastHit; this.lastHit = lastHit;
} }
public CooldownVisualization.Factory getVisualizationFactory() { public CooldownVisualization.Factory getVisualizationFactory() {
return visualizationFactory; return visualizationFactory;
} }
public void setVisualizationFactory(CooldownVisualization.Factory visualizationFactory) { public void setVisualizationFactory(CooldownVisualization.Factory visualizationFactory) {
this.visualizationFactory = visualizationFactory; this.visualizationFactory = visualizationFactory;
} }
} }
@@ -21,67 +21,71 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Vector; import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9;
import com.viaversion.viaversion.data.entity.EntityTrackerBase; import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.fastutil.ints.*; import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntOpenHashMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.fastutil.ints.IntArrayList;
import com.viaversion.viaversion.libs.fastutil.ints.IntList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class EntityTracker1_9 extends EntityTrackerBase { public class EntityTracker1_9 extends EntityTrackerBase {
private final Int2ObjectMap<IntList> vehicles = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap<IntList> vehicles = new Int2ObjectOpenHashMap<>();
private final Int2ObjectMap<Vector> offsets = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap<Vector> offsets = new Int2ObjectOpenHashMap<>();
private final Int2IntMap status = new Int2IntOpenHashMap(); private final Int2IntMap status = new Int2IntOpenHashMap();
public EntityTracker1_9(UserConnection connection) { public EntityTracker1_9(UserConnection connection) {
super(connection, EntityTypes1_9.EntityType.PLAYER); super(connection, EntityTypes1_9.EntityType.PLAYER);
} }
@Override @Override
public void removeEntity(int id) { public void removeEntity(int id) {
vehicles.remove(id); vehicles.remove(id);
offsets.remove(id); offsets.remove(id);
status.remove(id); status.remove(id);
vehicles.forEach((vehicle, passengers) -> passengers.rem(id)); vehicles.forEach((vehicle, passengers) -> passengers.rem(id));
vehicles.int2ObjectEntrySet().removeIf(entry -> entry.getValue().isEmpty()); vehicles.int2ObjectEntrySet().removeIf(entry -> entry.getValue().isEmpty());
super.removeEntity(id); super.removeEntity(id);
} }
public void resetEntityOffset(final int id) { public void resetEntityOffset(final int id) {
offsets.remove(id); offsets.remove(id);
} }
public Vector getEntityOffset(final int id) { public Vector getEntityOffset(final int id) {
return offsets.get(id); return offsets.get(id);
} }
public void setEntityOffset(final int id, Vector offset) { public void setEntityOffset(final int id, Vector offset) {
offsets.put(id, offset); offsets.put(id, offset);
} }
public IntList getPassengers(final int id) { public IntList getPassengers(final int id) {
return vehicles.getOrDefault(id, new IntArrayList()); return vehicles.getOrDefault(id, new IntArrayList());
} }
public void setPassengers(final int id, final IntList passengers) { public void setPassengers(final int id, final IntList passengers) {
vehicles.put(id, passengers); vehicles.put(id, passengers);
} }
public boolean isInsideVehicle(final int id) { public boolean isInsideVehicle(final int id) {
for (List<Integer> vehicle : vehicles.values()) { for (List<Integer> vehicle : vehicles.values()) {
if (vehicle.contains(id)) return true; if (vehicle.contains(id)) return true;
} }
return false; return false;
} }
public Integer getVehicle(final int passenger) { public Integer getVehicle(final int passenger) {
for (Map.Entry<Integer, IntList> vehicle : vehicles.int2ObjectEntrySet()) { for (Map.Entry<Integer, IntList> vehicle : vehicles.int2ObjectEntrySet()) {
if (vehicle.getValue().contains(passenger)) return vehicle.getKey(); if (vehicle.getValue().contains(passenger)) return vehicle.getKey();
} }
return null; return null;
} }
public Int2IntMap getStatus() { public Int2IntMap getStatus() {
return status; return status;
} }
} }
@@ -21,22 +21,22 @@ import com.viaversion.viaversion.api.connection.StorableObject;
public class LevitationStorage implements StorableObject { public class LevitationStorage implements StorableObject {
private boolean active; private boolean active;
private int amplifier; private int amplifier;
public boolean isActive() { public boolean isActive() {
return active; return active;
} }
public void setActive(boolean active) { public void setActive(boolean active) {
this.active = active; this.active = active;
} }
public int getAmplifier() { public int getAmplifier() {
return amplifier; return amplifier;
} }
public void setAmplifier(int amplifier) { public void setAmplifier(int amplifier) {
this.amplifier = amplifier; this.amplifier = amplifier;
} }
} }
@@ -20,77 +20,76 @@ package com.viaversion.viarewind.protocol.v1_9to1_8.storage;
import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8; import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.api.connection.StorableObject; import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
public class PlayerPositionTracker implements StorableObject { public class PlayerPositionTracker implements StorableObject {
private final Queue<PacketWrapper> animations = new ConcurrentLinkedQueue<>(); private final Queue<PacketWrapper> animations = new ConcurrentLinkedQueue<>();
private double posX, posY, posZ; private double posX, posY, posZ;
private float yaw, pitch; private float yaw, pitch;
private boolean onGround; private boolean onGround;
private int confirmId = -1; private int confirmId = -1;
public void setPos(double x, double y, double z) { public void setPos(double x, double y, double z) {
this.posX = x; this.posX = x;
this.posY = y; this.posY = y;
this.posZ = z; this.posZ = z;
} }
public void sendAnimations() { public void sendAnimations() {
PacketWrapper wrapper; PacketWrapper wrapper;
while ((wrapper = animations.poll()) != null) { while ((wrapper = animations.poll()) != null) {
wrapper.sendToServer(Protocol1_9To1_8.class); wrapper.sendToServer(Protocol1_9To1_8.class);
} }
} }
public void queueAnimation(final PacketWrapper wrapper) { public void queueAnimation(final PacketWrapper wrapper) {
animations.add(wrapper); animations.add(wrapper);
} }
public void setYaw(float yaw) { public double getPosX() {
this.yaw = yaw % 360f; return this.posX;
} }
public void setPitch(float pitch) { public double getPosY() {
this.pitch = pitch % 360f; return this.posY;
} }
public double getPosX() { public double getPosZ() {
return this.posX; return this.posZ;
} }
public double getPosY() { public float getYaw() {
return this.posY; return this.yaw;
} }
public double getPosZ() { public void setYaw(float yaw) {
return this.posZ; this.yaw = yaw % 360f;
} }
public float getYaw() { public float getPitch() {
return this.yaw; return this.pitch;
} }
public float getPitch() { public void setPitch(float pitch) {
return this.pitch; this.pitch = pitch % 360f;
} }
public boolean isOnGround() { public boolean isOnGround() {
return this.onGround; return this.onGround;
} }
public int getConfirmId() { public void setOnGround(boolean onGround) {
return this.confirmId; this.onGround = onGround;
} }
public void setOnGround(boolean onGround) { public int getConfirmId() {
this.onGround = onGround; return this.confirmId;
} }
public void setConfirmId(int confirmId) { public void setConfirmId(int confirmId) {
this.confirmId = confirmId; this.confirmId = confirmId;
} }
} }
@@ -30,83 +30,82 @@ 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.components.TranslationComponent;
import com.viaversion.viaversion.libs.mcstructs.text.serializer.TextComponentSerializer; import com.viaversion.viaversion.libs.mcstructs.text.serializer.TextComponentSerializer;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class WindowTracker extends StoredObject { public class WindowTracker extends StoredObject {
private final HashMap<Short, String> types = new HashMap<>(); private final HashMap<Short, String> types = new HashMap<>();
private final HashMap<Short, Item[]> brewingItems = new HashMap<>(); private final HashMap<Short, Item[]> brewingItems = new HashMap<>();
private final Map<Short, Short> enchantmentProperties = new HashMap<>(); private final Map<Short, Short> enchantmentProperties = new HashMap<>();
public WindowTracker(UserConnection user) { public WindowTracker(UserConnection user) {
super(user); super(user);
} }
public String get(short windowId) { public static void updateBrewingStand(UserConnection user, Item blazePowder, short windowId) {
return types.get(windowId); if (blazePowder != null && blazePowder.identifier() != 377) {
} return;
}
int amount = blazePowder == null ? 0 : blazePowder.amount();
public void put(short windowId, String type) { PacketWrapper openWindow = PacketWrapper.create(ClientboundPackets1_8.OPEN_SCREEN, user);
types.put(windowId, type); openWindow.write(Types.UNSIGNED_BYTE, windowId);
} openWindow.write(Types.STRING, "minecraft:brewing_stand");
public void remove(short windowId) { TextComponent title = new StringComponent().
types.remove(windowId); append(new TranslationComponent("container.brewing")).
brewingItems.remove(windowId); append(new StringComponent(": " + TextFormatting.DARK_GRAY)).
} append(new StringComponent(amount + " " + TextFormatting.DARK_RED)).
append(new TranslationComponent("item.blazePowder.name", TextFormatting.DARK_RED));
public Item[] getBrewingItems(short windowId) { openWindow.write(Types.COMPONENT, TextComponentSerializer.V1_8.serializeJson(title));
return brewingItems.computeIfAbsent(windowId, key -> new Item[]{ openWindow.write(Types.UNSIGNED_BYTE, (short) 420);
new DataItem(), openWindow.scheduleSend(Protocol1_9To1_8.class);
new DataItem(),
new DataItem(),
new DataItem()
});
}
public short getEnchantmentValue(final short key) { Item[] items = user.get(WindowTracker.class).getBrewingItems(windowId);
if (!enchantmentProperties.containsKey(key)) { for (int i = 0; i < items.length; i++) {
return 0; PacketWrapper setSlot = PacketWrapper.create(ClientboundPackets1_8.CONTAINER_SET_SLOT, user);
} setSlot.write(Types.BYTE, (byte) windowId);
return enchantmentProperties.remove(key); setSlot.write(Types.SHORT, (short) i);
} setSlot.write(Types.ITEM1_8, items[i]);
setSlot.scheduleSend(Protocol1_9To1_8.class);
}
}
public void putEnchantmentProperty(short key, short value) { public String get(short windowId) {
enchantmentProperties.put(key, value); return types.get(windowId);
} }
public void clearEnchantmentProperties() { public void put(short windowId, String type) {
enchantmentProperties.clear(); types.put(windowId, type);
} }
public static void updateBrewingStand(UserConnection user, Item blazePowder, short windowId) { public void remove(short windowId) {
if (blazePowder != null && blazePowder.identifier() != 377) { types.remove(windowId);
return; brewingItems.remove(windowId);
} }
int amount = blazePowder == null ? 0 : blazePowder.amount();
PacketWrapper openWindow = PacketWrapper.create(ClientboundPackets1_8.OPEN_SCREEN, user); public Item[] getBrewingItems(short windowId) {
openWindow.write(Types.UNSIGNED_BYTE, windowId); return brewingItems.computeIfAbsent(windowId, key -> new Item[]{
openWindow.write(Types.STRING, "minecraft:brewing_stand"); new DataItem(),
new DataItem(),
new DataItem(),
new DataItem()
});
}
TextComponent title = new StringComponent(). public short getEnchantmentValue(final short key) {
append(new TranslationComponent("container.brewing")). if (!enchantmentProperties.containsKey(key)) {
append(new StringComponent(": " + TextFormatting.DARK_GRAY)). return 0;
append(new StringComponent(amount + " " + TextFormatting.DARK_RED)). }
append(new TranslationComponent("item.blazePowder.name", TextFormatting.DARK_RED)); return enchantmentProperties.remove(key);
}
openWindow.write(Types.COMPONENT, TextComponentSerializer.V1_8.serializeJson(title)); public void putEnchantmentProperty(short key, short value) {
openWindow.write(Types.UNSIGNED_BYTE, (short) 420); enchantmentProperties.put(key, value);
openWindow.scheduleSend(Protocol1_9To1_8.class); }
Item[] items = user.get(WindowTracker.class).getBrewingItems(windowId); public void clearEnchantmentProperties() {
for (int i = 0; i < items.length; i++) { enchantmentProperties.clear();
PacketWrapper setSlot = PacketWrapper.create(ClientboundPackets1_8.CONTAINER_SET_SLOT, user); }
setSlot.write(Types.BYTE, (byte) windowId);
setSlot.write(Types.SHORT, (short) i);
setSlot.write(Types.ITEM1_8, items[i]);
setSlot.scheduleSend(Protocol1_9To1_8.class);
}
}
} }
@@ -23,10 +23,10 @@ import com.viaversion.viaversion.api.connection.UserConnection;
public class CooldownIndicatorTask implements Runnable { public class CooldownIndicatorTask implements Runnable {
@Override @Override
public void run() { public void run() {
for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) { for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) {
connection.get(CooldownStorage.class).tick(connection); connection.get(CooldownStorage.class).tick(connection);
} }
} }
} }
@@ -25,32 +25,31 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import java.util.logging.Level; import java.util.logging.Level;
public class LevitationUpdateTask implements Runnable { public class LevitationUpdateTask implements Runnable {
@Override @Override
public void run() { public void run() {
if (!ViaRewind.getConfig().emulateLevitationEffect()) { if (!ViaRewind.getConfig().emulateLevitationEffect()) {
return; return;
} }
for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) { for (UserConnection connection : Via.getManager().getConnectionManager().getConnections()) {
final LevitationStorage levitation = connection.get(LevitationStorage.class); final LevitationStorage levitation = connection.get(LevitationStorage.class);
if (!levitation.isActive()) { if (!levitation.isActive()) {
continue; continue;
} }
final PacketWrapper velocityPacket = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_MOTION, connection); final PacketWrapper velocityPacket = PacketWrapper.create(ClientboundPackets1_8.SET_ENTITY_MOTION, connection);
velocityPacket.write(Types.VAR_INT, connection.getEntityTracker(Protocol1_9To1_8.class).clientEntityId()); velocityPacket.write(Types.VAR_INT, connection.getEntityTracker(Protocol1_9To1_8.class).clientEntityId());
velocityPacket.write(Types.SHORT, (short) 0); velocityPacket.write(Types.SHORT, (short) 0);
velocityPacket.write(Types.SHORT, (short) ((levitation.getAmplifier() + 1) * 360)); velocityPacket.write(Types.SHORT, (short) ((levitation.getAmplifier() + 1) * 360));
velocityPacket.write(Types.SHORT, (short) 0); velocityPacket.write(Types.SHORT, (short) 0);
try { try {
velocityPacket.scheduleSend(Protocol1_9To1_8.class); velocityPacket.scheduleSend(Protocol1_9To1_8.class);
} catch (Exception e) { } catch (Exception e) {
ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to send levitation packet", e); ViaRewind.getPlatform().getLogger().log(Level.SEVERE, "Failed to send levitation packet", e);
} }
} }
} }
} }
@@ -26,75 +26,74 @@ import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13; import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter; import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
import com.viaversion.viaversion.util.ComponentUtil; import com.viaversion.viaversion.util.ComponentUtil;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@Deprecated @Deprecated
public class ChatUtil { public class ChatUtil {
private static final Pattern UNUSED_COLOR_PATTERN = Pattern.compile("(?>(?>§[0-fk-or])*(§r|\\Z))|(?>(?>§[0-f])*(§[0-f]))"); private static final Pattern UNUSED_COLOR_PATTERN = Pattern.compile("(?>(?>§[0-fk-or])*(§r|\\Z))|(?>(?>§[0-f])*(§[0-f]))");
private static final JsonNBTComponentRewriter<ClientboundPacketType> LEGACY_REWRITER = new JsonNBTComponentRewriter<>(null, JsonNBTComponentRewriter.ReadType.JSON) { private static final JsonNBTComponentRewriter<ClientboundPacketType> LEGACY_REWRITER = new JsonNBTComponentRewriter<>(null, JsonNBTComponentRewriter.ReadType.JSON) {
@Override @Override
protected void handleTranslate(JsonObject object, String translate) { protected void handleTranslate(JsonObject object, String translate) {
String text = Protocol1_12_2To1_13.MAPPINGS.getMojangTranslation().get(translate); String text = Protocol1_12_2To1_13.MAPPINGS.getMojangTranslation().get(translate);
if (text != null) { if (text != null) {
object.addProperty("translate", text); object.addProperty("translate", text);
} }
} }
}; };
public static String jsonToLegacy(String json) { public static String jsonToLegacy(String json) {
if (json == null || json.equals("null") || json.isEmpty()) { if (json == null || json.equals("null") || json.isEmpty()) {
return ""; return "";
} }
try { try {
return jsonToLegacy(JsonParser.parseString(json)); return jsonToLegacy(JsonParser.parseString(json));
} catch (Exception e) { } catch (Exception e) {
if (!Via.getConfig().isSuppressConversionWarnings()) { if (!Via.getConfig().isSuppressConversionWarnings()) {
ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Could not convert component to legacy text: " + json, e); ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Could not convert component to legacy text: " + json, e);
} }
} }
return ""; return "";
} }
public static String jsonToLegacy(JsonElement component) { public static String jsonToLegacy(JsonElement component) {
if (component.isJsonNull() || component.isJsonArray() && component.getAsJsonArray().isEmpty() || component.isJsonObject() && component.getAsJsonObject().isEmpty()) { if (component.isJsonNull() || component.isJsonArray() && component.getAsJsonArray().isEmpty() || component.isJsonObject() && component.getAsJsonObject().isEmpty()) {
return ""; return "";
} else if (component.isJsonPrimitive()) { } else if (component.isJsonPrimitive()) {
return component.getAsString(); return component.getAsString();
} else { } else {
try { try {
LEGACY_REWRITER.processText(null, component); LEGACY_REWRITER.processText(null, component);
String legacy = ComponentUtil.jsonToLegacy(component); String legacy = ComponentUtil.jsonToLegacy(component);
int attempts = 0; int attempts = 0;
while (legacy.startsWith("§f") && attempts++ < 10) { while (legacy.startsWith("§f") && attempts++ < 10) {
legacy = legacy.substring(2); legacy = legacy.substring(2);
} }
return legacy; return legacy;
} catch (Exception ex) { } catch (Exception ex) {
if (!Via.getConfig().isSuppressConversionWarnings()) { if (!Via.getConfig().isSuppressConversionWarnings()) {
ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Could not convert component to legacy text: " + component, ex); ViaRewind.getPlatform().getLogger().log(Level.WARNING, "Could not convert component to legacy text: " + component, ex);
} }
} }
return ""; return "";
} }
} }
public static String removeUnusedColor(String legacy, char last) { public static String removeUnusedColor(String legacy, char last) {
if (legacy == null) return null; if (legacy == null) return null;
legacy = UNUSED_COLOR_PATTERN.matcher(legacy).replaceAll("$1$2"); legacy = UNUSED_COLOR_PATTERN.matcher(legacy).replaceAll("$1$2");
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (int i = 0; i < legacy.length(); i++) { for (int i = 0; i < legacy.length(); i++) {
char current = legacy.charAt(i); char current = legacy.charAt(i);
if (current != '§' || i == legacy.length() - 1) { if (current != '§' || i == legacy.length() - 1) {
builder.append(current); builder.append(current);
continue; continue;
} }
current = legacy.charAt(++i); current = legacy.charAt(++i);
if (current == last) continue; if (current == last) continue;
builder.append('§').append(current); builder.append('§').append(current);
last = current; last = current;
} }
return builder.toString(); return builder.toString();
} }
} }
@@ -19,31 +19,30 @@ package com.viaversion.viarewind;
import com.viaversion.viarewind.api.ViaRewindPlatform; import com.viaversion.viarewind.api.ViaRewindPlatform;
import com.viaversion.viarewind.fabric.util.LoggerWrapper; import com.viaversion.viarewind.fabric.util.LoggerWrapper;
import net.fabricmc.loader.api.FabricLoader;
import org.apache.logging.log4j.LogManager;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.logging.Logger; import java.util.logging.Logger;
import net.fabricmc.loader.api.FabricLoader;
import org.apache.logging.log4j.LogManager;
public class ViaFabricAddon implements ViaRewindPlatform, Runnable { public class ViaFabricAddon implements ViaRewindPlatform, Runnable {
private final Logger logger = new LoggerWrapper(LogManager.getLogger("ViaRewind")); private final Logger logger = new LoggerWrapper(LogManager.getLogger("ViaRewind"));
private File configDir; private File configDir;
@Override @Override
public void run() { public void run() {
final Path configDirPath = FabricLoader.getInstance().getConfigDir().resolve("ViaRewind"); final Path configDirPath = FabricLoader.getInstance().getConfigDir().resolve("ViaRewind");
this.configDir = configDirPath.toFile(); this.configDir = configDirPath.toFile();
this.init(new File(getDataFolder(), "config.yml")); this.init(new File(getDataFolder(), "config.yml"));
} }
@Override @Override
public File getDataFolder() { public File getDataFolder() {
return this.configDir; return this.configDir;
} }
@Override @Override
public Logger getLogger() { public Logger getLogger() {
return this.logger; return this.logger;
} }
} }
@@ -30,12 +30,12 @@ public class LoggerWrapper extends Logger {
this.base = logger; this.base = logger;
} }
@Override @Override
public void log(LogRecord record) { public void log(LogRecord record) {
this.log(record.getLevel(), record.getMessage()); this.log(record.getLevel(), record.getMessage());
} }
@Override @Override
public void log(Level level, String msg) { public void log(Level level, String msg) {
if (level == Level.FINE) { if (level == Level.FINE) {
this.base.debug(msg); this.base.debug(msg);
@@ -51,7 +51,7 @@ public class LoggerWrapper extends Logger {
} }
@Override @Override
public void log(Level level, String msg, Object param1) { public void log(Level level, String msg, Object param1) {
if (level == Level.FINE) { if (level == Level.FINE) {
this.base.debug(msg, param1); this.base.debug(msg, param1);
@@ -67,12 +67,12 @@ public class LoggerWrapper extends Logger {
} }
@Override @Override
public void log(Level level, String msg, Object[] params) { public void log(Level level, String msg, Object[] params) {
log(level, MessageFormat.format(msg, params)); log(level, MessageFormat.format(msg, params));
} }
@Override @Override
public void log(Level level, String msg, Throwable params) { public void log(Level level, String msg, Throwable params) {
if (level == Level.FINE) { if (level == Level.FINE) {
this.base.debug(msg, params); this.base.debug(msg, params);
@@ -87,4 +87,4 @@ public class LoggerWrapper extends Logger {
} }
} }
} }
+3 -1
View File
@@ -29,7 +29,9 @@
"custom": { "custom": {
"modmenu:api": true, "modmenu:api": true,
"modmenu": { "modmenu": {
"badges": [ "library" ], "badges": [
"library"
],
"parent": "viafabric" "parent": "viafabric"
} }
} }
@@ -24,59 +24,58 @@ import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Dependency; import com.velocitypowered.api.plugin.Dependency;
import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.viaversion.viarewind.api.ViaRewindPlatform;
import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.velocity.util.LoggerWrapper; import com.viaversion.viaversion.velocity.util.LoggerWrapper;
import com.viaversion.viarewind.api.ViaRewindPlatform;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.logging.Logger; import java.util.logging.Logger;
@Plugin(id = "viarewind", @Plugin(id = "viarewind",
name = "ViaRewind", name = "ViaRewind",
version = ViaRewindPlatform.VERSION, version = ViaRewindPlatform.VERSION,
authors = { "FlorianMichael/EnZaXD", "Gerrygames", "creeper123123321"}, authors = {"FlorianMichael/EnZaXD", "Gerrygames", "creeper123123321"},
description = "ViaVersion addon to allow 1.8.x and 1.7.x clients on newer server versions.", description = "ViaVersion addon to allow 1.8.x and 1.7.x clients on newer server versions.",
dependencies = { dependencies = {
@Dependency(id = "viaversion"), @Dependency(id = "viaversion"),
@Dependency(id = "viabackwards") @Dependency(id = "viabackwards")
}, },
url = "https://viaversion.com/rewind" url = "https://viaversion.com/rewind"
) )
public class VelocityPlugin implements ViaRewindPlatform { public class VelocityPlugin implements ViaRewindPlatform {
private Logger logger; private Logger logger;
@Inject @Inject
private org.slf4j.Logger loggerSlf4j; private org.slf4j.Logger loggerSlf4j;
@Inject @Inject
@DataDirectory @DataDirectory
private Path configPath; private Path configPath;
@Subscribe(order = PostOrder.LATE) @Subscribe(order = PostOrder.LATE)
public void onProxyStart(ProxyInitializeEvent e) { public void onProxyStart(ProxyInitializeEvent e) {
this.logger = new LoggerWrapper(loggerSlf4j); this.logger = new LoggerWrapper(loggerSlf4j);
Via.getManager().addEnableListener(() -> this.init(new File(getDataFolder(), "config.yml"))); Via.getManager().addEnableListener(() -> this.init(new File(getDataFolder(), "config.yml")));
} }
@Override @Override
public File getDataFolder() { public File getDataFolder() {
return configPath.toFile(); return configPath.toFile();
} }
@Override @Override
public Logger getLogger() { public Logger getLogger() {
return this.logger; return this.logger;
} }
@Override @Override
public String compressHandlerName() { public String compressHandlerName() {
return "compression-encoder"; return "compression-encoder";
} }
@Override @Override
public String decompressHandlerName() { public String decompressHandlerName() {
return "compression-decoder"; return "compression-decoder";
} }
} }