Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58442ec177 | ||
|
|
2a49fc0bf8 | ||
|
|
7fb8675271 | ||
|
|
57a8744a53 | ||
|
|
09222f1024 | ||
|
|
b4870a49e3 | ||
|
|
f7a48d028b | ||
|
|
382ef3953a | ||
|
|
9be32ca18b | ||
|
|
e0cd121a58 | ||
|
|
96631cee0c | ||
|
|
8c0487fc05 | ||
|
|
aec60f8cef | ||
|
|
a3080800b0 | ||
|
|
85f9414b95 | ||
|
|
e7f07d1fdb | ||
|
|
83efd0a267 | ||
|
|
5c05c61fbf | ||
|
|
fad350c811 | ||
|
|
d3d8d1cab3 | ||
|
|
a3437ca6ba | ||
|
|
17bd048d10 | ||
|
|
955b76f599 | ||
|
|
e3dc9e5b66 | ||
|
|
6095128007 | ||
|
|
0355447d53 | ||
|
|
58fd0bdc9e | ||
|
|
cdc35aa5dc | ||
|
|
10efba31cf | ||
|
|
ef204c2ab2 | ||
|
|
555e1a7722 | ||
|
|
7400784e4f | ||
|
|
2154f0a2cf | ||
|
|
14b11bdd10 | ||
|
|
c5738a2203 | ||
|
|
43ad855499 | ||
|
|
2533619339 | ||
|
|
b133dad642 | ||
|
|
464a85c52b | ||
|
|
7698ee7683 | ||
|
|
c7eb2e4b97 | ||
|
|
e71c88f860 | ||
|
|
c96b2bd859 | ||
|
|
ce4f21b7d8 | ||
|
|
2a55025e99 | ||
|
|
c86da22f4e | ||
|
|
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
@@ -7,7 +7,7 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
**Before reporting a bug, please see if using master/dev builds from https://ci.viaversion.com/ fixes your issue.**
|
||||
Whenever you see fit, you can upload images or video to any of the textfields.
|
||||
Whenever you see fit, you can upload images or videos to any of the text fields.
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
|
||||
@@ -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
|
||||
@@ -10,19 +10,19 @@ jobs:
|
||||
# Only run on PRs if the source branch is on a different repo. We do not need to run everything twice.
|
||||
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 11
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: artifact
|
||||
path: build/libs
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Supported Versions:
|
||||
|
||||

|
||||

