Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adb10f5fe7 | ||
|
|
a268d3d298 | ||
|
|
b60771e96e | ||
|
|
435a986068 | ||
|
|
6c58f0980c | ||
|
|
e3dde71821 | ||
|
|
47b15e5fef | ||
|
|
ed196bdf99 | ||
|
|
9247e87bbf | ||
|
|
08727f959f | ||
|
|
78342da180 | ||
|
|
2b735172bd | ||
|
|
b032a868bb | ||
|
|
c4fa3b0ff8 | ||
|
|
0c3a1803e1 | ||
|
|
04f9971dee | ||
|
|
9c3395b76b | ||
|
|
f9bbb5b1a3 | ||
|
|
087bbdce1f | ||
|
|
494bf62535 | ||
|
|
4f2a5bb7e2 | ||
|
|
1c511a82b2 | ||
|
|
0c39723d1a | ||
|
|
322af00e80 | ||
|
|
a88747d904 | ||
|
|
e194d27bea | ||
|
|
22daa60eb6 | ||
|
|
6eca07966c | ||
|
|
56cc711c01 | ||
|
|
c2ee558235 | ||
|
|
c8a010c390 | ||
|
|
53c54485eb | ||
|
|
f42a308f2c | ||
|
|
44250cbb99 | ||
|
|
55ffe72198 | ||
|
|
a47dd2ecdb | ||
|
|
8a5233b6a1 | ||
|
|
c8a1279e75 | ||
|
|
57ef90e851 | ||
|
|
2262681351 | ||
|
|
56e1d0a69d | ||
|
|
63ffb51df5 | ||
|
|
b33bd2ac2b | ||
|
|
1afff77a0f | ||
|
|
26af09f2a4 | ||
|
|
a8e475dbf0 | ||
|
|
6388021c6d | ||
|
|
f4aa96a5f8 | ||
|
|
6baae5e4f7 | ||
|
|
189b244a3a | ||
|
|
12d538fe0d | ||
|
|
34f0dbf642 | ||
|
|
548f80bb7c | ||
|
|
9113a77331 | ||
|
|
e3e85db02a | ||
|
|
c4d9209c81 | ||
|
|
24d887a53d | ||
|
|
702ced200e | ||
|
|
40f5cb6e71 | ||
|
|
7ab0c41be6 | ||
|
|
66b21431f2 | ||
|
|
c6cd655f7e | ||
|
|
e9bccda259 |
No files matched your search
@@ -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
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Supported Versions:
|
||||
|
||||

|
||||

