mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2026-11-04 08:52:10 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f040077c13 | ||
|
|
1f404820b7 | ||
|
|
742e70fff6 | ||
|
|
dd6a1a7f6e | ||
|
|
08ef7c2f35 | ||
|
|
e128469313 | ||
|
|
cbb753271e | ||
|
|
29f299d882 | ||
|
|
41138aabd1 | ||
|
|
b90f20cfeb | ||
|
|
585028beb7 |
No files matched your search
@@ -26,7 +26,7 @@ jobs:
|
||||
run: ./gradlew build
|
||||
- name: Upload Artifacts to GitHub
|
||||
# Only upload on the preview repository as there is no CI job for it.
|
||||
if: ${{ github.repository == 'ViaVersionDev' && github.ref_name == 'preview' }}
|
||||
if: ${{ github.repository == 'ViaVersion/ViaVersionDev' && github.ref_name == 'preview' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Artifacts
|
||||
|
||||
@@ -24,6 +24,7 @@ dependencies {
|
||||
}
|
||||
implementation(rootProject.libs.text) {
|
||||
exclude("com.google.code.gson", "gson")
|
||||
exclude("com.google.guava", "guava")
|
||||
exclude("com.viaversion", "nbt")
|
||||
}
|
||||
api(libs.snakeYaml)
|
||||
|
||||
@@ -123,6 +123,20 @@ public interface EntityTracker {
|
||||
*/
|
||||
void setClientEntityId(int clientEntityId);
|
||||
|
||||
/**
|
||||
* Returns whether the client player has the "insta build" ability, usually from creative mode.
|
||||
*
|
||||
* @return whether the client player can insta build
|
||||
*/
|
||||
boolean canInstaBuild();
|
||||
|
||||
/**
|
||||
* Sets whether the client player has the "insta build" ability, usually from creative mode.
|
||||
*
|
||||
* @param instaBuild whether the client player can insta build
|
||||
*/
|
||||
void setInstaBuild(boolean instaBuild);
|
||||
|
||||
/**
|
||||
* Returns the current world section height (block height / 16).
|
||||
* This is always 16 for sub 1.17 worlds.
|
||||
|
||||
@@ -24,22 +24,28 @@ package com.viaversion.viaversion.api.minecraft;
|
||||
|
||||
public enum GameMode {
|
||||
|
||||
NOT_SET(""),
|
||||
SURVIVAL("Survival Mode"),
|
||||
CREATIVE("Creative Mode"),
|
||||
ADVENTURE("Adventure Mode"),
|
||||
SPECTATOR("Spectator Mode");
|
||||
NOT_SET("", -1),
|
||||
SURVIVAL("Survival Mode", 0),
|
||||
CREATIVE("Creative Mode", 1),
|
||||
ADVENTURE("Adventure Mode", 2),
|
||||
SPECTATOR("Spectator Mode", 3);
|
||||
|
||||
private final String text;
|
||||
private final int id;
|
||||
|
||||
GameMode(String text) {
|
||||
GameMode(String text, final int id) {
|
||||
this.text = text;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String text() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static GameMode getById(int id) {
|
||||
return switch (id) {
|
||||
case -1 -> NOT_SET;
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
||||
* Copyright (C) 2016-2025 ViaVersion and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.type.types.chunk;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class ChunkBiomesType1_19_4 extends Type<DataPalette[]> {
|
||||
private final PaletteTypeBase paletteType;
|
||||
private final int ySectionCount;
|
||||
|
||||
public ChunkBiomesType1_19_4(final int ySectionCount, final int globalPaletteBiomeBits) {
|
||||
this(ySectionCount, new PaletteType1_18(PaletteType.BIOMES, globalPaletteBiomeBits));
|
||||
}
|
||||
|
||||
protected ChunkBiomesType1_19_4(final int ySectionCount, final PaletteTypeBase paletteType) {
|
||||
super(DataPalette[].class);
|
||||
this.paletteType = paletteType;
|
||||
this.ySectionCount = ySectionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataPalette[] read(final ByteBuf buffer) {
|
||||
final ByteBuf data = buffer.readSlice(Types.VAR_INT.readPrimitive(buffer));
|
||||
final DataPalette[] sections = new DataPalette[ySectionCount];
|
||||
for (int i = 0; i < ySectionCount; i++) {
|
||||
sections[i] = paletteType.read(data);
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final ByteBuf buffer, final DataPalette[] value) {
|
||||
int size = 0;
|
||||
for (final DataPalette biomes : value) {
|
||||
size += paletteType.serializedSize(biomes);
|
||||
}
|
||||
Types.VAR_INT.writePrimitive(buffer, size);
|
||||
for (final DataPalette biomes : value) {
|
||||
paletteType.write(buffer, biomes);
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
||||
* Copyright (C) 2016-2025 ViaVersion and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.type.types.chunk;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
|
||||
|
||||
public class ChunkBiomesType1_21_5 extends ChunkBiomesType1_19_4 {
|
||||
|
||||
public ChunkBiomesType1_21_5(final int ySectionCount, final int globalPaletteBiomeBits) {
|
||||
super(ySectionCount, new PaletteType1_21_5(PaletteType.BIOMES, globalPaletteBiomeBits));
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
||||
* Copyright (C) 2016-2025 ViaVersion and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viaversion.bukkit.util;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class LegacyBlockToItem {
|
||||
private static final LegacyBlockToItem INSTANCE;
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
static {
|
||||
LegacyBlockToItem instance = null;
|
||||
try {
|
||||
instance = new LegacyBlockToItem();
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
Via.getPlatform().getLogger().log(
|
||||
Level.WARNING,
|
||||
"Couldn't find reflection methods/fields for pick-block functionality.\n" +
|
||||
"Pick-block won't work on clients 1.21.4 and newer.", ex);
|
||||
}
|
||||
INSTANCE = instance;
|
||||
}
|
||||
|
||||
private final Method GET_WORLD_HANDLE;
|
||||
private final Method GET_BLOCK_TYPE;
|
||||
private final Method GET_BLOCK;
|
||||
private final Method GET_ITEM_FOR_BLOCK;
|
||||
private final Method GET_DROP_TYPE;
|
||||
private final Method TO_BUKKIT_ITEM_STACK;
|
||||
private final Method NEW_BUKKIT_ITEM_STACK;
|
||||
|
||||
private final Method SET_POSITION;
|
||||
private final Object BLOCK_POSITION;
|
||||
|
||||
public LegacyBlockToItem() throws ReflectiveOperationException {
|
||||
Class<?> blockPosition = NMSUtil.nms("BlockPosition");
|
||||
Class<?> mutableBlockPosition = NMSUtil.nms("BlockPosition$MutableBlockPosition");
|
||||
Class<?> world = NMSUtil.nms("World");
|
||||
Class<?> block = NMSUtil.nms("Block");
|
||||
Class<?> iBlockData = NMSUtil.nms("IBlockData");
|
||||
Class<?> nmsItem = NMSUtil.nms("Item");
|
||||
Class<?> nmsItemStack = NMSUtil.nms("ItemStack");
|
||||
Class<?> craftItemStack = NMSUtil.obc("inventory.CraftItemStack");
|
||||
|
||||
GET_WORLD_HANDLE = NMSUtil.obc("CraftWorld").getDeclaredMethod("getHandle");
|
||||
GET_BLOCK_TYPE = world.getDeclaredMethod("getType", blockPosition);
|
||||
GET_BLOCK = iBlockData.getDeclaredMethod("getBlock");
|
||||
GET_ITEM_FOR_BLOCK = block.getDeclaredMethod("i", iBlockData);
|
||||
GET_ITEM_FOR_BLOCK.setAccessible(true);
|
||||
|
||||
GET_DROP_TYPE = block.getDeclaredMethod("getDropType", iBlockData, Random.class, int.class);
|
||||
|
||||
TO_BUKKIT_ITEM_STACK = craftItemStack.getDeclaredMethod("asCraftMirror", nmsItemStack);
|
||||
NEW_BUKKIT_ITEM_STACK = craftItemStack.getDeclaredMethod("asNewCraftStack", nmsItem);
|
||||
|
||||
SET_POSITION = mutableBlockPosition.getDeclaredMethod("c", int.class, int.class, int.class);
|
||||
BLOCK_POSITION = mutableBlockPosition.getConstructor().newInstance();
|
||||
}
|
||||
|
||||
public static LegacyBlockToItem getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public @Nullable ItemStack blockToItem(final Block block) {
|
||||
try {
|
||||
// World nmsWorld = block.getWorld().getHandle();
|
||||
Object nmsWorld = GET_WORLD_HANDLE.invoke(block.getWorld());
|
||||
|
||||
// IBlockData blockData = nmsWorld.get(block.position());
|
||||
SET_POSITION.invoke(BLOCK_POSITION, block.getX(), block.getY(), block.getZ());
|
||||
Object blockData = GET_BLOCK_TYPE.invoke(nmsWorld, BLOCK_POSITION);
|
||||
|
||||
// Block nmsBlock = blockData.getBlock();
|
||||
Object nmsBlock = GET_BLOCK.invoke(blockData);
|
||||
// ItemStack is = nmsBlock.getItemForBlock(blockData);
|
||||
Object nmsItemStack = GET_ITEM_FOR_BLOCK.invoke(nmsBlock, blockData);
|
||||
|
||||
// CraftItemStack.asCraftMirror(nmsItemStack)
|
||||
ItemStack stack = (ItemStack) TO_BUKKIT_ITEM_STACK.invoke(null, nmsItemStack);
|
||||
if (stack.getType() != Material.AIR) return stack;
|
||||
|
||||
// Couldn't find an item for the block (eg: redstone dust, sugarcane, doors, etc.), use the drop instead
|
||||
Object nmsItem = GET_DROP_TYPE.invoke(nmsBlock, blockData, RANDOM, 0);
|
||||
return (ItemStack) NEW_BUKKIT_ITEM_STACK.invoke(null, nmsItem);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
Via.getPlatform().getLogger().log(
|
||||
Level.WARNING, "Failed when trying to find the right item for pick-block.", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -192,9 +192,7 @@ public class BukkitViaLoader implements ViaPlatformLoader {
|
||||
}
|
||||
}
|
||||
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_21_4)) {
|
||||
if (PaperViaInjector.hasMethod(Material.class, "isItem")) {
|
||||
Via.getManager().getProviders().use(PickItemProvider.class, new BukkitPickItemProvider(plugin));
|
||||
}
|
||||
Via.getManager().getProviders().use(PickItemProvider.class, new BukkitPickItemProvider(plugin));
|
||||
}
|
||||
|
||||
// Needs to be enabled on any version with the updated item desync check
|
||||
|
||||
+65
-22
@@ -21,6 +21,7 @@ import com.viaversion.viaversion.ViaVersionPlugin;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.BlockPosition;
|
||||
import com.viaversion.viaversion.bukkit.platform.PaperViaInjector;
|
||||
import com.viaversion.viaversion.bukkit.util.LegacyBlockToItem;
|
||||
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider.PickItemProvider;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -31,14 +32,17 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public final class BukkitPickItemProvider extends PickItemProvider {
|
||||
private static final boolean HAS_PLACEMENT_MATERIAL_METHOD = PaperViaInjector.hasMethod("org.bukkit.block.data.BlockData", "getPlacementMaterial");
|
||||
public class BukkitPickItemProvider extends PickItemProvider {
|
||||
private static final BlockToItem BLOCK_TO_ITEM = BlockToItem.build();
|
||||
private static final GetStorageContents GET_STORAGE_CONTENT = GetStorageContents.build();
|
||||
private static final SetInHand SET_IN_HAND = SetInHand.build();
|
||||
|
||||
private static final boolean HAS_SPAWN_EGG_METHOD = PaperViaInjector.hasMethod(ItemFactory.class, "getSpawnEgg", EntityType.class);
|
||||
private static final double BLOCK_RANGE = 4.5 + 1;
|
||||
private static final double BLOCK_RANGE_SQUARED = BLOCK_RANGE * BLOCK_RANGE;
|
||||
@@ -68,27 +72,13 @@ public final class BukkitPickItemProvider extends PickItemProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
final ItemStack item = blockToItem(block, includeData && player.getGameMode() == GameMode.CREATIVE);
|
||||
if (item != null) {
|
||||
final ItemStack item = BLOCK_TO_ITEM.apply(block, includeData && player.getGameMode() == GameMode.CREATIVE);
|
||||
if (item != null && item.getType() != Material.AIR) {
|
||||
pickItem(player, item);
|
||||
}
|
||||
}, player);
|
||||
}
|
||||
|
||||
private @Nullable ItemStack blockToItem(final Block block, final boolean includeData) {
|
||||
if (HAS_PLACEMENT_MATERIAL_METHOD) {
|
||||
final ItemStack item = new ItemStack(block.getBlockData().getPlacementMaterial(), 1);
|
||||
if (includeData && item.getItemMeta() instanceof final BlockStateMeta blockStateMeta) {
|
||||
blockStateMeta.setBlockState(block.getState());
|
||||
item.setItemMeta(blockStateMeta);
|
||||
}
|
||||
return item;
|
||||
} else if (block.getType().isItem()) {
|
||||
return new ItemStack(block.getType(), 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pickItemFromEntity(final UserConnection connection, final int entityId, final boolean includeData) {
|
||||
if (!HAS_SPAWN_EGG_METHOD) {
|
||||
@@ -120,7 +110,8 @@ public final class BukkitPickItemProvider extends PickItemProvider {
|
||||
private void pickItem(final Player player, final ItemStack item) {
|
||||
// Find matching item
|
||||
final PlayerInventory inventory = player.getInventory();
|
||||
final ItemStack[] contents = inventory.getStorageContents();
|
||||
// Prior to getStorageContents, getContents worked the same (it ignored armor)
|
||||
final ItemStack[] contents = GET_STORAGE_CONTENT.apply(inventory);
|
||||
int sourceSlot = -1;
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
final ItemStack content = contents[i];
|
||||
@@ -155,7 +146,7 @@ public final class BukkitPickItemProvider extends PickItemProvider {
|
||||
}
|
||||
|
||||
inventory.setItem(emptySlot, heldItem);
|
||||
inventory.setItemInMainHand(item);
|
||||
SET_IN_HAND.apply(inventory, item);
|
||||
}
|
||||
|
||||
private void moveToHotbar(final PlayerInventory inventory, final int sourceSlot, final ItemStack[] contents) {
|
||||
@@ -168,7 +159,7 @@ public final class BukkitPickItemProvider extends PickItemProvider {
|
||||
final int targetSlot = findEmptyHotbarSlot(inventory, heldSlot);
|
||||
inventory.setHeldItemSlot(targetSlot);
|
||||
final ItemStack heldItem = inventory.getItem(targetSlot);
|
||||
inventory.setItemInMainHand(contents[sourceSlot]);
|
||||
SET_IN_HAND.apply(inventory, contents[sourceSlot]);
|
||||
inventory.setItem(sourceSlot, heldItem);
|
||||
}
|
||||
|
||||
@@ -181,4 +172,56 @@ public final class BukkitPickItemProvider extends PickItemProvider {
|
||||
}
|
||||
return heldSlot;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface BlockToItem {
|
||||
ItemStack apply(final Block block, final boolean includeData);
|
||||
|
||||
static BlockToItem build() {
|
||||
if (PaperViaInjector.hasMethod("org.bukkit.block.data.BlockData", "getPlacementMaterial")) {
|
||||
return (block, includeData) -> {
|
||||
final ItemStack item = new ItemStack(block.getBlockData().getPlacementMaterial(), 1);
|
||||
if (includeData && item.getItemMeta() instanceof final BlockStateMeta blockStateMeta) {
|
||||
blockStateMeta.setBlockState(block.getState());
|
||||
item.setItemMeta(blockStateMeta);
|
||||
}
|
||||
return item;
|
||||
};
|
||||
} else if (PaperViaInjector.hasMethod(Material.class, "isItem")) {
|
||||
return (block, includeData) -> new ItemStack(block.getType(), 1);
|
||||
} else {
|
||||
LegacyBlockToItem legacy = LegacyBlockToItem.getInstance();
|
||||
return legacy != null ? (block, includeData) -> legacy.blockToItem(block) : (b, i) -> null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface GetStorageContents {
|
||||
ItemStack[] apply(final PlayerInventory inv);
|
||||
|
||||
static GetStorageContents build() {
|
||||
if (PaperViaInjector.hasMethod(Inventory.class, "getStorageContents")) {
|
||||
return Inventory::getStorageContents;
|
||||
} else {
|
||||
return Inventory::getContents;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface SetInHand {
|
||||
void apply(final PlayerInventory inv, final ItemStack stack);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
static SetInHand build() {
|
||||
if (PaperViaInjector.hasMethod(PlayerInventory.class, "setItemInMainHand")) {
|
||||
return PlayerInventory::setItemInMainHand;
|
||||
} else {
|
||||
return PlayerInventory::setItemInHand;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ dependencies {
|
||||
api(projects.viaversionApi)
|
||||
api(rootProject.libs.text) {
|
||||
exclude("com.google.code.gson", "gson")
|
||||
exclude("com.google.guava", "guava")
|
||||
exclude("com.viaversion", "nbt")
|
||||
}
|
||||
|
||||
// Note: If manually starting tests doesn't work for you in IJ, change 'Gradle -> Run Tests Using' to 'IntelliJ IDEA'
|
||||
|
||||
@@ -148,7 +148,7 @@ public class ViaManagerImpl implements ViaManager {
|
||||
platform.getLogger().warning("ViaVersion only supports newer client versions. Use ViaBackwards to allow older versions (ViaRewind for 1.7/1.8) to join.");
|
||||
platform.getLogger().warning("Get setup help at https://viaversion.com/setup or download ViaBackwards/ViaRewind directly at https://ci.viaversion.com/");
|
||||
platform.getLogger().warning("Need more help? Join our Discord at https://viaversion.com/discord");
|
||||
} else if (protocolVersion.highestSupportedProtocolVersion().olderThan(ProtocolVersion.v1_13)) {
|
||||
} else if (protocolVersion.highestSupportedProtocolVersion().olderThan(ProtocolVersion.v1_16)) {
|
||||
platform.getLogger().warning("This version of Minecraft is extremely outdated and support for it has reached its end of life. "
|
||||
+ "You will still be able to run Via on this Minecraft version, but we will prioritize issues with legacy Minecraft versions less. "
|
||||
+ "Please consider updating to give your players a better experience and to avoid issues that have long been fixed.");
|
||||
|
||||
@@ -43,6 +43,7 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
|
||||
private String currentWorld;
|
||||
private int biomesSent = -1;
|
||||
private Map<String, DimensionData> dimensions = Collections.emptyMap();
|
||||
private boolean instaBuild;
|
||||
|
||||
public EntityTrackerBase(UserConnection connection, @Nullable EntityType playerType) {
|
||||
this.connection = connection;
|
||||
@@ -131,6 +132,16 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
|
||||
this.clientEntityId = clientEntityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInstaBuild() {
|
||||
return instaBuild;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInstaBuild(final boolean instaBuild) {
|
||||
this.instaBuild = instaBuild;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int currentWorldSectionHeight() {
|
||||
return currentWorldSectionHeight;
|
||||
|
||||
+4
-25
@@ -19,7 +19,6 @@ package com.viaversion.viaversion.protocols.template;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
|
||||
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
|
||||
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
|
||||
@@ -42,33 +41,13 @@ final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_2
|
||||
registerTrackerWithData1_19(ClientboundPackets1_21_2.ADD_ENTITY, EntityTypes1_21_4.FALLING_BLOCK);
|
||||
registerSetEntityData(ClientboundPackets1_21_2.SET_ENTITY_DATA, /*Types1_OLD_ENTITY_DATA_LIST, */Types1_21_4.ENTITY_DATA_LIST); // Specify old and new entity data list if changed
|
||||
registerRemoveEntities(ClientboundPackets1_21_2.REMOVE_ENTITIES);
|
||||
registerPlayerAbilities(ClientboundPackets1_21_2.PLAYER_ABILITIES);
|
||||
registerGameEvent(ClientboundPackets1_21_2.GAME_EVENT);
|
||||
registerLogin1_20_5(ClientboundPackets1_21_2.LOGIN);
|
||||
registerRespawn1_20_5(ClientboundPackets1_21_2.RESPAWN);
|
||||
|
||||
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
|
||||
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.LOGIN, wrapper -> {
|
||||
final int entityId = wrapper.passthrough(Types.INT); // Entity id
|
||||
wrapper.passthrough(Types.BOOLEAN); // Hardcore
|
||||
wrapper.passthrough(Types.STRING_ARRAY); // World List
|
||||
wrapper.passthrough(Types.VAR_INT); // Max players
|
||||
wrapper.passthrough(Types.VAR_INT); // View distance
|
||||
wrapper.passthrough(Types.VAR_INT); // Simulation distance
|
||||
wrapper.passthrough(Types.BOOLEAN); // Reduced debug info
|
||||
wrapper.passthrough(Types.BOOLEAN); // Show death screen
|
||||
wrapper.passthrough(Types.BOOLEAN); // Limited crafting
|
||||
|
||||
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
|
||||
final String world = wrapper.passthrough(Types.STRING);
|
||||
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world);
|
||||
|
||||
trackPlayer(wrapper.user(), entityId);
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.RESPAWN, wrapper -> {
|
||||
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
|
||||
final String world = wrapper.passthrough(Types.STRING);
|
||||
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-3
@@ -55,9 +55,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import net.lenni0451.mcstructs.core.TextFormatting;
|
||||
import net.lenni0451.mcstructs.text.ATextComponent;
|
||||
import net.lenni0451.mcstructs.text.Style;
|
||||
import net.lenni0451.mcstructs.text.TextComponent;
|
||||
import net.lenni0451.mcstructs.text.TextFormatting;
|
||||
import net.lenni0451.mcstructs.text.components.TranslationComponent;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
@@ -394,7 +394,7 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
|
||||
|
||||
// Add the replacements
|
||||
final ListTag<StringTag> parameters = tag.getListTag("parameters", StringTag.class);
|
||||
final List<ATextComponent> arguments = new ArrayList<>();
|
||||
final List<TextComponent> arguments = new ArrayList<>();
|
||||
if (parameters != null) {
|
||||
for (final StringTag element : parameters) {
|
||||
JsonElement argument = null;
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
|
||||
new StatisticsRewriter<>(this).register(ClientboundPackets1_20_3.AWARD_STATS);
|
||||
|
||||
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.SYSTEM_CHAT);
|
||||
componentRewriter.registerDisguisedChat(ClientboundPackets1_20_3.DISGUISED_CHAT);
|
||||
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.DISGUISED_CHAT);
|
||||
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_20_3.PLAYER_COMBAT_KILL);
|
||||
|
||||
// People add item hovers to all sorts of weird places...
|
||||
|
||||
+5
-5
@@ -24,6 +24,7 @@ import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.entity.DimensionData;
|
||||
import com.viaversion.viaversion.api.minecraft.GameMode;
|
||||
import com.viaversion.viaversion.api.minecraft.Particle;
|
||||
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
|
||||
@@ -64,7 +65,6 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
|
||||
|
||||
private static final UUID CREATIVE_BLOCK_INTERACTION_RANGE = UUID.fromString("736565d2-e1a7-403d-a3f8-1aeb3e302542");
|
||||
private static final UUID CREATIVE_ENTITY_INTERACTION_RANGE = UUID.fromString("98491ef6-97b1-4584-ae82-71a8cc85cf73");
|
||||
private static final int CREATIVE_MODE_ID = 1;
|
||||
|
||||
public EntityPacketRewriter1_20_5(final Protocol1_20_3To1_20_5 protocol) {
|
||||
super(protocol);
|
||||
@@ -279,7 +279,7 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
|
||||
|
||||
// Handle creative interaction range
|
||||
final byte gamemode = wrapper.get(Types.BYTE, 0);
|
||||
if (gamemode == CREATIVE_MODE_ID) {
|
||||
if (gamemode == GameMode.CREATIVE.id()) {
|
||||
sendRangeAttributes(wrapper.user(), true);
|
||||
}
|
||||
});
|
||||
@@ -296,7 +296,7 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
|
||||
wrapper.passthrough(Types.LONG); // Seed
|
||||
|
||||
final byte gamemode = wrapper.passthrough(Types.BYTE);
|
||||
sendRangeAttributes(wrapper.user(), gamemode == CREATIVE_MODE_ID);
|
||||
sendRangeAttributes(wrapper.user(), gamemode == GameMode.CREATIVE.id());
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_20_3.UPDATE_MOB_EFFECT, wrapper -> {
|
||||
@@ -338,8 +338,8 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
|
||||
}
|
||||
|
||||
// Resend attributes either with their original list or with the creative range modifier added
|
||||
final float value = wrapper.passthrough(Types.FLOAT);
|
||||
sendRangeAttributes(wrapper.user(), value == CREATIVE_MODE_ID);
|
||||
final int value = (int) Math.floor(wrapper.passthrough(Types.FLOAT) + 0.5F);
|
||||
sendRangeAttributes(wrapper.user(), value == GameMode.CREATIVE.id());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+3
-20
@@ -26,7 +26,6 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityType;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
|
||||
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21;
|
||||
@@ -95,25 +94,9 @@ public final class EntityPacketRewriter1_21 extends EntityRewriter<ClientboundPa
|
||||
jukeboxSongsPacket.send(Protocol1_20_5To1_21.class);
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_20_5.LOGIN, new PacketHandlers() {
|
||||
@Override
|
||||
public void register() {
|
||||
map(Types.INT); // Entity id
|
||||
map(Types.BOOLEAN); // Hardcore
|
||||
map(Types.STRING_ARRAY); // World List
|
||||
map(Types.VAR_INT); // Max players
|
||||
map(Types.VAR_INT); // View distance
|
||||
map(Types.VAR_INT); // Simulation distance
|
||||
map(Types.BOOLEAN); // Reduced debug info
|
||||
map(Types.BOOLEAN); // Show death screen
|
||||
map(Types.BOOLEAN); // Limited crafting
|
||||
map(Types.VAR_INT); // Dimension id
|
||||
map(Types.STRING); // World
|
||||
handler(worldDataTrackerHandlerByKey1_20_5(3));
|
||||
handler(playerTrackerHandler());
|
||||
handler(wrapper -> wrapper.user().get(EfficiencyAttributeStorage.class)
|
||||
.onLoginSent(wrapper.get(Types.INT, 0), wrapper.user()));
|
||||
}
|
||||
registerLogin1_20_5(ClientboundPackets1_20_5.LOGIN);
|
||||
protocol.appendClientbound(ClientboundPackets1_20_5.LOGIN, wrapper -> {
|
||||
wrapper.user().get(EfficiencyAttributeStorage.class).onLoginSent(wrapper.get(Types.INT, 0), wrapper.user());
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_20_5.RESPAWN, wrapper -> {
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ public final class BlockItemPacketRewriter1_21_4 extends StructuredItemRewriter<
|
||||
// and consume time really high, so the eating animation doesn't play
|
||||
item.dataContainer().set(StructuredDataKey.CONSUMABLE1_21_2,
|
||||
new Consumable1_21_2(
|
||||
3600,
|
||||
3600,
|
||||
3,
|
||||
Holder.of(new SoundEvent("minecraft:intentionally_empty", null)),
|
||||
false,
|
||||
|
||||
+2
-23
@@ -77,29 +77,8 @@ public final class EntityPacketRewriter1_21_4 extends EntityRewriter<Clientbound
|
||||
};
|
||||
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.LOGIN, wrapper -> {
|
||||
final int entityId = wrapper.passthrough(Types.INT); // Entity id
|
||||
wrapper.passthrough(Types.BOOLEAN); // Hardcore
|
||||
wrapper.passthrough(Types.STRING_ARRAY); // World List
|
||||
wrapper.passthrough(Types.VAR_INT); // Max players
|
||||
wrapper.passthrough(Types.VAR_INT); // View distance
|
||||
wrapper.passthrough(Types.VAR_INT); // Simulation distance
|
||||
wrapper.passthrough(Types.BOOLEAN); // Reduced debug info
|
||||
wrapper.passthrough(Types.BOOLEAN); // Show death screen
|
||||
wrapper.passthrough(Types.BOOLEAN); // Limited crafting
|
||||
|
||||
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
|
||||
final String world = wrapper.passthrough(Types.STRING);
|
||||
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world);
|
||||
|
||||
trackPlayer(wrapper.user(), entityId);
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.RESPAWN, wrapper -> {
|
||||
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
|
||||
final String world = wrapper.passthrough(Types.STRING);
|
||||
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking
|
||||
});
|
||||
registerLogin1_20_5(ClientboundPackets1_21_2.LOGIN);
|
||||
registerRespawn1_20_5(ClientboundPackets1_21_2.RESPAWN);
|
||||
|
||||
protocol.registerServerbound(ServerboundPackets1_21_4.MOVE_VEHICLE, wrapper -> {
|
||||
wrapper.passthrough(Types.DOUBLE); // X
|
||||
|
||||
+21
@@ -31,6 +31,7 @@ import com.viaversion.viaversion.api.minecraft.Holder;
|
||||
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.Chunk1_21_5;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.Heightmap;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
|
||||
@@ -55,6 +56,8 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkBiomesType1_19_4;
|
||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkBiomesType1_21_5;
|
||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
|
||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
|
||||
@@ -149,6 +152,19 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
|
||||
wrapper.write(newChunkType, mappedChunk);
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.CHUNKS_BIOMES, wrapper -> {
|
||||
final EntityTracker tracker = protocol.getEntityRewriter().tracker(wrapper.user());
|
||||
final int globalPaletteBiomeBits = ceilLog2(tracker.biomesSent());
|
||||
final Type<DataPalette[]> biomesType = new ChunkBiomesType1_19_4(tracker.currentWorldSectionHeight(), globalPaletteBiomeBits);
|
||||
final Type<DataPalette[]> newBiomesType = new ChunkBiomesType1_21_5(tracker.currentWorldSectionHeight(), globalPaletteBiomeBits);
|
||||
|
||||
final int size = wrapper.passthrough(Types.VAR_INT);
|
||||
for (int i = 0; i < size; i++) {
|
||||
wrapper.passthrough(Types.CHUNK_POSITION);
|
||||
wrapper.passthroughAndMap(biomesType, newBiomesType);
|
||||
}
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.SET_CURSOR_ITEM, this::passthroughClientboundItem);
|
||||
registerSetPlayerInventory(ClientboundPackets1_21_2.SET_PLAYER_INVENTORY);
|
||||
registerCooldown1_21_2(ClientboundPackets1_21_2.COOLDOWN);
|
||||
@@ -158,6 +174,11 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
|
||||
registerMerchantOffers1_20_5(ClientboundPackets1_21_2.MERCHANT_OFFERS);
|
||||
|
||||
protocol.registerServerbound(ServerboundPackets1_21_5.SET_CREATIVE_MODE_SLOT, wrapper -> {
|
||||
if (!protocol.getEntityRewriter().tracker(wrapper.user()).canInstaBuild()) {
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
wrapper.passthrough(Types.SHORT); // Slot
|
||||
|
||||
final Item item = handleItemToServer(wrapper.user(), wrapper.read(Types1_21_5.LENGTH_PREFIXED_ITEM));
|
||||
|
||||
+1
-1
@@ -299,7 +299,7 @@ public final class ComponentRewriter1_21_5 extends JsonNBTComponentRewriter<Clie
|
||||
}
|
||||
|
||||
public Tag uglyJsonToTag(final UserConnection connection, final String value) {
|
||||
final Tag contents = SerializerVersion.V1_21_4.toTag(SerializerVersion.V1_21_4.toComponent(value));
|
||||
final Tag contents = SerializerVersion.V1_21_5.toTag(SerializerVersion.V1_21_4.toComponent(value));
|
||||
processTag(connection, contents);
|
||||
return contents;
|
||||
}
|
||||
|
||||
+5
-23
@@ -56,6 +56,8 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
|
||||
registerTrackerWithData1_19(ClientboundPackets1_21_2.ADD_ENTITY, EntityTypes1_21_5.FALLING_BLOCK);
|
||||
registerSetEntityData(ClientboundPackets1_21_2.SET_ENTITY_DATA, Types1_21_4.ENTITY_DATA_LIST, Types1_21_5.ENTITY_DATA_LIST);
|
||||
registerRemoveEntities(ClientboundPackets1_21_2.REMOVE_ENTITIES);
|
||||
registerPlayerAbilities(ClientboundPackets1_21_2.PLAYER_ABILITIES);
|
||||
registerGameEvent(ClientboundPackets1_21_2.GAME_EVENT);
|
||||
|
||||
// No more special experience orb add packet
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.ADD_EXPERIENCE_ORB, ClientboundPackets1_21_5.ADD_ENTITY, wrapper -> {
|
||||
@@ -115,30 +117,10 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
|
||||
wolfSoundVariantsPacket.send(Protocol1_21_4To1_21_5.class);
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.LOGIN, wrapper -> {
|
||||
registerRespawn1_20_5(ClientboundPackets1_21_2.RESPAWN);
|
||||
registerLogin1_20_5(ClientboundPackets1_21_2.LOGIN);
|
||||
protocol.appendClientbound(ClientboundPackets1_21_2.LOGIN, wrapper -> {
|
||||
wrapper.user().get(MessageIndexStorage.class).setIndex(0);
|
||||
|
||||
final int entityId = wrapper.passthrough(Types.INT); // Entity id
|
||||
wrapper.passthrough(Types.BOOLEAN); // Hardcore
|
||||
wrapper.passthrough(Types.STRING_ARRAY); // World List
|
||||
wrapper.passthrough(Types.VAR_INT); // Max players
|
||||
wrapper.passthrough(Types.VAR_INT); // View distance
|
||||
wrapper.passthrough(Types.VAR_INT); // Simulation distance
|
||||
wrapper.passthrough(Types.BOOLEAN); // Reduced debug info
|
||||
wrapper.passthrough(Types.BOOLEAN); // Show death screen
|
||||
wrapper.passthrough(Types.BOOLEAN); // Limited crafting
|
||||
|
||||
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
|
||||
final String world = wrapper.passthrough(Types.STRING);
|
||||
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world);
|
||||
|
||||
trackPlayer(wrapper.user(), entityId);
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.RESPAWN, wrapper -> {
|
||||
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
|
||||
final String world = wrapper.passthrough(Types.STRING);
|
||||
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world);
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_21_2.SET_PLAYER_TEAM, wrapper -> {
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.viaversion.viaversion.api.data.Mappings;
|
||||
import com.viaversion.viaversion.api.data.entity.DimensionData;
|
||||
import com.viaversion.viaversion.api.data.entity.EntityTracker;
|
||||
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
|
||||
import com.viaversion.viaversion.api.minecraft.GameMode;
|
||||
import com.viaversion.viaversion.api.minecraft.Particle;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
|
||||
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
|
||||
@@ -364,6 +365,60 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
|
||||
registerSetEntityData(packetType, null, dataType);
|
||||
}
|
||||
|
||||
public void registerLogin1_20_5(C packetType) {
|
||||
protocol.registerClientbound(packetType, wrapper -> {
|
||||
final int entityId = wrapper.passthrough(Types.INT);
|
||||
wrapper.passthrough(Types.BOOLEAN); // Hardcore
|
||||
wrapper.passthrough(Types.STRING_ARRAY); // World List
|
||||
wrapper.passthrough(Types.VAR_INT); // Max players
|
||||
wrapper.passthrough(Types.VAR_INT); // View distance
|
||||
wrapper.passthrough(Types.VAR_INT); // Simulation distance
|
||||
wrapper.passthrough(Types.BOOLEAN); // Reduced debug info
|
||||
wrapper.passthrough(Types.BOOLEAN); // Show death screen
|
||||
wrapper.passthrough(Types.BOOLEAN); // Limited crafting
|
||||
|
||||
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
|
||||
final String world = wrapper.passthrough(Types.STRING);
|
||||
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world);
|
||||
|
||||
wrapper.passthrough(Types.LONG); // Seed
|
||||
final byte gamemode = wrapper.passthrough(Types.BYTE);
|
||||
tracker(wrapper.user()).setInstaBuild(gamemode == GameMode.CREATIVE.id());
|
||||
|
||||
trackPlayer(wrapper.user(), entityId);
|
||||
});
|
||||
}
|
||||
|
||||
public void registerRespawn1_20_5(C packetType) {
|
||||
protocol.registerClientbound(packetType, wrapper -> {
|
||||
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
|
||||
final String world = wrapper.passthrough(Types.STRING);
|
||||
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking
|
||||
|
||||
wrapper.passthrough(Types.LONG); // Seed
|
||||
final byte gamemode = wrapper.passthrough(Types.BYTE);
|
||||
tracker(wrapper.user()).setInstaBuild(gamemode == GameMode.CREATIVE.id());
|
||||
});
|
||||
}
|
||||
|
||||
// Track the insta payer build ability
|
||||
public void registerPlayerAbilities(C packetType) {
|
||||
protocol.registerClientbound(packetType, wrapper -> {
|
||||
final byte flags = wrapper.passthrough(Types.BYTE);
|
||||
tracker(wrapper.user()).setInstaBuild((flags & 1 << 3) != 0);
|
||||
});
|
||||
}
|
||||
|
||||
public void registerGameEvent(C packetType) {
|
||||
protocol.registerClientbound(packetType, wrapper -> {
|
||||
final short event = wrapper.passthrough(Types.UNSIGNED_BYTE);
|
||||
if (event == 3) {
|
||||
final int value = (int) Math.floor(wrapper.passthrough(Types.FLOAT) + 0.5F);
|
||||
tracker(wrapper.user()).setInstaBuild(value == GameMode.CREATIVE.id());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void clearEntities(final UserConnection connection) {
|
||||
final EntityTracker tracker = tracker(connection);
|
||||
tracker.clearEntities();
|
||||
|
||||
@@ -198,6 +198,12 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
|
||||
|
||||
public void registerSetCreativeModeSlot1_21_5(S packetType, Type<Item> lengthPrefixedItemType, Type<Item> mappedLengthPrefixedItemType) {
|
||||
protocol.registerServerbound(packetType, wrapper -> {
|
||||
if (!protocol.getEntityRewriter().tracker(wrapper.user()).canInstaBuild()) {
|
||||
// Mimic server/client behavior
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
wrapper.passthrough(Types.SHORT); // Slot
|
||||
passthroughLengthPrefixedItem(wrapper, lengthPrefixedItemType, mappedLengthPrefixedItemType);
|
||||
});
|
||||
|
||||
@@ -25,12 +25,16 @@ import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.logging.Level;
|
||||
import net.lenni0451.mcstructs.text.ATextComponent;
|
||||
import net.lenni0451.mcstructs.text.Style;
|
||||
import net.lenni0451.mcstructs.text.events.hover.AHoverEvent;
|
||||
import net.lenni0451.mcstructs.text.events.hover.impl.TextHoverEvent;
|
||||
import net.lenni0451.mcstructs.text.serializer.LegacyStringDeserializer;
|
||||
import net.lenni0451.mcstructs.text.TextComponent;
|
||||
import net.lenni0451.mcstructs.text.components.StringComponent;
|
||||
import net.lenni0451.mcstructs.text.events.hover.HoverEvent;
|
||||
import net.lenni0451.mcstructs.text.events.hover.impl.EntityHoverEvent;
|
||||
import net.lenni0451.mcstructs.text.events.hover.impl.ItemHoverEvent;
|
||||
import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer;
|
||||
import net.lenni0451.mcstructs.text.stringformat.StringFormat;
|
||||
import net.lenni0451.mcstructs.text.stringformat.handling.ColorHandling;
|
||||
import net.lenni0451.mcstructs.text.stringformat.handling.DeserializerUnknownHandling;
|
||||
import net.lenni0451.mcstructs.text.utils.TextUtils;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
@@ -57,7 +61,7 @@ public final class ComponentUtil {
|
||||
|
||||
public static @Nullable JsonElement tagToJson(@Nullable final Tag tag) {
|
||||
try {
|
||||
final ATextComponent component = SerializerVersion.V1_20_3.toComponent(tag);
|
||||
final TextComponent component = SerializerVersion.V1_20_3.toComponent(tag);
|
||||
return component != null ? SerializerVersion.V1_19_4.toJson(component) : null;
|
||||
} catch (final Exception e) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings()) {
|
||||
@@ -73,7 +77,7 @@ public final class ComponentUtil {
|
||||
}
|
||||
|
||||
try {
|
||||
final ATextComponent component = SerializerVersion.V1_19_4.toComponent(element);
|
||||
final TextComponent component = SerializerVersion.V1_19_4.toComponent(element);
|
||||
return trimStrings(SerializerVersion.V1_20_3.toTag(component));
|
||||
} catch (final Exception e) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings()) {
|
||||
@@ -102,7 +106,7 @@ public final class ComponentUtil {
|
||||
|
||||
public static @Nullable String tagToJsonString(@Nullable final Tag tag) {
|
||||
try {
|
||||
final ATextComponent component = SerializerVersion.V1_20_5.toComponent(tag);
|
||||
final TextComponent component = SerializerVersion.V1_20_5.toComponent(tag);
|
||||
return component != null ? SerializerVersion.V1_20_3.toString(component) : null;
|
||||
} catch (final Exception e) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings()) {
|
||||
@@ -132,27 +136,41 @@ public final class ComponentUtil {
|
||||
}
|
||||
|
||||
public static @Nullable JsonElement convertJsonOrEmpty(@Nullable final String json, final SerializerVersion from, final SerializerVersion to) {
|
||||
final ATextComponent component = from.toComponent(json);
|
||||
final TextComponent component = from.toComponent(json);
|
||||
if (component == null) {
|
||||
return emptyJsonComponent();
|
||||
}
|
||||
return to.toJson(component);
|
||||
}
|
||||
|
||||
private static JsonElement convert(final SerializerVersion from, final SerializerVersion to, final ATextComponent component) {
|
||||
private static JsonElement convert(final SerializerVersion from, final SerializerVersion to, final TextComponent component) {
|
||||
if (from.ordinal() >= SerializerVersion.V1_16.ordinal() && to.ordinal() < SerializerVersion.V1_16.ordinal()) {
|
||||
// Convert hover event to legacy format
|
||||
final Style style = component.getStyle();
|
||||
final AHoverEvent hoverEvent = style.getHoverEvent();
|
||||
if (hoverEvent != null && !(hoverEvent instanceof TextHoverEvent)) {
|
||||
style.setHoverEvent(hoverEvent.toLegacy(to.jsonSerializer, to.snbtSerializer));
|
||||
final HoverEvent hoverEvent = style.getHoverEvent();
|
||||
if (hoverEvent instanceof EntityHoverEvent entityHoverEvent && entityHoverEvent.isModern()) {
|
||||
final EntityHoverEvent.ModernHolder entityData = entityHoverEvent.asModern();
|
||||
final CompoundTag tag = new CompoundTag();
|
||||
tag.putString("type", entityData.getType().get());
|
||||
tag.putString("id", entityData.getUuid().toString());
|
||||
tag.putString("name", to.toString(entityData.getName() != null ? entityData.getName() : new StringComponent("")));
|
||||
entityHoverEvent.setLegacyData(new StringComponent(to.toSNBT(tag)));
|
||||
} else if (hoverEvent instanceof ItemHoverEvent itemHoverEvent && itemHoverEvent.isModern()) {
|
||||
final ItemHoverEvent.ModernHolder itemData = itemHoverEvent.asModern();
|
||||
final CompoundTag tag = new CompoundTag();
|
||||
tag.putString("id", itemData.getId().get());
|
||||
tag.putByte("Count", (byte) itemData.getCount());
|
||||
if (itemData.getTag() != null) {
|
||||
tag.put("tag", itemData.getTag());
|
||||
}
|
||||
itemHoverEvent.setLegacyData(to.toSNBT(tag));
|
||||
}
|
||||
}
|
||||
return to.toJson(component);
|
||||
}
|
||||
|
||||
public static JsonElement legacyToJson(final String message) {
|
||||
return SerializerVersion.V1_12.toJson(LegacyStringDeserializer.parse(message, true));
|
||||
return SerializerVersion.V1_12.toJson(StringFormat.vanilla().fromString(message, ColorHandling.RESET, DeserializerUnknownHandling.WHITE));
|
||||
}
|
||||
|
||||
public static String legacyToJsonString(final String message) {
|
||||
@@ -160,7 +178,7 @@ public final class ComponentUtil {
|
||||
}
|
||||
|
||||
public static String legacyToJsonString(final String message, final boolean itemData) {
|
||||
final ATextComponent component = LegacyStringDeserializer.parse(message, true);
|
||||
final TextComponent component = StringFormat.vanilla().fromString(message, ColorHandling.RESET, DeserializerUnknownHandling.WHITE);
|
||||
if (itemData) {
|
||||
TextUtils.iterateAll(component, c -> {
|
||||
if (!c.getStyle().isEmpty()) {
|
||||
|
||||
@@ -20,10 +20,10 @@ package com.viaversion.viaversion.util;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
|
||||
import net.lenni0451.mcstructs.snbt.SNbtSerializer;
|
||||
import net.lenni0451.mcstructs.snbt.SNbt;
|
||||
import net.lenni0451.mcstructs.snbt.exceptions.SNbtDeserializeException;
|
||||
import net.lenni0451.mcstructs.snbt.exceptions.SNbtSerializeException;
|
||||
import net.lenni0451.mcstructs.text.ATextComponent;
|
||||
import net.lenni0451.mcstructs.text.TextComponent;
|
||||
import net.lenni0451.mcstructs.text.serializer.TextComponentCodec;
|
||||
import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer;
|
||||
|
||||
@@ -36,57 +36,59 @@ import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer;
|
||||
*/
|
||||
public enum SerializerVersion {
|
||||
V1_6(TextComponentSerializer.V1_6, null),
|
||||
V1_7(TextComponentSerializer.V1_7, SNbtSerializer.V1_7),
|
||||
V1_8(TextComponentSerializer.V1_8, SNbtSerializer.V1_8),
|
||||
V1_9(TextComponentSerializer.V1_9, SNbtSerializer.V1_8),
|
||||
V1_12(TextComponentSerializer.V1_12, SNbtSerializer.V1_12),
|
||||
V1_13(TextComponentSerializer.V1_12, SNbtSerializer.V1_13),
|
||||
V1_14(TextComponentSerializer.V1_14, SNbtSerializer.V1_14),
|
||||
V1_15(TextComponentSerializer.V1_15, SNbtSerializer.V1_14),
|
||||
V1_16(TextComponentSerializer.V1_16, SNbtSerializer.V1_14),
|
||||
V1_17(TextComponentSerializer.V1_17, SNbtSerializer.V1_14),
|
||||
V1_18(TextComponentSerializer.V1_18, SNbtSerializer.V1_14),
|
||||
V1_19_4(TextComponentSerializer.V1_19_4, SNbtSerializer.V1_14),
|
||||
V1_20_3(TextComponentCodec.V1_20_3, SNbtSerializer.V1_14),
|
||||
V1_20_5(TextComponentCodec.V1_20_5, SNbtSerializer.V1_14),
|
||||
V1_21_4(TextComponentCodec.V1_21_4, SNbtSerializer.V1_14);
|
||||
V1_7(TextComponentSerializer.V1_7, SNbt.V1_7),
|
||||
V1_8(TextComponentSerializer.V1_8, SNbt.V1_8),
|
||||
V1_9(TextComponentSerializer.V1_9, SNbt.V1_8),
|
||||
V1_12(TextComponentSerializer.V1_12, SNbt.V1_12),
|
||||
V1_13(TextComponentSerializer.V1_12, SNbt.V1_13),
|
||||
V1_14(TextComponentSerializer.V1_14, SNbt.V1_14),
|
||||
V1_15(TextComponentSerializer.V1_15, SNbt.V1_14),
|
||||
V1_16(TextComponentSerializer.V1_16, SNbt.V1_14),
|
||||
V1_17(TextComponentSerializer.V1_17, SNbt.V1_14),
|
||||
V1_18(TextComponentSerializer.V1_18, SNbt.V1_14),
|
||||
V1_19_4(TextComponentSerializer.V1_19_4, SNbt.V1_14),
|
||||
V1_20_3(TextComponentCodec.V1_20_3, SNbt.V1_14),
|
||||
V1_20_5(TextComponentCodec.V1_20_5, SNbt.V1_14),
|
||||
V1_21_4(TextComponentCodec.V1_21_4, SNbt.V1_14),
|
||||
V1_21_5(TextComponentCodec.V1_21_5, null/*Currently not needed and also not implemented 100% in MCStructs*/);
|
||||
|
||||
final TextComponentSerializer jsonSerializer;
|
||||
final SNbtSerializer<? extends Tag> snbtSerializer;
|
||||
final SNbt<? extends Tag> sNbt;
|
||||
final TextComponentCodec codec;
|
||||
|
||||
SerializerVersion(final TextComponentSerializer jsonSerializer, final SNbtSerializer<? extends Tag> snbtSerializer) {
|
||||
SerializerVersion(final TextComponentSerializer jsonSerializer, final SNbt<? extends Tag> sNbt) {
|
||||
this.jsonSerializer = jsonSerializer;
|
||||
this.snbtSerializer = snbtSerializer;
|
||||
this.sNbt = sNbt;
|
||||
this.codec = null;
|
||||
}
|
||||
|
||||
SerializerVersion(final TextComponentCodec codec, final SNbtSerializer<? extends Tag> snbtSerializer) {
|
||||
SerializerVersion(final TextComponentCodec codec, final SNbt<? extends Tag> sNbt) {
|
||||
this.codec = codec;
|
||||
this.jsonSerializer = codec.asSerializer();
|
||||
this.snbtSerializer = snbtSerializer;
|
||||
this.sNbt = sNbt;
|
||||
}
|
||||
|
||||
public String toString(final ATextComponent component) {
|
||||
public String toString(final TextComponent component) {
|
||||
return jsonSerializer.serialize(component);
|
||||
}
|
||||
|
||||
public JsonElement toJson(final ATextComponent component) {
|
||||
public JsonElement toJson(final TextComponent component) {
|
||||
return jsonSerializer.serializeJson(component);
|
||||
}
|
||||
|
||||
public Tag toTag(final ATextComponent component) {
|
||||
public Tag toTag(final TextComponent component) {
|
||||
if (codec == null) {
|
||||
throw new IllegalStateException("Cannot convert component to NBT with this version");
|
||||
}
|
||||
return codec.serializeNbt(component);
|
||||
|
||||
return codec.serializeNbtTree(component);
|
||||
}
|
||||
|
||||
public ATextComponent toComponent(final JsonElement json) {
|
||||
public TextComponent toComponent(final JsonElement json) {
|
||||
return jsonSerializer.deserialize(json);
|
||||
}
|
||||
|
||||
public ATextComponent toComponent(final String json) {
|
||||
public TextComponent toComponent(final String json) {
|
||||
if (ordinal() >= SerializerVersion.V1_20_3.ordinal()) {
|
||||
return jsonSerializer.deserializeParser(json);
|
||||
} else if (ordinal() >= SerializerVersion.V1_9.ordinal()) {
|
||||
@@ -96,7 +98,7 @@ public enum SerializerVersion {
|
||||
}
|
||||
}
|
||||
|
||||
public ATextComponent toComponent(final Tag tag) {
|
||||
public TextComponent toComponent(final Tag tag) {
|
||||
if (codec == null) {
|
||||
throw new IllegalStateException("Cannot convert NBT to component with this version");
|
||||
}
|
||||
@@ -104,22 +106,24 @@ public enum SerializerVersion {
|
||||
}
|
||||
|
||||
public Tag toTag(final String snbt) {
|
||||
if (snbtSerializer == null) {
|
||||
if (sNbt == null) {
|
||||
throw new IllegalStateException("Cannot convert SNBT to NBT with this version");
|
||||
}
|
||||
|
||||
try {
|
||||
return snbtSerializer.deserialize(snbt);
|
||||
return sNbt.deserialize(snbt);
|
||||
} catch (SNbtDeserializeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String toSNBT(final Tag tag) {
|
||||
if (snbtSerializer == null) {
|
||||
if (sNbt == null) {
|
||||
throw new IllegalStateException("Cannot convert SNBT to NBT with this version");
|
||||
}
|
||||
|
||||
try {
|
||||
return snbtSerializer.serialize(tag);
|
||||
return sNbt.serialize(tag);
|
||||
} catch (SNbtSerializeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
|
||||
projectVersion=5.3.0
|
||||
projectVersion=5.3.1
|
||||
|
||||
# Smile emoji
|
||||
mcVersions=1.21.5,1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9
|
||||
|
||||
@@ -5,7 +5,7 @@ metadata.format.version = "1.1"
|
||||
gson = "2.12.1"
|
||||
fastutil = "8.5.15"
|
||||
vianbt = "5.1.0"
|
||||
mcstructs = "5-2.5.5-SNAPSHOT"
|
||||
mcstructs = "5-3.0.0"
|
||||
|
||||
# Common provided
|
||||
netty = "4.0.20.Final"
|
||||
@@ -19,7 +19,7 @@ checkerQual = "3.49.1"
|
||||
paper = "1.20.4-R0.1-SNAPSHOT"
|
||||
legacyBukkit = "1.8.8-R0.1-SNAPSHOT"
|
||||
velocity = "3.1.1"
|
||||
viaProxy = "3.4.0-SNAPSHOT"
|
||||
viaProxy = "3.4.1-SNAPSHOT"
|
||||
|
||||
[libraries]
|
||||
|
||||
|
||||
Reference in new issue
Block a user