|
||||
|
||||
On Paper you may also use ProtocolSupport, but ensure you have the right build for your server version.
|
||||
|
||||
@@ -51,7 +51,7 @@ You can find official dev builds here:
|
||||
<dependency>
|
||||
<groupId>com.viaversion</groupId>
|
||||
<artifactId>viaversion-api</artifactId>
|
||||
<version>LATEST</version>
|
||||
<version>[4.0.0,5.0.0)</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -84,6 +84,8 @@ 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 v1_19_3 = register(761, "1.19.3");
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.minecraft;
|
||||
|
||||
public final class ProfileKey {
|
||||
private final long expiresAt;
|
||||
private final byte[] publicKey;
|
||||
private final byte[] keySignature;
|
||||
|
||||
public ProfileKey(final long expiresAt, final byte[] publicKey, final byte[] keySignature) {
|
||||
this.expiresAt = expiresAt;
|
||||
this.publicKey = publicKey;
|
||||
this.keySignature = keySignature;
|
||||
}
|
||||
|
||||
public long expiresAt() {
|
||||
return expiresAt;
|
||||
}
|
||||
|
||||
public byte[] publicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public byte[] keySignature() {
|
||||
return keySignature;
|
||||
}
|
||||
}
|
||||
@@ -42,4 +42,6 @@ public interface BlockEntity {
|
||||
int typeId();
|
||||
|
||||
@Nullable CompoundTag tag();
|
||||
|
||||
BlockEntity withTypeId(int typeId);
|
||||
}
|
||||
+5
@@ -56,4 +56,9 @@ public final class BlockEntityImpl implements BlockEntity {
|
||||
public CompoundTag tag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity withTypeId(int typeId) {
|
||||
return new BlockEntityImpl(packedXZ, y, typeId, tag);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,18 @@ public interface ChunkSection {
|
||||
return y << 8 | z << 4 | x;
|
||||
}
|
||||
|
||||
static int xFromIndex(int idx) {
|
||||
return idx & 0xF;
|
||||
}
|
||||
|
||||
static int yFromIndex(int idx) {
|
||||
return idx >> 8 & 0xF;
|
||||
}
|
||||
|
||||
static int zFromIndex(int idx) {
|
||||
return idx >> 4 & 0xF;
|
||||
}
|
||||
|
||||
@Deprecated/*(forRemoval = true)*/
|
||||
default int getFlatBlock(int idx) {
|
||||
return palette(PaletteType.BLOCKS).idAt(idx);
|
||||
|
||||
+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);
|
||||
}
|
||||
}
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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.minecraft.entities;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.util.EntityTypeUtil;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public enum Entity1_19_3Types implements EntityType {
|
||||
|
||||
ENTITY(null, null),
|
||||
|
||||
AREA_EFFECT_CLOUD(ENTITY),
|
||||
END_CRYSTAL(ENTITY),
|
||||
EVOKER_FANGS(ENTITY),
|
||||
EXPERIENCE_ORB(ENTITY),
|
||||
EYE_OF_ENDER(ENTITY),
|
||||
FALLING_BLOCK(ENTITY),
|
||||
FIREWORK_ROCKET(ENTITY),
|
||||
ITEM(ENTITY),
|
||||
LLAMA_SPIT(ENTITY),
|
||||
TNT(ENTITY),
|
||||
SHULKER_BULLET(ENTITY),
|
||||
FISHING_BOBBER(ENTITY),
|
||||
|
||||
LIVINGENTITY(ENTITY, null),
|
||||
ARMOR_STAND(LIVINGENTITY),
|
||||
MARKER(ENTITY),
|
||||
PLAYER(LIVINGENTITY),
|
||||
|
||||
ABSTRACT_INSENTIENT(LIVINGENTITY, null),
|
||||
ENDER_DRAGON(ABSTRACT_INSENTIENT),
|
||||
|
||||
BEE(ABSTRACT_INSENTIENT),
|
||||
|
||||
ABSTRACT_CREATURE(ABSTRACT_INSENTIENT, null),
|
||||
|
||||
ABSTRACT_AGEABLE(ABSTRACT_CREATURE, null),
|
||||
VILLAGER(ABSTRACT_AGEABLE),
|
||||
WANDERING_TRADER(ABSTRACT_AGEABLE),
|
||||
|
||||
// Animals
|
||||
ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null),
|
||||
AXOLOTL(ABSTRACT_ANIMAL),
|
||||
DOLPHIN(ABSTRACT_INSENTIENT),
|
||||
CHICKEN(ABSTRACT_ANIMAL),
|
||||
COW(ABSTRACT_ANIMAL),
|
||||
MOOSHROOM(COW),
|
||||
PANDA(ABSTRACT_INSENTIENT),
|
||||
PIG(ABSTRACT_ANIMAL),
|
||||
POLAR_BEAR(ABSTRACT_ANIMAL),
|
||||
RABBIT(ABSTRACT_ANIMAL),
|
||||
SHEEP(ABSTRACT_ANIMAL),
|
||||
TURTLE(ABSTRACT_ANIMAL),
|
||||
FOX(ABSTRACT_ANIMAL),
|
||||
FROG(ABSTRACT_ANIMAL),
|
||||
GOAT(ABSTRACT_ANIMAL),
|
||||
|
||||
ABSTRACT_TAMEABLE_ANIMAL(ABSTRACT_ANIMAL, null),
|
||||
CAT(ABSTRACT_TAMEABLE_ANIMAL),
|
||||
OCELOT(ABSTRACT_TAMEABLE_ANIMAL),
|
||||
WOLF(ABSTRACT_TAMEABLE_ANIMAL),
|
||||
|
||||
ABSTRACT_PARROT(ABSTRACT_TAMEABLE_ANIMAL, null),
|
||||
PARROT(ABSTRACT_PARROT),
|
||||
|
||||
// Horses
|
||||
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
|
||||
CHESTED_HORSE(ABSTRACT_HORSE, null),
|
||||
DONKEY(CHESTED_HORSE),
|
||||
MULE(CHESTED_HORSE),
|
||||
LLAMA(CHESTED_HORSE),
|
||||
TRADER_LLAMA(CHESTED_HORSE),
|
||||
HORSE(ABSTRACT_HORSE),
|
||||
SKELETON_HORSE(ABSTRACT_HORSE),
|
||||
ZOMBIE_HORSE(ABSTRACT_HORSE),
|
||||
CAMEL(ABSTRACT_HORSE),
|
||||
|
||||
// Golem
|
||||
ABSTRACT_GOLEM(ABSTRACT_CREATURE, null),
|
||||
SNOW_GOLEM(ABSTRACT_GOLEM),
|
||||
IRON_GOLEM(ABSTRACT_GOLEM),
|
||||
SHULKER(ABSTRACT_GOLEM),
|
||||
|
||||
// Fish
|
||||
ABSTRACT_FISHES(ABSTRACT_CREATURE, null),
|
||||
COD(ABSTRACT_FISHES),
|
||||
PUFFERFISH(ABSTRACT_FISHES),
|
||||
SALMON(ABSTRACT_FISHES),
|
||||
TROPICAL_FISH(ABSTRACT_FISHES),
|
||||
|
||||
// Monsters
|
||||
ABSTRACT_MONSTER(ABSTRACT_CREATURE, null),
|
||||
BLAZE(ABSTRACT_MONSTER),
|
||||
CREEPER(ABSTRACT_MONSTER),
|
||||
ENDERMITE(ABSTRACT_MONSTER),
|
||||
ENDERMAN(ABSTRACT_MONSTER),
|
||||
GIANT(ABSTRACT_MONSTER),
|
||||
SILVERFISH(ABSTRACT_MONSTER),
|
||||
VEX(ABSTRACT_MONSTER),
|
||||
WITCH(ABSTRACT_MONSTER),
|
||||
WITHER(ABSTRACT_MONSTER),
|
||||
RAVAGER(ABSTRACT_MONSTER),
|
||||
|
||||
ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null),
|
||||
|
||||
PIGLIN(ABSTRACT_PIGLIN),
|
||||
PIGLIN_BRUTE(ABSTRACT_PIGLIN),
|
||||
|
||||
HOGLIN(ABSTRACT_ANIMAL),
|
||||
STRIDER(ABSTRACT_ANIMAL),
|
||||
TADPOLE(ABSTRACT_FISHES),
|
||||
ZOGLIN(ABSTRACT_MONSTER),
|
||||
WARDEN(ABSTRACT_MONSTER),
|
||||
|
||||
// Illagers
|
||||
ABSTRACT_ILLAGER_BASE(ABSTRACT_MONSTER, null),
|
||||
ABSTRACT_EVO_ILLU_ILLAGER(ABSTRACT_ILLAGER_BASE, null),
|
||||
EVOKER(ABSTRACT_EVO_ILLU_ILLAGER),
|
||||
ILLUSIONER(ABSTRACT_EVO_ILLU_ILLAGER),
|
||||
VINDICATOR(ABSTRACT_ILLAGER_BASE),
|
||||
PILLAGER(ABSTRACT_ILLAGER_BASE),
|
||||
|
||||
// Skeletons
|
||||
ABSTRACT_SKELETON(ABSTRACT_MONSTER, null),
|
||||
SKELETON(ABSTRACT_SKELETON),
|
||||
STRAY(ABSTRACT_SKELETON),
|
||||
WITHER_SKELETON(ABSTRACT_SKELETON),
|
||||
|
||||
// Guardians
|
||||
GUARDIAN(ABSTRACT_MONSTER),
|
||||
ELDER_GUARDIAN(GUARDIAN),
|
||||
|
||||
// Spiders
|
||||
SPIDER(ABSTRACT_MONSTER),
|
||||
CAVE_SPIDER(SPIDER),
|
||||
|
||||
// Zombies
|
||||
ZOMBIE(ABSTRACT_MONSTER),
|
||||
DROWNED(ZOMBIE),
|
||||
HUSK(ZOMBIE),
|
||||
ZOMBIFIED_PIGLIN(ZOMBIE),
|
||||
ZOMBIE_VILLAGER(ZOMBIE),
|
||||
|
||||
// Flying entities
|
||||
ABSTRACT_FLYING(ABSTRACT_INSENTIENT, null),
|
||||
GHAST(ABSTRACT_FLYING),
|
||||
PHANTOM(ABSTRACT_FLYING),
|
||||
|
||||
ABSTRACT_AMBIENT(ABSTRACT_INSENTIENT, null),
|
||||
BAT(ABSTRACT_AMBIENT),
|
||||
ALLAY(ABSTRACT_CREATURE),
|
||||
|
||||
ABSTRACT_WATERMOB(ABSTRACT_INSENTIENT, null),
|
||||
SQUID(ABSTRACT_WATERMOB),
|
||||
GLOW_SQUID(SQUID),
|
||||
|
||||
// Slimes
|
||||
SLIME(ABSTRACT_INSENTIENT),
|
||||
MAGMA_CUBE(SLIME),
|
||||
|
||||
// Hangable objects
|
||||
ABSTRACT_HANGING(ENTITY, null),
|
||||
LEASH_KNOT(ABSTRACT_HANGING),
|
||||
ITEM_FRAME(ABSTRACT_HANGING),
|
||||
GLOW_ITEM_FRAME(ITEM_FRAME),
|
||||
PAINTING(ABSTRACT_HANGING),
|
||||
|
||||
ABSTRACT_LIGHTNING(ENTITY, null),
|
||||
LIGHTNING_BOLT(ABSTRACT_LIGHTNING),
|
||||
|
||||
// Arrows
|
||||
ABSTRACT_ARROW(ENTITY, null),
|
||||
ARROW(ABSTRACT_ARROW),
|
||||
SPECTRAL_ARROW(ABSTRACT_ARROW),
|
||||
TRIDENT(ABSTRACT_ARROW),
|
||||
|
||||
// Fireballs
|
||||
ABSTRACT_FIREBALL(ENTITY, null),
|
||||
DRAGON_FIREBALL(ABSTRACT_FIREBALL),
|
||||
FIREBALL(ABSTRACT_FIREBALL),
|
||||
SMALL_FIREBALL(ABSTRACT_FIREBALL),
|
||||
WITHER_SKULL(ABSTRACT_FIREBALL),
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE_ABSTRACT(ENTITY, null),
|
||||
SNOWBALL(PROJECTILE_ABSTRACT),
|
||||
ENDER_PEARL(PROJECTILE_ABSTRACT),
|
||||
EGG(PROJECTILE_ABSTRACT),
|
||||
POTION(PROJECTILE_ABSTRACT),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE_ABSTRACT),
|
||||
|
||||
// Vehicles
|
||||
MINECART_ABSTRACT(ENTITY, null),
|
||||
CHESTED_MINECART_ABSTRACT(MINECART_ABSTRACT, null),
|
||||
CHEST_MINECART(CHESTED_MINECART_ABSTRACT),
|
||||
HOPPER_MINECART(CHESTED_MINECART_ABSTRACT),
|
||||
MINECART(MINECART_ABSTRACT),
|
||||
FURNACE_MINECART(MINECART_ABSTRACT),
|
||||
COMMAND_BLOCK_MINECART(MINECART_ABSTRACT),
|
||||
TNT_MINECART(MINECART_ABSTRACT),
|
||||
SPAWNER_MINECART(MINECART_ABSTRACT),
|
||||
BOAT(ENTITY),
|
||||
CHEST_BOAT(BOAT);
|
||||
|
||||
private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values());
|
||||
private final EntityType parent;
|
||||
private final String identifier;
|
||||
private int id = -1;
|
||||
|
||||
Entity1_19_3Types(final EntityType parent) {
|
||||
this.parent = parent;
|
||||
this.identifier = "minecraft:" + name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
Entity1_19_3Types(final EntityType parent, @Nullable final String identifier) {
|
||||
this.parent = parent;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
if (id == -1) {
|
||||
throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String identifier() {
|
||||
Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type");
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable EntityType getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstractType() {
|
||||
return identifier == null;
|
||||
}
|
||||
|
||||
public static EntityType getTypeFromId(final int typeId) {
|
||||
return EntityTypeUtil.getTypeFromId(TYPES, typeId, ENTITY);
|
||||
}
|
||||
|
||||
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
|
||||
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.minecraft.metadata.types;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.types.minecraft.ParticleType;
|
||||
|
||||
public final class MetaTypes1_19_3 extends AbstractMetaTypes {
|
||||
|
||||
public final MetaType byteType = add(0, Type.BYTE);
|
||||
public final MetaType varIntType = add(1, Type.VAR_INT);
|
||||
public final MetaType longType = add(2, Type.VAR_LONG);
|
||||
public final MetaType floatType = add(3, Type.FLOAT);
|
||||
public final MetaType stringType = add(4, Type.STRING);
|
||||
public final MetaType componentType = add(5, Type.COMPONENT);
|
||||
public final MetaType optionalComponentType = add(6, Type.OPTIONAL_COMPONENT);
|
||||
public final MetaType itemType = add(7, Type.FLAT_VAR_INT_ITEM);
|
||||
public final MetaType booleanType = add(8, Type.BOOLEAN);
|
||||
public final MetaType rotationType = add(9, Type.ROTATION);
|
||||
public final MetaType positionType = add(10, Type.POSITION1_14);
|
||||
public final MetaType optionalPositionType = add(11, Type.OPTIONAL_POSITION_1_14);
|
||||
public final MetaType directionType = add(12, Type.VAR_INT);
|
||||
public final MetaType optionalUUIDType = add(13, Type.OPTIONAL_UUID);
|
||||
public final MetaType blockStateType = add(14, Type.VAR_INT);
|
||||
public final MetaType nbtType = add(15, Type.NBT);
|
||||
public final MetaType particleType;
|
||||
public final MetaType villagerDatatType = add(17, Type.VILLAGER_DATA);
|
||||
public final MetaType optionalVarIntType = add(18, Type.OPTIONAL_VAR_INT);
|
||||
public final MetaType poseType = add(19, Type.VAR_INT);
|
||||
public final MetaType catVariantType = add(20, Type.VAR_INT);
|
||||
public final MetaType frogVariantType = add(21, Type.VAR_INT);
|
||||
public final MetaType optionalGlobalPosition = add(22, Type.OPTIONAL_GLOBAL_POSITION);
|
||||
public final MetaType paintingVariantType = add(23, Type.VAR_INT);
|
||||
|
||||
public MetaTypes1_19_3(final ParticleType particleType) {
|
||||
super(24);
|
||||
this.particleType = add(16, particleType);
|
||||
}
|
||||
}
|
||||
@@ -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,8 @@ 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 v1_19_3 = register(761, "1.19.3");
|
||||
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;
|
||||
@@ -87,6 +87,7 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
|
||||
public static final ByteType BYTE = new ByteType();
|
||||
public static final UnsignedByteType UNSIGNED_BYTE = new UnsignedByteType();
|
||||
public static final Type<byte[]> BYTE_ARRAY_PRIMITIVE = new ByteArrayType();
|
||||
public static final Type<byte[]> OPTIONAL_BYTE_ARRAY_PRIMITIVE = new ByteArrayType.OptionalByteArrayType();
|
||||
public static final Type<byte[]> SHORT_BYTE_ARRAY = new ShortByteArrayType();
|
||||
public static final Type<byte[]> REMAINING_BYTES = new RemainingBytesType();
|
||||
|
||||
@@ -95,6 +96,7 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
|
||||
|
||||
public static final IntType INT = new IntType();
|
||||
public static final FloatType FLOAT = new FloatType();
|
||||
public static final FloatType.OptionalFloatType OPTIONAL_FLOAT = new FloatType.OptionalFloatType();
|
||||
public static final DoubleType DOUBLE = new DoubleType();
|
||||
|
||||
public static final LongType LONG = new LongType();
|
||||
@@ -104,15 +106,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 +152,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 +174,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();
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
|
||||
public class BitSetType extends Type<BitSet> {
|
||||
|
||||
private final int length;
|
||||
private final int bytesLength;
|
||||
|
||||
public BitSetType(final int length) {
|
||||
super(BitSet.class);
|
||||
this.length = length;
|
||||
this.bytesLength = -Math.floorDiv(-length, 8); // Ceiled quotient
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitSet read(ByteBuf buffer) {
|
||||
final byte[] bytes = new byte[bytesLength];
|
||||
buffer.readBytes(bytes);
|
||||
return BitSet.valueOf(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buffer, BitSet object) {
|
||||
Preconditions.checkArgument(object.length() <= length, "BitSet of length " + object.length() + " larger than max length " + length);
|
||||
final byte[] bytes = object.toByteArray();
|
||||
buffer.writeBytes(Arrays.copyOf(bytes, bytesLength));
|
||||
}
|
||||
}
|
||||
@@ -23,26 +23,51 @@
|
||||
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;
|
||||
|
||||
public class ByteArrayType extends Type<byte[]> {
|
||||
|
||||
private final int length;
|
||||
|
||||
public ByteArrayType(final int length) {
|
||||
super(byte[].class);
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public ByteArrayType() {
|
||||
super(byte[].class);
|
||||
this.length = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buffer, byte[] object) throws Exception {
|
||||
Type.VAR_INT.writePrimitive(buffer, object.length);
|
||||
public void write(final ByteBuf buffer, final byte[] object) throws Exception {
|
||||
if (this.length != -1) {
|
||||
Preconditions.checkArgument(length == object.length, "Length does not match expected length");
|
||||
} else {
|
||||
Type.VAR_INT.writePrimitive(buffer, object.length);
|
||||
}
|
||||
buffer.writeBytes(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] read(ByteBuf buffer) throws Exception {
|
||||
int length = Type.VAR_INT.readPrimitive(buffer);
|
||||
public byte[] read(final ByteBuf buffer) throws Exception {
|
||||
final int length = this.length == -1 ? Type.VAR_INT.readPrimitive(buffer) : this.length;
|
||||
Preconditions.checkArgument(buffer.isReadable(length), "Length is fewer than readable bytes");
|
||||
byte[] array = new byte[length];
|
||||
final byte[] array = new byte[length];
|
||||
buffer.readBytes(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static final class OptionalByteArrayType extends OptionalType<byte[]> {
|
||||
|
||||
public OptionalByteArrayType() {
|
||||
super(Type.BYTE_ARRAY_PRIMITIVE);
|
||||
}
|
||||
|
||||
public OptionalByteArrayType(final int length) {
|
||||
super(new ByteArrayType(length));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.api.type.types;
|
||||
|
||||
import com.viaversion.viaversion.api.type.OptionalType;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.TypeConverter;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@@ -67,4 +68,11 @@ public class FloatType extends Type<Float> implements TypeConverter<Float> {
|
||||
}
|
||||
return (Float) o;
|
||||
}
|
||||
|
||||
public static final class OptionalFloatType extends OptionalType<Float> {
|
||||
|
||||
public OptionalFloatType() {
|
||||
super(Type.FLOAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+12
-16
@@ -24,6 +24,8 @@ package com.viaversion.viaversion.api.type.types.version;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionImpl;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
@@ -38,16 +40,14 @@ public class ChunkSectionType1_8 extends Type<ChunkSection> {
|
||||
@Override
|
||||
public ChunkSection read(ByteBuf buffer) throws Exception {
|
||||
ChunkSection chunkSection = new ChunkSectionImpl(true);
|
||||
DataPalette blocks = chunkSection.palette(PaletteType.BLOCKS);
|
||||
|
||||
// 0 index needs to be air in 1.9
|
||||
chunkSection.addPaletteEntry(0);
|
||||
blocks.addId(0);
|
||||
|
||||
ByteBuf littleEndianView = buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
for (int i = 0; i < ChunkSection.SIZE; i++) {
|
||||
int mask = littleEndianView.readShort();
|
||||
int type = mask >> 4;
|
||||
int data = mask & 0xF;
|
||||
chunkSection.setBlockWithData(i, type, data);
|
||||
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
blocks.setIdAt(idx, littleEndianView.readShort());
|
||||
}
|
||||
|
||||
return chunkSection;
|
||||
@@ -55,15 +55,11 @@ public class ChunkSectionType1_8 extends Type<ChunkSection> {
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buffer, ChunkSection chunkSection) throws Exception {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int block = chunkSection.getFlatBlock(x, y, z);
|
||||
buffer.writeByte(block);
|
||||
buffer.writeByte(block >> 8);
|
||||
}
|
||||
}
|
||||
DataPalette blocks = chunkSection.palette(PaletteType.BLOCKS);
|
||||
|
||||
ByteBuf littleEndianView = buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
littleEndianView.writeShort(blocks.idAt(idx));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+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));
|
||||
}
|
||||
}
|
||||
+11
-20
@@ -20,29 +20,20 @@
|
||||
* 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.types.version;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
|
||||
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaTypes1_19_3;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import com.viaversion.viaversion.api.type.types.minecraft.MetaListType;
|
||||
import com.viaversion.viaversion.api.type.types.minecraft.ParticleType;
|
||||
|
||||
public class OptPosition1_14Type extends Type<Position> {
|
||||
public OptPosition1_14Type() {
|
||||
super(Position.class);
|
||||
}
|
||||
import java.util.List;
|
||||
|
||||
@Override
|
||||
public Position read(ByteBuf buffer) throws Exception {
|
||||
boolean present = buffer.readBoolean();
|
||||
if (!present) return null;
|
||||
return Type.POSITION1_14.read(buffer);
|
||||
}
|
||||
public final class Types1_19_3 {
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buffer, Position object) throws Exception {
|
||||
buffer.writeBoolean(object != null);
|
||||
if (object != null) {
|
||||
Type.POSITION1_14.write(buffer, object);
|
||||
}
|
||||
}
|
||||
public static final ParticleType PARTICLE = new ParticleType(); // Only safe to use after protocol loading
|
||||
public static final MetaTypes1_19_3 META_TYPES = new MetaTypes1_19_3(PARTICLE);
|
||||
public static final Type<Metadata> METADATA = new MetadataType(META_TYPES);
|
||||
public static final Type<List<Metadata>> METADATA_LIST = new MetaListType(METADATA);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -24,29 +24,28 @@ package com.viaversion.viaversion.util;
|
||||
|
||||
import java.util.function.IntToLongFunction;
|
||||
|
||||
public class CompactArrayUtil {
|
||||
//Oh no
|
||||
private static final int[] MAGIC = {
|
||||
-1, -1, 0, Integer.MIN_VALUE, 0, 0, 1431655765, 1431655765, 0, Integer.MIN_VALUE,
|
||||
0, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756,
|
||||
0, Integer.MIN_VALUE, 0, 2, 477218588, 477218588, 0, 429496729, 429496729, 0,
|
||||
390451572, 390451572, 0, 357913941, 357913941, 0, 330382099, 330382099, 0, 306783378,
|
||||
306783378, 0, 286331153, 286331153, 0, Integer.MIN_VALUE, 0, 3, 252645135, 252645135,
|
||||
0, 238609294, 238609294, 0, 226050910, 226050910, 0, 214748364, 214748364, 0,
|
||||
204522252, 204522252, 0, 195225786, 195225786, 0, 186737708, 186737708, 0, 178956970,
|
||||
178956970, 0, 171798691, 171798691, 0, 165191049, 165191049, 0, 159072862, 159072862,
|
||||
0, 153391689, 153391689, 0, 148102320, 148102320, 0, 143165576, 143165576, 0,
|
||||
138547332, 138547332, 0, Integer.MIN_VALUE, 0, 4, 130150524, 130150524, 0, 126322567,
|
||||
126322567, 0, 122713351, 122713351, 0, 119304647, 119304647, 0, 116080197, 116080197,
|
||||
0, 113025455, 113025455, 0, 110127366, 110127366, 0, 107374182, 107374182, 0,
|
||||
104755299, 104755299, 0, 102261126, 102261126, 0, 99882960, 99882960, 0, 97612893,
|
||||
97612893, 0, 95443717, 95443717, 0, 93368854, 93368854, 0, 91382282, 91382282,
|
||||
0, 89478485, 89478485, 0, 87652393, 87652393, 0, 85899345, 85899345, 0,
|
||||
84215045, 84215045, 0, 82595524, 82595524, 0, 81037118, 81037118, 0, 79536431,
|
||||
79536431, 0, 78090314, 78090314, 0, 76695844, 76695844, 0, 75350303, 75350303,
|
||||
0, 74051160, 74051160, 0, 72796055, 72796055, 0, 71582788, 71582788, 0,
|
||||
70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE,
|
||||
0, 5};
|
||||
public final class CompactArrayUtil {
|
||||
private static final long[] RECIPROCAL_MULT_AND_ADD = {
|
||||
0xffffffffL, 0x00000000, 0x55555555, 0x00000000, 0x33333333, 0x2aaaaaaa, 0x24924924, 0x00000000,
|
||||
0x1c71c71c, 0x19999999, 0x1745d174, 0x15555555, 0x13b13b13, 0x12492492, 0x11111111, 0x00000000,
|
||||
0xf0f0f0f, 0xe38e38e, 0xd79435e, 0xccccccc, 0xc30c30c, 0xba2e8ba, 0xb21642c, 0xaaaaaaa,
|
||||
0xa3d70a3, 0x9d89d89, 0x97b425e, 0x9249249, 0x8d3dcb0, 0x8888888, 0x8421084, 0x00000000,
|
||||
0x7c1f07c, 0x7878787, 0x7507507, 0x71c71c7, 0x6eb3e45, 0x6bca1af, 0x6906906, 0x6666666,
|
||||
0x63e7063, 0x6186186, 0x5f417d0, 0x5d1745d, 0x5b05b05, 0x590b216, 0x572620a, 0x5555555,
|
||||
0x5397829, 0x51eb851, 0x5050505, 0x4ec4ec4, 0x4d4873e, 0x4bda12f, 0x4a7904a, 0x4924924,
|
||||
0x47dc11f, 0x469ee58, 0x456c797, 0x4444444, 0x4325c53, 0x4210842, 0x4104104, 0x00000000
|
||||
};
|
||||
// Incrementally shift with each 0x80000000/0x00000000 tuple
|
||||
private static final int[] RECIPROCAL_RIGHT_SHIFT = {
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 0, 0, 0, 0, 3,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 5
|
||||
};
|
||||
|
||||
private CompactArrayUtil() {
|
||||
throw new AssertionError();
|
||||
@@ -55,10 +54,10 @@ public class CompactArrayUtil {
|
||||
public static long[] createCompactArrayWithPadding(int bitsPerEntry, int entries, IntToLongFunction valueGetter) {
|
||||
long maxEntryValue = (1L << bitsPerEntry) - 1;
|
||||
char valuesPerLong = (char) (64 / bitsPerEntry);
|
||||
int magicIndex = 3 * (valuesPerLong - 1);
|
||||
long divideMul = Integer.toUnsignedLong(MAGIC[magicIndex]);
|
||||
long divideAdd = Integer.toUnsignedLong(MAGIC[magicIndex + 1]);
|
||||
int divideShift = MAGIC[magicIndex + 2];
|
||||
int magicIndex = valuesPerLong - 1;
|
||||
long divideAdd = RECIPROCAL_MULT_AND_ADD[magicIndex];
|
||||
long divideMul = divideAdd != 0 ? divideAdd : 0x80000000L; // Special case for the 0x80000000/0x00000000 tuple
|
||||
int divideShift = RECIPROCAL_RIGHT_SHIFT[magicIndex];
|
||||
int size = (entries + valuesPerLong - 1) / valuesPerLong;
|
||||
|
||||
long[] data = new long[size];
|
||||
@@ -76,10 +75,10 @@ public class CompactArrayUtil {
|
||||
public static void iterateCompactArrayWithPadding(int bitsPerEntry, int entries, long[] data, BiIntConsumer consumer) {
|
||||
long maxEntryValue = (1L << bitsPerEntry) - 1;
|
||||
char valuesPerLong = (char) (64 / bitsPerEntry);
|
||||
int magicIndex = 3 * (valuesPerLong - 1);
|
||||
long divideMul = Integer.toUnsignedLong(MAGIC[magicIndex]);
|
||||
long divideAdd = Integer.toUnsignedLong(MAGIC[magicIndex + 1]);
|
||||
int divideShift = MAGIC[magicIndex + 2];
|
||||
int magicIndex = valuesPerLong - 1;
|
||||
long divideAdd = RECIPROCAL_MULT_AND_ADD[magicIndex];
|
||||
long divideMul = divideAdd != 0 ? divideAdd : 0x80000000L;
|
||||
int divideShift = RECIPROCAL_RIGHT_SHIFT[magicIndex];
|
||||
|
||||
for (int i = 0; i < entries; i++) {
|
||||
int cellIndex = (int) (i * divideMul + divideAdd >> 32L >> divideShift);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -34,29 +34,21 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PipelineUtil {
|
||||
private static Method DECODE_METHOD;
|
||||
private static Method ENCODE_METHOD;
|
||||
private static Method MTM_DECODE;
|
||||
public final class PipelineUtil {
|
||||
private static final Method DECODE_METHOD;
|
||||
private static final Method ENCODE_METHOD;
|
||||
private static final Method MTM_DECODE;
|
||||
|
||||
static {
|
||||
try {
|
||||
DECODE_METHOD = ByteToMessageDecoder.class.getDeclaredMethod("decode", ChannelHandlerContext.class, ByteBuf.class, List.class);
|
||||
DECODE_METHOD.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
ENCODE_METHOD = MessageToByteEncoder.class.getDeclaredMethod("encode", ChannelHandlerContext.class, Object.class, ByteBuf.class);
|
||||
ENCODE_METHOD.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
MTM_DECODE = MessageToMessageDecoder.class.getDeclaredMethod("decode", ChannelHandlerContext.class, Object.class, List.class);
|
||||
MTM_DECODE.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ tasks {
|
||||
publishShadowJar()
|
||||
|
||||
fun ShadowJar.configureRelocations() {
|
||||
relocate("javassist", "com.viaversion.viaversion.libs.javassist")
|
||||
relocate("com.google.gson", "com.viaversion.viaversion.libs.gson")
|
||||
relocate("com.github.steveice10.opennbt", "com.viaversion.viaversion.libs.opennbt")
|
||||
relocate("it.unimi.dsi.fastutil", "com.viaversion.viaversion.libs.fastutil")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
dependencies {
|
||||
implementation(projects.viaversionBukkitLegacy)
|
||||
implementation(projects.viaversionCommon)
|
||||
implementation(libs.javassist)
|
||||
compileOnly(libs.paper) {
|
||||
exclude("junit", "junit")
|
||||
exclude("com.google.code.gson", "gson")
|
||||
exclude("javax.persistence", "persistence-api")
|
||||
}
|
||||
compileOnly(projects.compat.protocolsupportCompat)
|
||||
}
|
||||
@@ -26,18 +26,16 @@ import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||
import com.viaversion.viaversion.api.platform.PlatformTask;
|
||||
import com.viaversion.viaversion.api.platform.UnsupportedSoftware;
|
||||
import com.viaversion.viaversion.api.platform.ViaPlatform;
|
||||
import com.viaversion.viaversion.bukkit.classgenerator.ClassGenerator;
|
||||
import com.viaversion.viaversion.bukkit.commands.BukkitCommandHandler;
|
||||
import com.viaversion.viaversion.bukkit.commands.BukkitCommandSender;
|
||||
import com.viaversion.viaversion.bukkit.listeners.ProtocolLibEnableListener;
|
||||
import com.viaversion.viaversion.bukkit.platform.BukkitViaAPI;
|
||||
import com.viaversion.viaversion.bukkit.platform.BukkitViaConfig;
|
||||
import com.viaversion.viaversion.bukkit.platform.BukkitViaInjector;
|
||||
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;
|
||||
@@ -59,8 +57,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
|
||||
private final List<Runnable> queuedTasks = new ArrayList<>();
|
||||
private final List<Runnable> asyncQueuedTasks = new ArrayList<>();
|
||||
private final boolean protocolSupport;
|
||||
private boolean compatSpigotBuild;
|
||||
private boolean spigot = true;
|
||||
private boolean lateBind;
|
||||
|
||||
public ViaVersionPlugin() {
|
||||
@@ -88,37 +84,13 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Via should load before PL, so we can't check for it in the constructor
|
||||
Plugin protocolLib = Bukkit.getPluginManager().getPlugin("ProtocolLib");
|
||||
ProtocolLibEnableListener.checkCompat(protocolLib);
|
||||
|
||||
// Spigot detector
|
||||
try {
|
||||
Class.forName("org.spigotmc.SpigotConfig");
|
||||
} catch (ClassNotFoundException e) {
|
||||
spigot = false;
|
||||
}
|
||||
|
||||
// Check if it's a spigot build with a protocol mod
|
||||
try {
|
||||
NMSUtil.nms(
|
||||
"PacketEncoder",
|
||||
"net.minecraft.network.PacketEncoder"
|
||||
).getDeclaredField("version");
|
||||
compatSpigotBuild = true;
|
||||
} catch (Exception e) {
|
||||
compatSpigotBuild = false;
|
||||
}
|
||||
|
||||
if (getServer().getPluginManager().getPlugin("ViaBackwards") != null) {
|
||||
MappingDataLoader.enableMappingsCache();
|
||||
}
|
||||
|
||||
// Generate classes needed (only works if it's compat or ps)
|
||||
ClassGenerator.generate();
|
||||
lateBind = !((BukkitViaInjector) Via.getManager().getInjector()).isBinded();
|
||||
|
||||
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded" + (lateBind ? ", waiting for boot. (late-bind)" : ", injecting!"));
|
||||
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now loaded" + (lateBind ? ", waiting for boot. (late-bind)" : ", injecting!"));
|
||||
if (!lateBind) {
|
||||
((ViaManagerImpl) Via.getManager()).init();
|
||||
}
|
||||
@@ -133,10 +105,8 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
|
||||
getCommand("viaversion").setExecutor(commandHandler);
|
||||
getCommand("viaversion").setTabCompleter(commandHandler);
|
||||
|
||||
getServer().getPluginManager().registerEvents(new ProtocolLibEnableListener(), this);
|
||||
|
||||
// Warn them if they have anti-xray on and they aren't using spigot
|
||||
if (conf.isAntiXRay() && !spigot) {
|
||||
if (conf.isAntiXRay() && !isSpigot()) {
|
||||
getLogger().info("You have anti-xray on in your config, since you're not using spigot it won't fix xray!");
|
||||
}
|
||||
|
||||
@@ -285,31 +255,40 @@ 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;
|
||||
}
|
||||
|
||||
public boolean isCompatSpigotBuild() {
|
||||
return compatSpigotBuild;
|
||||
}
|
||||
|
||||
public boolean isSpigot() {
|
||||
return this.spigot;
|
||||
}
|
||||
|
||||
public boolean isProtocolSupport() {
|
||||
return protocolSupport;
|
||||
}
|
||||
|
||||
private boolean isSpigot() {
|
||||
try {
|
||||
Class.forName("org.spigotmc.SpigotConfig");
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ViaVersionPlugin getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
-363
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* 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.classgenerator;
|
||||
|
||||
import com.viaversion.viaversion.ViaVersionPlugin;
|
||||
import com.viaversion.viaversion.bukkit.handlers.BukkitDecodeHandler;
|
||||
import com.viaversion.viaversion.bukkit.handlers.BukkitEncodeHandler;
|
||||
import com.viaversion.viaversion.bukkit.util.NMSUtil;
|
||||
import com.viaversion.viaversion.classgenerator.generated.BasicHandlerConstructor;
|
||||
import com.viaversion.viaversion.classgenerator.generated.HandlerConstructor;
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtField;
|
||||
import javassist.CtMethod;
|
||||
import javassist.CtNewConstructor;
|
||||
import javassist.CtNewMethod;
|
||||
import javassist.LoaderClassPath;
|
||||
import javassist.NotFoundException;
|
||||
import javassist.expr.ConstructorCall;
|
||||
import javassist.expr.ExprEditor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.EventExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
//TODO maybe clean this up a bit 👀
|
||||
public final class ClassGenerator {
|
||||
private static final boolean useModules = hasModuleMethod();
|
||||
private static HandlerConstructor constructor = new BasicHandlerConstructor();
|
||||
private static String psPackage;
|
||||
private static Class psConnectListener;
|
||||
|
||||
public static HandlerConstructor getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public static void generate() {
|
||||
if (ViaVersionPlugin.getInstance().isCompatSpigotBuild() || ViaVersionPlugin.getInstance().isProtocolSupport()) {
|
||||
try {
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
pool.insertClassPath(new LoaderClassPath(Bukkit.class.getClassLoader()));
|
||||
for (Plugin p : Bukkit.getPluginManager().getPlugins()) {
|
||||
pool.insertClassPath(new LoaderClassPath(p.getClass().getClassLoader()));
|
||||
}
|
||||
|
||||
if (ViaVersionPlugin.getInstance().isCompatSpigotBuild()) {
|
||||
Class decodeSuper = NMSUtil.nms("PacketDecoder", "net.minecraft.network.PacketDecoder");
|
||||
Class encodeSuper = NMSUtil.nms("PacketEncoder", "net.minecraft.network.PacketEncoder");
|
||||
// Generate the classes
|
||||
addSpigotCompatibility(pool, BukkitDecodeHandler.class, decodeSuper);
|
||||
addSpigotCompatibility(pool, BukkitEncodeHandler.class, encodeSuper);
|
||||
} else {
|
||||
// ProtocolSupport compatibility
|
||||
Class encodeSuper;
|
||||
Class decodeSuper;
|
||||
if (isMultiplatformPS()) {
|
||||
psConnectListener = makePSConnectListener(pool);
|
||||
return;
|
||||
} else {
|
||||
String psPackage = getOldPSPackage();
|
||||
decodeSuper = Class.forName(psPackage.equals("unknown") ? "protocolsupport.protocol.pipeline.common.PacketDecoder" : psPackage + ".wrapped.WrappedDecoder");
|
||||
encodeSuper = Class.forName(psPackage.equals("unknown") ? "protocolsupport.protocol.pipeline.common.PacketEncoder" : psPackage + ".wrapped.WrappedEncoder");
|
||||
}
|
||||
// Generate the classes
|
||||
addPSCompatibility(pool, BukkitDecodeHandler.class, decodeSuper);
|
||||
addPSCompatibility(pool, BukkitEncodeHandler.class, encodeSuper);
|
||||
}
|
||||
|
||||
|
||||
// Implement Constructor
|
||||
CtClass generated = pool.makeClass("com.viaversion.viaversion.classgenerator.generated.GeneratedConstructor");
|
||||
CtClass handlerInterface = pool.get(HandlerConstructor.class.getName());
|
||||
|
||||
generated.setInterfaces(new CtClass[]{handlerInterface});
|
||||
// Import required classes
|
||||
pool.importPackage("com.viaversion.viaversion.classgenerator.generated");
|
||||
pool.importPackage("com.viaversion.viaversion.classgenerator");
|
||||
pool.importPackage("com.viaversion.viaversion.api.connection");
|
||||
pool.importPackage("io.netty.handler.codec");
|
||||
// Implement Methods
|
||||
generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" +
|
||||
" return new BukkitEncodeHandler(info, minecraftEncoder);\n" +
|
||||
" }", generated));
|
||||
generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" +
|
||||
" return new BukkitDecodeHandler(info, minecraftDecoder);\n" +
|
||||
" }", generated));
|
||||
|
||||
constructor = (HandlerConstructor) toClass(generated).getConstructor().newInstance();
|
||||
} catch (ReflectiveOperationException | CannotCompileException | NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addSpigotCompatibility(ClassPool pool, Class input, Class superclass) {
|
||||
String newName = "com.viaversion.viaversion.classgenerator.generated." + input.getSimpleName();
|
||||
|
||||
try {
|
||||
CtClass generated = pool.getAndRename(input.getName(), newName);
|
||||
if (superclass != null) {
|
||||
CtClass toExtend = pool.get(superclass.getName());
|
||||
generated.setSuperclass(toExtend);
|
||||
|
||||
// If it's NMS satisfy constructor.
|
||||
if (superclass.getName().startsWith("net.minecraft")) {
|
||||
// Modify constructor to call super
|
||||
if (generated.getConstructors().length != 0) {
|
||||
generated.getConstructors()[0].instrument(new ExprEditor() {
|
||||
@Override
|
||||
public void edit(ConstructorCall c) throws CannotCompileException {
|
||||
if (c.isSuper()) {
|
||||
// Constructor for both has a stats thing.
|
||||
c.replace("super(null);");
|
||||
}
|
||||
super.edit(c);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
toClass(generated);
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (CannotCompileException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void addPSCompatibility(ClassPool pool, Class input, Class superclass) {
|
||||
boolean newPS = getOldPSPackage().equals("unknown");
|
||||
String newName = "com.viaversion.viaversion.classgenerator.generated." + input.getSimpleName();
|
||||
|
||||
try {
|
||||
CtClass generated = pool.getAndRename(input.getName(), newName);
|
||||
if (superclass != null) {
|
||||
CtClass toExtend = pool.get(superclass.getName());
|
||||
generated.setSuperclass(toExtend);
|
||||
|
||||
if (!newPS) {
|
||||
// Override setRealEncoder / setRealDecoder
|
||||
pool.importPackage(getOldPSPackage());
|
||||
pool.importPackage(getOldPSPackage() + ".wrapped");
|
||||
if (superclass.getName().endsWith("Decoder")) {
|
||||
// Decoder
|
||||
generated.addMethod(CtMethod.make("public void setRealDecoder(IPacketDecoder dec) {\n" +
|
||||
" ((WrappedDecoder) this.minecraftDecoder).setRealDecoder(dec);\n" +
|
||||
" }", generated));
|
||||
} else {
|
||||
// Encoder
|
||||
pool.importPackage("protocolsupport.api");
|
||||
pool.importPackage("java.lang.reflect");
|
||||
generated.addMethod(CtMethod.make("public void setRealEncoder(IPacketEncoder enc) {\n" +
|
||||
" try {\n" +
|
||||
// Tell ProtocolSupport to decode MINECRAFT_FUTURE packets using the default decoder (for 1.9.4)
|
||||
" Field field = enc.getClass().getDeclaredField(\"version\");\n" +
|
||||
" field.setAccessible(true);\n" +
|
||||
" ProtocolVersion version = (ProtocolVersion) field.get(enc);\n" +
|
||||
|
||||
" if (version == ProtocolVersion.MINECRAFT_FUTURE) enc = enc.getClass().getConstructor(\n" +
|
||||
" new Class[]{ProtocolVersion.class}).newInstance(new Object[] {ProtocolVersion.getLatest()});\n" +
|
||||
" } catch (Exception e) {\n" +
|
||||
// I guess we're not on 1.9.4
|
||||
" }\n" +
|
||||
" ((WrappedEncoder) this.minecraftEncoder).setRealEncoder(enc);\n" +
|
||||
" }", generated));
|
||||
}
|
||||
}
|
||||
}
|
||||
toClass(generated);
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (CannotCompileException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static Class makePSConnectListener(ClassPool pool) {
|
||||
HandshakeProtocolType type = handshakeVersionMethod();
|
||||
try {
|
||||
// Reference classes
|
||||
CtClass toExtend = pool.get("protocolsupport.api.Connection$PacketListener");
|
||||
CtClass connectListenerClazz = pool.makeClass("com.viaversion.viaversion.classgenerator.generated.ProtocolSupportConnectListener");
|
||||
connectListenerClazz.setSuperclass(toExtend);
|
||||
// Import packages
|
||||
pool.importPackage("java.util.Arrays");
|
||||
pool.importPackage("protocolsupport.api.ProtocolVersion");
|
||||
pool.importPackage("protocolsupport.api.ProtocolType");
|
||||
pool.importPackage("protocolsupport.api.Connection");
|
||||
pool.importPackage("protocolsupport.api.Connection.PacketListener");
|
||||
pool.importPackage("protocolsupport.api.Connection.PacketListener.PacketEvent");
|
||||
pool.importPackage("protocolsupport.protocol.ConnectionImpl");
|
||||
pool.importPackage(NMSUtil.nms(
|
||||
"PacketHandshakingInSetProtocol",
|
||||
"net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol"
|
||||
).getName());
|
||||
// Add connection reference field
|
||||
connectListenerClazz.addField(CtField.make("private ConnectionImpl connection;", connectListenerClazz));
|
||||
// Bake constructor
|
||||
connectListenerClazz.addConstructor(CtNewConstructor.make(
|
||||
"public ProtocolSupportConnectListener (ConnectionImpl connection) {\n"
|
||||
+ " this.connection = connection;\n"
|
||||
+ "}", connectListenerClazz));
|
||||
// Add the listening method
|
||||
connectListenerClazz.addMethod(CtNewMethod.make(
|
||||
// On packet receive
|
||||
"public void onPacketReceiving(protocolsupport.api.Connection.PacketListener.PacketEvent event) {\n"
|
||||
// Check if we are getting handshake packet.
|
||||
+ " if (event.getPacket() instanceof PacketHandshakingInSetProtocol) {\n"
|
||||
// Get protocol version.
|
||||
+ " PacketHandshakingInSetProtocol packet = (PacketHandshakingInSetProtocol) event.getPacket();\n"
|
||||
+ " int protoVersion = packet." + type.methodName() + "();\n"
|
||||
// ViaVersion has at this point already spoofed the connectionversion. (Since it is higher up the pipeline)
|
||||
// If via has put the protoVersion to the server we can spoof ProtocolSupport's version.
|
||||
+ " if (connection.getVersion() == ProtocolVersion.MINECRAFT_FUTURE && protoVersion == com.viaversion.viaversion.api.Via.getAPI().getServerVersion().lowestSupportedVersion()) {\n"
|
||||
+ " connection.setVersion(ProtocolVersion.getLatest(ProtocolType.PC));\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
// Id version is not serverversion viaversion will not spoof. ProtocolSupport will handle the rest.
|
||||
// In any case, remove the packet listener and wrap up.
|
||||
+ " connection.removePacketListener(this);\n"
|
||||
+ "}", connectListenerClazz));
|
||||
return toClass(connectListenerClazz);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void registerPSConnectListener(ViaVersionPlugin plugin) {
|
||||
if (psConnectListener != null) {
|
||||
try {
|
||||
Class<? extends Event> connectionOpenEvent = (Class<? extends Event>) Class.forName("protocolsupport.api.events.ConnectionOpenEvent");
|
||||
Bukkit.getPluginManager().registerEvent(connectionOpenEvent, new Listener() {
|
||||
}, EventPriority.HIGH, new EventExecutor() {
|
||||
@Override
|
||||
public void execute(@NonNull Listener listener, @NonNull Event event) throws EventException {
|
||||
try {
|
||||
Object connection = event.getClass().getMethod("getConnection").invoke(event);
|
||||
Object connectListener = psConnectListener.getConstructor(connection.getClass()).newInstance(connection);
|
||||
Method addConnectListener = connection.getClass().getMethod("addPacketListener", Class.forName("protocolsupport.api.Connection$PacketListener"));
|
||||
addConnectListener.invoke(connection, connectListener);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, plugin);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Class getPSConnectListener() {
|
||||
return psConnectListener;
|
||||
}
|
||||
|
||||
public static String getOldPSPackage() {
|
||||
if (psPackage == null) {
|
||||
try {
|
||||
Class.forName("protocolsupport.protocol.core.IPacketDecoder");
|
||||
psPackage = "protocolsupport.protocol.core";
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
Class.forName("protocolsupport.protocol.pipeline.IPacketDecoder");
|
||||
psPackage = "protocolsupport.protocol.pipeline";
|
||||
} catch (ClassNotFoundException e1) {
|
||||
psPackage = "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
return psPackage;
|
||||
}
|
||||
|
||||
public static boolean isMultiplatformPS() {
|
||||
try {
|
||||
Class.forName("protocolsupport.zplatform.impl.spigot.network.pipeline.SpigotPacketEncoder");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static HandshakeProtocolType handshakeVersionMethod() {
|
||||
Class<?> clazz = null;
|
||||
// Check for the mapped method
|
||||
try {
|
||||
clazz = NMSUtil.nms(
|
||||
"PacketHandshakingInSetProtocol",
|
||||
"net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol"
|
||||
);
|
||||
clazz.getMethod("getProtocolVersion");
|
||||
return HandshakeProtocolType.MAPPED;
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
|
||||
// Check for obfusacted b/c methods
|
||||
try {
|
||||
if (clazz.getMethod("b").getReturnType() == int.class) {
|
||||
return HandshakeProtocolType.OBFUSCATED_OLD;
|
||||
} else if (clazz.getMethod("c").getReturnType() == int.class) {
|
||||
return HandshakeProtocolType.OBFUSCATED_NEW;
|
||||
}
|
||||
throw new UnsupportedOperationException("Protocol version method not found in " + clazz.getSimpleName());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static Class<?> toClass(CtClass ctClass) throws CannotCompileException {
|
||||
return useModules ? ctClass.toClass(HandlerConstructor.class) : ctClass.toClass(HandlerConstructor.class.getClassLoader());
|
||||
}
|
||||
|
||||
private static boolean hasModuleMethod() {
|
||||
try {
|
||||
Class.class.getDeclaredMethod("getModule");
|
||||
return true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private enum HandshakeProtocolType {
|
||||
|
||||
MAPPED("getProtocolVersion"),
|
||||
OBFUSCATED_OLD("b"),
|
||||
OBFUSCATED_NEW("c");
|
||||
|
||||
private final String methodName;
|
||||
|
||||
HandshakeProtocolType(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public String methodName() {
|
||||
return methodName;
|
||||
}
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.compat;
|
||||
|
||||
import com.viaversion.viaversion.ViaVersionPlugin;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.bukkit.util.NMSUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
public final class ProtocolSupportCompat {
|
||||
|
||||
public static void registerPSConnectListener(ViaVersionPlugin plugin) {
|
||||
Via.getPlatform().getLogger().info("Registering ProtocolSupport compat connection listener");
|
||||
try {
|
||||
//noinspection unchecked
|
||||
Class<? extends Event> connectionOpenEvent = (Class<? extends Event>) Class.forName("protocolsupport.api.events.ConnectionOpenEvent");
|
||||
Bukkit.getPluginManager().registerEvent(connectionOpenEvent, new Listener() {
|
||||
}, EventPriority.HIGH, (listener, event) -> {
|
||||
try {
|
||||
Object connection = event.getClass().getMethod("getConnection").invoke(event);
|
||||
ProtocolSupportConnectionListener connectListener = new ProtocolSupportConnectionListener(connection);
|
||||
ProtocolSupportConnectionListener.ADD_PACKET_LISTENER_METHOD.invoke(connection, connectListener);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Via.getPlatform().getLogger().log(Level.WARNING, "Error when handling ProtocolSupport event", e);
|
||||
}
|
||||
}, plugin);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Via.getPlatform().getLogger().log(Level.WARNING, "Unable to register ProtocolSupport listener", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isMultiplatformPS() {
|
||||
try {
|
||||
Class.forName("protocolsupport.zplatform.impl.spigot.network.pipeline.SpigotPacketEncoder");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static HandshakeProtocolType handshakeVersionMethod() {
|
||||
Class<?> clazz = null;
|
||||
// Check for the mapped method
|
||||
try {
|
||||
clazz = NMSUtil.nms(
|
||||
"PacketHandshakingInSetProtocol",
|
||||
"net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol"
|
||||
);
|
||||
clazz.getMethod("getProtocolVersion");
|
||||
return HandshakeProtocolType.MAPPED;
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
|
||||
// Check for obfusacted b/c methods
|
||||
try {
|
||||
if (clazz.getMethod("b").getReturnType() == int.class) {
|
||||
return HandshakeProtocolType.OBFUSCATED_B;
|
||||
} else if (clazz.getMethod("c").getReturnType() == int.class) {
|
||||
return HandshakeProtocolType.OBFUSCATED_C;
|
||||
}
|
||||
throw new UnsupportedOperationException("Protocol version method not found in " + clazz.getSimpleName());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
enum HandshakeProtocolType {
|
||||
|
||||
MAPPED("getProtocolVersion"),
|
||||
OBFUSCATED_B("b"),
|
||||
OBFUSCATED_C("c");
|
||||
|
||||
private final String methodName;
|
||||
|
||||
HandshakeProtocolType(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public String methodName() {
|
||||
return methodName;
|
||||
}
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.compat;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.bukkit.util.NMSUtil;
|
||||
import protocolsupport.api.Connection;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
final class ProtocolSupportConnectionListener extends Connection.PacketListener {
|
||||
|
||||
static final Method ADD_PACKET_LISTENER_METHOD;
|
||||
private static final Class<?> HANDSHAKE_PACKET_CLASS;
|
||||
private static final Method GET_VERSION_METHOD;
|
||||
private static final Method SET_VERSION_METHOD;
|
||||
private static final Method REMOVE_PACKET_LISTENER_METHOD;
|
||||
private static final Method GET_LATEST_METHOD;
|
||||
private static final Object PROTOCOL_VERSION_MINECRAFT_FUTURE;
|
||||
private static final Object PROTOCOL_TYPE_PC;
|
||||
|
||||
static {
|
||||
try {
|
||||
HANDSHAKE_PACKET_CLASS = NMSUtil.nms(
|
||||
"PacketHandshakingInSetProtocol",
|
||||
"net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol"
|
||||
);
|
||||
|
||||
final Class<?> connectionImplClass = Class.forName("protocolsupport.protocol.ConnectionImpl");
|
||||
final Class<?> connectionClass = Class.forName("protocolsupport.api.Connection");
|
||||
final Class<?> packetListenerClass = Class.forName("protocolsupport.api.Connection$PacketListener");
|
||||
final Class<?> protocolVersionClass = Class.forName("protocolsupport.api.ProtocolVersion");
|
||||
final Class<?> protocolTypeClass = Class.forName("protocolsupport.api.ProtocolType");
|
||||
GET_VERSION_METHOD = connectionClass.getDeclaredMethod("getVersion");
|
||||
SET_VERSION_METHOD = connectionImplClass.getDeclaredMethod("setVersion", protocolVersionClass);
|
||||
PROTOCOL_VERSION_MINECRAFT_FUTURE = protocolVersionClass.getDeclaredField("MINECRAFT_FUTURE").get(null);
|
||||
GET_LATEST_METHOD = protocolVersionClass.getDeclaredMethod("getLatest", protocolTypeClass);
|
||||
PROTOCOL_TYPE_PC = protocolTypeClass.getDeclaredField("PC").get(null);
|
||||
ADD_PACKET_LISTENER_METHOD = connectionClass.getDeclaredMethod("addPacketListener", packetListenerClass);
|
||||
REMOVE_PACKET_LISTENER_METHOD = connectionClass.getDeclaredMethod("removePacketListener", packetListenerClass);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final Object connection;
|
||||
|
||||
ProtocolSupportConnectionListener(final Object connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceiving(final Connection.PacketListener.PacketEvent event) {
|
||||
try {
|
||||
// Check if we are getting handshake packet.
|
||||
if (HANDSHAKE_PACKET_CLASS.isInstance(event.getPacket()) && GET_VERSION_METHOD.invoke(connection) == PROTOCOL_VERSION_MINECRAFT_FUTURE) {
|
||||
final Object packet = event.getPacket();
|
||||
final int protocolVersion = (int) HANDSHAKE_PACKET_CLASS.getDeclaredMethod(ProtocolSupportCompat.handshakeVersionMethod().methodName()).invoke(packet);
|
||||
|
||||
// ViaVersion has at this point already spoofed the connectionversion. (Since it is higher up the pipeline)
|
||||
// If via has put the protoVersion to the server we can spoof ProtocolSupport's version.
|
||||
if (protocolVersion == Via.getAPI().getServerVersion().lowestSupportedVersion()) {
|
||||
SET_VERSION_METHOD.invoke(connection, GET_LATEST_METHOD.invoke(null, PROTOCOL_TYPE_PC));
|
||||
}
|
||||
}
|
||||
// Id version is not serverversion viaversion will not spoof. ProtocolSupport will handle the rest.
|
||||
// In any case, remove the packet listener and wrap up.
|
||||
REMOVE_PACKET_LISTENER_METHOD.invoke(connection, this);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
-13
@@ -18,33 +18,48 @@
|
||||
package com.viaversion.viaversion.bukkit.handlers;
|
||||
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.bukkit.classgenerator.ClassGenerator;
|
||||
import com.viaversion.viaversion.bukkit.platform.PaperViaInjector;
|
||||
import com.viaversion.viaversion.classgenerator.generated.HandlerConstructor;
|
||||
import com.viaversion.viaversion.connection.UserConnectionImpl;
|
||||
import com.viaversion.viaversion.platform.WrappedChannelInitializer;
|
||||
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitChannelInitializer extends ChannelInitializer<Channel> implements WrappedChannelInitializer {
|
||||
public final class BukkitChannelInitializer extends ChannelInitializer<Channel> implements WrappedChannelInitializer {
|
||||
|
||||
public static final String VIA_ENCODER = "via-encoder";
|
||||
public static final String VIA_DECODER = "via-decoder";
|
||||
public static final String MINECRAFT_ENCODER = "encoder";
|
||||
public static final String MINECRAFT_DECODER = "decoder";
|
||||
public static final String MINECRAFT_COMPRESSOR = "compress";
|
||||
public static final String MINECRAFT_DECOMPRESSOR = "decompress";
|
||||
public static final Object COMPRESSION_ENABLED_EVENT = paperCompressionEnabledEvent();
|
||||
private static final Method INIT_CHANNEL_METHOD;
|
||||
private final ChannelInitializer<Channel> original;
|
||||
|
||||
|
||||
static {
|
||||
try {
|
||||
INIT_CHANNEL_METHOD = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
||||
INIT_CHANNEL_METHOD.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Object paperCompressionEnabledEvent() {
|
||||
try {
|
||||
final Class<?> eventClass = Class.forName("io.papermc.paper.network.ConnectionEvent");
|
||||
return eventClass.getDeclaredField("COMPRESSION_THRESHOLD_SET").get(null);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public BukkitChannelInitializer(ChannelInitializer<Channel> oldInit) {
|
||||
this.original = oldInit;
|
||||
}
|
||||
@@ -62,7 +77,7 @@ public class BukkitChannelInitializer extends ChannelInitializer<Channel> implem
|
||||
}
|
||||
|
||||
public static void afterChannelInitialize(Channel channel) {
|
||||
UserConnection connection = new UserConnectionImpl(channel);
|
||||
final UserConnection connection = new UserConnectionImpl(channel);
|
||||
new ProtocolPipelineImpl(connection);
|
||||
|
||||
if (PaperViaInjector.PAPER_PACKET_LIMITER) {
|
||||
@@ -70,12 +85,9 @@ public class BukkitChannelInitializer extends ChannelInitializer<Channel> implem
|
||||
}
|
||||
|
||||
// Add our transformers
|
||||
HandlerConstructor constructor = ClassGenerator.getConstructor();
|
||||
MessageToByteEncoder encoder = constructor.newEncodeHandler(connection, (MessageToByteEncoder) channel.pipeline().get("encoder"));
|
||||
ByteToMessageDecoder decoder = constructor.newDecodeHandler(connection, (ByteToMessageDecoder) channel.pipeline().get("decoder"));
|
||||
|
||||
channel.pipeline().replace("encoder", "encoder", encoder);
|
||||
channel.pipeline().replace("decoder", "decoder", decoder);
|
||||
final ChannelPipeline pipeline = channel.pipeline();
|
||||
pipeline.addBefore(MINECRAFT_ENCODER, VIA_ENCODER, new BukkitEncodeHandler(connection));
|
||||
pipeline.addBefore(MINECRAFT_DECODER, VIA_DECODER, new BukkitDecodeHandler(connection));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+37
-32
@@ -26,59 +26,64 @@ import com.viaversion.viaversion.exception.CancelDecoderException;
|
||||
import com.viaversion.viaversion.exception.InformativeException;
|
||||
import com.viaversion.viaversion.util.PipelineUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitDecodeHandler extends ByteToMessageDecoder {
|
||||
private final ByteToMessageDecoder minecraftDecoder;
|
||||
private final UserConnection info;
|
||||
@ChannelHandler.Sharable
|
||||
public final class BukkitDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
||||
private final UserConnection connection;
|
||||
|
||||
public BukkitDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
|
||||
this.info = info;
|
||||
this.minecraftDecoder = minecraftDecoder;
|
||||
public BukkitDecodeHandler(final UserConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
||||
if (!info.checkServerboundPacket()) {
|
||||
bytebuf.clear(); // Don't accumulate
|
||||
protected void decode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List<Object> out) throws Exception {
|
||||
if (!connection.checkServerboundPacket()) {
|
||||
throw CancelDecoderException.generate(null);
|
||||
}
|
||||
if (!connection.shouldTransformPacket()) {
|
||||
out.add(bytebuf.retain());
|
||||
return;
|
||||
}
|
||||
|
||||
ByteBuf transformedBuf = null;
|
||||
final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||
try {
|
||||
if (info.shouldTransformPacket()) {
|
||||
transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||
info.transformServerbound(transformedBuf, CancelDecoderException::generate);
|
||||
}
|
||||
|
||||
try {
|
||||
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, transformedBuf == null ? bytebuf : transformedBuf));
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof Exception) {
|
||||
throw (Exception) e.getCause();
|
||||
} else if (e.getCause() instanceof Error) {
|
||||
throw (Error) e.getCause();
|
||||
}
|
||||
}
|
||||
connection.transformIncoming(transformedBuf, CancelDecoderException::generate);
|
||||
out.add(transformedBuf.retain());
|
||||
} finally {
|
||||
if (transformedBuf != null) {
|
||||
transformedBuf.release();
|
||||
}
|
||||
transformedBuf.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; // ProtocolLib compat
|
||||
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.exceptionCaught(ctx, cause);
|
||||
if (!NMSUtil.isDebugPropertySet() && PipelineUtil.containsCause(cause, InformativeException.class)
|
||||
&& (info.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
|
||||
&& (connection.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
|
||||
cause.printStackTrace(); // Print if CB doesn't already do it
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(final ChannelHandlerContext ctx, final Object event) throws Exception {
|
||||
if (BukkitChannelInitializer.COMPRESSION_ENABLED_EVENT == null || event != BukkitChannelInitializer.COMPRESSION_ENABLED_EVENT) {
|
||||
super.userEventTriggered(ctx, event);
|
||||
return;
|
||||
}
|
||||
|
||||
// When compression handlers are added, the order becomes Minecraft Encoder -> Compressor -> Via Encoder; fix the order again
|
||||
final ChannelPipeline pipeline = ctx.pipeline();
|
||||
pipeline.addAfter(BukkitChannelInitializer.MINECRAFT_COMPRESSOR, BukkitChannelInitializer.VIA_ENCODER, pipeline.remove(BukkitChannelInitializer.VIA_ENCODER));
|
||||
pipeline.addAfter(BukkitChannelInitializer.MINECRAFT_DECOMPRESSOR, BukkitChannelInitializer.VIA_DECODER, pipeline.remove(BukkitChannelInitializer.VIA_DECODER));
|
||||
super.userEventTriggered(ctx, event);
|
||||
}
|
||||
}
|
||||
+72
-53
@@ -24,80 +24,99 @@ import com.viaversion.viaversion.bukkit.util.NMSUtil;
|
||||
import com.viaversion.viaversion.exception.CancelCodecException;
|
||||
import com.viaversion.viaversion.exception.CancelEncoderException;
|
||||
import com.viaversion.viaversion.exception.InformativeException;
|
||||
import com.viaversion.viaversion.handlers.ChannelHandlerContextWrapper;
|
||||
import com.viaversion.viaversion.handlers.ViaCodecHandler;
|
||||
import com.viaversion.viaversion.util.PipelineUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaCodecHandler {
|
||||
private static Field versionField;
|
||||
@ChannelHandler.Sharable
|
||||
public final class BukkitEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
||||
private final UserConnection connection;
|
||||
private boolean handledCompression = BukkitChannelInitializer.COMPRESSION_ENABLED_EVENT != null;
|
||||
|
||||
static {
|
||||
try {
|
||||
// Attempt to get any version info from the handler
|
||||
versionField = NMSUtil.nms(
|
||||
"PacketEncoder",
|
||||
"net.minecraft.network.PacketEncoder"
|
||||
).getDeclaredField("version");
|
||||
|
||||
versionField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// Not compat version
|
||||
}
|
||||
}
|
||||
|
||||
private final UserConnection info;
|
||||
private final MessageToByteEncoder minecraftEncoder;
|
||||
|
||||
public BukkitEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
|
||||
this.info = info;
|
||||
this.minecraftEncoder = minecraftEncoder;
|
||||
public BukkitEncodeHandler(final UserConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
|
||||
if (versionField != null) {
|
||||
versionField.set(minecraftEncoder, versionField.get(this));
|
||||
protected void encode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List<Object> out) throws Exception {
|
||||
if (!connection.checkClientboundPacket()) {
|
||||
throw CancelEncoderException.generate(null);
|
||||
}
|
||||
// handle the packet type
|
||||
if (!(o instanceof ByteBuf)) {
|
||||
// call minecraft encoder
|
||||
try {
|
||||
PipelineUtil.callEncode(this.minecraftEncoder, new ChannelHandlerContextWrapper(ctx, this), o, bytebuf);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof Exception) {
|
||||
throw (Exception) e.getCause();
|
||||
} else if (e.getCause() instanceof Error) {
|
||||
throw (Error) e.getCause();
|
||||
}
|
||||
if (!connection.shouldTransformPacket()) {
|
||||
out.add(bytebuf.retain());
|
||||
return;
|
||||
}
|
||||
|
||||
final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||
try {
|
||||
final boolean needsCompression = !handledCompression && handleCompressionOrder(ctx, transformedBuf);
|
||||
connection.transformClientbound(transformedBuf, CancelEncoderException::generate);
|
||||
if (needsCompression) {
|
||||
recompress(ctx, transformedBuf);
|
||||
}
|
||||
|
||||
} else {
|
||||
bytebuf.writeBytes((ByteBuf) o);
|
||||
out.add(transformedBuf.retain());
|
||||
} finally {
|
||||
transformedBuf.release();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleCompressionOrder(final ChannelHandlerContext ctx, final ByteBuf buf) throws Exception {
|
||||
final ChannelPipeline pipeline = ctx.pipeline();
|
||||
final List<String> names = pipeline.names();
|
||||
final int compressorIndex = names.indexOf(BukkitChannelInitializer.MINECRAFT_COMPRESSOR);
|
||||
if (compressorIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
handledCompression = true;
|
||||
if (compressorIndex > names.indexOf(BukkitChannelInitializer.VIA_ENCODER)) {
|
||||
// Need to decompress this packet due to bad order
|
||||
final ByteBuf decompressed = (ByteBuf) PipelineUtil.callDecode((ByteToMessageDecoder) pipeline.get(BukkitChannelInitializer.MINECRAFT_DECOMPRESSOR), ctx, buf).get(0);
|
||||
try {
|
||||
buf.clear().writeBytes(decompressed);
|
||||
} finally {
|
||||
decompressed.release();
|
||||
}
|
||||
|
||||
pipeline.addAfter(BukkitChannelInitializer.MINECRAFT_COMPRESSOR, BukkitChannelInitializer.VIA_ENCODER, pipeline.remove(BukkitChannelInitializer.VIA_ENCODER));
|
||||
pipeline.addAfter(BukkitChannelInitializer.MINECRAFT_DECOMPRESSOR, BukkitChannelInitializer.VIA_DECODER, pipeline.remove(BukkitChannelInitializer.VIA_DECODER));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void recompress(final ChannelHandlerContext ctx, final ByteBuf buf) throws Exception {
|
||||
final ByteBuf compressed = ctx.alloc().buffer();
|
||||
try {
|
||||
PipelineUtil.callEncode((MessageToByteEncoder<ByteBuf>) ctx.pipeline().get(BukkitChannelInitializer.MINECRAFT_COMPRESSOR), ctx, buf, compressed);
|
||||
buf.clear().writeBytes(compressed);
|
||||
} finally {
|
||||
compressed.release();
|
||||
}
|
||||
transform(bytebuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ByteBuf bytebuf) throws Exception {
|
||||
if (!info.checkClientboundPacket()) throw CancelEncoderException.generate(null);
|
||||
if (!info.shouldTransformPacket()) return;
|
||||
info.transformClientbound(bytebuf, CancelEncoderException::generate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; // ProtocolLib compat
|
||||
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.exceptionCaught(ctx, cause);
|
||||
if (!NMSUtil.isDebugPropertySet() && PipelineUtil.containsCause(cause, InformativeException.class)
|
||||
&& (info.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
|
||||
&& (connection.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
|
||||
cause.printStackTrace(); // Print if CB doesn't already do it
|
||||
}
|
||||
}
|
||||
|
||||
public UserConnection connection() {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -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.connection() : 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);
|
||||
}
|
||||
|
||||
}
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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.bukkit.platform.BukkitViaInjector;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ProtocolLibEnableListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPluginEnable(PluginEnableEvent e) {
|
||||
// Will likely never happen, but try to account for hacky plugin loading systems anyways
|
||||
if (e.getPlugin().getName().equals("ProtocolLib")) {
|
||||
checkCompat(e.getPlugin());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginDisable(PluginDisableEvent e) {
|
||||
if (e.getPlugin().getName().equals("ProtocolLib")) {
|
||||
((BukkitViaInjector) Via.getManager().getInjector()).setProtocolLib(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkCompat(@Nullable Plugin protocolLib) {
|
||||
if (protocolLib != null) {
|
||||
String version = protocolLib.getDescription().getVersion();
|
||||
String majorVersion = version.split("\\.", 2)[0];
|
||||
try {
|
||||
// Only need the compat check for version < 5
|
||||
if (Integer.parseInt(majorVersion) < 5) {
|
||||
((BukkitViaInjector) Via.getManager().getInjector()).setProtocolLib(true);
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
Via.getPlatform().getLogger().warning("ProtocolLib version check failed for version " + version);
|
||||
}
|
||||
}
|
||||
((BukkitViaInjector) Via.getManager().getInjector()).setProtocolLib(false);
|
||||
}
|
||||
}
|
||||
+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;
|
||||
}
|
||||
}
|
||||
@@ -43,14 +43,17 @@ public class BukkitViaAPI extends ViaAPIBase<Player> {
|
||||
@Override
|
||||
public int getPlayerVersion(UUID uuid) {
|
||||
UserConnection connection = Via.getManager().getConnectionManager().getConnectedClient(uuid);
|
||||
if (connection == null) {
|
||||
if (connection != null) {
|
||||
return connection.getProtocolInfo().getProtocolVersion();
|
||||
}
|
||||
|
||||
if (isProtocolSupport()) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null && isProtocolSupport()) {
|
||||
if (player != null) {
|
||||
return ProtocolSupportUtil.getProtocolVersion(player);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return connection.getProtocolInfo().getProtocolVersion();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,16 +61,6 @@ public class BukkitViaAPI extends ViaAPIBase<Player> {
|
||||
sendRawPacket(player.getUniqueId(), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this version is a compatibility build for spigot.
|
||||
* Eg. 1.9.1 / 1.9.2 allow certain versions to connect
|
||||
*
|
||||
* @return true if compat Spigot build
|
||||
*/
|
||||
public boolean isCompatSpigotBuild() {
|
||||
return plugin.isCompatSpigotBuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if ProtocolSupport is also being used.
|
||||
*
|
||||
@@ -76,5 +69,4 @@ public class BukkitViaAPI extends ViaAPIBase<Player> {
|
||||
public boolean isProtocolSupport() {
|
||||
return plugin.isProtocolSupport();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,7 +35,6 @@ import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitViaInjector extends LegacyViaInjector {
|
||||
private boolean protocolLib;
|
||||
|
||||
@Override
|
||||
public void inject() throws ReflectiveOperationException {
|
||||
@@ -112,11 +111,6 @@ public class BukkitViaInjector extends LegacyViaInjector {
|
||||
throw new RuntimeException("Failed to get server");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDecoderName() {
|
||||
return protocolLib ? "protocol_lib_decoder" : "decoder";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Object getServerConnection() throws ReflectiveOperationException {
|
||||
Class<?> serverClass = NMSUtil.nms(
|
||||
@@ -189,8 +183,4 @@ public class BukkitViaInjector extends LegacyViaInjector {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setProtocolLib(boolean protocolLib) {
|
||||
this.protocolLib = protocolLib;
|
||||
}
|
||||
}
|
||||
+16
-3
@@ -23,21 +23,25 @@ import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
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.compat.ProtocolSupportCompat;
|
||||
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,11 +81,17 @@ 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");
|
||||
|
||||
// Add ProtocolSupport ConnectListener if necessary.
|
||||
ClassGenerator.registerPSConnectListener(plugin);
|
||||
if (plugin.isProtocolSupport() && ProtocolSupportCompat.isMultiplatformPS()) {
|
||||
ProtocolSupportCompat.registerPSConnectListener(plugin);
|
||||
}
|
||||
|
||||
int serverProtocolVersion = Via.getAPI().getServerVersion().lowestSupportedVersion();
|
||||
|
||||
/* 1.9 client to 1.8 server */
|
||||
@@ -174,6 +183,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
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ public final class PaperViaInjector {
|
||||
}
|
||||
|
||||
private static boolean hasPacketLimiter() {
|
||||
return hasClass("com.destroystokyo.paper.PaperConfig$PacketLimit") || hasClass("io.papermc.paper.PaperConfig$PacketLimit");
|
||||
return hasClass("com.destroystokyo.paper.PaperConfig$PacketLimit") || hasClass("io.papermc.paper.configuration.GlobalConfiguration$PacketLimiter");
|
||||
}
|
||||
|
||||
private static boolean hasClass(final String className) {
|
||||
|
||||
+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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ package com.viaversion.viaversion.bukkit.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class NMSUtil {
|
||||
public final class NMSUtil {
|
||||
private static final String BASE = Bukkit.getServer().getClass().getPackage().getName();
|
||||
private static final String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
||||
private static final boolean DEBUG_PROPERTY = loadDebugProperty();
|
||||
@@ -53,10 +53,6 @@ public class NMSUtil {
|
||||
return Class.forName(BASE + "." + className);
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
return BASE.substring(BASE.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if debug=true is set in the server.properties (added by CB)
|
||||
*/
|
||||
|
||||
+14
-10
@@ -22,27 +22,31 @@ import org.bukkit.entity.Player;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ProtocolSupportUtil {
|
||||
private static Method protocolVersionMethod = null;
|
||||
private static Method getIdMethod = null;
|
||||
public final class ProtocolSupportUtil {
|
||||
private static final Method PROTOCOL_VERSION_METHOD;
|
||||
private static final Method GET_ID_METHOD;
|
||||
|
||||
static {
|
||||
Method protocolVersionMethod = null;
|
||||
Method getIdMethod = null;
|
||||
try {
|
||||
protocolVersionMethod = Class.forName("protocolsupport.api.ProtocolSupportAPI").getMethod("getProtocolVersion", Player.class);
|
||||
getIdMethod = Class.forName("protocolsupport.api.ProtocolVersion").getMethod("getId");
|
||||
} catch (Exception e) {
|
||||
} catch (ReflectiveOperationException e) {
|
||||
// ProtocolSupport not installed.
|
||||
}
|
||||
PROTOCOL_VERSION_METHOD = protocolVersionMethod;
|
||||
GET_ID_METHOD = getIdMethod;
|
||||
}
|
||||
|
||||
public static int getProtocolVersion(Player player) {
|
||||
if (protocolVersionMethod == null) return -1;
|
||||
if (PROTOCOL_VERSION_METHOD == null) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
Object version = protocolVersionMethod.invoke(null, player);
|
||||
return (int) getIdMethod.invoke(version);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
Object version = PROTOCOL_VERSION_METHOD.invoke(null, player);
|
||||
return (int) GET_ID_METHOD.invoke(version);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return -1;
|
||||
|
||||
+18
-10
@@ -20,17 +20,25 @@ package com.viaversion.viaversion.classgenerator.generated;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.bukkit.handlers.BukkitDecodeHandler;
|
||||
import com.viaversion.viaversion.bukkit.handlers.BukkitEncodeHandler;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
|
||||
public class BasicHandlerConstructor implements HandlerConstructor {
|
||||
@Override
|
||||
public BukkitEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
|
||||
return new BukkitEncodeHandler(info, minecraftEncoder);
|
||||
}
|
||||
public interface HandlerSupplier {
|
||||
|
||||
@Override
|
||||
public BukkitDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
|
||||
return new BukkitDecodeHandler(info, minecraftDecoder);
|
||||
MessageToMessageEncoder<ByteBuf> newEncodeHandler(UserConnection connection);
|
||||
|
||||
MessageToMessageDecoder<ByteBuf> newDecodeHandler(UserConnection connection);
|
||||
|
||||
final class DefaultHandlerSupplier implements HandlerSupplier {
|
||||
@Override
|
||||
public MessageToMessageEncoder<ByteBuf> newEncodeHandler(final UserConnection connection) {
|
||||
return new BukkitEncodeHandler(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageToMessageDecoder<ByteBuf> newDecodeHandler(final UserConnection connection) {
|
||||
return new BukkitDecodeHandler(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
@@ -1,5 +1,5 @@
|
||||
dependencies {
|
||||
implementation(projects.viaversionCommon)
|
||||
implementation(projects.javaCompat)
|
||||
implementation(projects.compat)
|
||||
compileOnly(libs.bungee)
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -235,16 +235,6 @@ public abstract class LegacyViaInjector implements ViaInjector {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEncoderName() {
|
||||
return "encoder";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDecoderName() {
|
||||
return "decoder";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Vanilla server connection object the channels to be injected should be searched in.
|
||||
*
|
||||
|
||||
@@ -66,7 +66,9 @@ 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_19_3to1_19_1.Protocol1_19_3To1_19_1;
|
||||
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;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.Protocol1_9_3To1_9_1_2;
|
||||
@@ -118,7 +120,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 +176,9 @@ 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);
|
||||
|
||||
registerProtocol(new Protocol1_19_3To1_19_1(), ProtocolVersion.v1_19_3, ProtocolVersion.v1_19_1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -315,7 +320,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 +388,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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+31
-24
@@ -25,12 +25,15 @@ import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.Entity1_12Types;
|
||||
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
|
||||
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
|
||||
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.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_12;
|
||||
@@ -38,6 +41,8 @@ import com.viaversion.viaversion.data.entity.EntityTrackerBase;
|
||||
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.metadata.MetadataRewriter1_12To1_11_1;
|
||||
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.packets.InventoryPackets;
|
||||
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.providers.InventoryQuickMoveProvider;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9_1_2to1_9_3_4.types.Chunk1_9_3_4Type;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ClientboundPackets1_9_3;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ServerboundPackets1_9_3;
|
||||
@@ -125,33 +130,28 @@ public class Protocol1_12To1_11_1 extends AbstractProtocol<ClientboundPackets1_9
|
||||
Chunk1_9_3_4Type type = new Chunk1_9_3_4Type(clientWorld);
|
||||
Chunk chunk = wrapper.passthrough(type);
|
||||
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
if (section == null)
|
||||
continue;
|
||||
for (int s = 0; s < chunk.getSections().length; s++) {
|
||||
ChunkSection section = chunk.getSections()[s];
|
||||
if (section == null) continue;
|
||||
DataPalette blocks = section.palette(PaletteType.BLOCKS);
|
||||
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int block = section.getBlockWithoutData(x, y, z);
|
||||
// Is this a bed?
|
||||
if (block == 26) {
|
||||
// NBT -> { color:14, x:132, y:64, z:222, id:"minecraft:bed" } (Debug output)
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.put("color", new IntTag(14)); // Set color to red (Default in previous versions)
|
||||
tag.put("x", new IntTag(x + (chunk.getX() << 4)));
|
||||
tag.put("y", new IntTag(y + (i << 4)));
|
||||
tag.put("z", new IntTag(z + (chunk.getZ() << 4)));
|
||||
tag.put("id", new StringTag("minecraft:bed"));
|
||||
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
int id = blocks.idAt(idx) >> 4;
|
||||
// Is this a bed?
|
||||
if (id != 26) continue;
|
||||
|
||||
// Add a fake block entity
|
||||
chunk.getBlockEntities().add(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
// NBT -> { color:14, x:132, y:64, z:222, id:"minecraft:bed" } (Debug output)
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.put("color", new IntTag(14)); // Set color to red (Default in previous versions)
|
||||
tag.put("x", new IntTag(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4)));
|
||||
tag.put("y", new IntTag(ChunkSection.yFromIndex(idx) + (s << 4)));
|
||||
tag.put("z", new IntTag(ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)));
|
||||
tag.put("id", new StringTag("minecraft:bed"));
|
||||
|
||||
// Add a fake block entity
|
||||
chunk.getBlockEntities().add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -167,9 +167,16 @@ public class Protocol1_12To1_11_1 extends AbstractProtocol<ClientboundPackets1_9
|
||||
map(Type.UNSIGNED_BYTE);
|
||||
map(Type.INT);
|
||||
handler(wrapper -> {
|
||||
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
|
||||
UserConnection user = wrapper.user();
|
||||
ClientWorld clientChunks = user.get(ClientWorld.class);
|
||||
int dimensionId = wrapper.get(Type.INT, 1);
|
||||
clientChunks.setEnvironment(dimensionId);
|
||||
|
||||
// Reset recipes
|
||||
if (user.getProtocolInfo().getProtocolVersion() >= ProtocolVersion.v1_13.getVersion()) {
|
||||
wrapper.create(ClientboundPackets1_13.DECLARE_RECIPES, packetWrapper -> packetWrapper.write(Type.VAR_INT, 0))
|
||||
.scheduleSend(Protocol1_13To1_12_2.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
+30
-49
@@ -28,6 +28,8 @@ import com.viaversion.viaversion.api.minecraft.BlockFace;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
|
||||
@@ -75,31 +77,25 @@ public class ConnectionData {
|
||||
}
|
||||
|
||||
public static void updateChunkSectionNeighbours(UserConnection user, int chunkX, int chunkZ, int chunkSectionY) {
|
||||
int chunkMinY = chunkSectionY << 4;
|
||||
List<BlockChangeRecord1_8> updates = new ArrayList<>();
|
||||
for (int chunkDeltaX = -1; chunkDeltaX <= 1; chunkDeltaX++) {
|
||||
for (int chunkDeltaZ = -1; chunkDeltaZ <= 1; chunkDeltaZ++) {
|
||||
if (Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ) == 0) continue;
|
||||
int distance = Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ);
|
||||
if (distance == 0) continue;
|
||||
|
||||
List<BlockChangeRecord1_8> updates = new ArrayList<>();
|
||||
|
||||
if (Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ) == 2) { // Corner
|
||||
for (int blockY = chunkSectionY * 16; blockY < chunkSectionY * 16 + 16; blockY++) {
|
||||
int chunkMinX = (chunkX + chunkDeltaX) << 4;
|
||||
int chunkMinZ = (chunkZ + chunkDeltaZ) << 4;
|
||||
if (distance == 2) { // Corner
|
||||
for (int blockY = chunkMinY; blockY < chunkMinY + 16; blockY++) {
|
||||
int blockPosX = chunkDeltaX == 1 ? 0 : 15;
|
||||
int blockPosZ = chunkDeltaZ == 1 ? 0 : 15;
|
||||
updateBlock(user,
|
||||
new Position(
|
||||
((chunkX + chunkDeltaX) << 4) + blockPosX,
|
||||
(short) blockY,
|
||||
((chunkZ + chunkDeltaZ) << 4) + blockPosZ
|
||||
),
|
||||
updates
|
||||
);
|
||||
updateBlock(user, new Position(chunkMinX + blockPosX, blockY, chunkMinZ + blockPosZ), updates);
|
||||
}
|
||||
} else {
|
||||
for (int blockY = chunkSectionY * 16; blockY < chunkSectionY * 16 + 16; blockY++) {
|
||||
int xStart;
|
||||
int xEnd;
|
||||
int zStart;
|
||||
int zEnd;
|
||||
for (int blockY = chunkMinY; blockY < chunkMinY + 16; blockY++) {
|
||||
int xStart, xEnd;
|
||||
int zStart, zEnd;
|
||||
if (chunkDeltaX == 1) {
|
||||
xStart = 0;
|
||||
xEnd = 2;
|
||||
@@ -123,13 +119,7 @@ public class ConnectionData {
|
||||
}
|
||||
for (int blockX = xStart; blockX < xEnd; blockX++) {
|
||||
for (int blockZ = zStart; blockZ < zEnd; blockZ++) {
|
||||
updateBlock(user,
|
||||
new Position(
|
||||
((chunkX + chunkDeltaX) << 4) + blockX,
|
||||
(short) blockY,
|
||||
((chunkZ + chunkDeltaZ) << 4) + blockZ),
|
||||
updates
|
||||
);
|
||||
updateBlock(user, new Position(chunkMinX + blockX, blockY, chunkMinZ + blockZ), updates);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,6 +135,7 @@ public class ConnectionData {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
updates.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,17 +169,17 @@ public class ConnectionData {
|
||||
}
|
||||
|
||||
public static void connectBlocks(UserConnection user, Chunk chunk) {
|
||||
long xOff = chunk.getX() << 4;
|
||||
long zOff = chunk.getZ() << 4;
|
||||
int xOff = chunk.getX() << 4;
|
||||
int zOff = chunk.getZ() << 4;
|
||||
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
for (int s = 0; s < chunk.getSections().length; s++) {
|
||||
ChunkSection section = chunk.getSections()[s];
|
||||
if (section == null) continue;
|
||||
DataPalette blocks = section.palette(PaletteType.BLOCKS);
|
||||
|
||||
boolean willConnect = false;
|
||||
|
||||
for (int p = 0; p < section.getPaletteSize(); p++) {
|
||||
int id = section.getPaletteEntry(p);
|
||||
for (int p = 0; p < blocks.size(); p++) {
|
||||
int id = blocks.idByIndex(p);
|
||||
if (ConnectionData.connects(id)) {
|
||||
willConnect = true;
|
||||
break;
|
||||
@@ -196,24 +187,14 @@ public class ConnectionData {
|
||||
}
|
||||
if (!willConnect) continue;
|
||||
|
||||
long yOff = i << 4;
|
||||
int yOff = s << 4;
|
||||
|
||||
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);
|
||||
|
||||
ConnectionHandler handler = ConnectionData.getConnectionHandler(block);
|
||||
if (handler != null) {
|
||||
block = handler.connect(user, new Position(
|
||||
(int) (xOff + x),
|
||||
(short) (yOff + y),
|
||||
(int) (zOff + z)
|
||||
), block);
|
||||
section.setFlatBlock(x, y, z, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
int id = blocks.idAt(idx);
|
||||
ConnectionHandler handler = ConnectionData.getConnectionHandler(id);
|
||||
if (handler == null) continue;
|
||||
id = handler.connect(user, new Position(xOff + ChunkSection.xFromIndex(idx), yOff + ChunkSection.yFromIndex(idx), zOff + ChunkSection.zFromIndex(idx)), id);
|
||||
blocks.setIdAt(idx, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+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;
|
||||
|
||||
+20
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.packets;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.Entity1_13Types;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
|
||||
@@ -146,6 +147,25 @@ public class EntityPackets {
|
||||
}
|
||||
});
|
||||
|
||||
protocol.registerClientbound(ClientboundPackets1_12_1.ENTITY_EFFECT, new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
map(Type.VAR_INT); // Entity id
|
||||
map(Type.BYTE); // Effect id
|
||||
map(Type.BYTE); // Amplifier
|
||||
map(Type.VAR_INT); // Duration
|
||||
|
||||
handler(packetWrapper -> {
|
||||
byte flags = packetWrapper.read(Type.BYTE); // Input Flags
|
||||
|
||||
if (Via.getConfig().isNewEffectIndicator())
|
||||
flags |= 0x04;
|
||||
|
||||
packetWrapper.write(Type.BYTE, flags);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
metadataRewriter.registerRemoveEntities(ClientboundPackets1_12_1.DESTROY_ENTITIES);
|
||||
metadataRewriter.registerMetadataRewriter(ClientboundPackets1_12_1.ENTITY_METADATA, Types1_12.METADATA_LIST, Types1_13.METADATA_LIST);
|
||||
}
|
||||
|
||||
+6
-2
@@ -309,8 +309,12 @@ public class InventoryPackets extends ItemRewriter<Protocol1_13To1_12_2> {
|
||||
if (blockEntityTag.get("Patterns") instanceof ListTag) {
|
||||
for (Tag pattern : (ListTag) blockEntityTag.get("Patterns")) {
|
||||
if (pattern instanceof CompoundTag) {
|
||||
IntTag c = ((CompoundTag) pattern).get("Color");
|
||||
c.setValue(15 - c.asInt()); // Invert color id
|
||||
Tag c = ((CompoundTag) pattern).get("Color");
|
||||
if (c instanceof NumberTag) {
|
||||
// Invert color id
|
||||
((CompoundTag) pattern).put("Color",
|
||||
new IntTag(15 - ((NumberTag) c).asInt()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+295
-326
@@ -27,9 +27,10 @@ import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
|
||||
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 +84,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 +105,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 +135,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 +178,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 +206,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 +269,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 +303,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 +316,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 +327,210 @@ 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 s = 0; s < chunk.getSections().length; s++) {
|
||||
ChunkSection section = chunk.getSections()[s];
|
||||
if (section == null) continue;
|
||||
DataPalette blocks = section.palette(PaletteType.BLOCKS);
|
||||
|
||||
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 < blocks.size(); p++) {
|
||||
int old = blocks.idByIndex(p);
|
||||
int newId = toNewId(old);
|
||||
blocks.setIdByIndex(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 p = 0; p < blocks.size(); p++) {
|
||||
if (storage.isWelcome(blocks.idByIndex(p))) {
|
||||
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 idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
int id = blocks.idAt(idx);
|
||||
if (storage.isWelcome(id)) {
|
||||
storage.store(new Position(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4), ChunkSection.yFromIndex(idx) + (s << 4), ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)), id);
|
||||
} else if (!chunk.isFullChunk()) { // Update
|
||||
storage.remove(new Position(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4), ChunkSection.yFromIndex(idx) + (s << 4), ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
save_connections:
|
||||
{
|
||||
if (!Via.getConfig().isServersideBlockConnections() || !ConnectionData.needStoreBlocks()) break save_connections;
|
||||
|
||||
if (!chunk.isFullChunk()) { // Update
|
||||
ConnectionData.blockConnectionProvider.unloadChunkSection(wrapper.user(), chunk.getX(), s, chunk.getZ());
|
||||
}
|
||||
boolean willSave = false;
|
||||
for (int p = 0; p < blocks.size(); p++) {
|
||||
if (ConnectionData.isWelcome(blocks.idByIndex(p))) {
|
||||
willSave = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!willSave) break save_connections;
|
||||
|
||||
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
|
||||
int id = blocks.idAt(idx);
|
||||
if (ConnectionData.isWelcome(id)) {
|
||||
int globalX = ChunkSection.xFromIndex(idx) + (chunk.getX() << 4);
|
||||
int globalY = ChunkSection.yFromIndex(idx) + (s << 4);
|
||||
int globalZ = ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4);
|
||||
ConnectionData.blockConnectionProvider.storeBlock(wrapper.user(), globalX, globalY, globalZ, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
chunk.getBiomeData()[i] = 1; // Plains
|
||||
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();
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
chunk.getSections()[y >> 4].setFlatBlock(x & 0xF, y & 0xF, z & 0xF, newId);
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
|
||||
+5
-4
@@ -51,8 +51,8 @@ public class BannerHandler implements BlockEntityProvider.BlockEntityHandler {
|
||||
|
||||
Tag base = tag.get("Base");
|
||||
int color = 0;
|
||||
if (base != null) {
|
||||
color = ((NumberTag) tag.get("Base")).asInt();
|
||||
if (base instanceof NumberTag) {
|
||||
color = ((NumberTag) base).asInt();
|
||||
}
|
||||
// Standing banner
|
||||
if (blockId >= BANNER_START && blockId <= BANNER_STOP) {
|
||||
@@ -64,8 +64,9 @@ public class BannerHandler implements BlockEntityProvider.BlockEntityHandler {
|
||||
Via.getPlatform().getLogger().warning("Why does this block have the banner block entity? :(" + tag);
|
||||
}
|
||||
|
||||
if (tag.get("Patterns") instanceof ListTag) {
|
||||
for (Tag pattern : (ListTag) tag.get("Patterns")) {
|
||||
Tag patterns = tag.get("Patterns");
|
||||
if (patterns instanceof ListTag) {
|
||||
for (Tag pattern : (ListTag) patterns) {
|
||||
if (pattern instanceof CompoundTag) {
|
||||
Tag c = ((CompoundTag) pattern).get("Color");
|
||||
if (c instanceof IntTag) {
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class BedHandler implements BlockEntityProvider.BlockEntityHandler {
|
||||
int blockId = storage.get(position).getOriginal() - 972 + 748;
|
||||
|
||||
Tag color = tag.get("color");
|
||||
if (color != null) {
|
||||
if (color instanceof NumberTag) {
|
||||
blockId += (((NumberTag) color).asInt() * 16);
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 175 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user