|
||||
|
||||
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) {
|
||||
|
||||
@@ -25,6 +25,7 @@ package com.viaversion.viaversion.api;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
|
||||
import com.viaversion.viaversion.api.platform.ViaPlatform;
|
||||
import com.viaversion.viaversion.api.platform.ViaServerProxyPlatform;
|
||||
|
||||
public final class Via {
|
||||
private static ViaManager manager;
|
||||
@@ -63,6 +64,11 @@ public final class Via {
|
||||
return manager().getPlatform();
|
||||
}
|
||||
|
||||
public static ViaServerProxyPlatform<?> proxyPlatform() {
|
||||
Preconditions.checkArgument(manager().getPlatform() instanceof ViaServerProxyPlatform, "Platform is not proxying Minecraft servers!");
|
||||
return (ViaServerProxyPlatform<?>) manager().getPlatform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the ViaManager associated with the platform.
|
||||
*
|
||||
|
||||
@@ -64,7 +64,7 @@ public interface ViaAPI<T> {
|
||||
* @return API version incremented with meaningful API changes
|
||||
*/
|
||||
default int apiVersion() {
|
||||
return 12;
|
||||
return 15;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
+13
-17
@@ -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;
|
||||
}
|
||||
}
|
||||
+17
-18
@@ -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;
|
||||
}
|
||||
}
|
||||
+1
-10
@@ -269,15 +269,6 @@ public enum Entity1_19Types implements EntityType {
|
||||
}
|
||||
|
||||
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
|
||||
for (final Entity1_19Types type : values()) {
|
||||
if (type.isAbstractType()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int id = protocol.getMappingData().getEntityMappings().mappedId(type.identifier());
|
||||
Preconditions.checkArgument(id != -1, "Entity type %s has no id", type.identifier());
|
||||
type.id = id;
|
||||
}
|
||||
EntityTypeUtil.fill(values(), TYPES);
|
||||
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.platform;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
|
||||
public interface ProtocolDetectorService {
|
||||
|
||||
/**
|
||||
* Returns the protocol version of the proxied server, or -1 if unknown.
|
||||
*
|
||||
* @param serverName name of the proxied server
|
||||
* @return protocol version of the proxied server, or -1 if unknown
|
||||
*/
|
||||
int serverProtocolVersion(String serverName);
|
||||
|
||||
/**
|
||||
* Probes all registered proxied servers for their protocol version.
|
||||
* This is executed automatically in the interval set in the ViaVersion config.
|
||||
*/
|
||||
void probeAllServers();
|
||||
|
||||
/**
|
||||
* Sets the stored protocol version of a proxied server.
|
||||
*
|
||||
* @param serverName name of the proxied server
|
||||
* @param protocolVersion protocol version of the server
|
||||
*/
|
||||
void setProtocolVersion(String serverName, int protocolVersion);
|
||||
|
||||
/**
|
||||
* Uncaches and returns the previously stored protocol version of the proxied server. Returns -1 if none was stored.
|
||||
*
|
||||
* @param serverName name of the proxied server
|
||||
* @return previously stored protocol version of the proxied server, or -1 if none was present
|
||||
*/
|
||||
int uncacheProtocolVersion(String serverName);
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable map of detected protocol versions.
|
||||
*
|
||||
* @return unmodifiable map of detected protocol versions
|
||||
*/
|
||||
Object2IntMap<String> detectedProtocolVersions();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.platform;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* Represents a platform that proxies a list of Minecraft servers (Velocity, Bungee).
|
||||
* A platform might not be a proxy platform, even if {@link ViaPlatform#isProxy()} is true.
|
||||
*
|
||||
* @param <T> platform player type
|
||||
*/
|
||||
@Beta
|
||||
public interface ViaServerProxyPlatform<T> extends ViaPlatform<T> {
|
||||
|
||||
/**
|
||||
* Returns a service to get protocol versions for proxied servers.
|
||||
*
|
||||
* @return protocol detector service
|
||||
*/
|
||||
ProtocolDetectorService protocolDetectorService();
|
||||
}
|
||||
@@ -300,9 +300,9 @@ public interface Protocol<C1 extends ClientboundPacketType, C2 extends Clientbou
|
||||
* <p>
|
||||
* To be overridden if needed.
|
||||
*
|
||||
* @param userConnection The user to initialise
|
||||
* @param connection 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/2", new VersionRange("1.19", 1, 2));
|
||||
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;
|
||||
}
|
||||
+13
-13
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -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 {
|
||||
|
||||
+3
-2
@@ -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 {
|
||||
|
||||
+13
-11
@@ -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 {
|
||||
|
||||
@@ -24,7 +24,7 @@ package com.viaversion.viaversion.api.type.types.minecraft;
|
||||
|
||||
import com.github.steveice10.opennbt.NBTIO;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.github.steveice10.opennbt.tag.limiter.TagLimiter;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufInputStream;
|
||||
@@ -35,21 +35,22 @@ import java.io.DataOutput;
|
||||
|
||||
public class NBTType extends Type<CompoundTag> {
|
||||
|
||||
private static final int MAX_NBT_BYTES = 2097152; // 2mb
|
||||
private static final int MAX_NESTING_LEVEL = 512;
|
||||
|
||||
public NBTType() {
|
||||
super(CompoundTag.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag read(ByteBuf buffer) throws Exception {
|
||||
Preconditions.checkArgument(buffer.readableBytes() <= 2097152, "Cannot read NBT (got %s bytes)", buffer.readableBytes());
|
||||
|
||||
int readerIndex = buffer.readerIndex();
|
||||
byte b = buffer.readByte();
|
||||
if (b == 0) {
|
||||
return null;
|
||||
} else {
|
||||
buffer.readerIndex(readerIndex);
|
||||
return NBTIO.readTag((DataInput) new ByteBufInputStream(buffer));
|
||||
return NBTIO.readTag((DataInput) new ByteBufInputStream(buffer), TagLimiter.create(MAX_NBT_BYTES, MAX_NESTING_LEVEL));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-15
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-15
@@ -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);
|
||||
}
|
||||
}
|
||||
+9
-15
@@ -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);
|
||||
}
|
||||
}
|
||||
+7
-20
@@ -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);
|
||||
}
|
||||
}
|
||||
+24
-32
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class InformativeException extends Exception {
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
StringBuilder builder = new StringBuilder("Please post this error to https://github.com/ViaVersion/ViaVersion/issues and follow the issue template\n{");
|
||||
StringBuilder builder = new StringBuilder("Please report this on the Via support Discord or open an issue on the relevant GitHub repository\n");
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, Object> entry : info.entrySet()) {
|
||||
if (!first) {
|
||||
@@ -57,11 +57,11 @@ public class InformativeException extends Exception {
|
||||
builder.append(entry.getKey()).append(": ").append(entry.getValue());
|
||||
first = false;
|
||||
}
|
||||
return builder.append("}\nActual Error: ").toString();
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
public Throwable fillInStackTrace() {
|
||||
// Don't record this stack
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -22,14 +22,18 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class EntityTypeUtil {
|
||||
public final class EntityTypeUtil {
|
||||
|
||||
private static final EntityType[] EMPTY_ARRAY = new EntityType[0];
|
||||
|
||||
/**
|
||||
* Returns an ordered array with each index representing the actual entity id.
|
||||
@@ -46,7 +50,29 @@ public class EntityTypeUtil {
|
||||
}
|
||||
|
||||
types.sort(Comparator.comparingInt(EntityType::getId));
|
||||
return types.toArray(new EntityType[0]);
|
||||
return types.toArray(EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets entity type ids based on the protocol's mapping data and fills the given typesToFill array with the index corresponding to the id.
|
||||
*
|
||||
* @param values full enum values
|
||||
* @param typesToFill yet unfilled array to be filled with types ordered by id
|
||||
* @param protocol protocol to get entity types from
|
||||
* @param idSetter function to set the internal entity id
|
||||
* @param <T> entity type
|
||||
*/
|
||||
public static <T extends EntityType> void initialize(final T[] values, final EntityType[] typesToFill, final Protocol<?, ?, ?, ?> protocol, final EntityIdSetter<T> idSetter) {
|
||||
for (final T type : values) {
|
||||
if (type.isAbstractType()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int id = protocol.getMappingData().getEntityMappings().mappedId(type.identifier());
|
||||
Preconditions.checkArgument(id != -1, "Entity type %s has no id", type.identifier());
|
||||
idSetter.setId(type, id);
|
||||
typesToFill[id] = type;
|
||||
}
|
||||
}
|
||||
|
||||
public static EntityType[] createSizedArray(final EntityType[] values) {
|
||||
@@ -56,15 +82,7 @@ public class EntityTypeUtil {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return new EntityType[(int) count];
|
||||
}
|
||||
|
||||
public static void fill(final EntityType[] values, final EntityType[] toFill) {
|
||||
for (final EntityType type : values) {
|
||||
if (!type.isAbstractType()) {
|
||||
toFill[type.getId()] = type;
|
||||
}
|
||||
}
|
||||
return new EntityType[count];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,4 +101,10 @@ public class EntityTypeUtil {
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface EntityIdSetter<T extends EntityType> {
|
||||
|
||||
void setId(T entityType, int id);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -285,15 +286,23 @@ 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)
|
||||
final List<UnsupportedSoftware> list = new ArrayList<>(ViaPlatform.super.getUnsupportedSoftwareClasses());
|
||||
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;
|
||||
}
|
||||
|
||||
+4
@@ -100,4 +100,8 @@ public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaCode
|
||||
cause.printStackTrace(); // Print if CB doesn't already do it
|
||||
}
|
||||
}
|
||||
|
||||
public UserConnection getInfo() {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.listeners;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.ProtocolInfo;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.bukkit.handlers.BukkitEncodeHandler;
|
||||
import com.viaversion.viaversion.bukkit.util.NMSUtil;
|
||||
import io.netty.channel.Channel;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class JoinListener implements Listener {
|
||||
|
||||
private static final Method GET_HANDLE;
|
||||
private static final Field CONNECTION;
|
||||
private static final Field NETWORK_MANAGER;
|
||||
private static final Field CHANNEL;
|
||||
|
||||
static {
|
||||
Method gh = null;
|
||||
Field conn = null, nm = null, ch = null;
|
||||
try {
|
||||
gh = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle");
|
||||
conn = findField(gh.getReturnType(), "PlayerConnection", "ServerGamePacketListenerImpl");
|
||||
nm = findField(conn.getType(), "NetworkManager", "Connection");
|
||||
ch = findField(nm.getType(), "Channel");
|
||||
} catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException e) {
|
||||
Via.getPlatform().getLogger().log(
|
||||
Level.WARNING,
|
||||
"Couldn't find reflection methods/fields to access Channel from player.\n" +
|
||||
"Login race condition fixer will be disabled.\n" +
|
||||
" Some plugins that use ViaAPI on join event may work incorrectly.", e);
|
||||
}
|
||||
GET_HANDLE = gh;
|
||||
CONNECTION = conn;
|
||||
NETWORK_MANAGER = nm;
|
||||
CHANNEL = ch;
|
||||
}
|
||||
|
||||
// Loosely search a field with any name, as long as it matches a type name.
|
||||
private static Field findField(Class<?> cl, String... types) throws NoSuchFieldException {
|
||||
for (Field field : cl.getDeclaredFields()) {
|
||||
for (String type : types)
|
||||
if (field.getType().getSimpleName().equals(type))
|
||||
return field;
|
||||
}
|
||||
throw new NoSuchFieldException(types[0]);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
if (CHANNEL == null) return;
|
||||
Player player = e.getPlayer();
|
||||
|
||||
Channel channel;
|
||||
try {
|
||||
channel = getChannel(player);
|
||||
} catch (Exception ex) {
|
||||
Via.getPlatform().getLogger().log(Level.WARNING, ex,
|
||||
() -> "Could not find Channel for logging-in player " + player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
// The connection has already closed, that was a quick leave
|
||||
if (!channel.isOpen()) return;
|
||||
|
||||
UserConnection user = getUserConnection(channel);
|
||||
if (user == null) {
|
||||
Via.getPlatform().getLogger().log(Level.WARNING,
|
||||
"Could not find UserConnection for logging-in player {0}",
|
||||
player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
ProtocolInfo info = user.getProtocolInfo();
|
||||
info.setUuid(player.getUniqueId());
|
||||
info.setUsername(player.getName());
|
||||
Via.getManager().getConnectionManager().onLoginSuccess(user);
|
||||
}
|
||||
|
||||
private @Nullable UserConnection getUserConnection(Channel channel) {
|
||||
BukkitEncodeHandler encoder = channel.pipeline().get(BukkitEncodeHandler.class);
|
||||
return encoder != null ? encoder.getInfo() : null;
|
||||
}
|
||||
|
||||
private Channel getChannel(Player player) throws Exception {
|
||||
Object entityPlayer = GET_HANDLE.invoke(player);
|
||||
Object pc = CONNECTION.get(entityPlayer);
|
||||
Object nm = NETWORK_MANAGER.get(pc);
|
||||
return (Channel) CHANNEL.get(nm);
|
||||
}
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.listeners.protocol1_19to1_18_2;
|
||||
|
||||
import com.viaversion.viaversion.ViaVersionPlugin;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
|
||||
import com.viaversion.viaversion.bukkit.util.NMSUtil;
|
||||
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
|
||||
public final class BlockBreakListener extends ViaBukkitListener {
|
||||
|
||||
private static final Class<?> CRAFT_BLOCK_STATE_CLASS;
|
||||
|
||||
static {
|
||||
try {
|
||||
CRAFT_BLOCK_STATE_CLASS = NMSUtil.obc("block.CraftBlockState");
|
||||
} catch (final ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockBreakListener(ViaVersionPlugin plugin) {
|
||||
super(plugin, Protocol1_19To1_18_2.class);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void blockBreak(BlockBreakEvent event) {
|
||||
final Block block = event.getBlock();
|
||||
if (!event.isCancelled() || !isBlockEntity(block.getState())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to resend the block entity data after an ack has been sent out
|
||||
final int serverProtocolVersion = Via.getAPI().getServerVersion().highestSupportedVersion();
|
||||
final long delay = serverProtocolVersion > ProtocolVersion.v1_8.getVersion() && serverProtocolVersion < ProtocolVersion.v1_14.getVersion() ? 2 : 1;
|
||||
getPlugin().getServer().getScheduler().runTaskLater(getPlugin(), () -> {
|
||||
final BlockState state = block.getState();
|
||||
if (isBlockEntity(state)) {
|
||||
state.update(true, false);
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
|
||||
private boolean isBlockEntity(final BlockState state) {
|
||||
// We love legacy versions
|
||||
return state.getClass() != CRAFT_BLOCK_STATE_CLASS;
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -24,20 +24,24 @@ import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.bukkit.classgenerator.ClassGenerator;
|
||||
import com.viaversion.viaversion.bukkit.listeners.JoinListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.UpdateListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.multiversion.PlayerSneakListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.protocol1_15to1_14_4.EntityToggleGlideListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.protocol1_19to1_18_2.BlockBreakListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.ArmorListener;
|
||||
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 +51,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;
|
||||
@@ -78,6 +81,9 @@ public class BukkitViaLoader implements ViaPlatformLoader {
|
||||
// Update Listener
|
||||
registerListener(new UpdateListener());
|
||||
|
||||
// Login listener
|
||||
registerListener(new JoinListener());
|
||||
|
||||
/* Base Protocol */
|
||||
final ViaVersionPlugin plugin = (ViaVersionPlugin) Bukkit.getPluginManager().getPlugin("ViaVersion");
|
||||
|
||||
@@ -174,6 +180,10 @@ public class BukkitViaLoader implements ViaPlatformLoader {
|
||||
ConnectionData.blockConnectionProvider = blockConnectionProvider;
|
||||
}
|
||||
}
|
||||
if (serverProtocolVersion < ProtocolVersion.v1_19.getVersion()) {
|
||||
Via.getManager().getProviders().use(AckSequenceProvider.class, new BukkitAckSequenceProvider(plugin));
|
||||
storeListener(new BlockBreakListener(plugin)).register();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.api.protocol.version.ProtocolVersion;
|
||||
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) {
|
||||
final int serverProtocolVersion = connection.getProtocolInfo().getServerProtocolVersion();
|
||||
final long delay = serverProtocolVersion > ProtocolVersion.v1_8.getVersion() && serverProtocolVersion < ProtocolVersion.v1_14.getVersion() ? 2 : 1;
|
||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new AckSequenceTask(connection, sequenceStorage), delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package com.viaversion.viaversion;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.ViaAPI;
|
||||
@@ -24,17 +25,19 @@ import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||
import com.viaversion.viaversion.api.configuration.ConfigurationProvider;
|
||||
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||
import com.viaversion.viaversion.api.platform.PlatformTask;
|
||||
import com.viaversion.viaversion.api.platform.ViaPlatform;
|
||||
import com.viaversion.viaversion.api.platform.UnsupportedSoftware;
|
||||
import com.viaversion.viaversion.api.platform.ViaServerProxyPlatform;
|
||||
import com.viaversion.viaversion.bungee.commands.BungeeCommand;
|
||||
import com.viaversion.viaversion.bungee.commands.BungeeCommandHandler;
|
||||
import com.viaversion.viaversion.bungee.commands.BungeeCommandSender;
|
||||
import com.viaversion.viaversion.bungee.platform.BungeeViaTask;
|
||||
import com.viaversion.viaversion.bungee.platform.BungeeViaAPI;
|
||||
import com.viaversion.viaversion.bungee.platform.BungeeViaConfig;
|
||||
import com.viaversion.viaversion.bungee.platform.BungeeViaInjector;
|
||||
import com.viaversion.viaversion.bungee.platform.BungeeViaLoader;
|
||||
import com.viaversion.viaversion.bungee.platform.BungeeViaTask;
|
||||
import com.viaversion.viaversion.bungee.service.ProtocolDetectorService;
|
||||
import com.viaversion.viaversion.dump.PluginInfo;
|
||||
import com.viaversion.viaversion.unsupported.UnsupportedServerSoftware;
|
||||
import com.viaversion.viaversion.util.GsonUtil;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@@ -49,14 +52,15 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BungeePlugin extends Plugin implements ViaPlatform<ProxiedPlayer>, Listener {
|
||||
public class BungeePlugin extends Plugin implements ViaServerProxyPlatform<ProxiedPlayer>, Listener {
|
||||
private final ProtocolDetectorService protocolDetectorService = new ProtocolDetectorService();
|
||||
private BungeeViaAPI api;
|
||||
private BungeeViaConfig config;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
try {
|
||||
ProtocolConstants.class.getField("MINECRAFT_1_18");
|
||||
ProtocolConstants.class.getField("MINECRAFT_1_19_1");
|
||||
} catch (NoSuchFieldException e) {
|
||||
getLogger().warning(" / \\");
|
||||
getLogger().warning(" / \\");
|
||||
@@ -197,7 +201,7 @@ public class BungeePlugin extends Plugin implements ViaPlatform<ProxiedPlayer>,
|
||||
));
|
||||
|
||||
platformSpecific.add("plugins", GsonUtil.getGson().toJsonTree(plugins));
|
||||
platformSpecific.add("servers", GsonUtil.getGson().toJsonTree(ProtocolDetectorService.getDetectedIds()));
|
||||
platformSpecific.add("servers", GsonUtil.getGson().toJsonTree(protocolDetectorService.detectedProtocolVersions()));
|
||||
return platformSpecific;
|
||||
}
|
||||
|
||||
@@ -205,4 +209,25 @@ public class BungeePlugin extends Plugin implements ViaPlatform<ProxiedPlayer>,
|
||||
public boolean isOldClientsAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<UnsupportedSoftware> getUnsupportedSoftwareClasses() {
|
||||
final Collection<UnsupportedSoftware> list = new ArrayList<>(ViaServerProxyPlatform.super.getUnsupportedSoftwareClasses());
|
||||
list.add(new UnsupportedServerSoftware.Builder()
|
||||
.name("FlameCord")
|
||||
.addClassName("dev._2lstudios.flamecord.FlameCord")
|
||||
.reason(UnsupportedServerSoftware.Reason.BREAKING_PROXY_SOFTWARE)
|
||||
.build());
|
||||
return ImmutableList.copyOf(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPlugin(final String name) {
|
||||
return getProxy().getPluginManager().getPlugin(name) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolDetectorService protocolDetectorService() {
|
||||
return protocolDetectorService;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -21,7 +21,6 @@ import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||
import com.viaversion.viaversion.api.command.ViaSubCommand;
|
||||
import com.viaversion.viaversion.bungee.platform.BungeeViaConfig;
|
||||
import com.viaversion.viaversion.bungee.service.ProtocolDetectorService;
|
||||
|
||||
public class ProbeSubCmd extends ViaSubCommand {
|
||||
@Override
|
||||
@@ -38,7 +37,7 @@ public class ProbeSubCmd extends ViaSubCommand {
|
||||
|
||||
@Override
|
||||
public boolean execute(ViaCommandSender sender, String[] args) {
|
||||
ProtocolDetectorService.getInstance().run();
|
||||
Via.proxyPlatform().protocolDetectorService().probeAllServers();
|
||||
sendMessage(sender, "&6Started searching for protocol versions");
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-3
@@ -29,7 +29,6 @@ import com.viaversion.viaversion.api.protocol.ProtocolPipeline;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.bungee.service.ProtocolDetectorService;
|
||||
import com.viaversion.viaversion.bungee.storage.BungeeStorage;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.packets.InventoryPackets;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9;
|
||||
@@ -96,7 +95,7 @@ public class BungeeServerHandler implements Listener {
|
||||
user.put(new BungeeStorage(e.getPlayer()));
|
||||
}
|
||||
|
||||
int protocolId = ProtocolDetectorService.getProtocolId(e.getTarget().getName());
|
||||
int protocolId = Via.proxyPlatform().protocolDetectorService().serverProtocolVersion(e.getTarget().getName());
|
||||
List<ProtocolPathEntry> protocols = Via.getManager().getProtocolManager().getProtocolPath(user.getProtocolInfo().getProtocolVersion(), protocolId);
|
||||
|
||||
// Check if ViaVersion can support that version
|
||||
@@ -164,7 +163,7 @@ public class BungeeServerHandler implements Listener {
|
||||
|
||||
storage.setCurrentServer(serverName);
|
||||
|
||||
int protocolId = ProtocolDetectorService.getProtocolId(serverName);
|
||||
int protocolId = Via.proxyPlatform().protocolDetectorService().serverProtocolVersion(serverName);
|
||||
|
||||
if (protocolId <= ProtocolVersion.v1_8.getVersion()) { // 1.8 doesn't have BossBar packet
|
||||
if (storage.getBossbar() != null) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package com.viaversion.viaversion.bungee.platform;
|
||||
|
||||
import com.viaversion.viaversion.ViaAPIBase;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.bungee.service.ProtocolDetectorService;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
@@ -41,6 +42,6 @@ public class BungeeViaAPI extends ViaAPIBase<ProxiedPlayer> {
|
||||
* @param serverInfo The serverinfo to probe
|
||||
*/
|
||||
public void probeServer(ServerInfo serverInfo) {
|
||||
ProtocolDetectorService.probeServer(serverInfo);
|
||||
((ProtocolDetectorService) Via.proxyPlatform().protocolDetectorService()).probeServer(serverInfo);
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import com.viaversion.viaversion.bungee.providers.BungeeEntityIdProvider;
|
||||
import com.viaversion.viaversion.bungee.providers.BungeeMainHandProvider;
|
||||
import com.viaversion.viaversion.bungee.providers.BungeeMovementTransmitter;
|
||||
import com.viaversion.viaversion.bungee.providers.BungeeVersionProvider;
|
||||
import com.viaversion.viaversion.bungee.service.ProtocolDetectorService;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.BossBarProvider;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.EntityIdProvider;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MainHandProvider;
|
||||
@@ -44,10 +43,9 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BungeeViaLoader implements ViaPlatformLoader {
|
||||
private final BungeePlugin plugin;
|
||||
|
||||
private final Set<Listener> listeners = new HashSet<>();
|
||||
private final Set<ScheduledTask> tasks = new HashSet<>();
|
||||
private final BungeePlugin plugin;
|
||||
|
||||
public BungeeViaLoader(BungeePlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -82,7 +80,7 @@ public class BungeeViaLoader implements ViaPlatformLoader {
|
||||
if (plugin.getConf().getBungeePingInterval() > 0) {
|
||||
tasks.add(plugin.getProxy().getScheduler().schedule(
|
||||
plugin,
|
||||
new ProtocolDetectorService(plugin),
|
||||
() -> Via.proxyPlatform().protocolDetectorService().probeAllServers(),
|
||||
0, plugin.getConf().getBungeePingInterval(),
|
||||
TimeUnit.SECONDS
|
||||
));
|
||||
|
||||
+52
-68
@@ -17,93 +17,77 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.bungee.service;
|
||||
|
||||
import com.viaversion.viaversion.BungeePlugin;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.bungee.platform.BungeeViaConfig;
|
||||
import com.viaversion.viaversion.bungee.providers.BungeeVersionProvider;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import com.viaversion.viaversion.platform.AbstractProtocolDetectorService;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Set;
|
||||
|
||||
public class ProtocolDetectorService implements Runnable {
|
||||
private static final Map<String, Integer> detectedProtocolIds = new ConcurrentHashMap<>();
|
||||
private static ProtocolDetectorService instance;
|
||||
private final BungeePlugin plugin;
|
||||
public final class ProtocolDetectorService extends AbstractProtocolDetectorService {
|
||||
|
||||
public ProtocolDetectorService(BungeePlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
instance = this;
|
||||
}
|
||||
public void probeServer(final ServerInfo serverInfo) {
|
||||
final String serverName = serverInfo.getName();
|
||||
serverInfo.ping((serverPing, throwable) -> {
|
||||
// Ensure protocol is positive, some services will return -1
|
||||
if (throwable != null || serverPing == null || serverPing.getVersion() == null || serverPing.getVersion().getProtocol() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
public static Integer getProtocolId(String serverName) {
|
||||
// Step 1. Check Config
|
||||
Map<String, Integer> servers = ((BungeeViaConfig) Via.getConfig()).getBungeeServerProtocols();
|
||||
Integer protocol = servers.get(serverName);
|
||||
if (protocol != null) {
|
||||
return protocol;
|
||||
}
|
||||
// Step 2. Check Detected
|
||||
Integer detectedProtocol = detectedProtocolIds.get(serverName);
|
||||
if (detectedProtocol != null) {
|
||||
return detectedProtocol;
|
||||
}
|
||||
// Step 3. Use Default
|
||||
Integer defaultProtocol = servers.get("default");
|
||||
if (defaultProtocol != null) {
|
||||
return defaultProtocol;
|
||||
}
|
||||
// Step 4: Use bungee lowest supported... *cries*
|
||||
return BungeeVersionProvider.getLowestSupportedVersion();
|
||||
}
|
||||
final int oldProtocolVersion = serverProtocolVersion(serverName);
|
||||
if (oldProtocolVersion == serverPing.getVersion().getProtocol()) {
|
||||
// Same value as previously
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (final Map.Entry<String, ServerInfo> lists : plugin.getProxy().getServers().entrySet()) {
|
||||
probeServer(lists.getValue());
|
||||
}
|
||||
}
|
||||
setProtocolVersion(serverName, serverPing.getVersion().getProtocol());
|
||||
|
||||
public static void probeServer(final ServerInfo serverInfo) {
|
||||
final String key = serverInfo.getName();
|
||||
serverInfo.ping(new Callback<ServerPing>() {
|
||||
@Override
|
||||
public void done(ServerPing serverPing, Throwable throwable) {
|
||||
if (throwable == null && serverPing != null && serverPing.getVersion() != null) {
|
||||
// Ensure protocol is positive, some services will return -1
|
||||
if (serverPing.getVersion().getProtocol() > 0) {
|
||||
detectedProtocolIds.put(key, serverPing.getVersion().getProtocol());
|
||||
if (((BungeeViaConfig) Via.getConfig()).isBungeePingSave()) {
|
||||
Map<String, Integer> servers = ((BungeeViaConfig) Via.getConfig()).getBungeeServerProtocols();
|
||||
Integer protocol = servers.get(key);
|
||||
if (protocol != null && protocol == serverPing.getVersion().getProtocol()) {
|
||||
return;
|
||||
}
|
||||
// Ensure we're the only ones writing to the config
|
||||
synchronized (Via.getPlatform().getConfigurationProvider()) {
|
||||
servers.put(key, serverPing.getVersion().getProtocol());
|
||||
}
|
||||
// Save
|
||||
Via.getPlatform().getConfigurationProvider().saveConfig();
|
||||
}
|
||||
}
|
||||
if (((BungeeViaConfig) Via.getConfig()).isBungeePingSave()) {
|
||||
final Map<String, Integer> servers = ((BungeeViaConfig) Via.getConfig()).getBungeeServerProtocols();
|
||||
final Integer protocol = servers.get(serverName);
|
||||
if (protocol != null && protocol == serverPing.getVersion().getProtocol()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure we're the only ones writing to the config
|
||||
synchronized (Via.getPlatform().getConfigurationProvider()) {
|
||||
servers.put(serverName, serverPing.getVersion().getProtocol());
|
||||
}
|
||||
Via.getPlatform().getConfigurationProvider().saveConfig();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Map<String, Integer> getDetectedIds() {
|
||||
return new HashMap<>(detectedProtocolIds);
|
||||
@Override
|
||||
public void probeAllServers() {
|
||||
final Collection<ServerInfo> servers = ProxyServer.getInstance().getServers().values();
|
||||
final Set<String> serverNames = new HashSet<>(servers.size());
|
||||
for (final ServerInfo serverInfo : servers) {
|
||||
probeServer(serverInfo);
|
||||
serverNames.add(serverInfo.getName());
|
||||
}
|
||||
|
||||
// Remove servers that aren't registered anymore
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
detectedProtocolIds.keySet().retainAll(serverNames);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static ProtocolDetectorService getInstance() {
|
||||
return instance;
|
||||
@Override
|
||||
protected Map<String, Integer> configuredServers() {
|
||||
return ((BungeeViaConfig) Via.getConfig()).getBungeeServerProtocols();
|
||||
}
|
||||
|
||||
public BungeePlugin getPlugin() {
|
||||
return plugin;
|
||||
@Override
|
||||
protected int lowestSupportedProtocolVersion() {
|
||||
return BungeeVersionProvider.getLowestSupportedVersion();
|
||||
}
|
||||
}
|
||||
@@ -157,7 +157,7 @@ public class ViaManagerImpl implements ViaManager {
|
||||
loader.load();
|
||||
// Common tasks
|
||||
mappingLoadingTask = Via.getPlatform().runRepeatingSync(() -> {
|
||||
if (protocolManager.checkForMappingCompletion()) {
|
||||
if (protocolManager.checkForMappingCompletion() && mappingLoadingTask != null) {
|
||||
mappingLoadingTask.cancel();
|
||||
mappingLoadingTask = null;
|
||||
}
|
||||
@@ -235,9 +235,9 @@ public class ViaManagerImpl implements ViaManager {
|
||||
}
|
||||
}
|
||||
|
||||
private final void unsupportedSoftwareWarning() {
|
||||
private void unsupportedSoftwareWarning() {
|
||||
boolean found = false;
|
||||
for (UnsupportedSoftware software : platform.getUnsupportedSoftwareClasses()) {
|
||||
for (final UnsupportedSoftware software : platform.getUnsupportedSoftwareClasses()) {
|
||||
if (!software.findMatch()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+12
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
+17
-4
@@ -20,6 +20,7 @@ package com.viaversion.viaversion.connection;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.ConnectionManager;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
@@ -37,17 +38,29 @@ public class ConnectionManagerImpl implements ConnectionManager {
|
||||
@Override
|
||||
public void onLoginSuccess(UserConnection connection) {
|
||||
Objects.requireNonNull(connection, "connection is null!");
|
||||
connections.add(connection);
|
||||
Channel channel = connection.getChannel();
|
||||
|
||||
// This user has already disconnected...
|
||||
if (channel != null && !channel.isOpen()) return;
|
||||
|
||||
boolean newlyAdded = connections.add(connection);
|
||||
|
||||
if (isFrontEnd(connection)) {
|
||||
UUID id = connection.getProtocolInfo().getUuid();
|
||||
if (clients.put(id, connection) != null) {
|
||||
UserConnection previous = clients.put(id, connection);
|
||||
if (previous != null && previous != connection) {
|
||||
Via.getPlatform().getLogger().warning("Duplicate UUID on frontend connection! (" + id + ")");
|
||||
}
|
||||
}
|
||||
|
||||
if (connection.getChannel() != null) {
|
||||
connection.getChannel().closeFuture().addListener((ChannelFutureListener) future -> onDisconnect(connection));
|
||||
if (channel != null) {
|
||||
// We managed to add a user that had already disconnected!
|
||||
// Let's clean up the mess here and now
|
||||
if (!channel.isOpen()) {
|
||||
onDisconnect(connection);
|
||||
} else if (newlyAdded) { // Setup to clean-up on disconnect
|
||||
channel.closeFuture().addListener((ChannelFutureListener) future -> onDisconnect(connection));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.platform;
|
||||
|
||||
import com.viaversion.viaversion.api.platform.ProtocolDetectorService;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public abstract class AbstractProtocolDetectorService implements ProtocolDetectorService {
|
||||
protected final Object2IntMap<String> detectedProtocolIds = new Object2IntOpenHashMap<>();
|
||||
protected final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
protected AbstractProtocolDetectorService() {
|
||||
detectedProtocolIds.defaultReturnValue(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serverProtocolVersion(final String serverName) {
|
||||
// Step 1. Check detected
|
||||
lock.readLock().lock();
|
||||
final int detectedProtocol;
|
||||
try {
|
||||
detectedProtocol = detectedProtocolIds.getInt(serverName);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
if (detectedProtocol != -1) {
|
||||
return detectedProtocol;
|
||||
}
|
||||
|
||||
// Step 2. Check config (CME moment?)
|
||||
final Map<String, Integer> servers = configuredServers();
|
||||
final Integer protocol = servers.get(serverName);
|
||||
if (protocol != null) {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
// Step 3. Use Default (CME moment intensifies?)
|
||||
final Integer defaultProtocol = servers.get("default");
|
||||
if (defaultProtocol != null) {
|
||||
return defaultProtocol;
|
||||
}
|
||||
|
||||
// Step 4: Use the proxy's lowest supported... *cries*
|
||||
return lowestSupportedProtocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocolVersion(final String serverName, final int protocolVersion) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
detectedProtocolIds.put(serverName, protocolVersion);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int uncacheProtocolVersion(final String serverName) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
return detectedProtocolIds.removeInt(serverName);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object2IntMap<String> detectedProtocolVersions() {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return new Object2IntOpenHashMap<>(detectedProtocolIds);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Map<String, Integer> configuredServers();
|
||||
|
||||
protected abstract int lowestSupportedProtocolVersion();
|
||||
}
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+4
@@ -48,6 +48,10 @@ public class BlockConnectionProvider implements Provider {
|
||||
|
||||
}
|
||||
|
||||
public void unloadChunkSection(UserConnection connection, int chunkX, int chunkY, int chunkZ) {
|
||||
|
||||
}
|
||||
|
||||
public boolean storesBlocks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
+5
@@ -47,6 +47,11 @@ public class PacketBlockConnectionProvider extends BlockConnectionProvider {
|
||||
connection.get(BlockConnectionStorage.class).unloadChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunkSection(UserConnection connection, int chunkX, int chunkY, int chunkZ) {
|
||||
connection.get(BlockConnectionStorage.class).unloadSection(chunkX, chunkY, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storesBlocks() {
|
||||
return true;
|
||||
|
||||
+2
-1
@@ -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;
|
||||
|
||||
+306
-324
@@ -29,7 +29,6 @@ import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
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.api.type.types.Particle;
|
||||
@@ -83,19 +82,16 @@ public class WorldPackets {
|
||||
map(Type.VAR_INT); // 0 - Entity ID
|
||||
map(Type.UUID); // 1 - Entity UUID
|
||||
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
PaintingProvider provider = Via.getManager().getProviders().get(PaintingProvider.class);
|
||||
String motive = wrapper.read(Type.STRING);
|
||||
handler(wrapper -> {
|
||||
PaintingProvider provider = Via.getManager().getProviders().get(PaintingProvider.class);
|
||||
String motive = wrapper.read(Type.STRING);
|
||||
|
||||
Optional<Integer> id = provider.getIntByIdentifier(motive);
|
||||
Optional<Integer> id = provider.getIntByIdentifier(motive);
|
||||
|
||||
if (!id.isPresent() && (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug())) {
|
||||
Via.getPlatform().getLogger().warning("Could not find painting motive: " + motive + " falling back to default (0)");
|
||||
}
|
||||
wrapper.write(Type.VAR_INT, id.orElse(0));
|
||||
if (!id.isPresent() && (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug())) {
|
||||
Via.getPlatform().getLogger().warning("Could not find painting motive: " + motive + " falling back to default (0)");
|
||||
}
|
||||
wrapper.write(Type.VAR_INT, id.orElse(0));
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -107,27 +103,24 @@ public class WorldPackets {
|
||||
map(Type.UNSIGNED_BYTE); // 1 - Action
|
||||
map(Type.NBT); // 2 - NBT data
|
||||
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
Position position = wrapper.get(Type.POSITION, 0);
|
||||
short action = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
||||
CompoundTag tag = wrapper.get(Type.NBT, 0);
|
||||
handler(wrapper -> {
|
||||
Position position = wrapper.get(Type.POSITION, 0);
|
||||
short action = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
||||
CompoundTag tag = wrapper.get(Type.NBT, 0);
|
||||
|
||||
BlockEntityProvider provider = Via.getManager().getProviders().get(BlockEntityProvider.class);
|
||||
int newId = provider.transform(wrapper.user(), position, tag, true);
|
||||
BlockEntityProvider provider = Via.getManager().getProviders().get(BlockEntityProvider.class);
|
||||
int newId = provider.transform(wrapper.user(), position, tag, true);
|
||||
|
||||
if (newId != -1) {
|
||||
BlockStorage storage = wrapper.user().get(BlockStorage.class);
|
||||
BlockStorage.ReplacementData replacementData = storage.get(position);
|
||||
if (replacementData != null) {
|
||||
replacementData.setReplacement(newId);
|
||||
}
|
||||
if (newId != -1) {
|
||||
BlockStorage storage = wrapper.user().get(BlockStorage.class);
|
||||
BlockStorage.ReplacementData replacementData = storage.get(position);
|
||||
if (replacementData != null) {
|
||||
replacementData.setReplacement(newId);
|
||||
}
|
||||
}
|
||||
|
||||
if (action == 5) { // Set type of flower in flower pot
|
||||
wrapper.cancel(); // Removed
|
||||
}
|
||||
if (action == 5) { // Set type of flower in flower pot
|
||||
wrapper.cancel(); // Removed
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -140,43 +133,40 @@ public class WorldPackets {
|
||||
map(Type.UNSIGNED_BYTE); // Action Id
|
||||
map(Type.UNSIGNED_BYTE); // Action param
|
||||
map(Type.VAR_INT); // Block Id - /!\ NOT BLOCK STATE ID
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
Position pos = wrapper.get(Type.POSITION, 0);
|
||||
short action = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
||||
short param = wrapper.get(Type.UNSIGNED_BYTE, 1);
|
||||
int blockId = wrapper.get(Type.VAR_INT, 0);
|
||||
handler(wrapper -> {
|
||||
Position pos = wrapper.get(Type.POSITION, 0);
|
||||
short action = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
||||
short param = wrapper.get(Type.UNSIGNED_BYTE, 1);
|
||||
int blockId = wrapper.get(Type.VAR_INT, 0);
|
||||
|
||||
if (blockId == 25)
|
||||
blockId = 73;
|
||||
else if (blockId == 33)
|
||||
blockId = 99;
|
||||
else if (blockId == 29)
|
||||
blockId = 92;
|
||||
else if (blockId == 54)
|
||||
blockId = 142;
|
||||
else if (blockId == 146)
|
||||
blockId = 305;
|
||||
else if (blockId == 130)
|
||||
blockId = 249;
|
||||
else if (blockId == 138)
|
||||
blockId = 257;
|
||||
else if (blockId == 52)
|
||||
blockId = 140;
|
||||
else if (blockId == 209)
|
||||
blockId = 472;
|
||||
else if (blockId >= 219 && blockId <= 234)
|
||||
blockId = blockId - 219 + 483;
|
||||
if (blockId == 25)
|
||||
blockId = 73;
|
||||
else if (blockId == 33)
|
||||
blockId = 99;
|
||||
else if (blockId == 29)
|
||||
blockId = 92;
|
||||
else if (blockId == 54)
|
||||
blockId = 142;
|
||||
else if (blockId == 146)
|
||||
blockId = 305;
|
||||
else if (blockId == 130)
|
||||
blockId = 249;
|
||||
else if (blockId == 138)
|
||||
blockId = 257;
|
||||
else if (blockId == 52)
|
||||
blockId = 140;
|
||||
else if (blockId == 209)
|
||||
blockId = 472;
|
||||
else if (blockId >= 219 && blockId <= 234)
|
||||
blockId = blockId - 219 + 483;
|
||||
|
||||
if (blockId == 73) { // Note block
|
||||
PacketWrapper blockChange = wrapper.create(0x0B); // block change
|
||||
blockChange.write(Type.POSITION, pos);
|
||||
blockChange.write(Type.VAR_INT, 249 + (action * 24 * 2) + (param * 2));
|
||||
blockChange.send(Protocol1_13To1_12_2.class);
|
||||
}
|
||||
wrapper.set(Type.VAR_INT, 0, blockId);
|
||||
if (blockId == 73) { // Note block
|
||||
PacketWrapper blockChange = wrapper.create(0x0B); // block change
|
||||
blockChange.write(Type.POSITION, pos);
|
||||
blockChange.write(Type.VAR_INT, 249 + (action * 24 * 2) + (param * 2));
|
||||
blockChange.send(Protocol1_13To1_12_2.class);
|
||||
}
|
||||
wrapper.set(Type.VAR_INT, 0, blockId);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -186,27 +176,24 @@ public class WorldPackets {
|
||||
public void registerMap() {
|
||||
map(Type.POSITION);
|
||||
map(Type.VAR_INT);
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
Position position = wrapper.get(Type.POSITION, 0);
|
||||
int newId = toNewId(wrapper.get(Type.VAR_INT, 0));
|
||||
handler(wrapper -> {
|
||||
Position position = wrapper.get(Type.POSITION, 0);
|
||||
int newId = toNewId(wrapper.get(Type.VAR_INT, 0));
|
||||
|
||||
UserConnection userConnection = wrapper.user();
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), newId);
|
||||
newId = ConnectionData.connect(userConnection, position, newId);
|
||||
}
|
||||
wrapper.set(Type.VAR_INT, 0, checkStorage(wrapper.user(), position, newId));
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
ConnectionData.update(userConnection, position);
|
||||
}
|
||||
UserConnection userConnection = wrapper.user();
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), newId);
|
||||
newId = ConnectionData.connect(userConnection, position, newId);
|
||||
}
|
||||
wrapper.set(Type.VAR_INT, 0, checkStorage(wrapper.user(), position, newId));
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
ConnectionData.update(userConnection, position);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -217,56 +204,53 @@ public class WorldPackets {
|
||||
map(Type.INT); // 0 - Chunk X
|
||||
map(Type.INT); // 1 - Chunk Z
|
||||
map(Type.BLOCK_CHANGE_RECORD_ARRAY); // 2 - Records
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
int chunkX = wrapper.get(Type.INT, 0);
|
||||
int chunkZ = wrapper.get(Type.INT, 1);
|
||||
UserConnection userConnection = wrapper.user();
|
||||
BlockChangeRecord[] records = wrapper.get(Type.BLOCK_CHANGE_RECORD_ARRAY, 0);
|
||||
// Convert ids
|
||||
handler(wrapper -> {
|
||||
int chunkX = wrapper.get(Type.INT, 0);
|
||||
int chunkZ = wrapper.get(Type.INT, 1);
|
||||
UserConnection userConnection = wrapper.user();
|
||||
BlockChangeRecord[] records = wrapper.get(Type.BLOCK_CHANGE_RECORD_ARRAY, 0);
|
||||
// Convert ids
|
||||
for (BlockChangeRecord record : records) {
|
||||
int newBlock = toNewId(record.getBlockId());
|
||||
Position position = new Position(
|
||||
record.getSectionX() + (chunkX * 16),
|
||||
record.getY(),
|
||||
record.getSectionZ() + (chunkZ * 16));
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), newBlock);
|
||||
}
|
||||
record.setBlockId(checkStorage(wrapper.user(), position, newBlock));
|
||||
}
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
for (BlockChangeRecord record : records) {
|
||||
int newBlock = toNewId(record.getBlockId());
|
||||
int blockState = record.getBlockId();
|
||||
|
||||
Position position = new Position(
|
||||
record.getSectionX() + (chunkX * 16),
|
||||
record.getY(),
|
||||
record.getSectionZ() + (chunkZ * 16));
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), newBlock);
|
||||
}
|
||||
record.setBlockId(checkStorage(wrapper.user(), position, newBlock));
|
||||
}
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
for (BlockChangeRecord record : records) {
|
||||
int blockState = record.getBlockId();
|
||||
|
||||
Position position = new Position(
|
||||
record.getSectionX() + (chunkX * 16),
|
||||
record.getY(),
|
||||
record.getSectionZ() + (chunkZ * 16));
|
||||
|
||||
ConnectionHandler handler = ConnectionData.getConnectionHandler(blockState);
|
||||
if (handler != null) {
|
||||
blockState = handler.connect(userConnection, position, blockState);
|
||||
record.setBlockId(blockState);
|
||||
}
|
||||
}
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
|
||||
for (BlockChangeRecord record : records) {
|
||||
Position position = new Position(
|
||||
record.getSectionX() + (chunkX * 16),
|
||||
record.getY(),
|
||||
record.getSectionZ() + (chunkZ * 16));
|
||||
ConnectionData.update(userConnection, position);
|
||||
ConnectionHandler handler = ConnectionData.getConnectionHandler(blockState);
|
||||
if (handler != null) {
|
||||
blockState = handler.connect(userConnection, position, blockState);
|
||||
record.setBlockId(blockState);
|
||||
}
|
||||
}
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
|
||||
for (BlockChangeRecord record : records) {
|
||||
Position position = new Position(
|
||||
record.getSectionX() + (chunkX * 16),
|
||||
record.getY(),
|
||||
record.getSectionZ() + (chunkZ * 16));
|
||||
ConnectionData.update(userConnection, position);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -283,34 +267,31 @@ public class WorldPackets {
|
||||
map(Type.FLOAT); // Radius
|
||||
map(Type.INT); // Record Count
|
||||
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
UserConnection userConnection = wrapper.user();
|
||||
int x = (int) Math.floor(wrapper.get(Type.FLOAT, 0));
|
||||
int y = (int) Math.floor(wrapper.get(Type.FLOAT, 1));
|
||||
int z = (int) Math.floor(wrapper.get(Type.FLOAT, 2));
|
||||
int recordCount = wrapper.get(Type.INT, 0);
|
||||
Position[] records = new Position[recordCount];
|
||||
handler(wrapper -> {
|
||||
UserConnection userConnection = wrapper.user();
|
||||
int x = (int) Math.floor(wrapper.get(Type.FLOAT, 0));
|
||||
int y = (int) Math.floor(wrapper.get(Type.FLOAT, 1));
|
||||
int z = (int) Math.floor(wrapper.get(Type.FLOAT, 2));
|
||||
int recordCount = wrapper.get(Type.INT, 0);
|
||||
Position[] records = new Position[recordCount];
|
||||
|
||||
for (int i = 0; i < recordCount; i++) {
|
||||
Position position = new Position(
|
||||
x + wrapper.passthrough(Type.BYTE),
|
||||
(short) (y + wrapper.passthrough(Type.BYTE)),
|
||||
z + wrapper.passthrough(Type.BYTE));
|
||||
records[i] = position;
|
||||
for (int i = 0; i < recordCount; i++) {
|
||||
Position position = new Position(
|
||||
x + wrapper.passthrough(Type.BYTE),
|
||||
(short) (y + wrapper.passthrough(Type.BYTE)),
|
||||
z + wrapper.passthrough(Type.BYTE));
|
||||
records[i] = position;
|
||||
|
||||
// Set to air
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), 0);
|
||||
}
|
||||
// Set to air
|
||||
ConnectionData.updateBlockStorage(userConnection, position.x(), position.y(), position.z(), 0);
|
||||
}
|
||||
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
|
||||
for (int i = 0; i < recordCount; i++) {
|
||||
ConnectionData.update(userConnection, records[i]);
|
||||
}
|
||||
for (int i = 0; i < recordCount; i++) {
|
||||
ConnectionData.update(userConnection, records[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -320,13 +301,10 @@ public class WorldPackets {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
int x = wrapper.passthrough(Type.INT);
|
||||
int z = wrapper.passthrough(Type.INT);
|
||||
ConnectionData.blockConnectionProvider.unloadChunk(wrapper.user(), x, z);
|
||||
}
|
||||
handler(wrapper -> {
|
||||
int x = wrapper.passthrough(Type.INT);
|
||||
int z = wrapper.passthrough(Type.INT);
|
||||
ConnectionData.blockConnectionProvider.unloadChunk(wrapper.user(), x, z);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -336,13 +314,10 @@ public class WorldPackets {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
map(Type.STRING);
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
String sound = wrapper.get(Type.STRING, 0).replace("minecraft:", "");
|
||||
String newSoundId = NamedSoundRewriter.getNewId(sound);
|
||||
wrapper.set(Type.STRING, 0, newSoundId);
|
||||
}
|
||||
handler(wrapper -> {
|
||||
String sound = wrapper.get(Type.STRING, 0).replace("minecraft:", "");
|
||||
String newSoundId = NamedSoundRewriter.getNewId(sound);
|
||||
wrapper.set(Type.STRING, 0, newSoundId);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -350,218 +325,225 @@ public class WorldPackets {
|
||||
protocol.registerClientbound(ClientboundPackets1_12_1.CHUNK_DATA, new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
|
||||
BlockStorage storage = wrapper.user().get(BlockStorage.class);
|
||||
handler(wrapper -> {
|
||||
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
|
||||
BlockStorage storage = wrapper.user().get(BlockStorage.class);
|
||||
|
||||
Chunk1_9_3_4Type type = new Chunk1_9_3_4Type(clientWorld);
|
||||
Chunk1_13Type type1_13 = new Chunk1_13Type(clientWorld);
|
||||
Chunk chunk = wrapper.read(type);
|
||||
wrapper.write(type1_13, chunk);
|
||||
Chunk1_9_3_4Type type = new Chunk1_9_3_4Type(clientWorld);
|
||||
Chunk1_13Type type1_13 = new Chunk1_13Type(clientWorld);
|
||||
Chunk chunk = wrapper.read(type);
|
||||
wrapper.write(type1_13, chunk);
|
||||
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
if (section == null)
|
||||
continue;
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
if (section == null)
|
||||
continue;
|
||||
|
||||
for (int p = 0; p < section.getPaletteSize(); p++) {
|
||||
int old = section.getPaletteEntry(p);
|
||||
int newId = toNewId(old);
|
||||
section.setPaletteEntry(p, newId);
|
||||
}
|
||||
for (int p = 0; p < section.getPaletteSize(); p++) {
|
||||
int old = section.getPaletteEntry(p);
|
||||
int newId = toNewId(old);
|
||||
section.setPaletteEntry(p, newId);
|
||||
}
|
||||
|
||||
boolean willSaveToStorage = false;
|
||||
for (int p = 0; p < section.getPaletteSize(); p++) {
|
||||
int newId = section.getPaletteEntry(p);
|
||||
if (storage.isWelcome(newId)) {
|
||||
willSaveToStorage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean willSaveConnection = false;
|
||||
if (Via.getConfig().isServersideBlockConnections() && ConnectionData.needStoreBlocks()) {
|
||||
for (int p = 0; p < section.getPaletteSize(); p++) {
|
||||
int newId = section.getPaletteEntry(p);
|
||||
if (ConnectionData.isWelcome(newId)) {
|
||||
willSaveConnection = true;
|
||||
storage:
|
||||
{
|
||||
if (chunk.isFullChunk()) {
|
||||
boolean willSave = false;
|
||||
for (int j = 0; j < section.getPaletteSize(); j++) {
|
||||
if (storage.isWelcome(section.getPaletteEntry(j))) {
|
||||
willSave = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!willSave) break storage;
|
||||
}
|
||||
|
||||
if (willSaveToStorage) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int block = section.getFlatBlock(x, y, z);
|
||||
if (storage.isWelcome(block)) {
|
||||
storage.store(new Position(
|
||||
(x + (chunk.getX() << 4)),
|
||||
(short) (y + (i << 4)),
|
||||
(z + (chunk.getZ() << 4))
|
||||
), block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (willSaveConnection) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int block = section.getFlatBlock(x, y, z);
|
||||
if (ConnectionData.isWelcome(block)) {
|
||||
ConnectionData.blockConnectionProvider.storeBlock(wrapper.user(), x + (chunk.getX() << 4),
|
||||
y + (i << 4),
|
||||
z + (chunk.getZ() << 4),
|
||||
block);
|
||||
}
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int block = section.getFlatBlock(x, y, z);
|
||||
Position pos = new Position(
|
||||
(x + (chunk.getX() << 4)),
|
||||
(y + (i << 4)),
|
||||
(z + (chunk.getZ() << 4))
|
||||
);
|
||||
if (storage.isWelcome(block)) {
|
||||
storage.store(pos, block);
|
||||
} else if (!chunk.isFullChunk()) { // Update
|
||||
storage.remove(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite biome id 255 to plains
|
||||
if (chunk.isBiomeData()) {
|
||||
int latestBiomeWarn = Integer.MIN_VALUE;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
int biome = chunk.getBiomeData()[i];
|
||||
if (!VALID_BIOMES.contains(biome)) {
|
||||
if (biome != 255 // is it generated naturally? *shrug*
|
||||
&& latestBiomeWarn != biome) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
||||
Via.getPlatform().getLogger().warning("Received invalid biome id " + biome);
|
||||
save_connections:
|
||||
{
|
||||
if (!Via.getConfig().isServersideBlockConnections()
|
||||
|| !ConnectionData.needStoreBlocks()) break save_connections;
|
||||
|
||||
if (!chunk.isFullChunk()) { // Update
|
||||
ConnectionData.blockConnectionProvider.unloadChunkSection(wrapper.user(), chunk.getX(), i, chunk.getZ());
|
||||
}
|
||||
boolean willSave = false;
|
||||
for (int j = 0; j < section.getPaletteSize(); j++) {
|
||||
if (ConnectionData.isWelcome(section.getPaletteEntry(j))) {
|
||||
willSave = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!willSave) break save_connections;
|
||||
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int block = section.getFlatBlock(x, y, z);
|
||||
if (ConnectionData.isWelcome(block)) {
|
||||
int globalX = x + (chunk.getX() << 4);
|
||||
int globalY = y + (i << 4);
|
||||
int globalZ = z + (chunk.getZ() << 4);
|
||||
ConnectionData.blockConnectionProvider.storeBlock(wrapper.user(), globalX,
|
||||
globalY, globalZ, block);
|
||||
}
|
||||
latestBiomeWarn = biome;
|
||||
}
|
||||
chunk.getBiomeData()[i] = 1; // Plains
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite BlockEntities to normal blocks
|
||||
BlockEntityProvider provider = Via.getManager().getProviders().get(BlockEntityProvider.class);
|
||||
final Iterator<CompoundTag> iterator = chunk.getBlockEntities().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
CompoundTag tag = iterator.next();
|
||||
int newId = provider.transform(wrapper.user(), null, tag, false);
|
||||
if (newId != -1) {
|
||||
int x = ((NumberTag) tag.get("x")).asInt();
|
||||
int y = ((NumberTag) tag.get("y")).asInt();
|
||||
int z = ((NumberTag) tag.get("z")).asInt();
|
||||
|
||||
Position position = new Position(x, (short) y, z);
|
||||
// Store the replacement blocks for blockupdates
|
||||
BlockStorage.ReplacementData replacementData = storage.get(position);
|
||||
if (replacementData != null) {
|
||||
replacementData.setReplacement(newId);
|
||||
}
|
||||
|
||||
chunk.getSections()[y >> 4].setFlatBlock(x & 0xF, y & 0xF, z & 0xF, newId);
|
||||
}
|
||||
|
||||
final Tag idTag = tag.get("id");
|
||||
if (idTag instanceof StringTag) {
|
||||
// No longer block entities
|
||||
final String id = ((StringTag) idTag).getValue();
|
||||
if (id.equals("minecraft:noteblock") || id.equals("minecraft:flower_pot")) {
|
||||
iterator.remove();
|
||||
// Rewrite biome id 255 to plains
|
||||
if (chunk.isBiomeData()) {
|
||||
int latestBiomeWarn = Integer.MIN_VALUE;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
int biome = chunk.getBiomeData()[i];
|
||||
if (!VALID_BIOMES.contains(biome)) {
|
||||
if (biome != 255 // is it generated naturally? *shrug*
|
||||
&& latestBiomeWarn != biome) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
||||
Via.getPlatform().getLogger().warning("Received invalid biome id " + biome);
|
||||
}
|
||||
latestBiomeWarn = biome;
|
||||
}
|
||||
chunk.getBiomeData()[i] = 1; // Plains
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
ConnectionData.connectBlocks(wrapper.user(), chunk);
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
if (section == null) continue;
|
||||
ConnectionData.updateChunkSectionNeighbours(wrapper.user(), chunk.getX(), chunk.getZ(), i);
|
||||
// Rewrite BlockEntities to normal blocks
|
||||
BlockEntityProvider provider = Via.getManager().getProviders().get(BlockEntityProvider.class);
|
||||
final Iterator<CompoundTag> iterator = chunk.getBlockEntities().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
CompoundTag tag = iterator.next();
|
||||
int newId = provider.transform(wrapper.user(), null, tag, false);
|
||||
if (newId != -1) {
|
||||
int x = ((NumberTag) tag.get("x")).asInt();
|
||||
int y = ((NumberTag) tag.get("y")).asInt();
|
||||
int z = ((NumberTag) tag.get("z")).asInt();
|
||||
|
||||
Position position = new Position(x, (short) y, z);
|
||||
// Store the replacement blocks for blockupdates
|
||||
BlockStorage.ReplacementData replacementData = storage.get(position);
|
||||
if (replacementData != null) {
|
||||
replacementData.setReplacement(newId);
|
||||
}
|
||||
|
||||
chunk.getSections()[y >> 4].setFlatBlock(x & 0xF, y & 0xF, z & 0xF, newId);
|
||||
}
|
||||
|
||||
final Tag idTag = tag.get("id");
|
||||
if (idTag instanceof StringTag) {
|
||||
// No longer block entities
|
||||
final String id = ((StringTag) idTag).getValue();
|
||||
if (id.equals("minecraft:noteblock") || id.equals("minecraft:flower_pot")) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
ConnectionData.connectBlocks(wrapper.user(), chunk);
|
||||
// Workaround for packet order issue
|
||||
wrapper.send(Protocol1_13To1_12_2.class);
|
||||
wrapper.cancel();
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
if (section == null) continue;
|
||||
ConnectionData.updateChunkSectionNeighbours(wrapper.user(), chunk.getX(), chunk.getZ(), i);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_12_1.SPAWN_PARTICLE, new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
map(Type.INT); // 0 - Particle ID
|
||||
map(Type.BOOLEAN); // 1 - Long Distance
|
||||
map(Type.FLOAT); // 2 - X
|
||||
map(Type.FLOAT); // 3 - Y
|
||||
map(Type.FLOAT); // 4 - Z
|
||||
map(Type.FLOAT); // 5 - Offset X
|
||||
map(Type.FLOAT); // 6 - Offset Y
|
||||
map(Type.FLOAT); // 7 - Offset Z
|
||||
map(Type.FLOAT); // 8 - Particle Data
|
||||
map(Type.INT); // 9 - Particle Count
|
||||
protocol.registerClientbound(ClientboundPackets1_12_1.SPAWN_PARTICLE, new
|
||||
|
||||
handler(new PacketHandler() {
|
||||
PacketRemapper() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
int particleId = wrapper.get(Type.INT, 0);
|
||||
public void registerMap() {
|
||||
map(Type.INT); // 0 - Particle ID
|
||||
map(Type.BOOLEAN); // 1 - Long Distance
|
||||
map(Type.FLOAT); // 2 - X
|
||||
map(Type.FLOAT); // 3 - Y
|
||||
map(Type.FLOAT); // 4 - Z
|
||||
map(Type.FLOAT); // 5 - Offset X
|
||||
map(Type.FLOAT); // 6 - Offset Y
|
||||
map(Type.FLOAT); // 7 - Offset Z
|
||||
map(Type.FLOAT); // 8 - Particle Data
|
||||
map(Type.INT); // 9 - Particle Count
|
||||
|
||||
// Get the data (Arrays are overrated)
|
||||
int dataCount = 0;
|
||||
// Particles with 1 data [BlockCrack,BlockDust,FallingDust]
|
||||
if (particleId == 37 || particleId == 38 || particleId == 46)
|
||||
dataCount = 1;
|
||||
// Particles with 2 data [IconCrack]
|
||||
else if (particleId == 36)
|
||||
dataCount = 2;
|
||||
handler(wrapper -> {
|
||||
int particleId = wrapper.get(Type.INT, 0);
|
||||
|
||||
Integer[] data = new Integer[dataCount];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = wrapper.read(Type.VAR_INT);
|
||||
// Get the data (Arrays are overrated)
|
||||
int dataCount = 0;
|
||||
// Particles with 1 data [BlockCrack,BlockDust,FallingDust]
|
||||
if (particleId == 37 || particleId == 38 || particleId == 46)
|
||||
dataCount = 1;
|
||||
// Particles with 2 data [IconCrack]
|
||||
else if (particleId == 36)
|
||||
dataCount = 2;
|
||||
|
||||
Particle particle = ParticleRewriter.rewriteParticle(particleId, data);
|
||||
Integer[] data = new Integer[dataCount];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = wrapper.read(Type.VAR_INT);
|
||||
|
||||
// Cancel if null or completely removed
|
||||
if (particle == null || particle.getId() == -1) {
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
Particle particle = ParticleRewriter.rewriteParticle(particleId, data);
|
||||
|
||||
//Handle reddust particle color
|
||||
if (particle.getId() == 11) {
|
||||
int count = wrapper.get(Type.INT, 1);
|
||||
float speed = wrapper.get(Type.FLOAT, 6);
|
||||
// Only handle for count = 0
|
||||
if (count == 0) {
|
||||
wrapper.set(Type.INT, 1, 1);
|
||||
wrapper.set(Type.FLOAT, 6, 0f);
|
||||
// Cancel if null or completely removed
|
||||
if (particle == null || particle.getId() == -1) {
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
List<Particle.ParticleData> arguments = particle.getArguments();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
//RGB values are represented by the X/Y/Z offset
|
||||
float colorValue = wrapper.get(Type.FLOAT, i + 3) * speed;
|
||||
if (colorValue == 0 && i == 0) {
|
||||
// https://minecraft.gamepedia.com/User:Alphappy/reddust
|
||||
colorValue = 1;
|
||||
//Handle reddust particle color
|
||||
if (particle.getId() == 11) {
|
||||
int count = wrapper.get(Type.INT, 1);
|
||||
float speed = wrapper.get(Type.FLOAT, 6);
|
||||
// Only handle for count = 0
|
||||
if (count == 0) {
|
||||
wrapper.set(Type.INT, 1, 1);
|
||||
wrapper.set(Type.FLOAT, 6, 0f);
|
||||
|
||||
List<Particle.ParticleData> arguments = particle.getArguments();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
//RGB values are represented by the X/Y/Z offset
|
||||
float colorValue = wrapper.get(Type.FLOAT, i + 3) * speed;
|
||||
if (colorValue == 0 && i == 0) {
|
||||
// https://minecraft.gamepedia.com/User:Alphappy/reddust
|
||||
colorValue = 1;
|
||||
}
|
||||
arguments.get(i).setValue(colorValue);
|
||||
wrapper.set(Type.FLOAT, i + 3, 0f);
|
||||
}
|
||||
arguments.get(i).setValue(colorValue);
|
||||
wrapper.set(Type.FLOAT, i + 3, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrapper.set(Type.INT, 0, particle.getId());
|
||||
for (Particle.ParticleData particleData : particle.getArguments())
|
||||
wrapper.write(particleData.getType(), particleData.getValue());
|
||||
wrapper.set(Type.INT, 0, particle.getId());
|
||||
for (Particle.ParticleData particleData : particle.getArguments())
|
||||
wrapper.write(particleData.getType(), particleData.getValue());
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static int toNewId(int oldId) {
|
||||
|
||||
+6
-2
@@ -111,11 +111,15 @@ public class BlockConnectionStorage implements StorableObject {
|
||||
}
|
||||
|
||||
public void unloadChunk(int x, int z) {
|
||||
for (int y = 0; y < 256; y += 16) {
|
||||
blockStorage.remove(getChunkSectionIndex(x << 4, y, z << 4));
|
||||
for (int y = 0; y < 16; y ++) {
|
||||
unloadSection(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadSection(int x, int y, int z) {
|
||||
blockStorage.remove(getChunkSectionIndex(x << 4, y << 4, z << 4));
|
||||
}
|
||||
|
||||
private Pair<byte[], NibbleArray> getChunkSection(long index, boolean requireNibbleArray) {
|
||||
Pair<byte[], NibbleArray> map = blockStorage.get(index);
|
||||
if (map == null) {
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.google.gson.JsonElement;
|
||||
|
||||
public final class ChatDecorationResult {
|
||||
|
||||
private final JsonElement content;
|
||||
private final boolean overlay;
|
||||
|
||||
public ChatDecorationResult(final JsonElement content, final boolean overlay) {
|
||||
this.content = content;
|
||||
this.overlay = overlay;
|
||||
}
|
||||
|
||||
public JsonElement content() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public boolean overlay() {
|
||||
return overlay;
|
||||
}
|
||||
}
|
||||
+142
@@ -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();
|
||||
}
|
||||
}
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* 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 chatTypeId = 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);
|
||||
|
||||
final CompoundTag chatType = wrapper.user().get(ChatTypeStorage.class).chatType(chatTypeId);
|
||||
final ChatDecorationResult decorationResult = decorateChatMessage(chatType, chatTypeId, senderName, teamName, unsignedContent != null ? unsignedContent : signedContent);
|
||||
if (decorationResult == null) {
|
||||
wrapper.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
wrapper.write(Type.COMPONENT, decorationResult.content());
|
||||
wrapper.write(Type.BOOLEAN, decorationResult.overlay());
|
||||
});
|
||||
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());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
registerClientbound(State.LOGIN, ClientboundLoginPackets.CUSTOM_QUERY.getId(), ClientboundLoginPackets.CUSTOM_QUERY.getId(), new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
map(Type.VAR_INT);
|
||||
map(Type.STRING);
|
||||
handler(wrapper -> {
|
||||
String identifier = wrapper.get(Type.STRING, 0);
|
||||
if (identifier.equals("velocity:player_info")) {
|
||||
byte[] data = wrapper.passthrough(Type.REMAINING_BYTES);
|
||||
// Velocity modern forwarding version above 1 includes the players public key.
|
||||
// This is an issue because the server will expect a 1.19 key and receive a 1.19.1 key.
|
||||
// Velocity modern forwarding versions: https://github.com/PaperMC/Velocity/blob/1a3fba4250553702d9dcd05731d04347bfc24c9f/proxy/src/main/java/com/velocitypowered/proxy/connection/VelocityConstants.java#L27-L29
|
||||
// And the version can be specified with a single byte: https://github.com/PaperMC/Velocity/blob/1a3fba4250553702d9dcd05731d04347bfc24c9f/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java#L88
|
||||
if (data.length == 1 && data[0] > 1) {
|
||||
data[0] = 1;
|
||||
} else if (data.length == 0) { // Or the version is omitted (default version would be used)
|
||||
data = new byte[]{1};
|
||||
wrapper.set(Type.REMAINING_BYTES, 0, data);
|
||||
} else {
|
||||
Via.getPlatform().getLogger().warning("Received unexpected data in velocity:player_info (length=" + data.length + ")");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final UserConnection connection) {
|
||||
connection.put(new ChatTypeStorage());
|
||||
}
|
||||
|
||||
public static @Nullable ChatDecorationResult decorateChatMessage(final CompoundTag chatType, final int chatTypeId, final JsonElement senderName, @Nullable final JsonElement teamName, final JsonElement message) {
|
||||
if (chatType == null) {
|
||||
Via.getPlatform().getLogger().warning("Chat message has unknown chat type id " + chatTypeId + ". Message: " + message);
|
||||
return null;
|
||||
}
|
||||
|
||||
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 null;
|
||||
}
|
||||
|
||||
overlay = true;
|
||||
}
|
||||
|
||||
final CompoundTag decoaration = chatData.get("decoration");
|
||||
if (decoaration == null) {
|
||||
return new ChatDecorationResult(message, overlay);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return new ChatDecorationResult(GsonComponentSerializer.gson().serializeToTree(componentBuilder.build()), overlay);
|
||||
}
|
||||
}
|
||||
+85
@@ -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();
|
||||
}
|
||||
}
|
||||
+47
@@ -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;
|
||||
}
|
||||
}
|
||||
+34
@@ -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;
|
||||
}
|
||||
}
|
||||
+53
-37
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
+59
@@ -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);
|
||||
}
|
||||
}
|
||||
+24
-16
@@ -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" +
|
||||
@@ -73,7 +75,7 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
private static final CompoundTag CHAT_REGISTRY;
|
||||
public static final CompoundTag CHAT_REGISTRY;
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -149,7 +151,7 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
|
||||
final PacketWrapper metaPacket = wrapper.create(ClientboundPackets1_19.ENTITY_METADATA);
|
||||
metaPacket.write(Type.VAR_INT, wrapper.get(Type.VAR_INT, 0)); // Entity id
|
||||
final List<Metadata> metadata = new ArrayList<>();
|
||||
metadata.add(new Metadata(8, Types1_19.META_TYPES.paintingVariantType, protocol.getMappingData().getPaintingMappings().getNewId(motive)));
|
||||
metadata.add(new Metadata(8, Types1_19.META_TYPES.paintingVariantType, protocol.getMappingData().getPaintingMappings().getNewIdOrDefault(motive, 0)));
|
||||
metaPacket.write(Types1_19.METADATA_LIST, metadata);
|
||||
metaPacket.send(Protocol1_19To1_18_2.class);
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
@@ -244,7 +245,7 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
|
||||
// Disable the chat preview
|
||||
final PacketWrapper displayPreviewPacket = wrapper.create(ClientboundPackets1_19.SET_DISPLAY_CHAT_PREVIEW);
|
||||
displayPreviewPacket.write(Type.BOOLEAN, false);
|
||||
displayPreviewPacket.send(Protocol1_19To1_18_2.class);
|
||||
displayPreviewPacket.scheduleSend(Protocol1_19To1_18_2.class);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
+33
-10
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
+34
@@ -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);
|
||||
}
|
||||
}
|
||||
+40
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -446,10 +446,10 @@ public abstract class EntityRewriter<T extends Protocol> extends RewriterBase<T>
|
||||
public PacketHandler worldDataTrackerHandlerByKey() {
|
||||
return wrapper -> {
|
||||
EntityTracker tracker = tracker(wrapper.user());
|
||||
String key = wrapper.get(Type.STRING, 0);
|
||||
DimensionData dimensionData = tracker.dimensionData(key);
|
||||
String dimensionKey = wrapper.get(Type.STRING, 0);
|
||||
DimensionData dimensionData = tracker.dimensionData(dimensionKey);
|
||||
if (dimensionData == null) {
|
||||
Via.getPlatform().getLogger().severe("Dimension data missing for dimension: " + key + ", falling back to overworld");
|
||||
Via.getPlatform().getLogger().severe("Dimension data missing for dimension: " + dimensionKey + ", falling back to overworld");
|
||||
dimensionData = tracker.dimensionData("minecraft:overworld");
|
||||
Preconditions.checkNotNull(dimensionData, "Overworld data missing");
|
||||
}
|
||||
@@ -457,7 +457,7 @@ public abstract class EntityRewriter<T extends Protocol> extends RewriterBase<T>
|
||||
tracker.setCurrentWorldSectionHeight(dimensionData.height() >> 4);
|
||||
tracker.setCurrentMinY(dimensionData.minY());
|
||||
|
||||
String world = wrapper.get(Type.STRING, 0);
|
||||
String world = wrapper.get(Type.STRING, 1);
|
||||
if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) {
|
||||
tracker.clearEntities();
|
||||
tracker.trackClientEntity();
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
+8
-6
@@ -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,14 +103,13 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Reason {
|
||||
|
||||
public static final String DANGEROUS_SERVER_SOFTWARE = "You are using server software that - outside of possibly breaking ViaVersion - can also cause severe damage to your server's integrity as a whole.";
|
||||
public static final String BREAKING_PROXY_SOFTWARE = "You are using proxy software that intentionally breaks ViaVersion. Please use another proxy software or move ViaVersion to each backend server instead of the proxy.";
|
||||
}
|
||||
}
|
||||
@@ -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,8 +18,6 @@
|
||||
package com.viaversion.viaversion.util;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
@@ -28,19 +26,23 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CommentStore {
|
||||
private final Map<String, List<String>> headers = Maps.newConcurrentMap();
|
||||
private final char pathSeperator;
|
||||
private final Map<String, List<String>> headers = new HashMap<>();
|
||||
private final String pathSeparator;
|
||||
private final String pathSeparatorQuoted;
|
||||
private final int indents;
|
||||
private List<String> mainHeader = Lists.newArrayList();
|
||||
private List<String> mainHeader = new ArrayList<>();
|
||||
|
||||
public CommentStore(char pathSeperator, int indents) {
|
||||
this.pathSeperator = pathSeperator;
|
||||
public CommentStore(final char pathSeparator, final int indents) {
|
||||
this.pathSeparator = Character.toString(pathSeparator);
|
||||
this.pathSeparatorQuoted = Pattern.quote(this.pathSeparator);
|
||||
this.indents = indents;
|
||||
}
|
||||
|
||||
@@ -49,7 +51,7 @@ public class CommentStore {
|
||||
*
|
||||
* @param header header
|
||||
*/
|
||||
public void mainHeader(String... header) {
|
||||
public void mainHeader(final String... header) {
|
||||
mainHeader = Arrays.asList(header);
|
||||
}
|
||||
|
||||
@@ -68,8 +70,7 @@ public class CommentStore {
|
||||
* @param key of option (or section)
|
||||
* @param header of option (or section)
|
||||
*/
|
||||
public void header(String key, String... header) {
|
||||
// String value = Joiner.on('\n').join(header);
|
||||
public void header(final String key, final String... header) {
|
||||
headers.put(key, Arrays.asList(header));
|
||||
}
|
||||
|
||||
@@ -79,126 +80,181 @@ public class CommentStore {
|
||||
* @param key of option (or section)
|
||||
* @return Header
|
||||
*/
|
||||
public List<String> header(String key) {
|
||||
public List<String> header(final String key) {
|
||||
return headers.get(key);
|
||||
}
|
||||
|
||||
public void storeComments(InputStream inputStream) throws IOException {
|
||||
InputStreamReader reader = new InputStreamReader(inputStream);
|
||||
String contents;
|
||||
try {
|
||||
contents = CharStreams.toString(reader);
|
||||
} finally {
|
||||
reader.close();
|
||||
public void storeComments(final InputStream inputStream) throws IOException {
|
||||
final String data;
|
||||
try (final InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||
data = CharStreams.toString(reader);
|
||||
}
|
||||
StringBuilder memoryData = new StringBuilder();
|
||||
// Parse headers
|
||||
final String pathSeparator = Character.toString(this.pathSeperator);
|
||||
|
||||
final List<String> currentComments = new ArrayList<>();
|
||||
boolean header = true;
|
||||
boolean multiLineValue = false;
|
||||
int currentIndents = 0;
|
||||
String key = "";
|
||||
List<String> headers = Lists.newArrayList();
|
||||
for (String line : contents.split("\n")) {
|
||||
if (line.isEmpty()) continue; // Skip empty lines
|
||||
int indent = getSuccessiveCharCount(line, ' ');
|
||||
String subline = indent > 0 ? line.substring(indent) : line;
|
||||
if (subline.startsWith("#")) {
|
||||
if (subline.startsWith("#>")) {
|
||||
String txt = subline.startsWith("#> ") ? subline.substring(3) : subline.substring(2);
|
||||
mainHeader.add(txt);
|
||||
continue; // Main header, handled by bukkit
|
||||
}
|
||||
|
||||
// Add header to list
|
||||
String txt = subline.startsWith("# ") ? subline.substring(2) : subline.substring(1);
|
||||
headers.add(txt);
|
||||
for (final String line : data.split("\n")) {
|
||||
final String s = line.trim();
|
||||
// It's a comment!
|
||||
if (s.startsWith("#")) {
|
||||
currentComments.add(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
int indents = indent / this.indents;
|
||||
if (indents <= currentIndents) {
|
||||
// Remove last section of key
|
||||
String[] array = key.split(Pattern.quote(pathSeparator));
|
||||
int backspace = currentIndents - indents + 1;
|
||||
key = join(array, this.pathSeperator, 0, array.length - backspace);
|
||||
// Header is over - save it!
|
||||
if (header) {
|
||||
if (!currentComments.isEmpty()) {
|
||||
currentComments.add("");
|
||||
mainHeader.addAll(currentComments);
|
||||
currentComments.clear();
|
||||
}
|
||||
header = false;
|
||||
}
|
||||
|
||||
// Add new section to key
|
||||
String separator = key.length() > 0 ? pathSeparator : "";
|
||||
String lineKey = line.contains(":") ? line.split(Pattern.quote(":"))[0] : line;
|
||||
key += separator + lineKey.substring(indent);
|
||||
// Save empty lines as well
|
||||
if (s.isEmpty()) {
|
||||
currentComments.add(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Multi line values?
|
||||
if (s.startsWith("- |")) {
|
||||
multiLineValue = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
final int indent = getIndents(line);
|
||||
final int indents = indent / this.indents;
|
||||
// Check if the multi line value is over
|
||||
if (multiLineValue) {
|
||||
if (indents > currentIndents) continue;
|
||||
|
||||
multiLineValue = false;
|
||||
}
|
||||
|
||||
// Check if this is a level lower
|
||||
if (indents <= currentIndents) {
|
||||
final String[] array = key.split(pathSeparatorQuoted);
|
||||
final int backspace = currentIndents - indents + 1;
|
||||
final int delta = array.length - backspace;
|
||||
key = delta >= 0 ? join(array, delta) : key;
|
||||
}
|
||||
|
||||
// Finish current key
|
||||
final String separator = key.isEmpty() ? "" : this.pathSeparator;
|
||||
final String lineKey = line.indexOf(':') != -1 ? line.split(Pattern.quote(":"))[0] : line;
|
||||
key += separator + lineKey.substring(indent);
|
||||
currentIndents = indents;
|
||||
|
||||
memoryData.append(line).append('\n');
|
||||
if (!headers.isEmpty()) {
|
||||
this.headers.put(key, headers);
|
||||
headers = Lists.newArrayList();
|
||||
if (!currentComments.isEmpty()) {
|
||||
headers.put(key, new ArrayList<>(currentComments));
|
||||
currentComments.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeComments(String yaml, File output) throws IOException {
|
||||
// Custom save
|
||||
final int indentLength = this.indents;
|
||||
final String pathSeparator = Character.toString(this.pathSeperator);
|
||||
StringBuilder fileData = new StringBuilder();
|
||||
int currentIndents = 0;
|
||||
String key = "";
|
||||
for (String h : mainHeader) {
|
||||
// Append main header to top of file
|
||||
fileData.append("#> ").append(h).append('\n');
|
||||
public void writeComments(final String rawYaml, final File output) throws IOException {
|
||||
final StringBuilder fileData = new StringBuilder();
|
||||
for (final String mainHeaderLine : mainHeader) {
|
||||
fileData.append(mainHeaderLine).append('\n');
|
||||
}
|
||||
|
||||
for (String line : yaml.split("\n")) {
|
||||
if (line.isEmpty() || line.trim().charAt(0) == '-') {
|
||||
// Remove last new line
|
||||
fileData.deleteCharAt(fileData.length() - 1);
|
||||
|
||||
int currentKeyIndents = 0;
|
||||
String key = "";
|
||||
for (final String line : rawYaml.split("\n")) {
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int indent = getIndents(line);
|
||||
final int indents = indent / this.indents;
|
||||
final boolean keyLine;
|
||||
final String substring = line.substring(indent);
|
||||
if (substring.trim().isEmpty() || substring.charAt(0) == '-') {
|
||||
keyLine = false;
|
||||
} else if (indents <= currentKeyIndents) {
|
||||
final String[] array = key.split(this.pathSeparatorQuoted);
|
||||
final int backspace = currentKeyIndents - indents + 1;
|
||||
key = join(array, array.length - backspace);
|
||||
keyLine = true;
|
||||
} else {
|
||||
keyLine = line.indexOf(':') != -1;
|
||||
}
|
||||
|
||||
if (!keyLine) {
|
||||
// Nothing to do, go to next line
|
||||
fileData.append(line).append('\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
int indent = getSuccessiveCharCount(line, ' ');
|
||||
int indents = indent / indentLength;
|
||||
String indentText = indent > 0 ? line.substring(0, indent) : "";
|
||||
if (indents <= currentIndents) {
|
||||
// Remove last section of key
|
||||
String[] array = key.split(Pattern.quote(pathSeparator));
|
||||
int backspace = currentIndents - indents + 1;
|
||||
key = join(array, this.pathSeperator, 0, array.length - backspace);
|
||||
final String newKey = substring.split(Pattern.quote(":"))[0]; // Not sure about the quote thing, so I'll just keep it :aaa:
|
||||
if (!key.isEmpty()) {
|
||||
key += this.pathSeparator;
|
||||
}
|
||||
key += newKey;
|
||||
|
||||
// Add comments
|
||||
final List<String> strings = headers.get(key);
|
||||
if (strings != null && !strings.isEmpty()) {
|
||||
final String indentText = indent > 0 ? line.substring(0, indent) : "";
|
||||
for (final String comment : strings) {
|
||||
if (comment.isEmpty()) {
|
||||
fileData.append('\n');
|
||||
} else {
|
||||
fileData.append(indentText).append(comment).append('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add new section to key
|
||||
String separator = !key.isEmpty() ? pathSeparator : "";
|
||||
String lineKey = line.contains(":") ? line.split(Pattern.quote(":"))[0] : line;
|
||||
key += separator + lineKey.substring(indent);
|
||||
|
||||
currentIndents = indents;
|
||||
|
||||
List<String> header = headers.get(key);
|
||||
String headerText = header != null ? addHeaderTags(header, indentText) : "";
|
||||
fileData.append(headerText).append(line).append('\n');
|
||||
currentKeyIndents = indents;
|
||||
fileData.append(line).append('\n');
|
||||
}
|
||||
|
||||
// Write data to file
|
||||
Files.write(fileData.toString(), output, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private String addHeaderTags(List<String> header, String indent) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String line : header) {
|
||||
private String addHeaderTags(final List<String> header, final String indent) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (final String line : header) {
|
||||
builder.append(indent).append("# ").append(line).append('\n');
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String join(String[] array, char joinChar, int start, int length) {
|
||||
String[] copy = new String[length - start];
|
||||
private String join(final String[] array, final char joinChar, final int start, final int length) {
|
||||
final String[] copy = new String[length - start];
|
||||
System.arraycopy(array, start, copy, 0, length - start);
|
||||
return Joiner.on(joinChar).join(copy);
|
||||
}
|
||||
|
||||
private int getSuccessiveCharCount(String text, char key) {
|
||||
private int getIndents(final String line) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < line.length(); i++) {
|
||||
if (line.charAt(i) != ' ') {
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private String join(final String[] array, final int length) {
|
||||
final String[] copy = new String[length];
|
||||
System.arraycopy(array, 0, copy, 0, length);
|
||||
return String.join(this.pathSeparator, copy);
|
||||
}
|
||||
|
||||
private int getSuccessiveSpaces(final String text) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
if (text.charAt(i) == key) {
|
||||
if (text.charAt(i) == ' ') {
|
||||
count += 1;
|
||||
} else {
|
||||
break;
|
||||
|
||||
@@ -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;
|
||||
@@ -65,9 +62,12 @@ public abstract class Config implements ConfigurationProvider {
|
||||
return getClass().getClassLoader().getResource("assets/viaversion/config.yml");
|
||||
}
|
||||
|
||||
public synchronized Map<String, Object> loadConfig(File location) {
|
||||
public Map<String, Object> loadConfig(File location) {
|
||||
return loadConfig(location, getDefaultConfigURL());
|
||||
}
|
||||
|
||||
public synchronized Map<String, Object> loadConfig(File location, URL jarConfigFile) {
|
||||
List<String> unsupported = getUnsupportedOptions();
|
||||
URL jarConfigFile = getDefaultConfigURL();
|
||||
try {
|
||||
commentStore.storeComments(jarConfigFile.openStream());
|
||||
for (String option : unsupported) {
|
||||
@@ -140,6 +140,10 @@ public abstract class Config implements ConfigurationProvider {
|
||||
saveConfig(this.configFile, this.config);
|
||||
}
|
||||
|
||||
public void saveConfig(final File file) {
|
||||
saveConfig(file, this.config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
this.configFile.getParentFile().mkdirs();
|
||||
@@ -214,6 +218,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 #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
Binary file not shown.
@@ -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
@@ -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.0
|
||||
projectVersion=4.4.2
|
||||
|
||||
# Gradle properties
|
||||
org.gradle.daemon=true
|
||||
|
||||
@@ -6,7 +6,7 @@ adventure = "4.9.3"
|
||||
gson = "2.8.8"
|
||||
fastutil = "8.5.6"
|
||||
flare = "2.0.0"
|
||||
openNBT = "2.0"
|
||||
openNBT = "2.1"
|
||||
javassist = "3.28.0-GA"
|
||||
|
||||
# Common provided
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||
import com.viaversion.viaversion.api.configuration.ConfigurationProvider;
|
||||
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||
import com.viaversion.viaversion.api.platform.PlatformTask;
|
||||
import com.viaversion.viaversion.api.platform.ViaPlatform;
|
||||
import com.viaversion.viaversion.api.platform.ViaServerProxyPlatform;
|
||||
import com.viaversion.viaversion.dump.PluginInfo;
|
||||
import com.viaversion.viaversion.util.ChatColorUtil;
|
||||
import com.viaversion.viaversion.util.GsonUtil;
|
||||
@@ -64,7 +64,7 @@ import java.util.concurrent.TimeUnit;
|
||||
description = "Allow newer Minecraft versions to connect to an older server version.",
|
||||
url = "https://viaversion.com"
|
||||
)
|
||||
public class VelocityPlugin implements ViaPlatform<Player> {
|
||||
public class VelocityPlugin implements ViaServerProxyPlatform<Player> {
|
||||
public static final LegacyComponentSerializer COMPONENT_SERIALIZER = LegacyComponentSerializer.builder().character(ChatColorUtil.COLOR_CHAR).extractUrls().build();
|
||||
public static ProxyServer PROXY;
|
||||
|
||||
@@ -76,6 +76,7 @@ public class VelocityPlugin implements ViaPlatform<Player> {
|
||||
@DataDirectory
|
||||
private Path configDir;
|
||||
|
||||
private final ProtocolDetectorService protocolDetectorService = new ProtocolDetectorService();
|
||||
private VelocityViaAPI api;
|
||||
private java.util.logging.Logger logger;
|
||||
private VelocityViaConfig conf;
|
||||
@@ -230,7 +231,7 @@ public class VelocityPlugin implements ViaPlatform<Player> {
|
||||
));
|
||||
}
|
||||
extra.add("plugins", GsonUtil.getGson().toJsonTree(plugins));
|
||||
extra.add("servers", GsonUtil.getGson().toJsonTree(ProtocolDetectorService.getDetectedIds()));
|
||||
extra.add("servers", GsonUtil.getGson().toJsonTree(protocolDetectorService.detectedProtocolVersions()));
|
||||
return extra;
|
||||
}
|
||||
|
||||
@@ -239,11 +240,21 @@ 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolDetectorService protocolDetectorService() {
|
||||
return protocolDetectorService;
|
||||
}
|
||||
|
||||
private boolean hasConnectionEvent() {
|
||||
try {
|
||||
Class.forName("com.velocitypowered.proxy.protocol.VelocityConnectionEvent");
|
||||
|
||||
+5
@@ -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>)
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -21,7 +21,6 @@ import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||
import com.viaversion.viaversion.api.command.ViaSubCommand;
|
||||
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
|
||||
import com.viaversion.viaversion.velocity.service.ProtocolDetectorService;
|
||||
|
||||
public class ProbeSubCmd extends ViaSubCommand {
|
||||
@Override
|
||||
@@ -38,7 +37,7 @@ public class ProbeSubCmd extends ViaSubCommand {
|
||||
|
||||
@Override
|
||||
public boolean execute(ViaCommandSender sender, String[] args) {
|
||||
ProtocolDetectorService.getInstance().run();
|
||||
Via.proxyPlatform().protocolDetectorService().probeAllServers();
|
||||
sendMessage(sender, "&6Started searching for protocol versions");
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,9 +29,9 @@ import com.viaversion.viaversion.velocity.listeners.UpdateListener;
|
||||
import com.viaversion.viaversion.velocity.providers.VelocityBossBarProvider;
|
||||
import com.viaversion.viaversion.velocity.providers.VelocityMovementTransmitter;
|
||||
import com.viaversion.viaversion.velocity.providers.VelocityVersionProvider;
|
||||
import com.viaversion.viaversion.velocity.service.ProtocolDetectorService;
|
||||
|
||||
public class VelocityViaLoader implements ViaPlatformLoader {
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
Object plugin = VelocityPlugin.PROXY.getPluginManager()
|
||||
@@ -51,7 +51,7 @@ public class VelocityViaLoader implements ViaPlatformLoader {
|
||||
int pingInterval = ((VelocityViaConfig) Via.getPlatform().getConf()).getVelocityPingInterval();
|
||||
if (pingInterval > 0) {
|
||||
Via.getPlatform().runRepeatingSync(
|
||||
new ProtocolDetectorService(),
|
||||
() -> Via.proxyPlatform().protocolDetectorService().probeAllServers(),
|
||||
pingInterval * 20L);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -24,7 +24,6 @@ import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.protocols.base.BaseVersionProvider;
|
||||
import com.viaversion.viaversion.velocity.platform.VelocityViaInjector;
|
||||
import com.viaversion.viaversion.velocity.service.ProtocolDetectorService;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -50,7 +49,7 @@ public class VelocityVersionProvider extends BaseVersionProvider {
|
||||
private int getBackProtocol(UserConnection user) throws Exception {
|
||||
//TODO use newly added Velocity netty event
|
||||
ChannelHandler mcHandler = user.getChannel().pipeline().get("handler");
|
||||
return ProtocolDetectorService.getProtocolId(
|
||||
return Via.proxyPlatform().protocolDetectorService().serverProtocolVersion(
|
||||
((ServerConnection) getAssociation.invoke(mcHandler)).getServerInfo().getName());
|
||||
}
|
||||
|
||||
|
||||
+56
-59
@@ -21,80 +21,77 @@ import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.viaversion.viaversion.VelocityPlugin;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.platform.AbstractProtocolDetectorService;
|
||||
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Set;
|
||||
|
||||
public class ProtocolDetectorService implements Runnable {
|
||||
private static final Map<String, Integer> detectedProtocolIds = new ConcurrentHashMap<>();
|
||||
private static ProtocolDetectorService instance;
|
||||
|
||||
public ProtocolDetectorService() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static Integer getProtocolId(String serverName) {
|
||||
// Step 1. Check Config
|
||||
Map<String, Integer> servers = ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols();
|
||||
Integer protocol = servers.get(serverName);
|
||||
if (protocol != null) {
|
||||
return protocol;
|
||||
}
|
||||
// Step 2. Check Detected
|
||||
Integer detectedProtocol = detectedProtocolIds.get(serverName);
|
||||
if (detectedProtocol != null) {
|
||||
return detectedProtocol;
|
||||
}
|
||||
// Step 3. Use Default
|
||||
Integer defaultProtocol = servers.get("default");
|
||||
if (defaultProtocol != null) {
|
||||
return defaultProtocol;
|
||||
}
|
||||
// Step 4: Use bungee lowest supported... *cries*
|
||||
try {
|
||||
return ProtocolVersion.getProtocol(Via.getManager().getInjector().getServerProtocolVersion()).getVersion();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return ProtocolVersion.v1_8.getVersion();
|
||||
}
|
||||
}
|
||||
public final class ProtocolDetectorService extends AbstractProtocolDetectorService {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (final RegisteredServer serv : VelocityPlugin.PROXY.getAllServers()) {
|
||||
probeServer(serv);
|
||||
public void probeAllServers() {
|
||||
final Collection<RegisteredServer> servers = VelocityPlugin.PROXY.getAllServers();
|
||||
final Set<String> serverNames = new HashSet<>(servers.size());
|
||||
for (final RegisteredServer server : servers) {
|
||||
probeServer(server);
|
||||
serverNames.add(server.getServerInfo().getName());
|
||||
}
|
||||
|
||||
// Remove servers that aren't registered anymore
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
detectedProtocolIds.keySet().retainAll(serverNames);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void probeServer(final RegisteredServer serverInfo) {
|
||||
final String key = serverInfo.getServerInfo().getName();
|
||||
serverInfo.ping().thenAccept((serverPing) -> {
|
||||
if (serverPing != null && serverPing.getVersion() != null) {
|
||||
detectedProtocolIds.put(key, serverPing.getVersion().getProtocol());
|
||||
if (((VelocityViaConfig) Via.getConfig()).isVelocityPingSave()) {
|
||||
Map<String, Integer> servers = ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols();
|
||||
Integer protocol = servers.get(key);
|
||||
if (protocol != null && protocol == serverPing.getVersion().getProtocol()) {
|
||||
return;
|
||||
}
|
||||
// Ensure we're the only ones writing to the config
|
||||
synchronized (Via.getPlatform().getConfigurationProvider()) {
|
||||
servers.put(key, serverPing.getVersion().getProtocol());
|
||||
}
|
||||
// Save
|
||||
Via.getPlatform().getConfigurationProvider().saveConfig();
|
||||
public void probeServer(final RegisteredServer server) {
|
||||
final String serverName = server.getServerInfo().getName();
|
||||
server.ping().thenAccept(serverPing -> {
|
||||
if (serverPing == null || serverPing.getVersion() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int oldProtocolVersion = serverProtocolVersion(serverName);
|
||||
if (oldProtocolVersion != -1 && oldProtocolVersion == serverPing.getVersion().getProtocol()) {
|
||||
// Same value as previously
|
||||
return;
|
||||
}
|
||||
|
||||
setProtocolVersion(serverName, serverPing.getVersion().getProtocol());
|
||||
|
||||
if (((VelocityViaConfig) Via.getConfig()).isVelocityPingSave()) {
|
||||
final Map<String, Integer> servers = configuredServers();
|
||||
final Integer protocol = servers.get(serverName);
|
||||
if (protocol != null && protocol == serverPing.getVersion().getProtocol()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure we're the only ones writing to the config
|
||||
synchronized (Via.getPlatform().getConfigurationProvider()) {
|
||||
servers.put(serverName, serverPing.getVersion().getProtocol());
|
||||
}
|
||||
Via.getPlatform().getConfigurationProvider().saveConfig();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Map<String, Integer> getDetectedIds() {
|
||||
return new HashMap<>(detectedProtocolIds);
|
||||
@Override
|
||||
protected Map<String, Integer> configuredServers() {
|
||||
return ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols();
|
||||
}
|
||||
|
||||
public static ProtocolDetectorService getInstance() {
|
||||
return instance;
|
||||
@Override
|
||||
protected int lowestSupportedProtocolVersion() {
|
||||
try {
|
||||
return ProtocolVersion.getProtocol(Via.getManager().getInjector().getServerProtocolVersion()).getVersion();
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
return ProtocolVersion.v1_8.getVersion();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user