Compare commits

..
42 Commits
Author SHA1 Message Date
Nassim Jahnke 4f2a5bb7e2 4.4.1 Release 2022-07-28 18:49:40 +02:00
Nassim Jahnke 1c511a82b2 Simplify component building 2022-07-28 14:56:35 +02:00
Nassim Jahnke 0c39723d1a Use translation key as text if not found 2022-07-28 13:43:08 +02:00
Nassim Jahnke 322af00e80 Handle 1.19 chat types 2022-07-28 13:14:28 +02:00
Nassim Jahnke a88747d904 Check for dimension equality after adding/replacing new fields 2022-07-28 11:47:12 +02:00
Nassim Jahnke e194d27bea Allow for more control over max path distance delta increase 2022-07-28 11:29:02 +02:00
Nassim Jahnke 22daa60eb6 4.4.0 Release 2022-07-27 19:01:23 +02:00
Nassim Jahnke 6eca07966c 1.19.1-rc3 2022-07-26 18:27:32 +02:00
Nassim Jahnke 56cc711c01 Update legacy palette handling as well 2022-07-25 13:18:13 +02:00
Nassim Jahnke c2ee558235 Fix reading of cursed Hypixel block palettes
Fixes #3037
2022-07-24 18:42:25 +02:00
Nassim Jahnke c8a010c390 Handle negative bits per value in palette 2022-07-24 17:30:30 +02:00
Nassim Jahnke 53c54485eb Cleanup optional types 2022-07-21 19:56:42 +02:00
Nassim Jahnke f42a308f2c 1.19.1-rc2 2022-07-21 19:06:34 +02:00
Nassim Jahnke 44250cbb99 1.19.1-pre6 2022-07-20 18:36:28 +02:00
Nassim Jahnke 55ffe72198 Fix overlay type check, update some comments 2022-07-15 21:33:55 +02:00
Nassim Jahnke a47dd2ecdb Support 1.19.1 clients on 1.19.0 servers 2022-07-15 21:03:56 +02:00
Nassim Jahnke 8a5233b6a1 what am I doing 2022-07-15 18:07:59 +02:00
Nassim Jahnke c8a1279e75 I was too hopeful 2022-07-15 16:51:12 +02:00
Nassim Jahnke 57ef90e851 1.19.1-pre5 2022-07-15 16:26:58 +02:00
_tomcraft 2262681351 Reference command permission to filter root suggestions (/via<tab>) (#3018) 2022-07-13 10:24:14 +02:00
Nassim Jahnke 56e1d0a69d Add optional type for smol cleanup 2022-07-09 11:47:58 +02:00
Nassim Jahnke 63ffb51df5 Fix player chat packet id
Mojang didn't register that in the correct spot alphabetically :(
2022-07-08 21:07:42 +02:00
Nassim Jahnke b33bd2ac2b 1.19.1-pre4 2022-07-08 16:20:54 +02:00
Nassim Jahnke 1afff77a0f 1.19.1-pre3 2022-07-06 17:47:47 +02:00
Nassim Jahnke 26af09f2a4 Update unsupported software list 2022-07-05 20:37:19 +02:00
Nassim Jahnke a8e475dbf0 Bump version to 4.4.0-SNAPSHOT
Too many funky things for a patch version
2022-07-01 12:35:57 +02:00
Nassim Jahnke 6388021c6d Fix 1.18.2->1.19.0 transforming, warn on 1.19.0 server 2022-06-30 20:00:55 +02:00
Nassim Jahnke f4aa96a5f8 1.19.1-pre2 2022-06-30 19:34:14 +02:00
Nassim Jahnke 6baae5e4f7 Merge remote-tracking branch 'origin/master' into dev 2022-06-30 10:42:27 +02:00
Nassim Jahnke 189b244a3a Delay ack by a tick, update warning for bad dimension registry 2022-06-30 10:41:54 +02:00
creeper123123321 12d538fe0d Use most similar dimension when the proper is not found (#2990) 2022-06-30 10:31:10 +02:00
_tomcraft 34f0dbf642 Safely handle bad configuration of 'block-protocols' and 'block-versions' (#2983) 2022-06-28 11:22:42 +02:00
Myles 548f80bb7c Add label for Feature Requests 2022-06-27 13:36:10 +01:00
Nassim Jahnke 9113a77331 1.19.1-rc1 except not really 2022-06-23 20:45:42 +02:00
Nassim Jahnke e3e85db02a 1.19.1-pre1 2022-06-21 21:01:24 +02:00
Camotoy c4d9209c81 Rewrite statistics for 1.19 (#2954) 2022-06-15 10:13:14 +02:00
Nassim Jahnke 24d887a53d Properly handle 1.19 acks on backend
Fixes #2935
2022-06-12 11:14:05 +02:00
Owen 702ced200e Generate a random seed to simulate random sounds (#2944) 2022-06-11 19:02:54 +02:00
qlowandqlow 40f5cb6e71 Fixed Bungeecord madness (#2934)
Co-authored-by: qlow <info@qlow.eu>
2022-06-09 17:10:22 +02:00
Nassim Jahnke 7ab0c41be6 Fix villager trade offers
Fixes #2919
2022-06-08 10:07:47 +02:00
Nassim Jahnke 66b21431f2 Fix sending of empty titles
Fixes #2923
2022-06-08 09:51:38 +02:00
Nassim Jahnke c6cd655f7e Bump version to 4.3.2-SNAPSHOT 2022-06-08 09:09:37 +02:00
68 changed files with 1570 additions and 297 deletions

No files matched your search

+2 -1
View File
@@ -1,5 +1,6 @@
name: Feature Request
description: Suggest a feature to be added
labels: [Feature Request]
body:
- type: textarea
@@ -34,4 +35,4 @@ body:
description: |
Does the feature apply to any specific version or environment?
validations:
required: false
required: false
+1 -1
View File
@@ -8,7 +8,7 @@
Supported Versions:
![Table (https://i.imgur.com/uDM9HR8.png)](https://i.imgur.com/RRa5KnK.png)
![Table (https://i.imgur.com/aSjHvQk.png)](https://i.imgur.com/aSjHvQk.png)
On Paper you may also use ProtocolSupport, but ensure you have the right build for your server version.
@@ -84,6 +84,7 @@ public class ProtocolVersion {
public static final ProtocolVersion v1_18 = register(757, "1.18/1.18.1", new VersionRange("1.18", 0, 1));
public static final ProtocolVersion v1_18_2 = register(758, "1.18.2");
public static final ProtocolVersion v1_19 = register(759, "1.19");
public static final ProtocolVersion v1_19_1 = register(760, "1.19.1");
public static final ProtocolVersion unknown = register(-1, "UNKNOWN");
public static ProtocolVersion register(int version, String name) {
@@ -64,7 +64,7 @@ public interface ViaAPI<T> {
* @return API version incremented with meaningful API changes
*/
default int apiVersion() {
return 12;
return 14;
}
/**
@@ -28,6 +28,7 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.WorldIdentifiers;
import com.viaversion.viaversion.api.protocol.version.BlockedProtocolVersions;
import it.unimi.dsi.fastutil.ints.IntSet;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface ViaVersionConfig {
@@ -455,4 +456,6 @@ public interface ViaVersionConfig {
WorldIdentifiers get1_16WorldNamesMap();
boolean cache1_17Light();
@Nullable String chatTypeFormat(String translationKey);
}
@@ -20,28 +20,24 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.minecraft;
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
public class OptPositionType extends Type<Position> {
public OptPositionType() {
super(Position.class);
public final class PlayerMessageSignature {
private final UUID uuid;
private final byte[] signatureBytes;
public PlayerMessageSignature(final UUID uuid, final byte[] signatureBytes) {
this.uuid = uuid;
this.signatureBytes = signatureBytes;
}
@Override
public Position read(ByteBuf buffer) throws Exception {
boolean present = buffer.readBoolean();
if (!present) return null;
return Type.POSITION.read(buffer);
public UUID uuid() {
return uuid;
}
@Override
public void write(ByteBuf buffer, Position object) throws Exception {
buffer.writeBoolean(object != null);
if (object != null)
Type.POSITION.write(buffer, object);
public byte[] signatureBytes() {
return signatureBytes;
}
}
@@ -20,29 +20,28 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.minecraft;
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public final class ProfileKey {
private final long expiresAt;
private final byte[] publicKey;
private final byte[] keySignature;
public class OptPosition1_14Type extends Type<Position> {
public OptPosition1_14Type() {
super(Position.class);
public ProfileKey(final long expiresAt, final byte[] publicKey, final byte[] keySignature) {
this.expiresAt = expiresAt;
this.publicKey = publicKey;
this.keySignature = keySignature;
}
@Override
public Position read(ByteBuf buffer) throws Exception {
boolean present = buffer.readBoolean();
if (!present) return null;
return Type.POSITION1_14.read(buffer);
public long expiresAt() {
return expiresAt;
}
@Override
public void write(ByteBuf buffer, Position object) throws Exception {
buffer.writeBoolean(object != null);
if (object != null) {
Type.POSITION1_14.write(buffer, object);
}
public byte[] publicKey() {
return publicKey;
}
public byte[] keySignature() {
return keySignature;
}
}
@@ -218,4 +218,12 @@ public interface ViaPlatform<T> {
default Collection<UnsupportedSoftware> getUnsupportedSoftwareClasses() {
return Collections.emptyList();
}
/**
* Returns whether the platform has a plugin/mod with the given name (even if disabled).
*
* @param name plugin or identifier
* @return whether the platform has a plugin/mod with the given name
*/
boolean hasPlugin(String name);
}
@@ -302,7 +302,7 @@ public interface Protocol<C1 extends ClientboundPacketType, C2 extends Clientbou
*
* @param userConnection The user to initialise
*/
default void init(UserConnection userConnection) {
default void init(UserConnection connection) {
}
/**
@@ -177,35 +177,49 @@ public interface ProtocolManager {
@Nullable Class<S> serverboundPacketsClass);
/**
* Returns whether protocol path calculation expects the path to come closer to the expected version with each entry, true by default.
* Sets the max delta the path calculation allows the distance to the target protocol version to increase.
* <p>
* In practice, this means a path will never go to a protocol version that puts it farther from the desired
* If set to 0, protocol paths will have to come closer to the target protocol version with every entry,
* never going farther away from it (1→5→10 and 1→11→10 are ok, 1→20→10 is not ok).
* If set to -1, no distance checks will be applied (1→20→10 is ok).
*
* @param maxPathDeltaIncrease the max delta the path calculation allows the distance to the target protocol version to increase
* @see #onlyCheckLoweringPathEntries()
*/
void setMaxPathDeltaIncrease(int maxPathDeltaIncrease);
/**
* Returns the max delta the path calculation allows the distance to the target protocol version to increase. 0 by default.
* <p>
* In practice, a value of 0 means a path will never go to a protocol version that puts it farther from the desired
* server protocol version, even if a path existed.
* If this is set to false, *all* possible paths will be checked until a fitting one is found.
* If this is set to -1, *all* possible paths will be checked until a fitting one is found.
* <p>
* Negative examples if this returns true:
* Negative examples if this returns 0:
* <ul>
* A possible path from 3 to 5 in order of 3→10→5 will be dismissed.
* A possible path from 5 to 3 in order of 5→0→3 will be dismissed.
* </ul>
* <p>
* Negative examples if this returns false:
* Negative examples if this returns -1:
* <ul>
* While searching for a path from 3 to 5, 3→2→1 could be checked first before 3→4→5 is found.
* While searching for a path from 5 to 3, 5→6→7 could be checked first before 5→4→3 is found.
* </ul>
*
* @return whether protocol path calculation expects the path to come closer to the expected version with each entry
* @return max delta the path calculation allows the distance to the target protocol version to increase
*/
boolean onlyCheckLoweringPathEntries();
int getMaxPathDeltaIncrease();
/**
* Sets whether protocol path calculation expects the path to come closer to the expected version with each entry.
*
* @param onlyCheckLoweringPathEntries whether protocol path calculation expects the path to come closer to the expected version with each entry
* @see #onlyCheckLoweringPathEntries()
*/
void setOnlyCheckLoweringPathEntries(boolean onlyCheckLoweringPathEntries);
@Deprecated/*(forRemoval = true)*/
default void setOnlyCheckLoweringPathEntries(final boolean onlyCheckLoweringPathEntries) {
setMaxPathDeltaIncrease(onlyCheckLoweringPathEntries ? 0 : -1);
}
@Deprecated/*(forRemoval = true)*/
default boolean onlyCheckLoweringPathEntries() {
return getMaxPathDeltaIncrease() != -1;
}
/**
* Returns the maximum protocol path size applied to {@link #getProtocolPath(int, int)}.
@@ -81,6 +81,7 @@ public class ProtocolVersion {
public static final ProtocolVersion v1_18 = register(757, "1.18/1.18.1", new VersionRange("1.18", 0, 1));
public static final ProtocolVersion v1_18_2 = register(758, "1.18.2");
public static final ProtocolVersion v1_19 = register(759, "1.19");
public static final ProtocolVersion v1_19_1 = register(760, "1.19.1");
public static final ProtocolVersion unknown = register(-1, "UNKNOWN");
public static ProtocolVersion register(int version, String name) {
@@ -24,13 +24,15 @@ package com.viaversion.viaversion.api.type;
import io.netty.buffer.ByteBuf;
@FunctionalInterface
public interface ByteBufReader<T> {
/**
* Read a value from a ByteBuf
* Reads a value from a ByteBuf.
*
* @param buffer The buffer to read from.
* @return The type based on the class type.
* @throws Exception Throws exception if it failed reading.
* @param buffer buffer to read from
* @return type based on the class type
* @throws Exception if it failed reading
*/
T read(ByteBuf buffer) throws Exception;
}
@@ -24,13 +24,15 @@ package com.viaversion.viaversion.api.type;
import io.netty.buffer.ByteBuf;
@FunctionalInterface
public interface ByteBufWriter<T> {
/**
* Write an object to a type to a ByteBuf
* Writes an object to a type to a ByteBuf.
*
* @param buffer The buffer to write to
* @param object The object to write
* @throws Exception Throws if it failed to write
* @param buffer buffer to write to
* @param value value to write
* @throws Exception if it failed to write
*/
void write(ByteBuf buffer, T object) throws Exception;
void write(ByteBuf buffer, T value) throws Exception;
}
@@ -20,31 +20,31 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.minecraft;
package com.viaversion.viaversion.api.type;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public class OptionalComponentType extends Type<JsonElement> {
public abstract class OptionalType<T> extends Type<T> {
private final Type<T> type;
public OptionalComponentType() {
super(JsonElement.class);
protected OptionalType(final Type<T> type) {
super(type.getOutputClass());
this.type = type;
}
@Override
public JsonElement read(ByteBuf buffer) throws Exception {
boolean present = buffer.readBoolean();
return present ? Type.COMPONENT.read(buffer) : null;
public @Nullable T read(ByteBuf buffer) throws Exception {
return buffer.readBoolean() ? type.read(buffer) : null;
}
@Override
public void write(ByteBuf buffer, JsonElement object) throws Exception {
if (object == null) {
public void write(final ByteBuf buffer, @Nullable final T value) throws Exception {
if (value == null) {
buffer.writeBoolean(false);
} else {
buffer.writeBoolean(true);
Type.COMPONENT.write(buffer, object);
type.write(buffer, value);
}
}
}
}
@@ -28,7 +28,9 @@ import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.EulerAngle;
import com.viaversion.viaversion.api.minecraft.GlobalPosition;
import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.ProfileKey;
import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.VillagerData;
import com.viaversion.viaversion.api.minecraft.item.Item;
@@ -60,17 +62,15 @@ import com.viaversion.viaversion.api.type.types.minecraft.FlatItemArrayType;
import com.viaversion.viaversion.api.type.types.minecraft.FlatItemType;
import com.viaversion.viaversion.api.type.types.minecraft.FlatVarIntItemArrayType;
import com.viaversion.viaversion.api.type.types.minecraft.FlatVarIntItemType;
import com.viaversion.viaversion.api.type.types.minecraft.GlobalPositionType;
import com.viaversion.viaversion.api.type.types.minecraft.ItemArrayType;
import com.viaversion.viaversion.api.type.types.minecraft.ItemType;
import com.viaversion.viaversion.api.type.types.minecraft.NBTType;
import com.viaversion.viaversion.api.type.types.minecraft.OptPosition1_14Type;
import com.viaversion.viaversion.api.type.types.minecraft.OptPositionType;
import com.viaversion.viaversion.api.type.types.minecraft.OptUUIDType;
import com.viaversion.viaversion.api.type.types.minecraft.OptionalComponentType;
import com.viaversion.viaversion.api.type.types.minecraft.OptionalGlobalPositionType;
import com.viaversion.viaversion.api.type.types.minecraft.OptionalVarIntType;
import com.viaversion.viaversion.api.type.types.minecraft.PlayerMessageSignatureType;
import com.viaversion.viaversion.api.type.types.minecraft.Position1_14Type;
import com.viaversion.viaversion.api.type.types.minecraft.PositionType;
import com.viaversion.viaversion.api.type.types.minecraft.ProfileKeyType;
import com.viaversion.viaversion.api.type.types.minecraft.VarLongBlockChangeRecordType;
import com.viaversion.viaversion.api.type.types.minecraft.VectorType;
import com.viaversion.viaversion.api.type.types.minecraft.VillagerDataType;
@@ -104,15 +104,17 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
/* Other Types */
public static final Type<JsonElement> COMPONENT = new ComponentType();
public static final Type<JsonElement> OPTIONAL_COMPONENT = new OptionalComponentType();
public static final Type<JsonElement> OPTIONAL_COMPONENT = new ComponentType.OptionalComponentType();
public static final Type<String> STRING = new StringType();
public static final Type<String> OPTIONAL_STRING = new StringType.OptionalStringType();
public static final Type<String[]> STRING_ARRAY = new ArrayType<>(Type.STRING);
public static final Type<UUID> UUID = new UUIDType();
public static final Type<UUID> OPTIONAL_UUID = new OptUUIDType();
public static final Type<UUID> UUID_INT_ARRAY = new UUIDIntArrayType();
public static final Type<UUID> OPTIONAL_UUID = new UUIDType.OptionalUUIDType();
public static final Type<UUID[]> UUID_ARRAY = new ArrayType<>(Type.UUID);
@Deprecated/*(forRemoval = true)*/
public static final Type<UUID> UUID_INT_ARRAY = new UUIDIntArrayType();
public static final VarIntType VAR_INT = new VarIntType();
public static final OptionalVarIntType OPTIONAL_VAR_INT = new OptionalVarIntType();
@@ -148,15 +150,16 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
/* MC Types */
public static final Type<Position> POSITION = new PositionType();
public static final Type<Position> OPTIONAL_POSITION = new PositionType.OptionalPositionType();
public static final Type<Position> POSITION1_14 = new Position1_14Type();
public static final Type<Position> OPTIONAL_POSITION_1_14 = new Position1_14Type.OptionalPosition1_14Type();
public static final Type<EulerAngle> ROTATION = new EulerAngleType();
public static final Type<Vector> VECTOR = new VectorType();
public static final Type<CompoundTag> NBT = new NBTType();
public static final Type<CompoundTag[]> NBT_ARRAY = new ArrayType<>(Type.NBT);
public static final Type<Position> OPTIONAL_POSITION = new OptPositionType();
public static final Type<Position> OPTIONAL_POSITION_1_14 = new OptPosition1_14Type();
public static final Type<GlobalPosition> OPTIONAL_GLOBAL_POSITION = new OptionalGlobalPositionType();
public static final Type<GlobalPosition> GLOBAL_POSITION = new GlobalPositionType();
public static final Type<GlobalPosition> OPTIONAL_GLOBAL_POSITION = new GlobalPositionType.OptionalGlobalPositionType();
public static final Type<BlockChangeRecord> BLOCK_CHANGE_RECORD = new BlockChangeRecordType();
public static final Type<BlockChangeRecord[]> BLOCK_CHANGE_RECORD_ARRAY = new ArrayType<>(Type.BLOCK_CHANGE_RECORD);
@@ -169,6 +172,13 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public static final Type<Item> ITEM = new ItemType();
public static final Type<Item[]> ITEM_ARRAY = new ItemArrayType();
public static final Type<ProfileKey> PROFILE_KEY = new ProfileKeyType();
public static final Type<ProfileKey> OPTIONAL_PROFILE_KEY = new ProfileKeyType.OptionalProfileKeyType();
public static final Type<PlayerMessageSignature> PLAYER_MESSAGE_SIGNATURE = new PlayerMessageSignatureType();
public static final Type<PlayerMessageSignature> OPTIONAL_PLAYER_MESSAGE_SIGNATURE = new PlayerMessageSignatureType.OptionalPlayerMessageSignatureType();
public static final Type<PlayerMessageSignature[]> PLAYER_MESSAGE_SIGNATURE_ARRAY = new ArrayType<>(PLAYER_MESSAGE_SIGNATURE);
/* 1.13 Flat Item (no data) */
public static final Type<Item> FLAT_ITEM = new FlatItemType();
public static final Type<Item> FLAT_VAR_INT_ITEM = new FlatVarIntItemType();
@@ -26,6 +26,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
@@ -51,4 +52,11 @@ public class ComponentType extends Type<JsonElement> {
public void write(ByteBuf buffer, JsonElement object) throws Exception {
STRING_TAG.write(buffer, object.toString());
}
public static final class OptionalComponentType extends OptionalType<JsonElement> {
public OptionalComponentType() {
super(Type.COMPONENT);
}
}
}
@@ -36,7 +36,7 @@ public class LongArrayType extends Type<long[]> {
int length = Type.VAR_INT.readPrimitive(buffer);
long[] array = new long[length];
for (int i = 0; i < array.length; i++) {
array[i] = Type.LONG.readPrimitive(buffer);
array[i] = buffer.readLong();
}
return array;
}
@@ -45,7 +45,7 @@ public class LongArrayType extends Type<long[]> {
public void write(ByteBuf buffer, long[] object) throws Exception {
Type.VAR_INT.writePrimitive(buffer, object.length);
for (long l : object) {
Type.LONG.writePrimitive(buffer, l);
buffer.writeLong(l);
}
}
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.type.types;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
@@ -67,4 +68,11 @@ public class StringType extends Type<String> {
Type.VAR_INT.writePrimitive(buffer, b.length);
buffer.writeBytes(b);
}
public static final class OptionalStringType extends OptionalType<String> {
public OptionalStringType() {
super(Type.STRING);
}
}
}
@@ -22,12 +22,14 @@
*/
package com.viaversion.viaversion.api.type.types;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
public class UUIDType extends Type<UUID> {
public UUIDType() {
super(UUID.class);
}
@@ -42,4 +44,11 @@ public class UUIDType extends Type<UUID> {
buffer.writeLong(object.getMostSignificantBits());
buffer.writeLong(object.getLeastSignificantBits());
}
public static final class OptionalUUIDType extends OptionalType<UUID> {
public OptionalUUIDType() {
super(Type.UUID);
}
}
}
@@ -26,6 +26,7 @@ import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public class FlatItemType extends BaseItemType {
public FlatItemType() {
@@ -33,7 +34,7 @@ public class FlatItemType extends BaseItemType {
}
@Override
public Item read(ByteBuf buffer) throws Exception {
public @Nullable Item read(ByteBuf buffer) throws Exception {
short id = buffer.readShort();
if (id < 0) {
return null;
@@ -47,7 +48,7 @@ public class FlatItemType extends BaseItemType {
}
@Override
public void write(ByteBuf buffer, Item object) throws Exception {
public void write(ByteBuf buffer, @Nullable Item object) throws Exception {
if (object == null) {
buffer.writeShort(-1);
} else {
@@ -25,6 +25,7 @@ package com.viaversion.viaversion.api.type.types.minecraft;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public class FlatVarIntItemType extends BaseItemType {
public FlatVarIntItemType() {
@@ -32,7 +33,7 @@ public class FlatVarIntItemType extends BaseItemType {
}
@Override
public Item read(ByteBuf buffer) throws Exception {
public @Nullable Item read(ByteBuf buffer) throws Exception {
boolean present = buffer.readBoolean();
if (!present) {
return null;
@@ -46,7 +47,7 @@ public class FlatVarIntItemType extends BaseItemType {
}
@Override
public void write(ByteBuf buffer, Item object) throws Exception {
public void write(ByteBuf buffer, @Nullable Item object) throws Exception {
if (object == null) {
buffer.writeBoolean(false);
} else {
@@ -23,30 +23,32 @@
package com.viaversion.viaversion.api.type.types.minecraft;
import com.viaversion.viaversion.api.minecraft.GlobalPosition;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class OptionalGlobalPositionType extends Type<GlobalPosition> {
public class GlobalPositionType extends Type<GlobalPosition> {
public OptionalGlobalPositionType() {
public GlobalPositionType() {
super(GlobalPosition.class);
}
@Override
public GlobalPosition read(ByteBuf buffer) throws Exception {
if (buffer.readBoolean()) {
final String dimension = Type.STRING.read(buffer);
return Type.POSITION1_14.read(buffer).withDimension(dimension);
}
return null;
final String dimension = Type.STRING.read(buffer);
return Type.POSITION1_14.read(buffer).withDimension(dimension);
}
@Override
public void write(ByteBuf buffer, GlobalPosition object) throws Exception {
buffer.writeBoolean(object != null);
if (object != null) {
Type.STRING.write(buffer, object.dimension());
Type.POSITION1_14.write(buffer, object);
Type.STRING.write(buffer, object.dimension());
Type.POSITION1_14.write(buffer, object);
}
public static final class OptionalGlobalPositionType extends OptionalType<GlobalPosition> {
public OptionalGlobalPositionType() {
super(Type.GLOBAL_POSITION);
}
}
}
@@ -25,6 +25,7 @@ package com.viaversion.viaversion.api.type.types.minecraft;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ItemType extends BaseItemType {
public ItemType() {
@@ -32,7 +33,7 @@ public class ItemType extends BaseItemType {
}
@Override
public Item read(ByteBuf buffer) throws Exception {
public @Nullable Item read(ByteBuf buffer) throws Exception {
short id = buffer.readShort();
if (id < 0) {
return null;
@@ -47,7 +48,7 @@ public class ItemType extends BaseItemType {
}
@Override
public void write(ByteBuf buffer, Item object) throws Exception {
public void write(ByteBuf buffer, @Nullable Item object) throws Exception {
if (object == null) {
buffer.writeShort(-1);
} else {
@@ -26,20 +26,23 @@ import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class OptionalVarIntType extends Type<Integer> {
public OptionalVarIntType() {
super(Integer.class);
}
@Override
public Integer read(ByteBuf buffer) throws Exception {
int read = Type.VAR_INT.readPrimitive(buffer);
if (read == 0) return null;
return read - 1;
public Integer read(final ByteBuf buffer) throws Exception {
final int value = Type.VAR_INT.readPrimitive(buffer);
return value == 0 ? null : value - 1;
}
@Override
public void write(ByteBuf buffer, Integer object) throws Exception {
if (object == null) Type.VAR_INT.writePrimitive(buffer, 0);
else Type.VAR_INT.writePrimitive(buffer, object + 1);
public void write(final ByteBuf buffer, final Integer object) throws Exception {
if (object == null) {
Type.VAR_INT.writePrimitive(buffer, 0);
} else {
Type.VAR_INT.writePrimitive(buffer, object + 1);
}
}
}
@@ -0,0 +1,53 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.minecraft;
import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class PlayerMessageSignatureType extends Type<PlayerMessageSignature> {
public PlayerMessageSignatureType() {
super(PlayerMessageSignature.class);
}
@Override
public PlayerMessageSignature read(final ByteBuf buffer) throws Exception {
return new PlayerMessageSignature(Type.UUID.read(buffer), Type.BYTE_ARRAY_PRIMITIVE.read(buffer));
}
@Override
public void write(final ByteBuf buffer, final PlayerMessageSignature value) throws Exception {
Type.UUID.write(buffer, value.uuid());
Type.BYTE_ARRAY_PRIMITIVE.write(buffer, value.signatureBytes());
}
public static final class OptionalPlayerMessageSignatureType extends OptionalType<PlayerMessageSignature> {
public OptionalPlayerMessageSignatureType() {
super(Type.PLAYER_MESSAGE_SIGNATURE);
}
}
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.type.types.minecraft;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
@@ -48,4 +49,11 @@ public class Position1_14Type extends Type<Position> {
| (object.y() & 0xfff)
| ((((long) object.z()) & 0x3ffffff) << 12));
}
public static final class OptionalPosition1_14Type extends OptionalType<Position> {
public OptionalPosition1_14Type() {
super(Type.POSITION1_14);
}
}
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.type.types.minecraft;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
@@ -48,4 +49,11 @@ public class PositionType extends Type<Position> {
| ((((long) object.y()) & 0xfff) << 26)
| (object.z() & 0x3ffffff));
}
public static final class OptionalPositionType extends OptionalType<Position> {
public OptionalPositionType() {
super(Type.POSITION);
}
}
}
@@ -22,31 +22,33 @@
*/
package com.viaversion.viaversion.api.type.types.minecraft;
import com.viaversion.viaversion.api.minecraft.ProfileKey;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
public class ProfileKeyType extends Type<ProfileKey> {
public class OptUUIDType extends Type<UUID> {
public OptUUIDType() {
super(UUID.class);
public ProfileKeyType() {
super(ProfileKey.class);
}
@Override
public UUID read(ByteBuf buffer) {
boolean present = buffer.readBoolean();
if (!present) return null;
return new UUID(buffer.readLong(), buffer.readLong());
public ProfileKey read(final ByteBuf buffer) throws Exception {
return new ProfileKey(buffer.readLong(), Type.BYTE_ARRAY_PRIMITIVE.read(buffer), Type.BYTE_ARRAY_PRIMITIVE.read(buffer));
}
@Override
public void write(ByteBuf buffer, UUID object) {
if (object == null) {
buffer.writeBoolean(false);
} else {
buffer.writeBoolean(true);
buffer.writeLong(object.getMostSignificantBits());
buffer.writeLong(object.getLeastSignificantBits());
public void write(final ByteBuf buffer, final ProfileKey object) throws Exception {
buffer.writeLong(object.expiresAt());
Type.BYTE_ARRAY_PRIMITIVE.write(buffer, object.publicKey());
Type.BYTE_ARRAY_PRIMITIVE.write(buffer, object.keySignature());
}
public static final class OptionalProfileKeyType extends OptionalType<ProfileKey> {
public OptionalProfileKeyType() {
super(Type.PROFILE_KEY);
}
}
}
@@ -41,8 +41,10 @@ public class ChunkSectionType1_13 extends Type<ChunkSection> {
int bitsPerBlock = buffer.readUnsignedByte();
int originalBitsPerBlock = bitsPerBlock;
if (bitsPerBlock == 0 || bitsPerBlock > 8) {
if (bitsPerBlock > 8) {
bitsPerBlock = GLOBAL_PALETTE;
} else if (bitsPerBlock < 4) {
bitsPerBlock = 4;
}
// Read palette
@@ -58,18 +60,13 @@ public class ChunkSectionType1_13 extends Type<ChunkSection> {
}
// Read blocks
long[] blockData = new long[Type.VAR_INT.readPrimitive(buffer)];
long[] blockData = Type.LONG_ARRAY_PRIMITIVE.read(buffer);
if (blockData.length > 0) {
int expectedLength = (int) Math.ceil(ChunkSection.SIZE * bitsPerBlock / 64.0);
if (blockData.length != expectedLength) {
throw new IllegalStateException("Block data length (" + blockData.length + ") does not match expected length (" + expectedLength + ")! bitsPerBlock=" + bitsPerBlock + ", originalBitsPerBlock=" + originalBitsPerBlock);
if (blockData.length == expectedLength) {
CompactArrayUtil.iterateCompactArray(bitsPerBlock, ChunkSection.SIZE, blockData,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::setFlatBlock : chunkSection::setPaletteIndex);
}
for (int i = 0; i < blockData.length; i++) {
blockData[i] = buffer.readLong();
}
CompactArrayUtil.iterateCompactArray(bitsPerBlock, ChunkSection.SIZE, blockData,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::setFlatBlock : chunkSection::setPaletteIndex);
}
return chunkSection;
@@ -88,7 +85,7 @@ public class ChunkSectionType1_13 extends Type<ChunkSection> {
buffer.writeByte(bitsPerBlock);
// Write pallet (or not)
// Write palette
if (bitsPerBlock != GLOBAL_PALETTE) {
Type.VAR_INT.writePrimitive(buffer, chunkSection.getPaletteSize());
for (int i = 0; i < chunkSection.getPaletteSize(); i++) {
@@ -98,9 +95,6 @@ public class ChunkSectionType1_13 extends Type<ChunkSection> {
long[] data = CompactArrayUtil.createCompactArray(bitsPerBlock, ChunkSection.SIZE,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::getFlatBlock : chunkSection::getPaletteIndex);
Type.VAR_INT.writePrimitive(buffer, data.length);
for (long l : data) {
buffer.writeLong(l);
}
Type.LONG_ARRAY_PRIMITIVE.write(buffer, data);
}
}
@@ -41,8 +41,10 @@ public class ChunkSectionType1_16 extends Type<ChunkSection> {
int bitsPerBlock = buffer.readUnsignedByte();
int originalBitsPerBlock = bitsPerBlock;
if (bitsPerBlock == 0 || bitsPerBlock > 8) {
if (bitsPerBlock > 8) {
bitsPerBlock = GLOBAL_PALETTE;
} else if (bitsPerBlock < 4) {
bitsPerBlock = 4;
}
// Read palette
@@ -58,19 +60,14 @@ public class ChunkSectionType1_16 extends Type<ChunkSection> {
}
// Read blocks
long[] blockData = new long[Type.VAR_INT.readPrimitive(buffer)];
long[] blockData = Type.LONG_ARRAY_PRIMITIVE.read(buffer);
if (blockData.length > 0) {
char valuesPerLong = (char) (64 / bitsPerBlock);
int expectedLength = (ChunkSection.SIZE + valuesPerLong - 1) / valuesPerLong;
if (blockData.length != expectedLength) {
throw new IllegalStateException("Block data length (" + blockData.length + ") does not match expected length (" + expectedLength + ")! bitsPerBlock=" + bitsPerBlock + ", originalBitsPerBlock=" + originalBitsPerBlock);
if (blockData.length == expectedLength) {
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerBlock, ChunkSection.SIZE, blockData,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::setFlatBlock : chunkSection::setPaletteIndex);
}
for (int i = 0; i < blockData.length; i++) {
blockData[i] = buffer.readLong();
}
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerBlock, ChunkSection.SIZE, blockData,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::setFlatBlock : chunkSection::setPaletteIndex);
}
return chunkSection;
@@ -89,7 +86,7 @@ public class ChunkSectionType1_16 extends Type<ChunkSection> {
buffer.writeByte(bitsPerBlock);
// Write pallet (or not)
// Write palette
if (bitsPerBlock != GLOBAL_PALETTE) {
Type.VAR_INT.writePrimitive(buffer, chunkSection.getPaletteSize());
for (int i = 0; i < chunkSection.getPaletteSize(); i++) {
@@ -99,9 +96,6 @@ public class ChunkSectionType1_16 extends Type<ChunkSection> {
long[] data = CompactArrayUtil.createCompactArrayWithPadding(bitsPerBlock, ChunkSection.SIZE,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::getFlatBlock : chunkSection::getPaletteIndex);
Type.VAR_INT.writePrimitive(buffer, data.length);
for (long l : data) {
buffer.writeLong(l);
}
Type.LONG_ARRAY_PRIMITIVE.write(buffer, data);
}
}
@@ -40,10 +40,6 @@ public class ChunkSectionType1_9 extends Type<ChunkSection> {
// Reaad bits per block
int bitsPerBlock = buffer.readUnsignedByte();
int originalBitsPerBlock = bitsPerBlock;
if (bitsPerBlock == 0) {
bitsPerBlock = GLOBAL_PALETTE;
}
if (bitsPerBlock < 4) {
bitsPerBlock = 4;
}
@@ -63,19 +59,14 @@ public class ChunkSectionType1_9 extends Type<ChunkSection> {
}
// Read blocks
long[] blockData = new long[Type.VAR_INT.readPrimitive(buffer)];
long[] blockData = Type.LONG_ARRAY_PRIMITIVE.read(buffer);
if (blockData.length > 0) {
int expectedLength = (int) Math.ceil(ChunkSection.SIZE * bitsPerBlock / 64.0);
if (blockData.length != expectedLength) {
throw new IllegalStateException("Block data length (" + blockData.length + ") does not match expected length (" + expectedLength + ")! bitsPerBlock=" + bitsPerBlock + ", originalBitsPerBlock=" + originalBitsPerBlock);
if (blockData.length == expectedLength) {
CompactArrayUtil.iterateCompactArray(bitsPerBlock, ChunkSection.SIZE, blockData,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::setFlatBlock
: chunkSection::setPaletteIndex);
}
for (int i = 0; i < blockData.length; i++) {
blockData[i] = buffer.readLong();
}
CompactArrayUtil.iterateCompactArray(bitsPerBlock, ChunkSection.SIZE, blockData,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::setFlatBlock
: chunkSection::setPaletteIndex);
}
return chunkSection;
@@ -92,10 +83,9 @@ public class ChunkSectionType1_9 extends Type<ChunkSection> {
bitsPerBlock = GLOBAL_PALETTE;
}
long maxEntryValue = (1L << bitsPerBlock) - 1;
buffer.writeByte(bitsPerBlock);
// Write pallet (or not)
// Write palette
if (bitsPerBlock != GLOBAL_PALETTE) {
Type.VAR_INT.writePrimitive(buffer, chunkSection.getPaletteSize());
for (int i = 0; i < chunkSection.getPaletteSize(); i++) {
@@ -107,9 +97,6 @@ public class ChunkSectionType1_9 extends Type<ChunkSection> {
long[] data = CompactArrayUtil.createCompactArray(bitsPerBlock, ChunkSection.SIZE,
bitsPerBlock == GLOBAL_PALETTE ? chunkSection::getFlatBlock : chunkSection::getPaletteIndex);
Type.VAR_INT.writePrimitive(buffer, data.length);
for (long l : data) {
buffer.writeLong(l);
}
Type.LONG_ARRAY_PRIMITIVE.write(buffer, data);
}
}
@@ -42,23 +42,25 @@ public final class PaletteType1_18 extends Type<DataPalette> {
@Override
public DataPalette read(final ByteBuf buffer) throws Exception {
int bitsPerValue = buffer.readByte();
final int originalBitsPerValue = bitsPerValue;
final int originalBitsPerValue = buffer.readByte();
int bitsPerValue = originalBitsPerValue;
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = globalPaletteBits;
}
// Read palette
final DataPaletteImpl palette;
if (bitsPerValue == 0) {
//TODO Create proper singleton palette Object
// Single value storage
palette = new DataPaletteImpl(type.size(), 1);
palette.addId(Type.VAR_INT.readPrimitive(buffer));
Type.VAR_INT.readPrimitive(buffer); // 0 values length
Type.LONG_ARRAY_PRIMITIVE.read(buffer); // Just eat it if not empty - thanks, Hypixel
return palette;
}
if (bitsPerValue < 0 || bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = globalPaletteBits;
} else if (type == PaletteType.BLOCKS && bitsPerValue < 4) {
bitsPerValue = 4; // Linear block palette values are always 4 bits
}
// Read palette
if (bitsPerValue != globalPaletteBits) {
final int paletteLength = Type.VAR_INT.readPrimitive(buffer);
palette = new DataPaletteImpl(type.size(), paletteLength);
@@ -70,38 +72,32 @@ public final class PaletteType1_18 extends Type<DataPalette> {
}
// Read values
final long[] values = new long[Type.VAR_INT.readPrimitive(buffer)];
final long[] values = Type.LONG_ARRAY_PRIMITIVE.read(buffer);
if (values.length > 0) {
final char valuesPerLong = (char) (64 / bitsPerValue);
final int valuesPerLong = (char) (64 / bitsPerValue);
final int expectedLength = (type.size() + valuesPerLong - 1) / valuesPerLong;
if (values.length != expectedLength) {
throw new IllegalStateException("Palette data length (" + values.length + ") does not match expected length (" + expectedLength + ")! bitsPerValue=" + bitsPerValue + ", originalBitsPerValue=" + originalBitsPerValue);
if (values.length == expectedLength) { // Thanks, Hypixel
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, type.size(), values,
bitsPerValue == globalPaletteBits ? palette::setIdAt : palette::setPaletteIndexAt);
}
for (int i = 0; i < values.length; i++) {
values[i] = buffer.readLong();
}
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, type.size(), values,
bitsPerValue == globalPaletteBits ? palette::setIdAt : palette::setPaletteIndexAt);
}
return palette;
}
@Override
public void write(final ByteBuf buffer, final DataPalette palette) throws Exception {
if (palette.size() == 1) {
final int size = palette.size();
if (size == 1) {
// Single value palette
buffer.writeByte(0); // 0 bit storage
Type.VAR_INT.writePrimitive(buffer, palette.idByIndex(0));
Type.VAR_INT.writePrimitive(buffer, 0); // Empty values length
return;
}/* else if (palette.size() == 0) {
Via.getPlatform().getLogger().warning("Palette size is 0!");
}*/
}
// 1, 2, and 3 bit linear block palettes can't be read by the client
final int min = type == PaletteType.BLOCKS ? 4 : 1;
int bitsPerValue = Math.max(min, MathUtil.ceilLog2(palette.size()));
int bitsPerValue = Math.max(min, MathUtil.ceilLog2(size));
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = globalPaletteBits;
}
@@ -109,17 +105,13 @@ public final class PaletteType1_18 extends Type<DataPalette> {
buffer.writeByte(bitsPerValue);
if (bitsPerValue != globalPaletteBits) {
// Write pallete
Type.VAR_INT.writePrimitive(buffer, palette.size());
for (int i = 0; i < palette.size(); i++) {
// Write palette
Type.VAR_INT.writePrimitive(buffer, size);
for (int i = 0; i < size; i++) {
Type.VAR_INT.writePrimitive(buffer, palette.idByIndex(i));
}
}
final long[] data = CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, type.size(), bitsPerValue == globalPaletteBits ? palette::idAt : palette::paletteIndexAt);
Type.VAR_INT.writePrimitive(buffer, data.length);
for (final long l : data) {
buffer.writeLong(l);
}
Type.LONG_ARRAY_PRIMITIVE.write(buffer, CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, type.size(), bitsPerValue == globalPaletteBits ? palette::idAt : palette::paletteIndexAt));
}
}
@@ -37,7 +37,8 @@ import com.viaversion.viaversion.bukkit.platform.BukkitViaLoader;
import com.viaversion.viaversion.bukkit.platform.BukkitViaTask;
import com.viaversion.viaversion.bukkit.util.NMSUtil;
import com.viaversion.viaversion.dump.PluginInfo;
import com.viaversion.viaversion.unsupported.UnsupportedSoftwareImpl;
import com.viaversion.viaversion.unsupported.UnsupportedPlugin;
import com.viaversion.viaversion.unsupported.UnsupportedServerSoftware;
import com.viaversion.viaversion.util.GsonUtil;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@@ -286,14 +287,22 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
@Override
public final Collection<UnsupportedSoftware> getUnsupportedSoftwareClasses() {
List<UnsupportedSoftware> list = new ArrayList<>(ViaPlatform.super.getUnsupportedSoftwareClasses());
list.add(new UnsupportedSoftwareImpl.Builder().name("Yatopia").reason(UnsupportedSoftwareImpl.Reason.DANGEROUS_SERVER_SOFTWARE)
list.add(new UnsupportedServerSoftware.Builder().name("Yatopia").reason(UnsupportedServerSoftware.Reason.DANGEROUS_SERVER_SOFTWARE)
.addClassName("org.yatopiamc.yatopia.server.YatopiaConfig")
.addClassName("net.yatopia.api.event.PlayerAttackEntityEvent")
.addClassName("yatopiamc.org.yatopia.server.YatopiaConfig") // Only the best kind of software relocates its own classes to hide itself :tinfoilhat:
.addMethod("org.bukkit.Server", "getLastTickTime").build());
list.add(new UnsupportedPlugin.Builder().name("software to mess with message signing").reason(UnsupportedPlugin.Reason.SECURE_CHAT_BYPASS)
.addPlugin("NoEncryption").addPlugin("NoReport")
.addPlugin("NoChatReports").addPlugin("NoChatReport").build());
return Collections.unmodifiableList(list);
}
@Override
public boolean hasPlugin(final String name) {
return getServer().getPluginManager().getPlugin(name) != null;
}
public boolean isLateBind() {
return lateBind;
}
@@ -32,12 +32,14 @@ import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.BlockListener
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.DeathListener;
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.HandItemCache;
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.PaperPatch;
import com.viaversion.viaversion.bukkit.providers.BukkitAckSequenceProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitBlockConnectionProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitInventoryQuickMoveProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitViaMovementTransmitter;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.providers.InventoryQuickMoveProvider;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.ConnectionData;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.provider.AckSequenceProvider;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
import org.bukkit.Bukkit;
@@ -47,7 +49,6 @@ import org.bukkit.event.Listener;
import org.bukkit.scheduler.BukkitTask;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -174,6 +175,9 @@ public class BukkitViaLoader implements ViaPlatformLoader {
ConnectionData.blockConnectionProvider = blockConnectionProvider;
}
}
if (serverProtocolVersion < ProtocolVersion.v1_19.getVersion()) {
Via.getManager().getProviders().use(AckSequenceProvider.class, new BukkitAckSequenceProvider(plugin));
}
}
@Override
@@ -0,0 +1,42 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.providers;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.bukkit.tasks.protocol1_19to1_18_2.AckSequenceTask;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.provider.AckSequenceProvider;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.storage.SequenceStorage;
public final class BukkitAckSequenceProvider extends AckSequenceProvider {
private final ViaVersionPlugin plugin;
public BukkitAckSequenceProvider(final ViaVersionPlugin plugin) {
this.plugin = plugin;
}
@Override
public void handleSequence(final UserConnection connection, final int sequence) {
final SequenceStorage sequenceStorage = connection.get(SequenceStorage.class);
final int previousSequence = sequenceStorage.setSequenceId(sequence);
if (previousSequence == -1) {
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new AckSequenceTask(connection, sequenceStorage), 1);
}
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.tasks.protocol1_19to1_18_2;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.storage.SequenceStorage;
public final class AckSequenceTask implements Runnable {
private final UserConnection connection;
private final SequenceStorage sequenceStorage;
public AckSequenceTask(final UserConnection connection, final SequenceStorage sequenceStorage) {
this.connection = connection;
this.sequenceStorage = sequenceStorage;
}
@Override
public void run() {
final int sequence = sequenceStorage.setSequenceId(-1);
try {
final PacketWrapper ackPacket = PacketWrapper.create(ClientboundPackets1_19.BLOCK_CHANGED_ACK, connection);
ackPacket.write(Type.VAR_INT, sequence);
ackPacket.scheduleSend(Protocol1_19To1_18_2.class);
} catch (final Exception e) {
e.printStackTrace();
}
}
}
+1
View File
@@ -8,5 +8,6 @@ loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, SkinRestorer]
softdepend: [ProtocolSupport, PacketListenerApi]
commands:
viaversion:
permission: viaversion.admin # The permission is also referenced here to filter root suggestions (/via<tab>)
description: Shows ViaVersion Version and more.
aliases: [viaver, vvbukkit]
@@ -56,7 +56,7 @@ public class BungeePlugin extends Plugin implements ViaPlatform<ProxiedPlayer>,
@Override
public void onLoad() {
try {
ProtocolConstants.class.getField("MINECRAFT_1_18");
ProtocolConstants.class.getField("MINECRAFT_1_19");
} catch (NoSuchFieldException e) {
getLogger().warning(" / \\");
getLogger().warning(" / \\");
@@ -205,4 +205,9 @@ public class BungeePlugin extends Plugin implements ViaPlatform<ProxiedPlayer>,
public boolean isOldClientsAllowed() {
return true;
}
@Override
public boolean hasPlugin(final String name) {
return getProxy().getPluginManager().getPlugin(name) != null;
}
}
@@ -25,7 +25,7 @@ public class BungeeCommand extends Command implements TabExecutor {
private final BungeeCommandHandler handler;
public BungeeCommand(BungeeCommandHandler handler) {
super("viaversion", "", "viaver", "vvbungee"); // The CommandHandler will handle the permission
super("viaversion", "viaversion.admin", "viaver", "vvbungee"); // The permission is also referenced here to filter root suggestions (/via<tab>)
this.handler = handler;
}
@@ -235,7 +235,7 @@ public class ViaManagerImpl implements ViaManager {
}
}
private final void unsupportedSoftwareWarning() {
private void unsupportedSoftwareWarning() {
boolean found = false;
for (UnsupportedSoftware software : platform.getUnsupportedSoftwareClasses()) {
if (!software.findMatch()) {
@@ -31,6 +31,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.IntPredicate;
@@ -89,6 +90,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private JsonElement resourcePack1_17PromptMessage;
private WorldIdentifiers map1_16WorldNames;
private boolean cache1_17Light;
private Map<String, String> chatTypeFormats;
protected AbstractViaConfig(File configFile) {
super(configFile);
@@ -157,13 +159,16 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
worlds.getOrDefault("nether", WorldIdentifiers.NETHER_DEFAULT),
worlds.getOrDefault("end", WorldIdentifiers.END_DEFAULT));
cache1_17Light = getBoolean("cache-1_17-light", true);
chatTypeFormats = get("chat-types-1_19", Map.class, new HashMap<String, String>());
}
private BlockedProtocolVersions loadBlockedProtocolVersions() {
IntSet blockedProtocols = new IntOpenHashSet(getIntegerList("block-protocols"));
List<Integer> blockProtocols = getListSafe("block-protocols", Integer.class, "Invalid blocked version protocol found in config: '%s'");
List<String> blockVersions = getListSafe("block-versions", String.class, "Invalid blocked version found in config: '%s'");
IntSet blockedProtocols = new IntOpenHashSet(blockProtocols);
int lowerBound = -1;
int upperBound = -1;
for (String s : getStringList("block-versions")) {
for (String s : blockVersions) {
if (s.isEmpty()) {
continue;
}
@@ -523,4 +528,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
public boolean cache1_17Light() {
return cache1_17Light;
}
@Override
public @Nullable String chatTypeFormat(final String translationKey) {
return chatTypeFormats.get(translationKey);
}
}
@@ -66,6 +66,7 @@ import com.viaversion.viaversion.protocols.protocol1_17_1to1_17.Protocol1_17_1To
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viaversion.protocols.protocol1_18_2to1_18.Protocol1_18_2To1_18;
import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.Protocol1_18To1_17_1;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.Protocol1_19_1To1_19;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viaversion.protocols.protocol1_9_1_2to1_9_3_4.Protocol1_9_1_2To1_9_3_4;
import com.viaversion.viaversion.protocols.protocol1_9_1to1_9.Protocol1_9_1To1_9;
@@ -118,7 +119,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
private boolean mappingsLoaded;
private ServerProtocolVersion serverProtocolVersion = new ServerProtocolVersionSingleton(-1);
private boolean onlyCheckLoweringPathEntries = true;
private int maxPathDeltaIncrease; // Only allow lowering path entries by default
private int maxProtocolPathSize = 50;
public ProtocolManagerImpl() {
@@ -174,6 +175,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
registerProtocol(new Protocol1_18_2To1_18(), ProtocolVersion.v1_18_2, ProtocolVersion.v1_18);
registerProtocol(new Protocol1_19To1_18_2(), ProtocolVersion.v1_19, ProtocolVersion.v1_18_2);
registerProtocol(new Protocol1_19_1To1_19(), ProtocolVersion.v1_19_1, ProtocolVersion.v1_19);
}
@Override
@@ -315,7 +317,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
if (current.containsKey(translatedToVersion)) continue;
// Check if the new version is farther away than the current client version
if (onlyCheckLoweringPathEntries && Math.abs(serverVersion - translatedToVersion) > Math.abs(serverVersion - clientVersion)) {
if (maxPathDeltaIncrease != -1 && Math.abs(serverVersion - translatedToVersion) - Math.abs(serverVersion - clientVersion) > maxPathDeltaIncrease) {
continue;
}
@@ -383,13 +385,13 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public void setOnlyCheckLoweringPathEntries(boolean onlyCheckLoweringPathEntries) {
this.onlyCheckLoweringPathEntries = onlyCheckLoweringPathEntries;
public void setMaxPathDeltaIncrease(final int maxPathDeltaIncrease) {
this.maxPathDeltaIncrease = Math.max(-1, maxPathDeltaIncrease);
}
@Override
public boolean onlyCheckLoweringPathEntries() {
return onlyCheckLoweringPathEntries;
public int getMaxPathDeltaIncrease() {
return maxPathDeltaIncrease;
}
@Override
@@ -54,4 +54,12 @@ public class ProtocolPathEntryImpl implements ProtocolPathEntry {
result = 31 * result + protocol.hashCode();
return result;
}
@Override
public String toString() {
return "ProtocolPathEntryImpl{" +
"outputProtocolVersion=" + outputProtocolVersion +
", protocol=" + protocol +
'}';
}
}
@@ -18,6 +18,7 @@
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.data;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -63,7 +64,7 @@ public class ComponentRewriter1_13 extends ComponentRewriter {
}
CompoundTag itemTag = tag.get("tag");
ShortTag damageTag = tag.get("Damage");
NumberTag damageTag = tag.get("Damage");
// Call item converter
short damage = damageTag != null ? damageTag.asShort() : 0;
@@ -0,0 +1,142 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.protocols.protocol1_19_1to1_19;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
public enum ClientboundPackets1_19_1 implements ClientboundPacketType {
SPAWN_ENTITY, // 0x00
SPAWN_EXPERIENCE_ORB, // 0x01
SPAWN_PLAYER, // 0x02
ENTITY_ANIMATION, // 0x03
STATISTICS, // 0x04
BLOCK_CHANGED_ACK, // 0x05
BLOCK_BREAK_ANIMATION, // 0x06
BLOCK_ENTITY_DATA, // 0x07
BLOCK_ACTION, // 0x08
BLOCK_CHANGE, // 0x09
BOSSBAR, // 0x0A
SERVER_DIFFICULTY, // 0x0B
CHAT_PREVIEW, // 0x0C
CLEAR_TITLES, // 0x0D
TAB_COMPLETE, // 0x0E
DECLARE_COMMANDS, // 0x0F
CLOSE_WINDOW, // 0x10
WINDOW_ITEMS, // 0x11
WINDOW_PROPERTY, // 0x12
SET_SLOT, // 0x13
COOLDOWN, // 0x14
CUSTOM_CHAT_COMPLETIONS, // 0x15
PLUGIN_MESSAGE, // 0x16
NAMED_SOUND, // 0x17
DELETE_CHAT_MESSAGE, // 0x18
DISCONNECT, // 0x19
ENTITY_STATUS, // 0x1A
EXPLOSION, // 0x1B
UNLOAD_CHUNK, // 0x1C
GAME_EVENT, // 0x1D
OPEN_HORSE_WINDOW, // 0x1E
WORLD_BORDER_INIT, // 0x1F
KEEP_ALIVE, // 0x20
CHUNK_DATA, // 0x21
EFFECT, // 0x22
SPAWN_PARTICLE, // 0x23
UPDATE_LIGHT, // 0x24
JOIN_GAME, // 0x25
MAP_DATA, // 0x26
TRADE_LIST, // 0x27
ENTITY_POSITION, // 0x28
ENTITY_POSITION_AND_ROTATION, // 0x29
ENTITY_ROTATION, // 0x2A
VEHICLE_MOVE, // 0x2B
OPEN_BOOK, // 0x2C
OPEN_WINDOW, // 0x2D
OPEN_SIGN_EDITOR, // 0x2E
PING, // 0x2F
CRAFT_RECIPE_RESPONSE, // 0x30
PLAYER_ABILITIES, // 0x31
PLAYER_CHAT_HEADER, // 0x32
PLAYER_CHAT, // 0x33
COMBAT_END, // 0x34
COMBAT_ENTER, // 0x35
COMBAT_KILL, // 0x36
PLAYER_INFO, // 0x37
FACE_PLAYER, // 0x38
PLAYER_POSITION, // 0x39
UNLOCK_RECIPES, // 0x3A
REMOVE_ENTITIES, // 0x3B
REMOVE_ENTITY_EFFECT, // 0x3C
RESOURCE_PACK, // 0x3D
RESPAWN, // 0x3E
ENTITY_HEAD_LOOK, // 0x3F
MULTI_BLOCK_CHANGE, // 0x40
SELECT_ADVANCEMENTS_TAB, // 0x41
SERVER_DATA, // 0x42
ACTIONBAR, // 0x43
WORLD_BORDER_CENTER, // 0x44
WORLD_BORDER_LERP_SIZE, // 0x45
WORLD_BORDER_SIZE, // 0x46
WORLD_BORDER_WARNING_DELAY, // 0x47
WORLD_BORDER_WARNING_DISTANCE, // 0x48
CAMERA, // 0x49
HELD_ITEM_CHANGE, // 0x4A
UPDATE_VIEW_POSITION, // 0x4B
UPDATE_VIEW_DISTANCE, // 0x4C
SPAWN_POSITION, // 0x4D
SET_DISPLAY_CHAT_PREVIEW, // 0x4E
DISPLAY_SCOREBOARD, // 0x4F
ENTITY_METADATA, // 0x50
ATTACH_ENTITY, // 0x51
ENTITY_VELOCITY, // 0x52
ENTITY_EQUIPMENT, // 0x53
SET_EXPERIENCE, // 0x54
UPDATE_HEALTH, // 0x55
SCOREBOARD_OBJECTIVE, // 0x56
SET_PASSENGERS, // 0x57
TEAMS, // 0x58
UPDATE_SCORE, // 0x59
SET_SIMULATION_DISTANCE, // 0x5A
TITLE_SUBTITLE, // 0x5B
TIME_UPDATE, // 0x5C
TITLE_TEXT, // 0x5D
TITLE_TIMES, // 0x5E
ENTITY_SOUND, // 0x5F
SOUND, // 0x60
STOP_SOUND, // 0x61
SYSTEM_CHAT, // 0x62
TAB_LIST, // 0x63
NBT_QUERY, // 0x64
COLLECT_ITEM, // 0x65
ENTITY_TELEPORT, // 0x66
ADVANCEMENTS, // 0x67
ENTITY_PROPERTIES, // 0x68
ENTITY_EFFECT, // 0x69
DECLARE_RECIPES, // 0x6A
TAGS; // 0x6B
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -0,0 +1,339 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.protocols.protocol1_19_1to1_19;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ProfileKey;
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.kyori.adventure.text.Component;
import com.viaversion.viaversion.libs.kyori.adventure.text.TranslatableComponent;
import com.viaversion.viaversion.libs.kyori.adventure.text.format.NamedTextColor;
import com.viaversion.viaversion.libs.kyori.adventure.text.format.Style;
import com.viaversion.viaversion.libs.kyori.adventure.text.format.TextDecoration;
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.storage.ChatTypeStorage;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.storage.NonceStorage;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ServerboundPackets1_19;
import com.viaversion.viaversion.util.CipherUtil;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public final class Protocol1_19_1To1_19 extends AbstractProtocol<ClientboundPackets1_19, ClientboundPackets1_19_1, ServerboundPackets1_19, ServerboundPackets1_19_1> {
private static final String CHAT_REGISTRY_SNBT = "{\n" +
" \"minecraft:chat_type\": {\n" +
" \"type\": \"minecraft:chat_type\",\n" +
" \"value\": [\n" +
" {\n" +
" \"name\":\"minecraft:chat\",\n" +
" \"id\":1,\n" +
" \"element\":{\n" +
" \"chat\":{\n" +
" \"translation_key\":\"chat.type.text\",\n" +
" \"parameters\":[\n" +
" \"sender\",\n" +
" \"content\"\n" +
" ]\n" +
" },\n" +
" \"narration\":{\n" +
" \"translation_key\":\"chat.type.text.narrate\",\n" +
" \"parameters\":[\n" +
" \"sender\",\n" +
" \"content\"\n" +
" ]\n" +
" }\n" +
" }\n" +
" }" +
" ]\n" +
" }\n" +
"}";
private static final CompoundTag CHAT_REGISTRY;
static {
try {
CHAT_REGISTRY = BinaryTagIO.readString(CHAT_REGISTRY_SNBT).get("minecraft:chat_type");
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
public Protocol1_19_1To1_19() {
super(ClientboundPackets1_19.class, ClientboundPackets1_19_1.class, ServerboundPackets1_19.class, ServerboundPackets1_19_1.class);
}
@Override
protected void registerPackets() {
registerClientbound(ClientboundPackets1_19.SYSTEM_CHAT, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.COMPONENT); // Content
handler(wrapper -> {
final int type = wrapper.read(Type.VAR_INT);
final boolean overlay = type == 2;
wrapper.write(Type.BOOLEAN, overlay);
});
}
});
registerClientbound(ClientboundPackets1_19.PLAYER_CHAT, ClientboundPackets1_19_1.SYSTEM_CHAT, new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
// Back to system chat
final JsonElement signedContent = wrapper.read(Type.COMPONENT);
final JsonElement unsignedContent = wrapper.read(Type.OPTIONAL_COMPONENT);
final int chatType = wrapper.read(Type.VAR_INT);
wrapper.read(Type.UUID); // Sender UUID
final JsonElement senderName = wrapper.read(Type.COMPONENT);
final JsonElement teamName = wrapper.read(Type.OPTIONAL_COMPONENT);
if (!decorateChatMessage(wrapper, chatType, senderName, teamName, unsignedContent != null ? unsignedContent : signedContent)) {
wrapper.cancel();
}
});
read(Type.LONG); // Timestamp
read(Type.LONG); // Salt
read(Type.BYTE_ARRAY_PRIMITIVE); // Signature
}
});
registerServerbound(ServerboundPackets1_19_1.CHAT_MESSAGE, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // Message
map(Type.LONG); // Timestamp
map(Type.LONG); // Salt
map(Type.BYTE_ARRAY_PRIMITIVE); // Signature
map(Type.BOOLEAN); // Signed preview
read(Type.PLAYER_MESSAGE_SIGNATURE_ARRAY); // Last seen messages
read(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE); // Last received message
}
});
registerServerbound(ServerboundPackets1_19_1.CHAT_COMMAND, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // Command
map(Type.LONG); // Timestamp
map(Type.LONG); // Salt
handler(wrapper -> {
final int signatures = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < signatures; i++) {
wrapper.passthrough(Type.STRING); // Argument name
wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE); // Signature
}
});
map(Type.BOOLEAN); // Signed preview
read(Type.PLAYER_MESSAGE_SIGNATURE_ARRAY); // Last seen messages
read(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE); // Last received message
}
});
cancelServerbound(ServerboundPackets1_19_1.CHAT_ACK);
registerClientbound(ClientboundPackets1_19.JOIN_GAME, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // Entity ID
map(Type.BOOLEAN); // Hardcore
map(Type.UNSIGNED_BYTE); // Gamemode
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // World List
handler(wrapper -> {
final ChatTypeStorage chatTypeStorage = wrapper.user().get(ChatTypeStorage.class);
chatTypeStorage.clear();
final CompoundTag registry = wrapper.passthrough(Type.NBT);
final ListTag chatTypes = ((CompoundTag) registry.get("minecraft:chat_type")).get("value");
for (final Tag chatType : chatTypes) {
final CompoundTag chatTypeCompound = (CompoundTag) chatType;
final NumberTag idTag = chatTypeCompound.get("id");
chatTypeStorage.addChatType(idTag.asInt(), chatTypeCompound);
}
// Replace chat types - they won't actually be used
registry.put("minecraft:chat_type", CHAT_REGISTRY.clone());
});
}
});
registerClientbound(ClientboundPackets1_19.SERVER_DATA, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.OPTIONAL_COMPONENT); // Motd
map(Type.OPTIONAL_STRING); // Encoded icon
map(Type.BOOLEAN); // Previews chat
create(Type.BOOLEAN, false); // Enforces secure chat
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // Name
handler(wrapper -> {
// Profile keys are not compatible; replace it with an empty one
final ProfileKey profileKey = wrapper.read(Type.OPTIONAL_PROFILE_KEY);
wrapper.write(Type.OPTIONAL_PROFILE_KEY, null);
if (profileKey == null) {
// Modified client that doesn't include the profile key, or already done in 1.18->1.19 protocol; no need to map it
wrapper.user().put(new NonceStorage(null));
}
});
read(Type.OPTIONAL_UUID); // Profile uuid
}
});
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO.getId(), ClientboundLoginPackets.HELLO.getId(), new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // Server id
handler(wrapper -> {
if (wrapper.user().has(NonceStorage.class)) {
return;
}
final byte[] publicKey = wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE);
final byte[] nonce = wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE);
wrapper.user().put(new NonceStorage(CipherUtil.encryptNonce(publicKey, nonce)));
});
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY.getId(), ServerboundLoginPackets.ENCRYPTION_KEY.getId(), new PacketRemapper() {
@Override
public void registerMap() {
map(Type.BYTE_ARRAY_PRIMITIVE); // Keys
handler(wrapper -> {
final NonceStorage nonceStorage = wrapper.user().remove(NonceStorage.class);
if (nonceStorage.nonce() == null) {
return;
}
final boolean isNonce = wrapper.read(Type.BOOLEAN);
wrapper.write(Type.BOOLEAN, true);
if (!isNonce) { // Should never be true at this point, but /shrug otherwise
wrapper.read(Type.LONG); // Salt
wrapper.read(Type.BYTE_ARRAY_PRIMITIVE); // Signature
wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, nonceStorage.nonce());
}
});
}
});
}
@Override
public void init(final UserConnection connection) {
connection.put(new ChatTypeStorage());
}
private boolean decorateChatMessage(final PacketWrapper wrapper, final int chatTypeId, final JsonElement senderName, @Nullable final JsonElement teamName, final JsonElement message) {
final CompoundTag chatType = wrapper.user().get(ChatTypeStorage.class).chatType(chatTypeId);
if (chatType == null) {
Via.getPlatform().getLogger().warning("Chat message has unknown chat type id " + chatTypeId + ". Message: " + message);
return false;
}
CompoundTag chatData = chatType.<CompoundTag>get("element").get("chat");
boolean overlay = false;
if (chatData == null) {
chatData = chatType.<CompoundTag>get("element").get("overlay");
if (chatData == null) {
// Either narration or something we don't know
return false;
}
overlay = true;
}
final CompoundTag decoaration = chatData.get("decoration");
if (decoaration == null) {
wrapper.write(Type.COMPONENT, message);
wrapper.write(Type.BOOLEAN, overlay);
return true;
}
final String translationKey = (String) decoaration.get("translation_key").getValue();
final TranslatableComponent.Builder componentBuilder = Component.translatable().key(translationKey);
// Add the style
final CompoundTag style = decoaration.get("style");
if (style != null) {
final Style.Builder styleBuilder = Style.style();
final StringTag color = style.get("color");
if (color != null) {
final NamedTextColor textColor = NamedTextColor.NAMES.value(color.getValue());
if (textColor != null) {
styleBuilder.color(NamedTextColor.NAMES.value(color.getValue()));
}
}
for (final String key : TextDecoration.NAMES.keys()) {
if (style.contains(key)) {
styleBuilder.decoration(TextDecoration.NAMES.value(key), style.<ByteTag>get(key).asByte() == 1);
}
}
componentBuilder.style(styleBuilder.build());
}
// Add the replacements
final ListTag parameters = decoaration.get("parameters");
if (parameters != null) {
final List<Component> arguments = new ArrayList<>();
for (final Tag element : parameters) {
JsonElement argument = null;
switch ((String) element.getValue()) {
case "sender":
argument = senderName;
break;
case "content":
argument = message;
break;
case "team_name":
Preconditions.checkNotNull(teamName, "Team name is null");
argument = teamName;
break;
default:
Via.getPlatform().getLogger().warning("Unknown parameter for chat decoration: " + element.getValue());
}
if (argument != null) {
arguments.add(GsonComponentSerializer.gson().deserializeFromTree(argument));
}
}
componentBuilder.args(arguments);
}
wrapper.write(Type.COMPONENT, GsonComponentSerializer.gson().serializeToTree(componentBuilder.build()));
wrapper.write(Type.BOOLEAN, overlay);
return true;
}
}
@@ -0,0 +1,85 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.protocols.protocol1_19_1to1_19;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
public enum ServerboundPackets1_19_1 implements ServerboundPacketType {
TELEPORT_CONFIRM, // 0x00
QUERY_BLOCK_NBT, // 0x01
SET_DIFFICULTY, // 0x02
CHAT_ACK, // 0x03
CHAT_COMMAND, // 0x04
CHAT_MESSAGE, // 0x05
CHAT_PREVIEW, // 0x06
CLIENT_STATUS, // 0x07
CLIENT_SETTINGS, // 0x08
TAB_COMPLETE, // 0x09
CLICK_WINDOW_BUTTON, // 0x0A
CLICK_WINDOW, // 0x0B
CLOSE_WINDOW, // 0x0C
PLUGIN_MESSAGE, // 0x0D
EDIT_BOOK, // 0x0E
ENTITY_NBT_REQUEST, // 0x0F
INTERACT_ENTITY, // 0x10
GENERATE_JIGSAW, // 0x11
KEEP_ALIVE, // 0x12
LOCK_DIFFICULTY, // 0x13
PLAYER_POSITION, // 0x14
PLAYER_POSITION_AND_ROTATION, // 0x15
PLAYER_ROTATION, // 0x16
PLAYER_MOVEMENT, // 0x17
VEHICLE_MOVE, // 0x18
STEER_BOAT, // 0x19
PICK_ITEM, // 0x1A
CRAFT_RECIPE_REQUEST, // 0x1B
PLAYER_ABILITIES, // 0x1C
PLAYER_DIGGING, // 0x1D
ENTITY_ACTION, // 0x1E
STEER_VEHICLE, // 0x1F
PONG, // 0x20
RECIPE_BOOK_DATA, // 0x21
SEEN_RECIPE, // 0x22
RENAME_ITEM, // 0x23
RESOURCE_PACK_STATUS, // 0x24
ADVANCEMENT_TAB, // 0x25
SELECT_TRADE, // 0x26
SET_BEACON_EFFECT, // 0x27
HELD_ITEM_CHANGE, // 0x28
UPDATE_COMMAND_BLOCK, // 0x29
UPDATE_COMMAND_BLOCK_MINECART, // 0x2A
CREATIVE_INVENTORY_ACTION, // 0x2B
UPDATE_JIGSAW_BLOCK, // 0x2C
UPDATE_STRUCTURE_BLOCK, // 0x2D
UPDATE_SIGN, // 0x2E
ANIMATION, // 0x2F
SPECTATE, // 0x30
PLAYER_BLOCK_PLACEMENT, // 0x31
USE_ITEM; // 0x32
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -0,0 +1,47 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.protocols.protocol1_19_1to1_19.storage;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class ChatTypeStorage implements StorableObject {
private final Int2ObjectMap<CompoundTag> chatTypes = new Int2ObjectOpenHashMap<>();
public @Nullable CompoundTag chatType(final int id) {
return chatTypes.isEmpty() ? Protocol1_19To1_18_2.MAPPINGS.chatType(id) : chatTypes.get(id);
}
public void addChatType(final int id, final CompoundTag chatType) {
chatTypes.put(id, chatType);
}
public void clear() {
chatTypes.clear();
}
@Override
public boolean clearOnServerSwitch() {
return false;
}
}
@@ -0,0 +1,34 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.protocols.protocol1_19_1to1_19.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class NonceStorage implements StorableObject {
private final byte[] nonce;
public NonceStorage(final byte @Nullable[] nonce) {
this.nonce = nonce;
}
public byte @Nullable [] nonce() {
return nonce;
}
}
@@ -17,13 +17,14 @@
*/
package com.viaversion.viaversion.protocols.protocol1_19to1_18_2;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.minecraft.entities.Entity1_19Types;
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.rewriter.EntityRewriter;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
@@ -31,39 +32,31 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.minecraft.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_19;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.kyori.adventure.text.Component;
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.ClientboundPackets1_18;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.data.MappingData;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.packets.EntityPackets;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.packets.InventoryPackets;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.packets.WorldPackets;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.provider.AckSequenceProvider;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.storage.DimensionRegistryStorage;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.storage.NonceStorage;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.storage.SequenceStorage;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.CipherUtil;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.concurrent.ThreadLocalRandom;
public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPackets1_18, ClientboundPackets1_19, ServerboundPackets1_17, ServerboundPackets1_19> {
public static final MappingData MAPPINGS = new MappingDataBase("1.18", "1.19", true);
private static final KeyFactory RSA_FACTORY;
static {
try {
RSA_FACTORY = KeyFactory.getInstance("RSA");
} catch (final NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static final MappingData MAPPINGS = new MappingData();
private final EntityPackets entityRewriter = new EntityPackets(this);
private final InventoryPackets itemRewriter = new InventoryPackets(this);
@@ -93,7 +86,7 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
map(Type.INT); // Z
map(Type.FLOAT); // Volume
map(Type.FLOAT); // Pitch
create(Type.LONG, 0L); // Seed
create(Type.LONG, randomLong()); // Seed
handler(soundRewriter.getSoundHandler());
}
});
@@ -105,7 +98,7 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
map(Type.VAR_INT); // Entity id
map(Type.FLOAT); // Volume
map(Type.FLOAT); // Pitch
create(Type.LONG, 0L); // Seed
create(Type.LONG, randomLong()); // Seed
handler(soundRewriter.getSoundHandler());
}
});
@@ -119,7 +112,30 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
map(Type.INT); // Z
map(Type.FLOAT); // Volume
map(Type.FLOAT); // Pitch
create(Type.LONG, 0L); // Seed
create(Type.LONG, randomLong()); // Seed
}
});
new StatisticsRewriter(this).register(ClientboundPackets1_18.STATISTICS);
final PacketHandler titleHandler = wrapper -> {
final JsonElement component = wrapper.read(Type.COMPONENT);
if (!component.isJsonNull()) {
wrapper.write(Type.COMPONENT, component);
} else {
wrapper.write(Type.COMPONENT, GsonComponentSerializer.gson().serializeToTree(Component.empty()));
}
};
registerClientbound(ClientboundPackets1_18.TITLE_TEXT, new PacketRemapper() {
@Override
public void registerMap() {
handler(titleHandler);
}
});
registerClientbound(ClientboundPackets1_18.TITLE_SUBTITLE, new PacketRemapper() {
@Override
public void registerMap() {
handler(titleHandler);
}
});
@@ -168,8 +184,8 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
public void registerMap() {
map(Type.COMPONENT); // Message
handler(wrapper -> {
int type = wrapper.read(Type.BYTE);
wrapper.write(Type.VAR_INT, type == 2 ? 1 : 0);
final int type = wrapper.read(Type.BYTE);
wrapper.write(Type.VAR_INT, type == 0 ? 1 : type);
});
read(Type.UUID); // Sender
}
@@ -221,13 +237,9 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
public void registerMap() {
map(Type.STRING); // Server id
handler(wrapper -> {
final byte[] pubKey = wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE);
final byte[] publicKey = wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE);
final byte[] nonce = wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE);
final EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKey);
final PublicKey key = RSA_FACTORY.generatePublic(keySpec);
final Cipher cipher = Cipher.getInstance(key.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, key);
wrapper.user().put(new NonceStorage(cipher.doFinal(nonce)));
wrapper.user().put(new NonceStorage(CipherUtil.encryptNonce(publicKey, nonce)));
});
}
});
@@ -236,13 +248,7 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
@Override
public void registerMap() {
map(Type.STRING); // Name
handler(wrapper -> {
if (wrapper.read(Type.BOOLEAN)) {
wrapper.read(Type.LONG); // Timestamp
wrapper.read(Type.BYTE_ARRAY_PRIMITIVE); // Key
wrapper.read(Type.BYTE_ARRAY_PRIMITIVE); // Signature
}
});
read(Type.OPTIONAL_PROFILE_KEY); // Public profile key
}
});
@@ -270,6 +276,10 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
});
}
private static long randomLong() {
return ThreadLocalRandom.current().nextLong();
}
@Override
protected void onMappingDataLoaded() {
Types1_19.PARTICLE.filler(this)
@@ -286,11 +296,17 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
entityRewriter.onMappingDataLoaded();
}
@Override
public void register(final ViaProviders providers) {
providers.register(AckSequenceProvider.class, new AckSequenceProvider());
}
@Override
public void init(final UserConnection user) {
if (!user.has(DimensionRegistryStorage.class)) {
user.put(new DimensionRegistryStorage());
}
user.put(new SequenceStorage());
addEntityTracker(user, new EntityTrackerBase(user, Entity1_19Types.PLAYER));
}
@@ -0,0 +1,59 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.protocols.protocol1_19to1_18_2.data;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.google.gson.JsonObject;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.IOException;
public final class MappingData extends MappingDataBase {
private final Int2ObjectMap<CompoundTag> defaultChatTypes = new Int2ObjectOpenHashMap<>();
public MappingData() {
super("1.18", "1.19", true);
}
@Override
protected void loadExtras(final JsonObject oldMappings, final JsonObject newMappings, @Nullable final JsonObject diffMappings) {
try {
final ListTag chatTypes = BinaryTagIO.readCompressedInputStream(MappingDataLoader.getResource("chat-types-1.19.nbt")).get("values");
for (final Tag chatType : chatTypes) {
final CompoundTag chatTypeCompound = (CompoundTag) chatType;
final NumberTag idTag = chatTypeCompound.get("id");
defaultChatTypes.put(idTag.asInt(), chatTypeCompound);
}
} catch (final IOException e) {
e.printStackTrace();
}
}
public @Nullable CompoundTag chatType(final int id) {
return defaultChatTypes.get(id);
}
}
@@ -21,6 +21,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.google.common.collect.Maps;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.entity.DimensionData;
import com.viaversion.viaversion.api.minecraft.Position;
@@ -39,23 +40,24 @@ import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPacke
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.storage.DimensionRegistryStorage;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.util.Pair;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
//TODO move to compressed nbt file
private static final String CHAT_REGISTRY_SNBT = "{\n" +
" \"minecraft:chat_type\": {\n" +
" \"type\": \"minecraft:chat_type\",\n" +
" \"value\": [\n" +
" {\n" +
" \"name\": \"minecraft:system\",\n" +
" \"id\": 0,\n" +
" \"id\": 1,\n" +
" \"element\": {\n" +
" \"chat\": {},\n" +
" \"narration\": {\n" +
@@ -65,7 +67,7 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
" },\n" +
" {\n" +
" \"name\": \"minecraft:game_info\",\n" +
" \"id\": 1,\n" +
" \"id\": 2,\n" +
" \"element\": {\n" +
" \"overlay\": {}\n" +
" }\n" +
@@ -216,10 +218,9 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
final CompoundTag dimensionCompound = (CompoundTag) dimension;
final CompoundTag element = dimensionCompound.get("element");
final String name = (String) dimensionCompound.get("name").getValue();
addMonsterSpawnData(element);
dimensionDataMap.put(name, new DimensionDataImpl(element));
dimensionsMap.put(element.clone(), name);
addMonsterSpawnData(element);
}
tracker(wrapper.user()).setDimensions(dimensionDataMap);
@@ -291,7 +292,7 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
}
// No public profile signature
wrapper.write(Type.BOOLEAN, false);
wrapper.write(Type.OPTIONAL_PROFILE_KEY, null);
} else if (action == 1 || action == 2) { // Update gamemode/update latency
wrapper.passthrough(Type.VAR_INT);
} else if (action == 3) { // Update display name
@@ -308,15 +309,22 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
private static void writeDimensionKey(final PacketWrapper wrapper, final DimensionRegistryStorage registryStorage) throws Exception {
// Find dimension key by data
final CompoundTag currentDimension = wrapper.read(Type.NBT);
final String dimensionKey = registryStorage.dimensionKey(currentDimension);
addMonsterSpawnData(currentDimension);
String dimensionKey = registryStorage.dimensionKey(currentDimension);
if (dimensionKey == null) {
Via.getPlatform().getLogger().severe("The server tried to send dimension data from a dimension the client wasn't told about on join. " +
"Plugins and mods have to make sure they are not creating new dimension types while players are online, and proxies need to make sure they don't scramble dimension data." +
" Known dimensions:");
for (final Map.Entry<CompoundTag, String> entry : registryStorage.dimensions().entrySet()) {
Via.getPlatform().getLogger().severe(entry.getValue() + ": " + entry.getKey());
if (!Via.getConfig().isSuppressConversionWarnings()) {
Via.getPlatform().getLogger().warning("The server tried to send dimension data from a dimension the client wasn't told about on join. " +
"Plugins and mods have to make sure they are not creating new dimension types while players are online, and proxies need to make sure they don't scramble dimension data." +
" Received dimension: " + currentDimension + ". Known dimensions: " + registryStorage.dimensions());
}
throw new IllegalArgumentException("Dimension not found in registry data from join packet: " + currentDimension);
// Try to find the most similar dimension
dimensionKey = registryStorage.dimensions().entrySet().stream()
.map(it -> new Pair<>(it, Maps.difference(currentDimension.getValue(), it.getKey().getValue()).entriesInCommon()))
.filter(it -> it.value().containsKey("min_y") && it.value().containsKey("height"))
.max(Comparator.comparingInt(it -> it.value().size()))
.orElseThrow(() -> new IllegalArgumentException("Dimension not found in registry data from join packet: " + currentDimension))
.key().getValue();
}
wrapper.write(Type.STRING, dimensionKey);
@@ -17,15 +17,15 @@
*/
package com.viaversion.viaversion.protocols.protocol1_19to1_18_2.packets;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.data.RecipeRewriter1_16;
import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.ClientboundPackets1_18;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ServerboundPackets1_19;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.provider.AckSequenceProvider;
import com.viaversion.viaversion.rewriter.ItemRewriter;
public final class InventoryPackets extends ItemRewriter<Protocol1_19To1_18_2> {
@@ -38,7 +38,6 @@ public final class InventoryPackets extends ItemRewriter<Protocol1_19To1_18_2> {
public void registerPackets() {
registerSetCooldown(ClientboundPackets1_18.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_18.WINDOW_ITEMS, Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT, Type.FLAT_VAR_INT_ITEM);
registerTradeList(ClientboundPackets1_18.TRADE_LIST, Type.FLAT_VAR_INT_ITEM);
registerSetSlot1_17_1(ClientboundPackets1_18.SET_SLOT, Type.FLAT_VAR_INT_ITEM);
registerAdvancements(ClientboundPackets1_18.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_18.ENTITY_EQUIPMENT, Type.FLAT_VAR_INT_ITEM);
@@ -64,6 +63,35 @@ public final class InventoryPackets extends ItemRewriter<Protocol1_19To1_18_2> {
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_18.WINDOW_PROPERTY);
protocol.registerClientbound(ClientboundPackets1_18.TRADE_LIST, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // Container id
handler(wrapper -> {
final int size = wrapper.read(Type.UNSIGNED_BYTE);
wrapper.write(Type.VAR_INT, size);
for (int i = 0; i < size; i++) {
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // First item
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Result
if (wrapper.read(Type.BOOLEAN)) {
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM));
} else {
wrapper.write(Type.FLAT_VAR_INT_ITEM, null);
}
wrapper.passthrough(Type.BOOLEAN); // Out of stock
wrapper.passthrough(Type.INT); // Uses
wrapper.passthrough(Type.INT); // Max uses
wrapper.passthrough(Type.INT); // Xp
wrapper.passthrough(Type.INT); // Special price diff
wrapper.passthrough(Type.FLOAT); // Price multiplier
wrapper.passthrough(Type.INT); //Demand
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_19.PLAYER_DIGGING, new PacketRemapper() {
@Override
public void registerMap() {
@@ -99,14 +127,9 @@ public final class InventoryPackets extends ItemRewriter<Protocol1_19To1_18_2> {
private PacketHandler sequenceHandler() {
return wrapper -> {
// Manually send and follow up with an acknowledgement
final int sequence = wrapper.read(Type.VAR_INT);
wrapper.sendToServer(Protocol1_19To1_18_2.class);
wrapper.cancel();
final PacketWrapper ackPacket = wrapper.create(ClientboundPackets1_19.BLOCK_CHANGED_ACK);
ackPacket.write(Type.VAR_INT, sequence);
ackPacket.scheduleSend(Protocol1_19To1_18_2.class);
final AckSequenceProvider provider = Via.getManager().getProviders().get(AckSequenceProvider.class);
provider.handleSequence(wrapper.user(), sequence);
};
}
}
@@ -0,0 +1,34 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.protocols.protocol1_19to1_18_2.provider;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.platform.providers.Provider;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
public class AckSequenceProvider implements Provider {
public void handleSequence(final UserConnection connection, final int sequence) throws Exception {
final PacketWrapper ackPacket = PacketWrapper.create(ClientboundPackets1_19.BLOCK_CHANGED_ACK, connection);
ackPacket.write(Type.VAR_INT, sequence);
ackPacket.scheduleSend(Protocol1_19To1_18_2.class);
}
}
@@ -0,0 +1,40 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.protocols.protocol1_19to1_18_2.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public final class SequenceStorage implements StorableObject {
private final Object lock = new Object();
private int sequenceId = -1;
public int sequenceId() {
synchronized (lock) {
return sequenceId;
}
}
public int setSequenceId(final int sequenceId) {
synchronized (lock) {
final int previousSequence = this.sequenceId;
this.sequenceId = sequenceId;
return previousSequence;
}
}
}
@@ -240,6 +240,32 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
});
}
public void registerTradeList1_19(ClientboundPacketType packetType, Type<Item> type) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Container id
int size = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < size; i++) {
handleItemToClient(wrapper.passthrough(type)); // Input
handleItemToClient(wrapper.passthrough(type)); // Output
handleItemToClient(wrapper.passthrough(type)); // Second Item
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
wrapper.passthrough(Type.INT); // Number of tools uses
wrapper.passthrough(Type.INT); // Maximum number of trade uses
wrapper.passthrough(Type.INT); // XP
wrapper.passthrough(Type.INT); // Special price
wrapper.passthrough(Type.FLOAT); // Price multiplier
wrapper.passthrough(Type.INT); // Demand
}
});
}
});
}
public void registerAdvancements(ClientboundPacketType packetType, Type<Item> type) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
@@ -0,0 +1,93 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.unsupported;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.platform.UnsupportedSoftware;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class UnsupportedPlugin implements UnsupportedSoftware {
private final String name;
private final List<String> identifiers;
private final String reason;
public UnsupportedPlugin(final String name, final List<String> identifiers, final String reason) {
Preconditions.checkNotNull(name);
Preconditions.checkNotNull(reason);
Preconditions.checkArgument(!identifiers.isEmpty());
this.name = name;
this.identifiers = Collections.unmodifiableList(identifiers);
this.reason = reason;
}
@Override
public String getName() {
return name;
}
@Override
public String getReason() {
return reason;
}
@Override
public final boolean findMatch() {
for (final String identifier : identifiers) {
if (Via.getPlatform().hasPlugin(identifier)) {
return true;
}
}
return false;
}
public static final class Builder {
private final List<String> identifiers = new ArrayList<>();
private String name;
private String reason;
public Builder name(final String name) {
this.name = name;
return this;
}
public Builder reason(final String reason) {
this.reason = reason;
return this;
}
public Builder addPlugin(final String identifier) {
identifiers.add(identifier);
return this;
}
public UnsupportedPlugin build() {
return new UnsupportedPlugin(name, identifiers, reason);
}
}
public static final class Reason {
public static final String SECURE_CHAT_BYPASS = "Instead of doing the obvious (or nothing at all), these kinds of plugins completely break chat message handling, usually then also breaking other plugins.";
}
}
@@ -26,14 +26,17 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
public final class UnsupportedSoftwareImpl implements UnsupportedSoftware {
public final class UnsupportedServerSoftware implements UnsupportedSoftware {
private final String name;
private final List<String> classNames;
private final List<UnsupportedMethods> methods;
private final String reason;
public UnsupportedSoftwareImpl(String name, List<String> classNames, List<UnsupportedMethods> methods, String reason) {
public UnsupportedServerSoftware(String name, List<String> classNames, List<UnsupportedMethods> methods, String reason) {
Preconditions.checkNotNull(name);
Preconditions.checkNotNull(reason);
Preconditions.checkArgument(!classNames.isEmpty() || !methods.isEmpty());
this.name = name;
this.classNames = Collections.unmodifiableList(classNames);
this.methods = Collections.unmodifiableList(methods);
@@ -51,7 +54,7 @@ public final class UnsupportedSoftwareImpl implements UnsupportedSoftware {
}
@Override
public boolean findMatch() {
public final boolean findMatch() {
for (String className : classNames) {
try {
Class.forName(className);
@@ -100,9 +103,7 @@ public final class UnsupportedSoftwareImpl implements UnsupportedSoftware {
}
public UnsupportedSoftware build() {
Preconditions.checkNotNull(name);
Preconditions.checkNotNull(reason);
return new UnsupportedSoftwareImpl(name, classNames, methods, reason);
return new UnsupportedServerSoftware(name, classNames, methods, reason);
}
}
@@ -0,0 +1,46 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.util;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public final class CipherUtil {
private static final KeyFactory RSA_FACTORY;
static {
try {
RSA_FACTORY = KeyFactory.getInstance("RSA");
} catch (final NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static byte[] encryptNonce(final byte[] publicKeyBytes, final byte[] nonceBytes) throws Exception {
final EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
final PublicKey key = RSA_FACTORY.generatePublic(keySpec);
final Cipher cipher = Cipher.getInstance(key.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(nonceBytes);
}
}
@@ -18,6 +18,7 @@
package com.viaversion.viaversion.util;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.configuration.ConfigurationProvider;
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@@ -26,11 +27,7 @@ import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
@@ -214,6 +211,23 @@ public abstract class Config implements ConfigurationProvider {
return o != null ? (List<String>) o : new ArrayList<>();
}
public <T> List<T> getListSafe(String key, Class<T> type, String invalidValueMessage) {
Object o = this.config.get(key);
if (o instanceof List) {
List<?> list = (List<?>) o;
List<T> filteredValues = new ArrayList<>();
for (Object o1 : list) {
if (type.isInstance(o1)) {
filteredValues.add(type.cast(o1));
} else if (invalidValueMessage != null) {
Via.getPlatform().getLogger().warning(String.format(invalidValueMessage, o1));
}
}
return filteredValues;
}
return new ArrayList<>();
}
public @Nullable JsonElement getSerializedComponent(String key) {
final Object o = this.config.get(key);
if (o != null && !((String) o).isEmpty()) {
@@ -164,6 +164,14 @@ resource-pack-1_17-prompt: ''
# Only disable this if you know what you are doing.
cache-1_17-light: true
#
# 1.19 chat type formats used for 1.19.1+ clients.
chat-types-1_19:
"chat.type.text": "<%s> %s"
"chat.type.announcement": "[%s] %s"
"commands.message.display.incoming": "%s whispers to you: %s"
"chat.type.team.text": "%s <%s> %s"
"chat.type.emote": "* %s %s"
#
#----------------------------------------------------------#
# 1.9+ CLIENTS ON 1.8 SERVERS OPTIONS #
#----------------------------------------------------------#
@@ -23957,7 +23957,7 @@
"entity.frog.lay_spawn",
"entity.frog.long_jump",
"entity.frog.step",
"entity.frog.tounge",
"entity.frog.tongue",
"block.roots.break",
"block.roots.step",
"block.roots.place",
@@ -137,4 +137,9 @@ public final class TestPlatform implements ViaPlatform {
public boolean isOldClientsAllowed() {
return false;
}
@Override
public boolean hasPlugin(final String name) {
return false;
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=4.3.1
projectVersion=4.4.1
# Gradle properties
org.gradle.daemon=true
@@ -228,6 +228,11 @@ public class SpongePlugin implements ViaPlatform<Player> {
return true;
}
@Override
public boolean hasPlugin(final String name) {
return game.pluginManager().plugin(name).isPresent();
}
@Override
public SpongeViaAPI getApi() {
return api;
@@ -239,6 +239,11 @@ public class VelocityPlugin implements ViaPlatform<Player> {
return true;
}
@Override
public boolean hasPlugin(final String name) {
return proxy.getPluginManager().getPlugin(name).isPresent();
}
@Override
public java.util.logging.Logger getLogger() {
return logger;
@@ -41,4 +41,9 @@ public class VelocityCommandHandler extends ViaCommandHandler implements SimpleC
public List<String> suggest(Invocation invocation) {
return onTabComplete(new VelocityCommandSender(invocation.source()), invocation.arguments());
}
@Override
public boolean hasPermission(Invocation invocation) {
return invocation.source().hasPermission("viaversion.admin"); // The permission is also referenced here to filter root suggestions (/via<tab>)
}
}