mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2026-11-04 08:52:10 -05:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
075181f06f |
No files matched your search
@@ -20,7 +20,7 @@ jobs:
|
||||
cache-disabled: false
|
||||
cache-provider: basic
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v6.1.0
|
||||
uses: actions/setup-java@v6.0.1
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
cache-disabled: false
|
||||
cache-provider: basic
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v6.1.0
|
||||
uses: actions/setup-java@v6.0.1
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
@@ -40,5 +40,5 @@ jobs:
|
||||
- name: Publish to Modrinth
|
||||
env:
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
run: ./gradlew publishMods --stacktrace
|
||||
run: ./gradlew modrinth --stacktrace
|
||||
continue-on-error: true
|
||||
@@ -500,13 +500,6 @@ public interface ViaVersionConfig extends Config {
|
||||
*/
|
||||
boolean handleInvalidItemCount();
|
||||
|
||||
/**
|
||||
* Backs up the original data of nested items (e.g. in containers or bundles) for 1.20.5+ clients on 1.20.4 and older servers.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean backupNestedItems();
|
||||
|
||||
/**
|
||||
* Tries to cancel block break/place sounds sent by 1.8 servers to 1.9+ clients to prevent them from playing twice
|
||||
*
|
||||
|
||||
+1
-2
@@ -33,8 +33,7 @@ public class StructuredDataKeys1_20_5 extends VersionedStructuredDataKeys {
|
||||
public final StructuredDataKey<Item[]> bundleContents;
|
||||
|
||||
public StructuredDataKeys1_20_5(final VersionedTypesHolder types) {
|
||||
// Also includes later vanilla limits
|
||||
this.container = add("container", types.itemArray().withMaxLength(256));
|
||||
this.container = add("container", types.itemArray());
|
||||
this.chargedProjectiles = add("charged_projectiles", types.itemArray().withMaxLength(1024));
|
||||
this.bundleContents = add("bundle_contents", types.itemArray().withMaxLength(1024));
|
||||
}
|
||||
|
||||
+3
-3
@@ -27,7 +27,7 @@ import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.util.Copyable;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.HashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public record BlockStateProperties(Map<String, String> properties) implements Copyable {
|
||||
@@ -36,7 +36,7 @@ public record BlockStateProperties(Map<String, String> properties) implements Co
|
||||
@Override
|
||||
public BlockStateProperties read(final ByteBuf buffer) {
|
||||
final int size = Types.VAR_INT.readPrimitive(buffer);
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
final Map<String, String> properties = new Object2ObjectOpenHashMap<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
properties.put(Types.STRING.read(buffer), Types.STRING.read(buffer));
|
||||
}
|
||||
@@ -64,6 +64,6 @@ public record BlockStateProperties(Map<String, String> properties) implements Co
|
||||
|
||||
@Override
|
||||
public BlockStateProperties copy() {
|
||||
return new BlockStateProperties(new HashMap<>(properties));
|
||||
return new BlockStateProperties(new Object2ObjectOpenHashMap<>(properties));
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -27,7 +27,6 @@ import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.util.Copyable;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
import com.viaversion.viaversion.util.Limit;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
@@ -42,7 +41,7 @@ public record Enchantments(Int2IntMap enchantments, boolean showInTooltip) imple
|
||||
@Override
|
||||
public Enchantments read(final ByteBuf buffer) {
|
||||
final Int2IntMap enchantments = new Int2IntOpenHashMap();
|
||||
final int size = Limit.max(Types.VAR_INT.readPrimitive(buffer), 256);
|
||||
final int size = Types.VAR_INT.readPrimitive(buffer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
final int id = Types.VAR_INT.readPrimitive(buffer);
|
||||
final int level = Types.VAR_INT.readPrimitive(buffer);
|
||||
@@ -66,7 +65,7 @@ public record Enchantments(Int2IntMap enchantments, boolean showInTooltip) imple
|
||||
@Override
|
||||
public Enchantments read(final ByteBuf buffer) {
|
||||
final Int2IntMap enchantments = new Int2IntOpenHashMap();
|
||||
final int size = Limit.max(Types.VAR_INT.readPrimitive(buffer), 256);
|
||||
final int size = Types.VAR_INT.readPrimitive(buffer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
final int id = Types.VAR_INT.readPrimitive(buffer);
|
||||
final int level = Types.VAR_INT.readPrimitive(buffer);
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public record PotionEffectData(int amplifier, int duration, boolean ambient, boo
|
||||
final boolean ambient = buffer.readBoolean();
|
||||
final boolean showParticles = buffer.readBoolean();
|
||||
final boolean showIcon = buffer.readBoolean();
|
||||
final PotionEffectData hiddenEffect = OPTIONAL_TYPE.readTrackingDepth(buffer);
|
||||
final PotionEffectData hiddenEffect = OPTIONAL_TYPE.read(buffer);
|
||||
return new PotionEffectData(amplifier, duration, ambient, showParticles, showIcon, hiddenEffect);
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -28,7 +28,6 @@ import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
import com.viaversion.viaversion.util.Limit;
|
||||
import com.viaversion.viaversion.util.Rewritable;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet;
|
||||
@@ -43,7 +42,7 @@ public record TooltipDisplay(boolean hideTooltip,
|
||||
public TooltipDisplay read(final ByteBuf buffer) {
|
||||
final boolean hideTooltip = buffer.readBoolean();
|
||||
final IntSortedSet hiddenComponents = new IntLinkedOpenHashSet();
|
||||
final int size = Limit.max(Types.VAR_INT.readPrimitive(buffer), 256);
|
||||
final int size = Types.VAR_INT.readPrimitive(buffer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
hiddenComponents.add(Types.VAR_INT.readPrimitive(buffer));
|
||||
}
|
||||
|
||||
+6
-6
@@ -32,7 +32,7 @@ import com.viaversion.viaversion.util.Copyable;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
import com.viaversion.viaversion.util.Rewritable;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.HashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||
import java.util.Map;
|
||||
|
||||
public record ArmorTrimMaterial1_20_5(String assetName, int itemId, float itemModelIndex,
|
||||
@@ -57,7 +57,7 @@ public record ArmorTrimMaterial1_20_5(String assetName, int itemId, float itemMo
|
||||
final float itemModelIndex = buffer.readFloat();
|
||||
|
||||
final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer);
|
||||
final Map<String, String> overrideArmorMaterials = new HashMap<>();
|
||||
final Map<String, String> overrideArmorMaterials = new Object2ObjectArrayMap<>();
|
||||
for (int i = 0; i < overrideArmorMaterialsSize; i++) {
|
||||
final int key = Types.VAR_INT.readPrimitive(buffer);
|
||||
final String value = Types.STRING.read(buffer);
|
||||
@@ -91,7 +91,7 @@ public record ArmorTrimMaterial1_20_5(String assetName, int itemId, float itemMo
|
||||
final float itemModelIndex = buffer.readFloat();
|
||||
|
||||
final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer);
|
||||
final Map<String, String> overrideArmorMaterials = new HashMap<>();
|
||||
final Map<String, String> overrideArmorMaterials = new Object2ObjectArrayMap<>();
|
||||
for (int i = 0; i < overrideArmorMaterialsSize; i++) {
|
||||
final String key = Types.STRING.read(buffer);
|
||||
final String value = Types.STRING.read(buffer);
|
||||
@@ -124,7 +124,7 @@ public record ArmorTrimMaterial1_20_5(String assetName, int itemId, float itemMo
|
||||
final int item = Types.VAR_INT.readPrimitive(buffer);
|
||||
|
||||
final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer);
|
||||
final Map<String, String> overrideArmorMaterials = new HashMap<>();
|
||||
final Map<String, String> overrideArmorMaterials = new Object2ObjectArrayMap<>();
|
||||
for (int i = 0; i < overrideArmorMaterialsSize; i++) {
|
||||
final String key = Types.STRING.read(buffer);
|
||||
final String value = Types.STRING.read(buffer);
|
||||
@@ -155,7 +155,7 @@ public record ArmorTrimMaterial1_20_5(String assetName, int itemId, float itemMo
|
||||
final String assetName = Types.STRING.read(buffer);
|
||||
|
||||
final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer);
|
||||
final Map<String, String> overrideArmorMaterials = new HashMap<>();
|
||||
final Map<String, String> overrideArmorMaterials = new Object2ObjectArrayMap<>();
|
||||
for (int i = 0; i < overrideArmorMaterialsSize; i++) {
|
||||
final String key = Types.STRING.read(buffer);
|
||||
final String value = Types.STRING.read(buffer);
|
||||
@@ -207,6 +207,6 @@ public record ArmorTrimMaterial1_20_5(String assetName, int itemId, float itemMo
|
||||
|
||||
@Override
|
||||
public ArmorTrimMaterial1_20_5 copy() {
|
||||
return new ArmorTrimMaterial1_20_5(assetName, itemId, itemModelIndex, new HashMap<>(overrideArmorMaterials), description);
|
||||
return new ArmorTrimMaterial1_20_5(assetName, itemId, itemModelIndex, new Object2ObjectArrayMap<>(overrideArmorMaterials), description);
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ public class PacketTracker {
|
||||
|
||||
// Warning system
|
||||
private long warningPeriodStart = System.nanoTime();
|
||||
private long lastWarning = warningPeriodStart - SECOND_NANOS;
|
||||
private long lastWarning = Long.MIN_VALUE;
|
||||
private int warnings;
|
||||
|
||||
public RateTracker(int windowSize) {
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
package com.viaversion.viaversion.api.type;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.codec.Ops;
|
||||
import com.viaversion.viaversion.util.NestingLimiter;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* Type for buffer reading and writing.
|
||||
@@ -65,22 +63,6 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T>, Cod
|
||||
return typeName != null && !typeName.isEmpty() ? typeName : this.getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a value and counts it towards the nesting depth limit of the current thread, to be used by recursive types.
|
||||
*
|
||||
* @param buffer buffer to read from
|
||||
* @return read value
|
||||
* @see NestingLimiter
|
||||
*/
|
||||
public T readTrackingDepth(final ByteBuf buffer) {
|
||||
NestingLimiter.increment();
|
||||
try {
|
||||
return read(buffer);
|
||||
} finally {
|
||||
NestingLimiter.decrement();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Ops ops, T value) {
|
||||
throw new UnsupportedOperationException("Write operation not supported for type: " + getTypeName());
|
||||
|
||||
@@ -31,7 +31,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ArrayType<T> extends Type<T[]> {
|
||||
private static final int MAX_PRESIZED_LENGTH = 128;
|
||||
protected final Type<T> elementType;
|
||||
private final int maxLength;
|
||||
|
||||
@@ -64,7 +63,7 @@ public class ArrayType<T> extends Type<T[]> {
|
||||
throw new IllegalArgumentException("Array length " + amount + " is longer than maximum " + maxLength);
|
||||
}
|
||||
|
||||
return amount <= MAX_PRESIZED_LENGTH ? readArray(buffer, amount) : readList(buffer, amount);
|
||||
return amount < Short.MAX_VALUE ? readArray(buffer, amount) : readList(buffer, amount);
|
||||
}
|
||||
|
||||
protected T[] readArray(ByteBuf buffer, int length) {
|
||||
|
||||
@@ -32,30 +32,15 @@ import io.netty.buffer.ByteBuf;
|
||||
public class ByteArrayType extends Type<byte[]> {
|
||||
|
||||
private final int length;
|
||||
private final int maxLength;
|
||||
|
||||
public ByteArrayType(final int length) {
|
||||
this(length, -1);
|
||||
super(byte[].class);
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public ByteArrayType() {
|
||||
this(-1, -1);
|
||||
}
|
||||
|
||||
private ByteArrayType(final int length, final int maxLength) {
|
||||
super(byte[].class);
|
||||
this.length = length;
|
||||
this.maxLength = maxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a length-prefixed byte array type that rejects arrays longer than the given maximum.
|
||||
*
|
||||
* @param maxLength maximum array length
|
||||
* @return length-prefixed byte array type with the given maximum length
|
||||
*/
|
||||
public static ByteArrayType withMaxLength(final int maxLength) {
|
||||
return new ByteArrayType(-1, maxLength);
|
||||
this.length = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,7 +48,6 @@ public class ByteArrayType extends Type<byte[]> {
|
||||
if (this.length != -1) {
|
||||
Preconditions.checkArgument(length == object.length, "Length does not match expected length");
|
||||
} else {
|
||||
checkMaxLength(object.length);
|
||||
Types.VAR_INT.writePrimitive(buffer, object.length);
|
||||
}
|
||||
buffer.writeBytes(object);
|
||||
@@ -71,20 +55,13 @@ public class ByteArrayType extends Type<byte[]> {
|
||||
|
||||
@Override
|
||||
public byte[] read(final ByteBuf buffer) {
|
||||
final int length = this.length == -1 ? checkMaxLength(Types.VAR_INT.readPrimitive(buffer)) : this.length;
|
||||
final int length = this.length == -1 ? Types.VAR_INT.readPrimitive(buffer) : this.length;
|
||||
Preconditions.checkArgument(buffer.isReadable(length), "Length is larger than readable bytes");
|
||||
final byte[] array = new byte[length];
|
||||
buffer.readBytes(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
private int checkMaxLength(final int length) {
|
||||
if (maxLength != -1 && length > maxLength) {
|
||||
throw new IllegalArgumentException("Byte array length " + length + " is longer than maximum " + maxLength);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final Ops ops, final byte[] value) {
|
||||
ops.writeBytes(value);
|
||||
|
||||
+2
-11
@@ -34,7 +34,6 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
public class HashedItemType1_21_5 extends Type<HashedItem> {
|
||||
private static final int MAX_DATA_TYPE_ID = 255; // Needs adjusting if we ever get beyond this
|
||||
|
||||
public HashedItemType1_21_5() {
|
||||
super(HashedItem.class);
|
||||
@@ -52,7 +51,7 @@ public class HashedItemType1_21_5 extends Type<HashedItem> {
|
||||
final int addedComponentsSize = Limit.max(Types.VAR_INT.readPrimitive(buffer), 256);
|
||||
final Int2IntMap dataHashes = new Int2IntOpenHashMap(addedComponentsSize);
|
||||
for (int i = 0; i < addedComponentsSize; i++) {
|
||||
final int dataType = readDataType(buffer);
|
||||
final int dataType = Types.VAR_INT.readPrimitive(buffer);
|
||||
final int hash = Types.INT.readPrimitive(buffer);
|
||||
dataHashes.put(dataType, hash);
|
||||
}
|
||||
@@ -60,20 +59,12 @@ public class HashedItemType1_21_5 extends Type<HashedItem> {
|
||||
final int removedComponentsSize = Limit.max(Types.VAR_INT.readPrimitive(buffer), 256);
|
||||
final IntSet removedData = new IntOpenHashSet(removedComponentsSize);
|
||||
for (int i = 0; i < removedComponentsSize; i++) {
|
||||
final int dataType = readDataType(buffer);
|
||||
final int dataType = Types.VAR_INT.readPrimitive(buffer);
|
||||
removedData.add(dataType);
|
||||
}
|
||||
return new HashedStructuredItem(id, amount, dataHashes, removedData);
|
||||
}
|
||||
|
||||
private static int readDataType(final ByteBuf buffer) {
|
||||
final int dataType = Types.VAR_INT.readPrimitive(buffer);
|
||||
if (dataType < 0 || dataType > MAX_DATA_TYPE_ID) {
|
||||
throw new IllegalArgumentException("Invalid data component type " + dataType);
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final ByteBuf buffer, final HashedItem value) {
|
||||
if (value.isEmpty()) {
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ public class StructuredDataType extends Type<StructuredData<?>> implements Struc
|
||||
}
|
||||
|
||||
<T> StructuredData<T> readData(final ByteBuf buffer, final StructuredDataKey<T> key, final int id) {
|
||||
return StructuredData.of(key, key.type().readTrackingDepth(buffer), id);
|
||||
return StructuredData.of(key, key.type().read(buffer), id);
|
||||
}
|
||||
|
||||
public DataFiller filler(final Protocol<?, ?, ?, ?> protocol) {
|
||||
|
||||
@@ -26,12 +26,9 @@ import com.viaversion.viaversion.api.minecraft.ProfileKey;
|
||||
import com.viaversion.viaversion.api.type.OptionalType;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.api.type.types.ByteArrayType;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class ProfileKeyType extends Type<ProfileKey> {
|
||||
private static final ByteArrayType PUBLIC_KEY_TYPE = ByteArrayType.withMaxLength(512);
|
||||
private static final ByteArrayType KEY_SIGNATURE_TYPE = ByteArrayType.withMaxLength(4096);
|
||||
|
||||
public ProfileKeyType() {
|
||||
super(ProfileKey.class);
|
||||
@@ -39,14 +36,14 @@ public class ProfileKeyType extends Type<ProfileKey> {
|
||||
|
||||
@Override
|
||||
public ProfileKey read(final ByteBuf buffer) {
|
||||
return new ProfileKey(buffer.readLong(), PUBLIC_KEY_TYPE.read(buffer), KEY_SIGNATURE_TYPE.read(buffer));
|
||||
return new ProfileKey(buffer.readLong(), Types.BYTE_ARRAY_PRIMITIVE.read(buffer), Types.BYTE_ARRAY_PRIMITIVE.read(buffer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final ByteBuf buffer, final ProfileKey object) {
|
||||
buffer.writeLong(object.expiresAt());
|
||||
PUBLIC_KEY_TYPE.write(buffer, object.publicKey());
|
||||
KEY_SIGNATURE_TYPE.write(buffer, object.keySignature());
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(buffer, object.publicKey());
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(buffer, object.keySignature());
|
||||
}
|
||||
|
||||
public static final class OptionalProfileKeyType extends OptionalType<ProfileKey> {
|
||||
|
||||
@@ -39,7 +39,9 @@ public interface Copyable {
|
||||
final int length = Array.getLength(object);
|
||||
final Object copy = Array.newInstance(componentType, length);
|
||||
if (componentType.isPrimitive()) {
|
||||
System.arraycopy(object, 0, copy, 0, length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Array.set(copy, i, Array.get(object, i));
|
||||
}
|
||||
} else {
|
||||
// See if we need to copy elements, too
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
||||
* Copyright (C) 2016-2026 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.util;
|
||||
|
||||
public final class NestingLimiter {
|
||||
|
||||
private static final ThreadLocal<int[]> STATE = ThreadLocal.withInitial(() -> new int[]{0, -1}); // Current depth, max depth
|
||||
|
||||
/**
|
||||
* Sets the max depth for reads on the current thread.
|
||||
*
|
||||
* @param maxDepth max depth, or -1 for no limit
|
||||
* @return the previous max depth, to be set again once done
|
||||
*/
|
||||
public static int setMaxDepth(final int maxDepth) {
|
||||
final int[] state = STATE.get();
|
||||
final int previous = state[1];
|
||||
state[1] = maxDepth;
|
||||
return previous;
|
||||
}
|
||||
|
||||
public static void increment() {
|
||||
final int[] state = STATE.get();
|
||||
if (state[1] != -1 && state[0] >= state[1]) {
|
||||
throw new IllegalArgumentException("Data is nested too deeply");
|
||||
}
|
||||
state[0]++;
|
||||
}
|
||||
|
||||
public static void decrement() {
|
||||
STATE.get()[0]--;
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,6 @@ public final class PipelineUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public static @Nullable ChannelHandlerContext getPreviousContext(String name, ChannelPipeline pipeline) {
|
||||
String previous = null;
|
||||
for (String entry : pipeline.toMap().keySet()) {
|
||||
|
||||
@@ -44,22 +44,11 @@ public final class UUIDUtil {
|
||||
}
|
||||
|
||||
public static @Nullable UUID parseUUID(final String uuidString) {
|
||||
// Check the format beforehand instead of catching the exception, exceptions are expensive
|
||||
if (uuidString.length() != 36) {
|
||||
try {
|
||||
return UUID.fromString(uuidString);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 36; i++) {
|
||||
final char c = uuidString.charAt(i);
|
||||
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
||||
if (c != '-') {
|
||||
return null;
|
||||
}
|
||||
} else if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return UUID.fromString(uuidString);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,6 @@ import com.viaversion.viaversion.commands.ViaCommandHandler;
|
||||
import com.viaversion.viaversion.configuration.ConfigurationProviderImpl;
|
||||
import com.viaversion.viaversion.connection.ConnectionManagerImpl;
|
||||
import com.viaversion.viaversion.debug.DebugHandlerImpl;
|
||||
import com.viaversion.viaversion.platform.UserConnectionViaVersionPlatform;
|
||||
import com.viaversion.viaversion.protocol.ProtocolManagerImpl;
|
||||
import com.viaversion.viaversion.protocol.ServerProtocolVersionRange;
|
||||
import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton;
|
||||
@@ -204,10 +203,6 @@ public class ViaManagerImpl implements ViaManager {
|
||||
// Refresh Versions
|
||||
protocolManager.refreshVersions();
|
||||
|
||||
if (protocolVersion.isKnown() && !(platform instanceof UserConnectionViaVersionPlatform)) {
|
||||
exploitableVersionsWarning(protocolVersion);
|
||||
}
|
||||
|
||||
for (final Runnable listener : postEnableListeners) {
|
||||
listener.run();
|
||||
}
|
||||
@@ -248,28 +243,6 @@ public class ViaManagerImpl implements ViaManager {
|
||||
platform.getLogger().info("ViaVersion has been disabled; uninjected the platform and shut down the scheduler.");
|
||||
}
|
||||
|
||||
private void exploitableVersionsWarning(final ServerProtocolVersion serverProtocolVersion) {
|
||||
if (!platform.isProxy() && isExploitableVersion(serverProtocolVersion.highestSupportedProtocolVersion())) {
|
||||
platform.getLogger().warning("The Vanilla protocol of Minecraft 1.20.5-1.21.4 is exploitable easily. Please consider updating your server to at least 1.21.5.");
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> versions = new ArrayList<>();
|
||||
for (final ProtocolVersion version : protocolManager.getSupportedVersions()) {
|
||||
if (isExploitableVersion(version) && !platform.getConf().blockedProtocolVersions().contains(version)) {
|
||||
versions.add('"' + version.getName() + '"');
|
||||
}
|
||||
}
|
||||
if (!versions.isEmpty()) {
|
||||
platform.getLogger().warning("The Vanilla protocol of Minecraft 1.20.5-1.21.4 is easily exploitable. "
|
||||
+ "If you don't need to support these versions, consider adding them to block-versions in the ViaVersion config: " + String.join(", ", versions));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isExploitableVersion(final ProtocolVersion version) {
|
||||
return version.betweenInclusive(ProtocolVersion.v1_20_5, ProtocolVersion.v1_21_4);
|
||||
}
|
||||
|
||||
private void checkJavaVersion() {
|
||||
int javaVersion = Runtime.version().feature();
|
||||
if (javaVersion < 17) {
|
||||
|
||||
@@ -95,7 +95,6 @@ public class AbstractViaConfig extends Config implements ViaVersionConfig {
|
||||
private boolean translateOcelotToCat;
|
||||
private boolean enforceSecureChat;
|
||||
private boolean handleInvalidItemCount;
|
||||
private boolean backupNestedItems;
|
||||
private boolean cancelBlockSounds;
|
||||
private boolean hideScoreboardNumbers;
|
||||
private boolean fix1_21PlacementRotation;
|
||||
@@ -173,7 +172,6 @@ public class AbstractViaConfig extends Config implements ViaVersionConfig {
|
||||
translateOcelotToCat = getBoolean("translate-ocelot-to-cat", true);
|
||||
enforceSecureChat = getBoolean("enforce-secure-chat", false);
|
||||
handleInvalidItemCount = getBoolean("handle-invalid-item-count", false);
|
||||
backupNestedItems = getBoolean("backup-nested-items", false);
|
||||
cancelBlockSounds = getBoolean("cancel-block-sounds", true);
|
||||
hideScoreboardNumbers = getBoolean("hide-scoreboard-numbers", false);
|
||||
fix1_21PlacementRotation = getBoolean("fix-1_21-placement-rotation", true);
|
||||
@@ -624,11 +622,6 @@ public class AbstractViaConfig extends Config implements ViaVersionConfig {
|
||||
return handleInvalidItemCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean backupNestedItems() {
|
||||
return backupNestedItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelBlockSounds() {
|
||||
return cancelBlockSounds;
|
||||
|
||||
@@ -36,17 +36,15 @@ import com.viaversion.viaversion.exception.CancelException;
|
||||
import com.viaversion.viaversion.exception.InformativeException;
|
||||
import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
|
||||
import com.viaversion.viaversion.util.ChatColorUtil;
|
||||
import com.viaversion.viaversion.util.NestingLimiter;
|
||||
import com.viaversion.viaversion.util.PipelineUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandler;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.codec.CodecException;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -56,12 +54,10 @@ import java.util.SplittableRandom;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class UserConnectionImpl implements UserConnection {
|
||||
private static final int PASSTHROUGH_DATA_BYTES = Long.BYTES + 2;
|
||||
private static final int MAX_SERVERBOUND_NESTING_DEPTH = 128;
|
||||
private static final AtomicLong IDS = new AtomicLong();
|
||||
private final long id = IDS.incrementAndGet();
|
||||
private final SplittableRandom random = new SplittableRandom();
|
||||
@@ -229,10 +225,10 @@ public class UserConnectionImpl implements UserConnection {
|
||||
|
||||
private void sendRawPacket(final ByteBuf packet, final boolean currentThread) {
|
||||
if (currentThread) {
|
||||
sendRawPacketFuture(packet);
|
||||
sendRawPacketNow(packet);
|
||||
} else {
|
||||
try {
|
||||
channel.eventLoop().execute(() -> sendRawPacketFuture(packet));
|
||||
channel.eventLoop().execute(() -> sendRawPacketNow(packet));
|
||||
} catch (Throwable e) {
|
||||
packet.release(); // Couldn't schedule
|
||||
e.printStackTrace();
|
||||
@@ -240,22 +236,25 @@ public class UserConnectionImpl implements UserConnection {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendRawPacketNow(final ByteBuf buf) {
|
||||
final ChannelPipeline pipeline = getChannel().pipeline();
|
||||
final ViaInjector injector = Via.getManager().getInjector();
|
||||
if (clientSide) {
|
||||
// We'll just assume that Via decoder isn't wrapping the original decoder
|
||||
pipeline.context(injector.getDecoderName()).fireChannelRead(buf);
|
||||
} else {
|
||||
pipeline.context(injector.getEncoderName()).writeAndFlush(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture sendRawPacketFuture(final ByteBuf packet) {
|
||||
final ViaInjector injector = Via.getManager().getInjector();
|
||||
final ChannelHandlerContext context = channel.pipeline().context(clientSide ? injector.getDecoderName() : injector.getEncoderName());
|
||||
if (context == null) {
|
||||
// Handlers are removed once the channel is closed
|
||||
packet.release();
|
||||
return channel.newFailedFuture(new ClosedChannelException());
|
||||
}
|
||||
|
||||
if (clientSide) {
|
||||
// Assume that decoder isn't wrapping
|
||||
context.fireChannelRead(packet);
|
||||
return channel.newSucceededFuture();
|
||||
getChannel().pipeline().context(Via.getManager().getInjector().getDecoderName()).fireChannelRead(packet);
|
||||
return getChannel().newSucceededFuture();
|
||||
} else {
|
||||
return context.writeAndFlush(packet);
|
||||
return channel.pipeline().context(Via.getManager().getInjector().getEncoderName()).writeAndFlush(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,6 +303,10 @@ public class UserConnectionImpl implements UserConnection {
|
||||
final int initialCapacity = active ? packet.readableBytes() + PASSTHROUGH_DATA_BYTES : packet.readableBytes();
|
||||
final ByteBuf buf = packet.alloc().buffer(initialCapacity);
|
||||
try {
|
||||
// We'll use passing through because there are some encoder wrappers
|
||||
ChannelHandlerContext context = PipelineUtil
|
||||
.getPreviousContext(Via.getManager().getInjector().getDecoderName(), channel.pipeline());
|
||||
|
||||
if (shouldTransformPacket()) {
|
||||
// Bypass serverbound packet decoder transforming
|
||||
Types.VAR_INT.writePrimitive(buf, PacketWrapper.PASSTHROUGH_ID);
|
||||
@@ -311,46 +314,27 @@ public class UserConnectionImpl implements UserConnection {
|
||||
}
|
||||
|
||||
buf.writeBytes(packet);
|
||||
} catch (Throwable t) {
|
||||
buf.release();
|
||||
throw t;
|
||||
if (currentThread) {
|
||||
fireChannelRead(context, buf);
|
||||
} else {
|
||||
try {
|
||||
channel.eventLoop().execute(() -> fireChannelRead(context, buf));
|
||||
} catch (Throwable t) {
|
||||
// Couldn't schedule
|
||||
buf.release();
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
packet.release();
|
||||
}
|
||||
|
||||
if (currentThread && channel.eventLoop().inEventLoop()) {
|
||||
fireChannelRead(buf);
|
||||
} else {
|
||||
try {
|
||||
channel.eventLoop().execute(() -> fireChannelRead(buf));
|
||||
} catch (Throwable t) {
|
||||
// Couldn't schedule
|
||||
buf.release();
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fireChannelRead(final ByteBuf buf) {
|
||||
final ChannelHandlerContext context = channel.pipeline().context(Via.getManager().getInjector().getDecoderName());
|
||||
if (context == null) {
|
||||
buf.release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Directly invoke the decoder, copied from Netty's fireChannelRead of the previous handler
|
||||
final ChannelHandler handler = context.handler();
|
||||
try {
|
||||
((ChannelInboundHandler) handler).channelRead(context, buf);
|
||||
} catch (Throwable t) {
|
||||
try {
|
||||
handler.exceptionCaught(context, t);
|
||||
} catch (Throwable e) {
|
||||
if (e != t) {
|
||||
e.addSuppressed(t);
|
||||
}
|
||||
Via.getPlatform().getLogger().log(Level.WARNING, "Exception thrown by exceptionCaught of " + handler, e);
|
||||
}
|
||||
private void fireChannelRead(@Nullable final ChannelHandlerContext context, final ByteBuf buf) {
|
||||
if (context != null) {
|
||||
context.fireChannelRead(buf);
|
||||
} else {
|
||||
channel.pipeline().fireChannelRead(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,7 +343,7 @@ public class UserConnectionImpl implements UserConnection {
|
||||
writeAndFlush(packet);
|
||||
} else {
|
||||
try {
|
||||
channel.eventLoop().execute(() -> writeAndFlush(packet));
|
||||
getChannel().eventLoop().execute(() -> writeAndFlush(packet));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
packet.release(); // Couldn't schedule
|
||||
@@ -368,12 +352,7 @@ public class UserConnectionImpl implements UserConnection {
|
||||
}
|
||||
|
||||
private void writeAndFlush(final ByteBuf buf) {
|
||||
final ChannelHandlerContext context = channel.pipeline().context(Via.getManager().getInjector().getEncoderName());
|
||||
if (context == null) {
|
||||
buf.release();
|
||||
return;
|
||||
}
|
||||
context.writeAndFlush(buf);
|
||||
getChannel().pipeline().context(Via.getManager().getInjector().getEncoderName()).writeAndFlush(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -427,13 +406,10 @@ public class UserConnectionImpl implements UserConnection {
|
||||
|
||||
final int valuesReaderIndex = buf.readerIndex();
|
||||
final PacketWrapperImpl wrapper = new PacketWrapperImpl(id, buf, this);
|
||||
final int previousMaxDepth = NestingLimiter.setMaxDepth(direction == Direction.SERVERBOUND ? MAX_SERVERBOUND_NESTING_DEPTH : -1);
|
||||
try {
|
||||
protocolInfo.getPipeline().transform(direction, protocolInfo.getState(direction), wrapper);
|
||||
} catch (final CancelException ex) {
|
||||
throw cancelSupplier.apply(ex);
|
||||
} finally {
|
||||
NestingLimiter.setMaxDepth(previousMaxDepth);
|
||||
}
|
||||
|
||||
writeToBuffer(wrapper, buf, id, valuesReaderIndex);
|
||||
|
||||
@@ -329,9 +329,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
|
||||
List<ProtocolPathEntry> path = calculateProtocolPath(clientVersion, serverVersion);
|
||||
if (path == null) {
|
||||
// Also cache that there is no path
|
||||
if (clientVersion.isKnown() && serverVersion.isKnown()) {
|
||||
pathCache.put(protocolKey, List.of());
|
||||
}
|
||||
pathCache.put(protocolKey, List.of());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+1
-46
@@ -21,7 +21,6 @@ import com.google.common.base.Preconditions;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.ProtocolInfo;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.api.protocol.packet.Direction;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketType;
|
||||
@@ -43,7 +42,6 @@ import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class PacketWrapperImpl implements PacketWrapper {
|
||||
@@ -273,7 +271,7 @@ public class PacketWrapperImpl implements PacketWrapper {
|
||||
.set("Server Protocol", protocolInfo.serverProtocolVersion().getName())
|
||||
.set("Index", index)
|
||||
.set("Type", type.getTypeName())
|
||||
.set("Data", new PacketValuesSummary(this.packetValues))
|
||||
.set("Data", this.packetValues)
|
||||
.set("Packet ID", this.id);
|
||||
}
|
||||
|
||||
@@ -623,49 +621,6 @@ public class PacketWrapperImpl implements PacketWrapper {
|
||||
'}';
|
||||
}
|
||||
|
||||
private static final class PacketValuesSummary {
|
||||
private final List<PacketValue<?>> values;
|
||||
private String s;
|
||||
|
||||
private PacketValuesSummary(final List<PacketValue<?>> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.s == null) {
|
||||
this.s = Via.getManager().isDebug() ? this.values.toString() : summarize();
|
||||
}
|
||||
return this.s;
|
||||
}
|
||||
|
||||
private String summarize() {
|
||||
final int maxLength = Math.max(0, Via.getConfig().maxErrorLength());
|
||||
final StringBuilder builder = new StringBuilder("[");
|
||||
for (final PacketValue<?> packetValue : this.values) {
|
||||
if (builder.length() > 1) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append('{').append(packetValue.type()).append(": ").append(stringToLog(packetValue.value())).append('}');
|
||||
if (builder.length() >= maxLength) {
|
||||
builder.setLength(maxLength);
|
||||
return builder.append("...").toString();
|
||||
}
|
||||
}
|
||||
return builder.append(']').toString();
|
||||
}
|
||||
|
||||
private static String stringToLog(@Nullable final Object value) {
|
||||
if (value == null || value instanceof Number || value instanceof Boolean || value instanceof Character
|
||||
|| value instanceof CharSequence || value instanceof UUID || value instanceof Enum<?>) {
|
||||
return String.valueOf(value);
|
||||
} else if (value instanceof Item item) {
|
||||
return "Item{id=" + item.identifier() + ", amount=" + item.amount() + "}";
|
||||
}
|
||||
return "<" + value.getClass().getSimpleName() + ">";
|
||||
}
|
||||
}
|
||||
|
||||
public static final class PacketValue<T> {
|
||||
private final Type<T> type;
|
||||
private T value;
|
||||
|
||||
@@ -154,9 +154,6 @@ public class InitialBaseProtocol extends AbstractProtocol<BaseClientboundPacket,
|
||||
info.setState(State.STATUS);
|
||||
} else if (state == LOGIN_INTENT || state == TRANSFER_INTENT) {
|
||||
info.setState(State.LOGIN);
|
||||
} else {
|
||||
// Unknown intent, don't handle further packets as handshakes
|
||||
wrapper.user().setActive(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-3
@@ -48,9 +48,7 @@ public class ServerboundBaseProtocol1_7 extends AbstractProtocol<BaseClientbound
|
||||
// State tracking
|
||||
registerServerbound(ServerboundLoginPackets.LOGIN_ACKNOWLEDGED, wrapper -> {
|
||||
final ProtocolInfo info = wrapper.user().getProtocolInfo();
|
||||
if (info.getUuid() != null) {
|
||||
info.setState(State.CONFIGURATION);
|
||||
}
|
||||
info.setState(State.CONFIGURATION);
|
||||
});
|
||||
|
||||
// Handle blocked version disconnect
|
||||
|
||||
+26
-5
@@ -24,6 +24,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WallConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
private static final BlockFace[] BLOCK_FACES = {BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST};
|
||||
private static final int[] OPPOSITES = {3, 2, 1, 0};
|
||||
|
||||
static List<ConnectionData.ConnectorInitAction> init() {
|
||||
List<ConnectionData.ConnectorInitAction> actions = new ArrayList<>(2);
|
||||
@@ -47,7 +49,7 @@ public class WallConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
@Override
|
||||
protected byte getStates(UserConnection user, BlockPosition position) {
|
||||
byte states = super.getStates(user, position);
|
||||
if (up(user, position, states)) states |= 16;
|
||||
if (up(user, position)) states |= 16;
|
||||
return states;
|
||||
}
|
||||
|
||||
@@ -56,9 +58,28 @@ public class WallConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
return 32;
|
||||
}
|
||||
|
||||
private boolean up(UserConnection user, BlockPosition position, byte states) {
|
||||
// Only straight walls with air above have no post, see BlockWall#getActualState
|
||||
boolean straight = states == (2 | 4) || states == (1 | 8);
|
||||
return !straight || getBlockData(user, position.getRelative(BlockFace.TOP)) != 0;
|
||||
public boolean up(UserConnection user, BlockPosition position) {
|
||||
if (isWall(getBlockData(user, position.getRelative(BlockFace.BOTTOM))) || isWall(getBlockData(user, position.getRelative(BlockFace.TOP))))
|
||||
return true;
|
||||
int blockFaces = getBlockFaces(user, position);
|
||||
if (blockFaces == 0 || blockFaces == 0xF) return true;
|
||||
for (int i = 0; i < BLOCK_FACES.length; i++) {
|
||||
if ((blockFaces & (1 << i)) != 0 && (blockFaces & (1 << OPPOSITES[i])) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int getBlockFaces(UserConnection user, BlockPosition position) {
|
||||
int blockFaces = 0;
|
||||
for (int i = 0; i < BLOCK_FACES.length; i++) {
|
||||
if (isWall(getBlockData(user, position.getRelative(BLOCK_FACES[i])))) {
|
||||
blockFaces |= 1 << i;
|
||||
}
|
||||
}
|
||||
return blockFaces;
|
||||
}
|
||||
|
||||
private boolean isWall(int id) {
|
||||
return getBlockStates().contains(id);
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -31,7 +31,6 @@ import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ClientboundPacke
|
||||
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
|
||||
import com.viaversion.viaversion.rewriter.ItemRewriter;
|
||||
import com.viaversion.viaversion.rewriter.RecipeRewriter;
|
||||
import com.viaversion.viaversion.util.Limit;
|
||||
|
||||
public final class ItemPacketRewriter1_17 extends ItemRewriter<ClientboundPackets1_16_2, ServerboundPackets1_17, Protocol1_16_4To1_17> {
|
||||
|
||||
@@ -56,7 +55,7 @@ public final class ItemPacketRewriter1_17 extends ItemRewriter<ClientboundPacket
|
||||
|
||||
handler(wrapper -> {
|
||||
// Affected items - throw them away!
|
||||
int length = Limit.max(wrapper.read(Types.VAR_INT), 128);
|
||||
int length = wrapper.read(Types.VAR_INT);
|
||||
for (int i = 0; i < length; i++) {
|
||||
wrapper.read(Types.SHORT); // Slot
|
||||
wrapper.read(Types.ITEM1_13_2);
|
||||
|
||||
+1
-2
@@ -55,7 +55,6 @@ import com.viaversion.viaversion.rewriter.SoundRewriter;
|
||||
import com.viaversion.viaversion.rewriter.TagRewriter;
|
||||
import com.viaversion.viaversion.util.CipherUtil;
|
||||
import com.viaversion.viaversion.util.ComponentUtil;
|
||||
import com.viaversion.viaversion.util.Limit;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPackets1_18, ClientboundPackets1_19, ServerboundPackets1_17, ServerboundPackets1_19> {
|
||||
@@ -244,7 +243,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
|
||||
final String command = wrapper.get(Types.STRING, 0);
|
||||
wrapper.set(Types.STRING, 0, "/" + command);
|
||||
|
||||
final int signatures = Limit.max(wrapper.read(Types.VAR_INT), 8);
|
||||
final int signatures = wrapper.read(Types.VAR_INT);
|
||||
for (int i = 0; i < signatures; i++) {
|
||||
wrapper.read(Types.STRING); // Argument name
|
||||
wrapper.read(Types.BYTE_ARRAY_PRIMITIVE); // Signature
|
||||
|
||||
-4
@@ -174,10 +174,6 @@ public final class ItemPacketRewriter1_19 extends ItemRewriter<ClientboundPacket
|
||||
private PacketHandler sequenceHandler() {
|
||||
return wrapper -> {
|
||||
final int sequence = wrapper.read(Types.VAR_INT);
|
||||
if (sequence < 0) {
|
||||
throw new IllegalArgumentException("Expected packet sequence nr >= 0");
|
||||
}
|
||||
|
||||
final AckSequenceProvider provider = Via.getManager().getProviders().get(AckSequenceProvider.class);
|
||||
provider.handleSequence(wrapper.user(), sequence);
|
||||
};
|
||||
|
||||
+1
-2
@@ -60,7 +60,6 @@ import com.viaversion.viaversion.rewriter.CommandRewriter;
|
||||
import com.viaversion.viaversion.rewriter.ParticleRewriter;
|
||||
import com.viaversion.viaversion.rewriter.TagRewriter;
|
||||
import com.viaversion.viaversion.util.ComponentUtil;
|
||||
import com.viaversion.viaversion.util.Limit;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import java.security.SignatureException;
|
||||
import java.util.List;
|
||||
@@ -222,7 +221,7 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol<ClientboundPa
|
||||
final ChatSession1_19_1 chatSession = wrapper.user().get(ChatSession1_19_1.class);
|
||||
final ReceivedMessagesStorage messagesStorage = wrapper.user().get(ReceivedMessagesStorage.class);
|
||||
|
||||
final int signatures = Limit.max(wrapper.read(Types.VAR_INT), 8);
|
||||
final int signatures = wrapper.read(Types.VAR_INT);
|
||||
for (int i = 0; i < signatures; i++) {
|
||||
wrapper.read(Types.STRING); // Argument name
|
||||
wrapper.read(Types.SIGNATURE_BYTES); // Signature
|
||||
|
||||
+3
-8
@@ -26,7 +26,6 @@ import com.viaversion.nbt.tag.NumberTag;
|
||||
import com.viaversion.nbt.tag.StringTag;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature;
|
||||
import com.viaversion.viaversion.api.minecraft.ProfileKey;
|
||||
import com.viaversion.viaversion.api.minecraft.signature.SignableCommandArgumentsProvider;
|
||||
import com.viaversion.viaversion.api.minecraft.signature.model.DecoratableMessage;
|
||||
@@ -35,9 +34,7 @@ import com.viaversion.viaversion.api.minecraft.signature.storage.ChatSession1_19
|
||||
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
|
||||
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.api.type.types.ArrayType;
|
||||
import com.viaversion.viaversion.libs.mcstructs.text.Style;
|
||||
import com.viaversion.viaversion.libs.mcstructs.text.TextComponent;
|
||||
import com.viaversion.viaversion.libs.mcstructs.text.TextFormatting;
|
||||
@@ -53,7 +50,6 @@ import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ServerboundPacke
|
||||
import com.viaversion.viaversion.protocols.v1_19to1_19_1.storage.ChatTypeStorage;
|
||||
import com.viaversion.viaversion.protocols.v1_19to1_19_1.storage.NonceStorage1_19_1;
|
||||
import com.viaversion.viaversion.util.CipherUtil;
|
||||
import com.viaversion.viaversion.util.Limit;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import com.viaversion.viaversion.util.ProtocolLogger;
|
||||
import com.viaversion.viaversion.util.SerializerVersion;
|
||||
@@ -68,7 +64,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPackets1_19, ClientboundPackets1_19_1, ServerboundPackets1_19, ServerboundPackets1_19_1> {
|
||||
|
||||
public static final ProtocolLogger LOGGER = new ProtocolLogger(Protocol1_19To1_19_1.class);
|
||||
private static final Type<PlayerMessageSignature[]> LAST_SEEN_MESSAGES_TYPE = new ArrayType<>(Types.PLAYER_MESSAGE_SIGNATURE, 5);
|
||||
|
||||
public Protocol1_19To1_19_1() {
|
||||
super(ClientboundPackets1_19.class, ClientboundPackets1_19_1.class, ServerboundPackets1_19.class, ServerboundPackets1_19_1.class);
|
||||
@@ -144,7 +139,7 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
|
||||
wrapper.set(Types.BOOLEAN, 0, decoratableMessage.isDecorated()); // Signed preview
|
||||
}
|
||||
});
|
||||
read(LAST_SEEN_MESSAGES_TYPE); // Last seen messages
|
||||
read(Types.PLAYER_MESSAGE_SIGNATURE_ARRAY); // Last seen messages
|
||||
read(Types.OPTIONAL_PLAYER_MESSAGE_SIGNATURE); // Last received message
|
||||
}
|
||||
});
|
||||
@@ -158,7 +153,7 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
|
||||
final ChatSession1_19_0 chatSession = wrapper.user().get(ChatSession1_19_0.class);
|
||||
final SignableCommandArgumentsProvider argumentsProvider = Via.getManager().getProviders().get(SignableCommandArgumentsProvider.class);
|
||||
|
||||
final int signatures = Limit.max(wrapper.read(Types.VAR_INT), 8);
|
||||
final int signatures = wrapper.read(Types.VAR_INT);
|
||||
for (int i = 0; i < signatures; i++) {
|
||||
wrapper.read(Types.STRING); // Argument name
|
||||
wrapper.read(Types.BYTE_ARRAY_PRIMITIVE); // Signature
|
||||
@@ -192,7 +187,7 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
|
||||
}
|
||||
});
|
||||
map(Types.BOOLEAN); // Signed preview
|
||||
read(LAST_SEEN_MESSAGES_TYPE); // Last seen messages
|
||||
read(Types.PLAYER_MESSAGE_SIGNATURE_ARRAY); // Last seen messages
|
||||
read(Types.OPTIONAL_PLAYER_MESSAGE_SIGNATURE); // Last received message
|
||||
}
|
||||
});
|
||||
|
||||
+1
-2
@@ -59,7 +59,6 @@ import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundConfi
|
||||
import com.viaversion.viaversion.rewriter.BlockRewriter;
|
||||
import com.viaversion.viaversion.rewriter.TagRewriter;
|
||||
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
|
||||
import com.viaversion.viaversion.util.Limit;
|
||||
import com.viaversion.viaversion.util.ProtocolLogger;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashSet;
|
||||
@@ -149,7 +148,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
|
||||
final ProtocolStorables1_20_5 storables = wrapper.user().storables(this);
|
||||
final AcknowledgedMessagesStorage storage = storables.acknowledgedMessages();
|
||||
final long salt = wrapper.read(Types.LONG);
|
||||
final int signatures = Limit.max(wrapper.read(Types.VAR_INT), 8);
|
||||
final int signatures = wrapper.read(Types.VAR_INT);
|
||||
if (storage.isSecureChatEnforced()) {
|
||||
wrapper.write(Types.LONG, salt);
|
||||
wrapper.write(Types.VAR_INT, signatures);
|
||||
|
||||
+10
-26
@@ -379,10 +379,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
|
||||
tag.putBoolean(nbtTagName(), true);
|
||||
structuredItem.dataContainer().set(StructuredDataKey.CUSTOM_DATA, tag);
|
||||
}
|
||||
return handleStructuredItemToClient(connection, structuredItem);
|
||||
}
|
||||
|
||||
private Item handleStructuredItemToClient(final UserConnection connection, final Item structuredItem) {
|
||||
// Add data components to fix issues in older protocols
|
||||
appendItemDataFixComponents(connection, structuredItem);
|
||||
|
||||
@@ -432,11 +429,6 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
|
||||
}
|
||||
|
||||
public Item toStructuredItem(final UserConnection connection, final Item old) {
|
||||
return toStructuredItem(connection, old, false);
|
||||
}
|
||||
|
||||
// Nested items are converted from a copy made by the root item, no need to copy again
|
||||
private Item toStructuredItem(final UserConnection connection, final Item old, final boolean copied) {
|
||||
final CompoundTag tag = old.tag();
|
||||
final StructuredItem item = new StructuredItem(old.identifier(), (byte) old.amount(), new StructuredDataContainer());
|
||||
final StructuredDataContainer data = item.dataContainer();
|
||||
@@ -490,7 +482,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
|
||||
|
||||
final CompoundTag blockEntityTag = tag.getCompoundTag("BlockEntityTag");
|
||||
if (blockEntityTag != null) {
|
||||
final CompoundTag clonedTag = copied ? blockEntityTag : blockEntityTag.copy();
|
||||
final CompoundTag clonedTag = blockEntityTag.copy();
|
||||
// Same as above
|
||||
updateBlockEntityTag(connection, data, clonedTag);
|
||||
CompoundTag spawnData = clonedTag.getCompoundTag("SpawnData");
|
||||
@@ -579,9 +571,9 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
|
||||
|
||||
updateMobTags(data, tag);
|
||||
|
||||
updateItemList(connection, data, tag, "ChargedProjectiles", StructuredDataKey.V1_20_5.chargedProjectiles, copied);
|
||||
updateItemList(connection, data, tag, "ChargedProjectiles", StructuredDataKey.V1_20_5.chargedProjectiles);
|
||||
if (old.identifier() == 927) {
|
||||
updateItemList(connection, data, tag, "Items", StructuredDataKey.V1_20_5.bundleContents, copied);
|
||||
updateItemList(connection, data, tag, "Items", StructuredDataKey.V1_20_5.bundleContents);
|
||||
}
|
||||
|
||||
updateEnchantments(data, tag, "Enchantments", StructuredDataKey.ENCHANTMENTS1_20_5, (hideFlagsValue & StructuredDataConverter.HIDE_ENCHANTMENTS) == 0);
|
||||
@@ -1269,12 +1261,12 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
|
||||
}
|
||||
|
||||
private void updateItemList(final UserConnection connection, final StructuredDataContainer data, final CompoundTag tag,
|
||||
final String key, final StructuredDataKey<Item[]> dataKey, final boolean copied) {
|
||||
final String key, final StructuredDataKey<Item[]> dataKey) {
|
||||
final ListTag<CompoundTag> itemsTag = tag.getListTag(key, CompoundTag.class);
|
||||
if (itemsTag != null) {
|
||||
final Item[] items = itemsTag.stream()
|
||||
.limit(256)
|
||||
.map(item -> itemFromTag(connection, copied ? item : item.copy()))
|
||||
.map(item -> itemFromTag(connection, item.copy()))
|
||||
.filter(item -> !item.isEmpty())
|
||||
.toArray(Item[]::new);
|
||||
data.set(dataKey, items);
|
||||
@@ -1294,11 +1286,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
|
||||
|
||||
final byte count = item.getByte("Count", (byte) 1);
|
||||
final CompoundTag tag = item.getCompoundTag("tag");
|
||||
final DataItem dataItem = new DataItem(itemId, count, tag);
|
||||
if (Via.getConfig().backupNestedItems()) {
|
||||
return handleItemToClient(connection, dataItem);
|
||||
}
|
||||
return handleStructuredItemToClient(connection, toStructuredItem(connection, dataItem, true));
|
||||
return handleItemToClient(connection, new DataItem(itemId, count, tag));
|
||||
}
|
||||
|
||||
private void updateEnchantments(final StructuredDataContainer data, final CompoundTag tag, final String key,
|
||||
@@ -1537,15 +1525,11 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
|
||||
|
||||
final ListTag<CompoundTag> itemsTag = tag.getListTag("Items", CompoundTag.class);
|
||||
if (itemsTag != null) {
|
||||
// Only convert once, items can contain further containers
|
||||
final int size = Math.min(itemsTag.size(), 256);
|
||||
final Item[] items = new Item[size];
|
||||
int highestSlot = 0;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int i = 0, size = Math.min(itemsTag.size(), 256); i < size; i++) {
|
||||
final CompoundTag itemTag = itemsTag.get(i);
|
||||
final Item item = itemFromTag(connection, itemTag);
|
||||
items[i] = item;
|
||||
if (item.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -1556,13 +1540,13 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
|
||||
|
||||
final Item[] filteredItems = new Item[highestSlot + 1];
|
||||
Arrays.fill(filteredItems, StructuredItem.empty());
|
||||
for (int i = 0; i < size; i++) {
|
||||
final Item item = items[i];
|
||||
for (final CompoundTag itemTag : itemsTag) {
|
||||
final Item item = itemFromTag(connection, itemTag);
|
||||
if (item.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int slot = itemsTag.get(i).getByte("Slot");
|
||||
final int slot = itemTag.getByte("Slot");
|
||||
if (slot >= 0 && slot < filteredItems.length) {
|
||||
filteredItems[slot] = item;
|
||||
}
|
||||
|
||||
+4
-8
@@ -34,7 +34,6 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
|
||||
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
|
||||
import com.viaversion.viaversion.exception.CancelException;
|
||||
import com.viaversion.viaversion.exception.InformativeException;
|
||||
@@ -49,6 +48,7 @@ import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundPacke
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.rewriter.BlockItemPacketRewriter1_20_2;
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.rewriter.BlockRewriter1_20_2;
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.rewriter.EntityPacketRewriter1_20_2;
|
||||
import com.viaversion.viaversion.connection.ProtocolStorablesBase;
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.storage.ConfigurationState;
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.storage.ConfigurationState.BridgePhase;
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.storage.LastResourcePack;
|
||||
@@ -151,15 +151,11 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
|
||||
registerServerbound(State.LOGIN, ServerboundLoginPackets.LOGIN_ACKNOWLEDGED.getId(), -1, wrapper -> {
|
||||
wrapper.cancel();
|
||||
|
||||
final ProtocolStorables1_20_2 storables = wrapper.user().storables(this);
|
||||
final ConfigurationState configurationState = storables.configurationState();
|
||||
if (configurationState.bridgePhase() != BridgePhase.PROFILE_SENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Overwrite the state set in the base protocol to what the server actually keeps sending
|
||||
wrapper.user().getProtocolInfo().setServerState(State.PLAY);
|
||||
|
||||
final ProtocolStorables1_20_2 storables = wrapper.user().storables(this);
|
||||
final ConfigurationState configurationState = storables.configurationState();
|
||||
configurationState.setBridgePhase(BridgePhase.CONFIGURATION);
|
||||
configurationState.sendQueuedPackets(wrapper.user());
|
||||
});
|
||||
@@ -344,7 +340,7 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
|
||||
protocolInfo.setServerState(State.CONFIGURATION);
|
||||
|
||||
final PacketWrapper registryDataPacket = PacketWrapper.create(ClientboundConfigurationPackets1_20_2.REGISTRY_DATA, connection);
|
||||
registryDataPacket.write(Types.COMPOUND_TAG, dimensionRegistry.copy());
|
||||
registryDataPacket.write(Types.COMPOUND_TAG, dimensionRegistry);
|
||||
registryDataPacket.send(Protocol1_20To1_20_2.class);
|
||||
|
||||
// If we tracked enables features, they'd be sent here
|
||||
|
||||
+49
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter;
|
||||
|
||||
import com.viaversion.nbt.tag.CompoundTag;
|
||||
import com.viaversion.nbt.tag.IntTag;
|
||||
import com.viaversion.nbt.tag.ListTag;
|
||||
import com.viaversion.nbt.tag.LongArrayTag;
|
||||
import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
@@ -272,6 +273,7 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
|
||||
|
||||
final StructuredDataContainer dataContainer = item.dataContainer();
|
||||
updateItemDataComponentTypeIds(dataContainer, true);
|
||||
backupHiddenAttributeModifiers(item);
|
||||
handleRewritablesToClient(connection, dataContainer, null);
|
||||
|
||||
updateItemData(item);
|
||||
@@ -298,6 +300,53 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
|
||||
super.handleItemDataComponentsToServer(connection, item, container);
|
||||
}
|
||||
|
||||
private void backupHiddenAttributeModifiers(final Item item) {
|
||||
final AttributeModifiers1_21 attributeModifiers = item.dataContainer().get(StructuredDataKey.ATTRIBUTE_MODIFIERS1_21);
|
||||
if (attributeModifiers == null || attributeModifiers.showInTooltip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ListTag<CompoundTag> modifiersTag = new ListTag<>(CompoundTag.class);
|
||||
for (final AttributeModifiers1_21.AttributeModifier modifier : attributeModifiers.modifiers()) {
|
||||
final CompoundTag modifierTag = new CompoundTag();
|
||||
modifierTag.putInt("attribute", modifier.attribute());
|
||||
modifierTag.putString("id", modifier.modifier().id());
|
||||
modifierTag.putDouble("amount", modifier.modifier().amount());
|
||||
modifierTag.putInt("operation", modifier.modifier().operation());
|
||||
modifierTag.putInt("slot", modifier.slotType());
|
||||
modifiersTag.add(modifierTag);
|
||||
}
|
||||
saveTag(createCustomTag(item), modifiersTag, "hidden_attribute_modifiers");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restoreBackupData(final Item item, final StructuredDataContainer container, final CompoundTag customData) {
|
||||
super.restoreBackupData(item, container, customData);
|
||||
|
||||
final ListTag<CompoundTag> modifiersTag = customData.getListTag(nbtTagName("hidden_attribute_modifiers"), CompoundTag.class);
|
||||
if (modifiersTag == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeBackupTag(customData, "hidden_attribute_modifiers");
|
||||
if (container.has(StructuredDataKey.ATTRIBUTE_MODIFIERS1_21_5)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final AttributeModifiers1_21.AttributeModifier[] modifiers = new AttributeModifiers1_21.AttributeModifier[modifiersTag.size()];
|
||||
for (int i = 0; i < modifiers.length; i++) {
|
||||
final CompoundTag modifierTag = modifiersTag.get(i);
|
||||
final AttributeModifiers1_21.ModifierData modifierData = new AttributeModifiers1_21.ModifierData(
|
||||
modifierTag.getString("id"),
|
||||
modifierTag.getDouble("amount"),
|
||||
modifierTag.getInt("operation")
|
||||
);
|
||||
modifiers[i] = new AttributeModifiers1_21.AttributeModifier(modifierTag.getInt("attribute"), modifierData, modifierTag.getInt("slot"));
|
||||
}
|
||||
// Show state is applied from tooltip_display afterwards
|
||||
container.set(StructuredDataKey.ATTRIBUTE_MODIFIERS1_21_5, new AttributeModifiers1_21(modifiers, true));
|
||||
}
|
||||
|
||||
public static void updateItemData(final Item item) {
|
||||
final StructuredDataContainer dataContainer = item.dataContainer();
|
||||
dataContainer.replaceKey(StructuredDataKey.TOOL1_20_5, StructuredDataKey.TOOL1_21_5);
|
||||
|
||||
+2
-9
@@ -31,12 +31,10 @@ import com.viaversion.viaversion.codec.hash.HashOps;
|
||||
import com.viaversion.viaversion.data.item.ItemHasherBase;
|
||||
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class ItemHashStorage1_21_5 implements ItemHasher {
|
||||
|
||||
private final Cache<Long, StructuredData<?>> hashToStructuredData = CacheBuilder.newBuilder().concurrencyLevel(1).maximumSize(512).build();
|
||||
private final long keyMultiplier = ThreadLocalRandom.current().nextLong() | 1; // Odd to keep keys unique, random to not have predictable buckets
|
||||
private boolean processingClientboundInventoryPacket;
|
||||
private final CodecContext context;
|
||||
|
||||
@@ -56,7 +54,7 @@ public class ItemHashStorage1_21_5 implements ItemHasher {
|
||||
return;
|
||||
}
|
||||
|
||||
final long key = key(structuredData.id(), hash);
|
||||
final long key = (long) structuredData.id() << 32 | hash;
|
||||
try {
|
||||
this.hashToStructuredData.get(key, structuredData::copy);
|
||||
} catch (final ExecutionException e) {
|
||||
@@ -65,16 +63,11 @@ public class ItemHashStorage1_21_5 implements ItemHasher {
|
||||
}
|
||||
|
||||
public StructuredData<?> dataFromHash(final int dataComponentId, final int hash) {
|
||||
final long key = key(dataComponentId, hash);
|
||||
final long key = (long) dataComponentId << 32 | hash;
|
||||
final StructuredData<?> data = this.hashToStructuredData.getIfPresent(key);
|
||||
return data != null ? data.copy() : null;
|
||||
}
|
||||
|
||||
private long key(final int dataComponentId, final int hash) {
|
||||
// Add a key multiplier to avoid collisions from Guava's cache unseeded hashing
|
||||
return ((long) dataComponentId << 32 | (hash & 0xFFFFFFFFL)) * this.keyMultiplier;
|
||||
}
|
||||
|
||||
private static <T> int hash(final Hasher hasher, final StructuredData<T> data) {
|
||||
hasher.write(data.key().type(), data.value());
|
||||
return hasher.hash();
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public final class ComponentRewriter1_21_11 extends NBTComponentRewriter<Clientb
|
||||
final StringTag sprite = tag.getStringTag("sprite");
|
||||
if (sprite != null) {
|
||||
final String strippedSprite = Key.stripNamespace(sprite.getValue());
|
||||
if (strippedSprite.startsWith("item/") || strippedSprite.startsWith("trims/items/")) {
|
||||
if (strippedSprite.startsWith("item/")) {
|
||||
tag.putString("atlas", "items");
|
||||
} else if (strippedSprite.startsWith("block/")) {
|
||||
tag.putString("atlas", "blocks");
|
||||
|
||||
-1
@@ -502,7 +502,6 @@ public final class BlockItemPacketRewriter1_21_2 extends StructuredItemRewriter<
|
||||
|
||||
final IntArrayTag emptyEnchantments = customData.getIntArrayTag(nbtTagName("0_enchants"));
|
||||
if (emptyEnchantments != null) {
|
||||
Limit.max(emptyEnchantments.length(), 256);
|
||||
Enchantments enchantments = dataContainer.get(StructuredDataKey.ENCHANTMENTS1_20_5);
|
||||
if (enchantments == null) {
|
||||
enchantments = new Enchantments(true);
|
||||
|
||||
+1
-15
@@ -212,24 +212,13 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
|
||||
return null;
|
||||
}
|
||||
|
||||
final MappingData mappingData = protocol.getMappingData();
|
||||
final FullMappings dataComponentMappings = mappingData != null ? mappingData.getDataComponentSerializerMappings() : null;
|
||||
if (dataComponentMappings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int dataComponentTypes = Math.max(dataComponentMappings.size(), dataComponentMappings.mappedSize());
|
||||
final OriginalHashedItem hashedItem = new OriginalHashedItem(idTag.asInt(), item.amount(), backupTagName);
|
||||
try {
|
||||
for (final Map.Entry<String, Tag> entry : originalHashes.entrySet()) {
|
||||
if (entry.getValue() instanceof IntTag hashTag) {
|
||||
final String key = entry.getKey();
|
||||
if (!key.equals("id")) {
|
||||
final int id = Integer.parseInt(key);
|
||||
if (id < 0 || id >= dataComponentTypes) {
|
||||
return null;
|
||||
}
|
||||
hashedItem.dataHashesById().put(id, hashTag.asInt());
|
||||
hashedItem.dataHashesById().put(Integer.parseInt(key), hashTag.asInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,9 +229,6 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
|
||||
final IntArrayTag removedTag = originalHashes.getIntArrayTag("removed");
|
||||
if (removedTag != null) {
|
||||
for (final int id : removedTag.getValue()) {
|
||||
if (id < 0 || id >= dataComponentTypes) {
|
||||
return null;
|
||||
}
|
||||
hashedItem.removedDataIds().add(id);
|
||||
}
|
||||
}
|
||||
|
||||
-29
@@ -418,35 +418,6 @@ public abstract class ComponentRewriterBase<C extends ClientboundPacketType> imp
|
||||
// Entity / block entity types
|
||||
handleTypedEntityData(componentsTag, "entity_data", protocol.getMappingData().getEntityMappings());
|
||||
handleTypedEntityData(componentsTag, "block_entity_data", protocol.getMappingData().getBlockEntityMappings());
|
||||
|
||||
handleTooltipDisplay(componentsTag);
|
||||
}
|
||||
|
||||
private void handleTooltipDisplay(final CompoundTag componentsTag) {
|
||||
final FullMappings mappings = protocol.getMappingData().getDataComponentSerializerMappings();
|
||||
if (Mappings.isFullIdentity(mappings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CompoundTag tooltipDisplay = TagUtil.getNamespacedCompoundTag(componentsTag, "tooltip_display");
|
||||
if (tooltipDisplay == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ListTag<StringTag> hiddenComponents = tooltipDisplay.getListTag("hidden_components", StringTag.class);
|
||||
if (hiddenComponents == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remap or remove data component types that have been renamed or removed
|
||||
hiddenComponents.getValue().removeIf(componentTag -> {
|
||||
final String mappedId = mappings.mappedIdentifier(componentTag.getValue());
|
||||
if (mappedId != null) {
|
||||
componentTag.setValue(mappedId);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void handleSoundEventTag(@Nullable final Tag soundEventTag, final FullMappings soundMappings) {
|
||||
|
||||
@@ -194,10 +194,6 @@ enforce-secure-chat: false
|
||||
# Handles items with invalid count values (higher than max stack size) on 1.20.3 servers.
|
||||
handle-invalid-item-count: false
|
||||
#
|
||||
# Backs up the original data of nested items (e.g. in shulker boxes or bundles) for 1.20.5+ clients on 1.20.4 and older servers.
|
||||
# This keeps their data intact when taken out individually in creative mode, but greatly increases the size of deeply nested items.
|
||||
backup-nested-items: false
|
||||
#
|
||||
# Hides sidebar scoreboard numbers for 1.20.3+ clients on older server versions.
|
||||
hide-scoreboard-numbers: false
|
||||
#
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
|
||||
projectVersion=5.12.3-SNAPSHOT
|
||||
projectVersion=5.12.2-SNAPSHOT
|
||||
|
||||
# note that modrinth may not have added the version on release yet
|
||||
# Smile emoji (note that modrinth may not have added the version on release yet)
|
||||
mcVersions=26.3, 26.2, 26.1.2, 26.1.1, 26.1, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 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
|
||||
mcVersionRange=1.8-26.3
|
||||
velocityVersion=3.4-4.2.1
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ metadata.format.version = "1.1"
|
||||
[versions]
|
||||
|
||||
gson = "2.14.0"
|
||||
snakeYaml = "2.7"
|
||||
snakeYaml = "2.6"
|
||||
fastutil = "8.5.15"
|
||||
vianbt = "5.4.1"
|
||||
mcstructs = "5-3.3.3-SNAPSHOT"
|
||||
vianbt = "5.4.0"
|
||||
mcstructs = "5-3.3.2-SNAPSHOT"
|
||||
|
||||
# Common provided
|
||||
netty = "4.0.20.Final"
|
||||
@@ -14,7 +14,7 @@ guava = "17.0"
|
||||
|
||||
junit = "6.1.3"
|
||||
platformLauncher = "6.1.3"
|
||||
checkerQual = "4.3.1"
|
||||
checkerQual = "4.3.0"
|
||||
|
||||
# Platforms
|
||||
paper = "1.20.4-R0.1-SNAPSHOT"
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=21bd5da2de49b642904077f38c0efdc7778e92b3ed0889392dca61b97e389607
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.2-bin.zip
|
||||
distributionSha256Sum=dce76f55f8e251a3a1f130eb120f30b3d271de2b76c9b0729d316b5a1b6dc01f
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.1-bin.zip
|
||||
networkTimeout=10000
|
||||
retries=0
|
||||
retryBackOffMs=500
|
||||
|
||||
+44
-30
@@ -1,6 +1,8 @@
|
||||
import com.modrinth.minotaur.TaskModrinthUpload
|
||||
|
||||
plugins {
|
||||
id("me.modmuss50.mod-publish-plugin") version "2.2.1"
|
||||
id("io.papermc.hangar-publish-plugin") version "0.1.4"
|
||||
id("com.modrinth.minotaur") version "2.+"
|
||||
|
||||
// A nice no-conflict comment for patching in downgrading
|
||||
}
|
||||
@@ -44,36 +46,45 @@ if (runNumber != null && (!isRelease || isMainBranch)) { // Only publish release
|
||||
"[$commitHash](https://github.com/ViaVersion/ViaVersion/commit/$commitHash) ${rootProject.latestCommitMessage()}"
|
||||
}
|
||||
|
||||
val mcVersionRange = property("mcVersionRange") as String
|
||||
val (mcVersionStart, mcVersionEnd) = mcVersionRange.split("-", limit = 2)
|
||||
publishMods {
|
||||
file.set(tasks.shadowJar.flatMap { it.archiveFile })
|
||||
type.set(if (isRelease) STABLE else if (isMainBranch) BETA else ALPHA)
|
||||
version.set(suffixedVersion)
|
||||
displayName.set(suffixedVersion)
|
||||
val mcVersions: List<String> = (property("mcVersions") as String)
|
||||
.split(",")
|
||||
.map { it.trim() }
|
||||
modrinth {
|
||||
token.set(System.getenv("MODRINTH_TOKEN"))
|
||||
projectId.set("viaversion")
|
||||
versionType.set(if (isRelease) "release" else if (isMainBranch) "beta" else "alpha")
|
||||
versionNumber.set(suffixedVersion)
|
||||
versionName.set(suffixedVersion)
|
||||
changelog.set(changelogContent)
|
||||
|
||||
val modrinthOptions = modrinthOptions {
|
||||
accessToken.set(providers.environmentVariable("MODRINTH_TOKEN"))
|
||||
projectId.set("P1OZGk5p")
|
||||
optional("viafabric", "viabackwards", "viarewind")
|
||||
uploadFile.set(tasks.shadowJar.flatMap { it.archiveFile })
|
||||
gameVersions.set(mcVersions)
|
||||
loaders.add("paper")
|
||||
loaders.add("folia")
|
||||
loaders.add("velocity")
|
||||
autoAddDependsOn.set(false)
|
||||
detectLoaders.set(false)
|
||||
dependencies {
|
||||
optional.project("viafabric")
|
||||
optional.project("viabackwards")
|
||||
optional.project("viarewind")
|
||||
}
|
||||
modrinth {
|
||||
from(modrinthOptions)
|
||||
modLoaders.addAll("paper", "folia", "velocity")
|
||||
minecraftVersionRange {
|
||||
start.set(mcVersionStart)
|
||||
end.set(mcVersionEnd)
|
||||
}
|
||||
}
|
||||
// Fabric requires 1.14+ (18w43b), so it is uploaded separately with only the supported versions
|
||||
modrinth("modrinthFabric") {
|
||||
from(modrinthOptions)
|
||||
modLoaders.add("fabric")
|
||||
minecraftVersionRange {
|
||||
start.set("1.14")
|
||||
end.set(mcVersionEnd)
|
||||
}
|
||||
}
|
||||
tasks.modrinth {
|
||||
notCompatibleWithConfigurationCache("")
|
||||
finalizedBy("modrinthFabric")
|
||||
}
|
||||
// Fabric requires 1.14+ (18w43b), so it is uploaded separately with only the supported versions
|
||||
val modrinthExtension = modrinth
|
||||
tasks.register<TaskModrinthUpload>("modrinthFabric") {
|
||||
group = "publishing"
|
||||
dependsOn(tasks.assemble)
|
||||
notCompatibleWithConfigurationCache("")
|
||||
doFirst {
|
||||
modrinthExtension.loaders.set(listOf("fabric"))
|
||||
modrinthExtension.gameVersions.set(mcVersions.filter { version ->
|
||||
val (major, minor) = version.split(".").map(String::toInt)
|
||||
major > 1 || minor >= 14
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +98,7 @@ if (runNumber != null && (!isRelease || isMainBranch)) { // Only publish release
|
||||
platforms {
|
||||
paper {
|
||||
jar.set(tasks.shadowJar.flatMap { it.archiveFile })
|
||||
platformVersions.set(listOf(mcVersionRange))
|
||||
platformVersions.set(listOf(property("mcVersionRange") as String))
|
||||
dependencies {
|
||||
hangar("ViaBackwards") {
|
||||
required = false
|
||||
@@ -112,4 +123,7 @@ if (runNumber != null && (!isRelease || isMainBranch)) { // Only publish release
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.named("publishPluginPublicationToHangar") {
|
||||
notCompatibleWithConfigurationCache("")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user