1508 lines
77 KiB
Java
1508 lines
77 KiB
Java
/*
|
|
* This file is part of ViaLegacy - https://github.com/RaphiMC/ViaLegacy
|
|
* Copyright (C) 2020-2024 RK_01/RaphiMC 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 net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10;
|
|
|
|
import com.google.common.base.Joiner;
|
|
import com.viaversion.viaversion.api.Via;
|
|
import com.viaversion.viaversion.api.connection.ProtocolInfo;
|
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
|
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
|
|
import com.viaversion.viaversion.api.minecraft.Environment;
|
|
import com.viaversion.viaversion.api.minecraft.Position;
|
|
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
|
|
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
|
|
import com.viaversion.viaversion.api.minecraft.item.DataItem;
|
|
import com.viaversion.viaversion.api.minecraft.item.Item;
|
|
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
|
|
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.packet.State;
|
|
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
|
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
|
|
import com.viaversion.viaversion.api.type.Type;
|
|
import com.viaversion.viaversion.api.type.types.chunk.BulkChunkType1_8;
|
|
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_8;
|
|
import com.viaversion.viaversion.api.type.types.version.Types1_8;
|
|
import com.viaversion.viaversion.libs.gson.JsonElement;
|
|
import com.viaversion.viaversion.libs.gson.JsonObject;
|
|
import com.viaversion.viaversion.libs.mcstructs.text.serializer.TextComponentSerializer;
|
|
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
|
|
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
|
|
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8;
|
|
import com.viaversion.viaversion.protocols.protocol1_8.ServerboundPackets1_8;
|
|
import com.viaversion.viaversion.util.IdAndData;
|
|
import net.raphimc.vialegacy.ViaLegacy;
|
|
import net.raphimc.vialegacy.api.data.ItemList1_6;
|
|
import net.raphimc.vialegacy.api.remapper.LegacyItemRewriter;
|
|
import net.raphimc.vialegacy.api.util.PacketUtil;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_7_6_10to1_7_2_5.ClientboundPackets1_7_2;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_7_6_10to1_7_2_5.ServerboundPackets1_7_2;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.data.Particle;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.metadata.MetadataRewriter;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.GameProfile;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.MapData;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.MapIcon;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.TabListEntry;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.providers.GameProfileFetcher;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.rewriter.ChatComponentRewriter;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.rewriter.ItemRewriter;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.storage.*;
|
|
import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.types.Types1_7_6;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.*;
|
|
import java.util.logging.Level;
|
|
|
|
public class Protocol1_8to1_7_6_10 extends AbstractProtocol<ClientboundPackets1_7_2, ClientboundPackets1_8, ServerboundPackets1_7_2, ServerboundPackets1_8> {
|
|
|
|
private final LegacyItemRewriter<Protocol1_8to1_7_6_10> itemRewriter = new ItemRewriter(this);
|
|
private final ChatComponentRewriter chatComponentRewriter = new ChatComponentRewriter(this);
|
|
private final MetadataRewriter metadataRewriter = new MetadataRewriter(this);
|
|
|
|
public Protocol1_8to1_7_6_10() {
|
|
super(ClientboundPackets1_7_2.class, ClientboundPackets1_8.class, ServerboundPackets1_7_2.class, ServerboundPackets1_8.class);
|
|
}
|
|
|
|
public static final ValueTransformer<String, String> LEGACY_TO_JSON = new ValueTransformer<String, String>(Type.STRING, Type.STRING) {
|
|
@Override
|
|
public String transform(PacketWrapper packetWrapper, String message) {
|
|
final JsonObject jsonObject = new JsonObject();
|
|
jsonObject.addProperty("text", message);
|
|
return jsonObject.toString();
|
|
}
|
|
};
|
|
|
|
public static final ValueTransformer<String, String> LEGACY_TO_JSON_TRANSLATE = new ValueTransformer<String, String>(Type.STRING, Type.STRING) {
|
|
@Override
|
|
public String transform(PacketWrapper packetWrapper, String message) {
|
|
final JsonObject jsonObject = new JsonObject();
|
|
jsonObject.addProperty("translate", message);
|
|
return jsonObject.toString();
|
|
}
|
|
};
|
|
|
|
@Override
|
|
protected void registerPackets() {
|
|
this.itemRewriter.register();
|
|
|
|
this.registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO.getId(), ClientboundLoginPackets.HELLO.getId(), new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.STRING); // server hash
|
|
map(Type.SHORT_BYTE_ARRAY, Type.BYTE_ARRAY_PRIMITIVE); // public key
|
|
map(Type.SHORT_BYTE_ARRAY, Type.BYTE_ARRAY_PRIMITIVE); // verify token
|
|
}
|
|
});
|
|
this.registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE.getId(), ClientboundLoginPackets.GAME_PROFILE.getId(), new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
read(Type.STRING); // uuid
|
|
read(Type.STRING); // name
|
|
handler(wrapper -> { // 1.7.10 ignores the data from the server
|
|
final ProtocolInfo protocolInfo = wrapper.user().getProtocolInfo();
|
|
wrapper.write(Type.STRING, protocolInfo.getUuid().toString()); // uuid
|
|
wrapper.write(Type.STRING, protocolInfo.getUsername()); // name
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.KEEP_ALIVE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // key
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.JOIN_GAME, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT); // entity id
|
|
map(Type.UNSIGNED_BYTE); // gamemode
|
|
map(Type.BYTE); // dimension id
|
|
map(Type.UNSIGNED_BYTE); // difficulty
|
|
map(Type.UNSIGNED_BYTE); // max players
|
|
map(Type.STRING); // level type
|
|
create(Type.BOOLEAN, false); // reduced debug info
|
|
handler(wrapper -> {
|
|
final ProtocolInfo protocolInfo = wrapper.user().getProtocolInfo();
|
|
final TablistStorage tablistStorage = wrapper.user().get(TablistStorage.class);
|
|
tablistStorage.sendTempEntry(new TabListEntry(protocolInfo.getUsername(), protocolInfo.getUuid())); // load own skin
|
|
|
|
final int entityId = wrapper.get(Type.INT, 0);
|
|
final byte dimensionId = wrapper.get(Type.BYTE, 0);
|
|
final EntityTracker tracker = wrapper.user().get(EntityTracker.class);
|
|
tracker.trackEntity(entityId, EntityTypes1_10.EntityType.PLAYER);
|
|
tracker.setPlayerID(entityId);
|
|
wrapper.user().get(DimensionTracker.class).changeDimension(dimensionId);
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.CHAT_MESSAGE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
handler(wrapper -> wrapper.write(Type.STRING, chatComponentRewriter.toClient(wrapper.user(), wrapper.read(Type.STRING)))); // message
|
|
create(Type.BYTE, (byte) 0); // position
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_EQUIPMENT, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.SHORT); // slot
|
|
map(Types1_7_6.ITEM, Type.ITEM1_8); // item
|
|
handler(wrapper -> itemRewriter.handleItemToClient(wrapper.user(), wrapper.get(Type.ITEM1_8, 0)));
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SPAWN_POSITION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Types1_7_6.POSITION_INT, Type.POSITION1_8); // position
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.UPDATE_HEALTH, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.FLOAT); // health
|
|
map(Type.SHORT, Type.VAR_INT); // food
|
|
map(Type.FLOAT); // saturation
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.RESPAWN, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT); // dimension id
|
|
map(Type.UNSIGNED_BYTE); // difficulty
|
|
map(Type.UNSIGNED_BYTE); // gamemode
|
|
map(Type.STRING); // worldType
|
|
handler(wrapper -> {
|
|
if (wrapper.user().get(DimensionTracker.class).changeDimension(wrapper.get(Type.INT, 0))) {
|
|
wrapper.user().get(ChunkTracker.class).clear();
|
|
wrapper.user().get(EntityTracker.class).clear();
|
|
}
|
|
|
|
final ProtocolInfo protocolInfo = wrapper.user().getProtocolInfo();
|
|
final TablistStorage tablistStorage = wrapper.user().get(TablistStorage.class);
|
|
tablistStorage.sendTempEntry(new TabListEntry(protocolInfo.getUsername(), protocolInfo.getUuid())); // load own skin
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.PLAYER_POSITION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.DOUBLE); // x
|
|
map(Type.DOUBLE, Type.DOUBLE, stance -> stance - 1.62F); // y
|
|
map(Type.DOUBLE); // z
|
|
map(Type.FLOAT); // yaw
|
|
map(Type.FLOAT); // pitch
|
|
read(Type.BOOLEAN); // onGround
|
|
create(Type.BYTE, (byte) 0); // flags
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.USE_BED, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Types1_7_6.POSITION_BYTE, Type.POSITION1_8); // position
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SPAWN_PLAYER, wrapper -> {
|
|
final int entityID = wrapper.passthrough(Type.VAR_INT); // entity id
|
|
final UUID uuid = UUID.fromString(wrapper.read(Type.STRING)); // uuid
|
|
wrapper.write(Type.UUID, uuid);
|
|
final String name = wrapper.read(Type.STRING); // name
|
|
|
|
final TablistStorage tablistStorage = wrapper.user().get(TablistStorage.class);
|
|
final TabListEntry tempTabEntry = new TabListEntry(name, uuid);
|
|
|
|
final int dataCount = wrapper.read(Type.VAR_INT); // properties count
|
|
for (int i = 0; i < dataCount; i++) {
|
|
final String key = wrapper.read(Type.STRING); // name
|
|
final String value = wrapper.read(Type.STRING); // value
|
|
final String signature = wrapper.read(Type.STRING); // signature
|
|
tempTabEntry.gameProfile.addProperty(new GameProfile.Property(key, value, signature));
|
|
}
|
|
|
|
wrapper.passthrough(Type.INT); // x
|
|
wrapper.passthrough(Type.INT); // y
|
|
wrapper.passthrough(Type.INT); // z
|
|
wrapper.passthrough(Type.BYTE); // yaw
|
|
wrapper.passthrough(Type.BYTE); // pitch
|
|
|
|
final short itemId = wrapper.read(Type.SHORT); // item in hand
|
|
final Item currentItem = new DataItem(itemId, (byte) 1, (short) 0, null);
|
|
itemRewriter.handleItemToClient(wrapper.user(), currentItem);
|
|
wrapper.write(Type.SHORT, (short) currentItem.identifier());
|
|
|
|
final List<Metadata> metadata = wrapper.read(Types1_7_6.METADATA_LIST); // metadata
|
|
metadataRewriter.transform(wrapper.user(), EntityTypes1_10.EntityType.PLAYER, metadata);
|
|
wrapper.write(Types1_8.METADATA_LIST, metadata);
|
|
|
|
tablistStorage.sendTempEntry(tempTabEntry);
|
|
|
|
wrapper.user().get(EntityTracker.class).trackEntity(entityID, EntityTypes1_10.EntityType.PLAYER);
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.COLLECT_ITEM, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // collected entity id
|
|
map(Type.INT, Type.VAR_INT); // collector entity id
|
|
handler(wrapper -> wrapper.user().get(EntityTracker.class).removeEntity(wrapper.get(Type.VAR_INT, 0)));
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SPAWN_ENTITY, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT); // entity id
|
|
map(Type.BYTE); // type id
|
|
map(Type.INT); // x
|
|
map(Type.INT); // y
|
|
map(Type.INT); // z
|
|
map(Type.BYTE); // pitch
|
|
map(Type.BYTE); // yaw
|
|
map(Type.INT); // data
|
|
handler(wrapper -> {
|
|
final EntityTracker tracker = wrapper.user().get(EntityTracker.class);
|
|
final int entityID = wrapper.get(Type.VAR_INT, 0);
|
|
final int typeID = wrapper.get(Type.BYTE, 0);
|
|
int x = wrapper.get(Type.INT, 0);
|
|
int y = wrapper.get(Type.INT, 1);
|
|
int z = wrapper.get(Type.INT, 2);
|
|
byte yaw = wrapper.get(Type.BYTE, 2);
|
|
int data = wrapper.get(Type.INT, 3);
|
|
final EntityTypes1_10.EntityType type = EntityTypes1_10.getTypeFromId(typeID, true);
|
|
tracker.trackEntity(entityID, type);
|
|
tracker.updateEntityLocation(entityID, x, y, z, false);
|
|
|
|
if (type == EntityTypes1_10.ObjectType.ITEM_FRAME.getType()) {
|
|
switch (data) {
|
|
case 0:
|
|
z += 32;
|
|
yaw = 0;
|
|
break;
|
|
case 1:
|
|
x -= 32;
|
|
yaw = 64;
|
|
break;
|
|
case 2:
|
|
z -= 32;
|
|
yaw = -128;
|
|
break;
|
|
case 3:
|
|
x += 32;
|
|
yaw = -64;
|
|
break;
|
|
}
|
|
} else if (type == EntityTypes1_10.ObjectType.FALLING_BLOCK.getType()) {
|
|
final int id = data & 0xffff;
|
|
final int metadata = data >> 16;
|
|
final IdAndData block = new IdAndData(id, metadata);
|
|
wrapper.user().get(ChunkTracker.class).remapBlockParticle(block);
|
|
data = block.getId() | block.getData() << 12;
|
|
}
|
|
|
|
y = realignEntityY(type, y);
|
|
|
|
wrapper.set(Type.INT, 0, x);
|
|
wrapper.set(Type.INT, 1, y);
|
|
wrapper.set(Type.INT, 2, z);
|
|
wrapper.set(Type.BYTE, 2, yaw);
|
|
wrapper.set(Type.INT, 3, data);
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SPAWN_MOB, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT); // entity id
|
|
map(Type.UNSIGNED_BYTE); // type id
|
|
map(Type.INT); // x
|
|
map(Type.INT); // y
|
|
map(Type.INT); // z
|
|
map(Type.BYTE); // yaw
|
|
map(Type.BYTE); // pitch
|
|
map(Type.BYTE); // head yaw
|
|
map(Type.SHORT); // velocity x
|
|
map(Type.SHORT); // velocity y
|
|
map(Type.SHORT); // velocity z
|
|
map(Types1_7_6.METADATA_LIST, Types1_8.METADATA_LIST); // metadata
|
|
handler(wrapper -> {
|
|
final EntityTracker tracker = wrapper.user().get(EntityTracker.class);
|
|
final int entityID = wrapper.get(Type.VAR_INT, 0);
|
|
final int typeID = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
|
final int x = wrapper.get(Type.INT, 0);
|
|
final int y = wrapper.get(Type.INT, 1);
|
|
final int z = wrapper.get(Type.INT, 2);
|
|
final List<Metadata> metadataList = wrapper.get(Types1_8.METADATA_LIST, 0);
|
|
final EntityTypes1_10.EntityType entityType = EntityTypes1_10.getTypeFromId(typeID, false);
|
|
tracker.trackEntity(entityID, entityType);
|
|
tracker.updateEntityLocation(entityID, x, y, z, false);
|
|
tracker.updateEntityMetadata(entityID, metadataList);
|
|
|
|
metadataRewriter.transform(wrapper.user(), entityType, metadataList);
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SPAWN_PAINTING, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT); // entity id
|
|
map(Type.STRING); // motive
|
|
map(Types1_7_6.POSITION_INT, Type.POSITION1_8); // position
|
|
map(Type.INT, Type.BYTE); // rotation
|
|
handler(wrapper -> {
|
|
final short rotation = wrapper.get(Type.BYTE, 0);
|
|
final Position pos = wrapper.get(Type.POSITION1_8, 0);
|
|
int modX = 0;
|
|
int modZ = 0;
|
|
switch (rotation) {
|
|
case 0:
|
|
modZ = 1;
|
|
break;
|
|
case 1:
|
|
modX = -1;
|
|
break;
|
|
case 2:
|
|
modZ = -1;
|
|
break;
|
|
case 3:
|
|
modX = 1;
|
|
break;
|
|
}
|
|
wrapper.set(Type.POSITION1_8, 0, new Position(pos.x() + modX, pos.y(), pos.z() + modZ));
|
|
|
|
final int entityID = wrapper.get(Type.VAR_INT, 0);
|
|
wrapper.user().get(EntityTracker.class).trackEntity(entityID, EntityTypes1_10.EntityType.PAINTING);
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SPAWN_EXPERIENCE_ORB, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT); // entity id
|
|
map(Type.INT); // x
|
|
map(Type.INT); // y
|
|
map(Type.INT); // z
|
|
map(Type.SHORT); // count
|
|
handler(wrapper -> {
|
|
final int entityID = wrapper.get(Type.VAR_INT, 0);
|
|
wrapper.user().get(EntityTracker.class).trackEntity(entityID, EntityTypes1_10.EntityType.EXPERIENCE_ORB);
|
|
|
|
wrapper.set(Type.INT, 1, realignEntityY(EntityTypes1_10.EntityType.EXPERIENCE_ORB, wrapper.get(Type.INT, 1)));
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_VELOCITY, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.SHORT); // velocity x
|
|
map(Type.SHORT); // velocity y
|
|
map(Type.SHORT); // velocity z
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.DESTROY_ENTITIES, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Types1_7_6.INT_ARRAY, Type.VAR_INT_ARRAY_PRIMITIVE); // entity ids
|
|
handler(wrapper -> {
|
|
final EntityTracker tracker = wrapper.user().get(EntityTracker.class);
|
|
for (int entityId : wrapper.get(Type.VAR_INT_ARRAY_PRIMITIVE, 0)) {
|
|
tracker.removeEntity(entityId);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_MOVEMENT, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_POSITION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.BYTE); // x
|
|
map(Type.BYTE); // y
|
|
map(Type.BYTE); // z
|
|
handler(wrapper -> {
|
|
final EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
|
|
final int entityId = wrapper.get(Type.VAR_INT, 0);
|
|
final byte x = wrapper.get(Type.BYTE, 0);
|
|
final byte y = wrapper.get(Type.BYTE, 1);
|
|
final byte z = wrapper.get(Type.BYTE, 2);
|
|
entityTracker.updateEntityLocation(entityId, x, y, z, true);
|
|
|
|
if (ViaLegacy.getConfig().isDynamicOnground()) {
|
|
final boolean onGround = wrapper.get(Type.BYTE, 1) > -8/*0.25D*/;
|
|
entityTracker.getGroundMap().put(wrapper.get(Type.VAR_INT, 0), onGround);
|
|
wrapper.write(Type.BOOLEAN, onGround); // onGround
|
|
} else {
|
|
wrapper.write(Type.BOOLEAN, true); // onGround
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_ROTATION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.BYTE); // yaw
|
|
map(Type.BYTE); // pitch
|
|
handler(wrapper -> {
|
|
if (ViaLegacy.getConfig().isDynamicOnground()) {
|
|
final EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
|
|
wrapper.write(Type.BOOLEAN, entityTracker.getGroundMap().getOrDefault(wrapper.get(Type.VAR_INT, 0), true)); // onGround
|
|
} else {
|
|
wrapper.write(Type.BOOLEAN, true); // onGround
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_POSITION_AND_ROTATION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.BYTE); // x
|
|
map(Type.BYTE); // y
|
|
map(Type.BYTE); // z
|
|
map(Type.BYTE); // yaw
|
|
map(Type.BYTE); // pitch
|
|
handler(wrapper -> {
|
|
final EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
|
|
final int entityId = wrapper.get(Type.VAR_INT, 0);
|
|
final byte x = wrapper.get(Type.BYTE, 0);
|
|
final byte y = wrapper.get(Type.BYTE, 1);
|
|
final byte z = wrapper.get(Type.BYTE, 2);
|
|
entityTracker.updateEntityLocation(entityId, x, y, z, true);
|
|
|
|
if (ViaLegacy.getConfig().isDynamicOnground()) {
|
|
final boolean onGround = wrapper.get(Type.BYTE, 1) > -8/*0.25D*/;
|
|
entityTracker.getGroundMap().put(wrapper.get(Type.VAR_INT, 0), onGround);
|
|
wrapper.write(Type.BOOLEAN, onGround); // onGround
|
|
} else {
|
|
wrapper.write(Type.BOOLEAN, true); // onGround
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_TELEPORT, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.INT); // x
|
|
map(Type.INT); // y
|
|
map(Type.INT); // z
|
|
map(Type.BYTE); // yaw
|
|
map(Type.BYTE); // pitch
|
|
create(Type.BOOLEAN, true); // onGround
|
|
handler(wrapper -> {
|
|
final EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
|
|
final int entityId = wrapper.get(Type.VAR_INT, 0);
|
|
final int x = wrapper.get(Type.INT, 0);
|
|
final int y = wrapper.get(Type.INT, 1);
|
|
final int z = wrapper.get(Type.INT, 2);
|
|
entityTracker.updateEntityLocation(entityId, x, y, z, false);
|
|
|
|
final EntityTypes1_10.EntityType type = entityTracker.getTrackedEntities().get(entityId);
|
|
wrapper.set(Type.INT, 1, realignEntityY(type, y));
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_HEAD_LOOK, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.BYTE); // head yaw
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ATTACH_ENTITY, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT); // riding entity id
|
|
map(Type.INT); // vehicle entity id
|
|
map(Type.UNSIGNED_BYTE); // leash state
|
|
handler(wrapper -> {
|
|
final short leashState = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
|
if (leashState == 0) {
|
|
final EntityTracker tracker = wrapper.user().get(EntityTracker.class);
|
|
final int ridingId = wrapper.get(Type.INT, 0);
|
|
final int vehicleId = wrapper.get(Type.INT, 1);
|
|
tracker.updateEntityAttachState(ridingId, vehicleId);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_METADATA, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Types1_7_6.METADATA_LIST, Types1_8.METADATA_LIST); // metadata
|
|
handler(wrapper -> {
|
|
final EntityTracker tracker = wrapper.user().get(EntityTracker.class);
|
|
final List<Metadata> metadataList = wrapper.get(Types1_8.METADATA_LIST, 0);
|
|
final int entityID = wrapper.get(Type.VAR_INT, 0);
|
|
if (tracker.getTrackedEntities().containsKey(entityID)) {
|
|
tracker.updateEntityMetadata(entityID, metadataList);
|
|
metadataRewriter.transform(wrapper.user(), tracker.getTrackedEntities().get(entityID), metadataList);
|
|
if (metadataList.isEmpty()) wrapper.cancel();
|
|
} else {
|
|
wrapper.cancel();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_EFFECT, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.BYTE); // effect id
|
|
map(Type.BYTE); // amplifier
|
|
map(Type.SHORT, Type.VAR_INT); // duration
|
|
create(Type.BOOLEAN, false); // hide particles
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.REMOVE_ENTITY_EFFECT, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
map(Type.BYTE); // effect id
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SET_EXPERIENCE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.FLOAT); // experience bar
|
|
map(Type.SHORT, Type.VAR_INT); // level
|
|
map(Type.SHORT, Type.VAR_INT); // total experience
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.ENTITY_PROPERTIES, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT, Type.VAR_INT); // entity id
|
|
handler(wrapper -> {
|
|
final int amount = wrapper.passthrough(Type.INT); // count
|
|
for (int i = 0; i < amount; i++) {
|
|
wrapper.passthrough(Type.STRING); // id
|
|
wrapper.passthrough(Type.DOUBLE); // baseValue
|
|
final int modifierlength = wrapper.read(Type.SHORT); // modifier count
|
|
wrapper.write(Type.VAR_INT, modifierlength);
|
|
for (int j = 0; j < modifierlength; j++) {
|
|
wrapper.passthrough(Type.UUID); // modifier uuid
|
|
wrapper.passthrough(Type.DOUBLE); // modifier amount
|
|
wrapper.passthrough(Type.BYTE); // modifier operation
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.CHUNK_DATA, wrapper -> {
|
|
final Environment dimension = wrapper.user().get(DimensionTracker.class).getDimension();
|
|
|
|
final Chunk chunk = wrapper.read(Types1_7_6.getChunk(dimension));
|
|
wrapper.user().get(ChunkTracker.class).trackAndRemap(chunk);
|
|
wrapper.write(ChunkType1_8.forEnvironment(dimension), chunk);
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.MULTI_BLOCK_CHANGE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.INT); // chunkX
|
|
map(Type.INT); // chunkZ
|
|
map(Types1_7_6.BLOCK_CHANGE_RECORD_ARRAY, Type.BLOCK_CHANGE_RECORD_ARRAY); // blockChangeRecords
|
|
handler(wrapper -> {
|
|
final int chunkX = wrapper.get(Type.INT, 0);
|
|
final int chunkZ = wrapper.get(Type.INT, 1);
|
|
final BlockChangeRecord[] blockChangeRecords = wrapper.get(Type.BLOCK_CHANGE_RECORD_ARRAY, 0);
|
|
for (BlockChangeRecord record : blockChangeRecords) {
|
|
final int targetX = record.getSectionX() + (chunkX << 4);
|
|
final int targetY = record.getY(-1);
|
|
final int targetZ = record.getSectionZ() + (chunkZ << 4);
|
|
final IdAndData block = IdAndData.fromRawData(record.getBlockId());
|
|
final Position pos = new Position(targetX, targetY, targetZ);
|
|
wrapper.user().get(ChunkTracker.class).trackAndRemap(pos, block);
|
|
record.setBlockId(block.toRawData());
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.BLOCK_CHANGE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Types1_7_6.POSITION_UBYTE, Type.POSITION1_8); // position
|
|
handler(wrapper -> {
|
|
final int blockId = wrapper.read(Type.VAR_INT); // block id
|
|
final int data = wrapper.read(Type.UNSIGNED_BYTE); // block data
|
|
final Position pos = wrapper.get(Type.POSITION1_8, 0); // position
|
|
final IdAndData block = new IdAndData(blockId, data);
|
|
wrapper.user().get(ChunkTracker.class).trackAndRemap(pos, block);
|
|
wrapper.write(Type.VAR_INT, block.toRawData());
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.BLOCK_ACTION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Types1_7_6.POSITION_SHORT, Type.POSITION1_8); // position
|
|
map(Type.UNSIGNED_BYTE); // type
|
|
map(Type.UNSIGNED_BYTE); // data
|
|
map(Type.VAR_INT); // block id
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.BLOCK_BREAK_ANIMATION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT); // entity id
|
|
map(Types1_7_6.POSITION_INT, Type.POSITION1_8); // position
|
|
map(Type.BYTE); // progress
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.MAP_BULK_CHUNK, wrapper -> {
|
|
final Chunk[] chunks = wrapper.read(Types1_7_6.CHUNK_BULK);
|
|
for (Chunk chunk : chunks) {
|
|
wrapper.user().get(ChunkTracker.class).trackAndRemap(chunk);
|
|
}
|
|
wrapper.write(BulkChunkType1_8.TYPE, chunks);
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.EXPLOSION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.FLOAT); // x
|
|
map(Type.FLOAT); // y
|
|
map(Type.FLOAT); // z
|
|
map(Type.FLOAT); // radius
|
|
map(Type.INT); // record count
|
|
handler(wrapper -> {
|
|
final int x = wrapper.get(Type.FLOAT, 0).intValue();
|
|
final int y = wrapper.get(Type.FLOAT, 1).intValue();
|
|
final int z = wrapper.get(Type.FLOAT, 2).intValue();
|
|
final int recordCount = wrapper.get(Type.INT, 0);
|
|
final ChunkTracker chunkTracker = wrapper.user().get(ChunkTracker.class);
|
|
for (int i = 0; i < recordCount; i++) {
|
|
final Position pos = new Position(x + wrapper.passthrough(Type.BYTE), y + wrapper.passthrough(Type.BYTE), z + wrapper.passthrough(Type.BYTE));
|
|
chunkTracker.trackAndRemap(pos, new IdAndData(0, 0));
|
|
}
|
|
});
|
|
map(Type.FLOAT); // velocity x
|
|
map(Type.FLOAT); // velocity y
|
|
map(Type.FLOAT); // velocity z
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.EFFECT, wrapper -> {
|
|
int effectId = wrapper.read(Type.INT); // effect id
|
|
final Position pos = wrapper.read(Types1_7_6.POSITION_UBYTE); // position
|
|
int data = wrapper.read(Type.INT); // data
|
|
final boolean disableRelativeVolume = wrapper.read(Type.BOOLEAN); // server wide
|
|
|
|
if (!disableRelativeVolume && effectId == 2006) { // block dust effect
|
|
wrapper.setPacketType(ClientboundPackets1_8.SPAWN_PARTICLE);
|
|
final Random rnd = new Random();
|
|
final ChunkTracker chunkTracker = wrapper.user().get(ChunkTracker.class);
|
|
final IdAndData block = chunkTracker.getBlockNotNull(pos);
|
|
if (block.getId() != 0) {
|
|
double var21 = Math.min(0.2F + (float) data / 15.0F, 10.0F);
|
|
if (var21 > 2.5D) var21 = 2.5D;
|
|
final float var25 = randomFloatClamp(rnd, 0.0F, ((float) Math.PI * 2F));
|
|
final double var26 = randomFloatClamp(rnd, 0.75F, 1.0F);
|
|
|
|
final float offsetY = (float) (0.20000000298023224D + var21 / 100.0D);
|
|
final float offsetX = (float) (Math.cos(var25) * 0.2F * var26 * var26 * (var21 + 0.2D));
|
|
final float offsetZ = (float) (Math.sin(var25) * 0.2F * var26 * var26 * (var21 + 0.2D));
|
|
final int amount = (int) (150.0D * var21);
|
|
|
|
wrapper.write(Type.INT, Particle.BLOCK_DUST.ordinal());
|
|
wrapper.write(Type.BOOLEAN, false); // longDistance
|
|
wrapper.write(Type.FLOAT, pos.x() + 0.5F);
|
|
wrapper.write(Type.FLOAT, pos.y() + 1.0F);
|
|
wrapper.write(Type.FLOAT, pos.z() + 0.5F);
|
|
wrapper.write(Type.FLOAT, offsetX);
|
|
wrapper.write(Type.FLOAT, offsetY);
|
|
wrapper.write(Type.FLOAT, offsetZ);
|
|
wrapper.write(Type.FLOAT, 0.15000000596046448F); // particleSpeed
|
|
wrapper.write(Type.INT, amount);
|
|
wrapper.write(Type.VAR_INT, block.getId() | (block.getData() << 12));
|
|
} else {
|
|
wrapper.cancel();
|
|
}
|
|
} else {
|
|
if (!disableRelativeVolume && effectId == 1003) { // door_open
|
|
if (Math.random() > 0.5) {
|
|
effectId = 1006; // door_close
|
|
}
|
|
} else if (!disableRelativeVolume && effectId == 2001) { // block break effect
|
|
final ChunkTracker chunkTracker = wrapper.user().get(ChunkTracker.class);
|
|
final int blockID = data & 4095;
|
|
final int blockData = data >> 12 & 255;
|
|
final IdAndData block = new IdAndData(blockID, blockData);
|
|
chunkTracker.remapBlockParticle(block);
|
|
data = block.getId() | (block.getData() << 12);
|
|
}
|
|
|
|
wrapper.write(Type.INT, effectId);
|
|
wrapper.write(Type.POSITION1_8, pos);
|
|
wrapper.write(Type.INT, data);
|
|
wrapper.write(Type.BOOLEAN, disableRelativeVolume);
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SPAWN_PARTICLE, wrapper -> {
|
|
final String[] parts = wrapper.read(Type.STRING).split("_", 3);
|
|
Particle particle = Particle.find(parts[0]);
|
|
if (particle == null) {
|
|
particle = Particle.BARRIER;
|
|
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
|
ViaLegacy.getPlatform().getLogger().warning("Could not find 1.8 particle for " + Arrays.toString(parts));
|
|
}
|
|
}
|
|
wrapper.write(Type.INT, particle.ordinal()); // particle id
|
|
wrapper.write(Type.BOOLEAN, false); // long distance
|
|
wrapper.passthrough(Type.FLOAT); // x
|
|
wrapper.passthrough(Type.FLOAT); // y
|
|
wrapper.passthrough(Type.FLOAT); // z
|
|
wrapper.passthrough(Type.FLOAT); // offset x
|
|
wrapper.passthrough(Type.FLOAT); // offset y
|
|
wrapper.passthrough(Type.FLOAT); // offset z
|
|
wrapper.passthrough(Type.FLOAT); // speed
|
|
wrapper.passthrough(Type.INT); // amount
|
|
|
|
if (particle == Particle.ICON_CRACK) {
|
|
final int id = Integer.parseInt(parts[1]);
|
|
int damage = 0;
|
|
if (parts.length > 2) damage = Integer.parseInt(parts[2]);
|
|
final DataItem item = new DataItem(id, (byte) 1, (short) damage, null);
|
|
itemRewriter.handleItemToClient(wrapper.user(), item);
|
|
wrapper.write(Type.VAR_INT, item.identifier()); // particle data
|
|
if (item.data() != 0)
|
|
wrapper.write(Type.VAR_INT, (int) item.data()); // particle data
|
|
} else if (particle == Particle.BLOCK_CRACK || particle == Particle.BLOCK_DUST) {
|
|
final int id = Integer.parseInt(parts[1]);
|
|
final int metadata = Integer.parseInt(parts[2]);
|
|
final IdAndData block = new IdAndData(id, metadata);
|
|
wrapper.user().get(ChunkTracker.class).remapBlockParticle(block);
|
|
wrapper.write(Type.VAR_INT, block.getId() | block.getData() << 12); // particle data
|
|
} else if (particle.extra > 0)
|
|
throw new IllegalStateException("Tried to write particle which requires extra data, but no handler was found");
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.GAME_EVENT, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.UNSIGNED_BYTE); // reason
|
|
map(Type.FLOAT); // value
|
|
handler(wrapper -> {
|
|
if (wrapper.get(Type.UNSIGNED_BYTE, 0) == 3) {
|
|
final PacketWrapper chatMessage = PacketWrapper.create(ClientboundPackets1_8.CHAT_MESSAGE, wrapper.user());
|
|
chatMessage.write(Type.STRING, LEGACY_TO_JSON.transform(chatMessage, "Your game mode has been updated")); // message
|
|
chatMessage.write(Type.BYTE, (byte) 0); // position
|
|
chatMessage.send(Protocol1_8to1_7_6_10.class);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.OPEN_WINDOW, wrapper -> {
|
|
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE); // window id
|
|
final short windowType = wrapper.read(Type.UNSIGNED_BYTE); // window type
|
|
String title = wrapper.read(Type.STRING); // title
|
|
short slots = wrapper.read(Type.UNSIGNED_BYTE); // slots
|
|
boolean useProvidedWindowTitle = wrapper.read(Type.BOOLEAN); // use provided title
|
|
|
|
wrapper.user().get(WindowTracker.class).types.put(windowId, windowType);
|
|
|
|
final String inventoryName;
|
|
switch (windowType) {
|
|
case 0:
|
|
inventoryName = "minecraft:chest";
|
|
break;
|
|
case 1:
|
|
inventoryName = "minecraft:crafting_table";
|
|
break;
|
|
case 2:
|
|
inventoryName = "minecraft:furnace";
|
|
break;
|
|
case 3:
|
|
inventoryName = "minecraft:dispenser";
|
|
break;
|
|
case 4:
|
|
inventoryName = "minecraft:enchanting_table";
|
|
break;
|
|
case 5:
|
|
inventoryName = "minecraft:brewing_stand";
|
|
break;
|
|
case 6:
|
|
inventoryName = "minecraft:villager";
|
|
if (!useProvidedWindowTitle || title.isEmpty()) {
|
|
title = "entity.Villager.name";
|
|
useProvidedWindowTitle = false;
|
|
}
|
|
break;
|
|
case 7:
|
|
inventoryName = "minecraft:beacon";
|
|
break;
|
|
case 8:
|
|
inventoryName = "minecraft:anvil";
|
|
break;
|
|
case 9:
|
|
inventoryName = "minecraft:hopper";
|
|
break;
|
|
case 10:
|
|
inventoryName = "minecraft:dropper";
|
|
break;
|
|
case 11:
|
|
inventoryName = "EntityHorse";
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException("Unknown window type: " + windowType);
|
|
}
|
|
|
|
if (windowType == 1/*crafting_table*/ || windowType == 4/*enchanting_table*/ || windowType == 8/*anvil*/) {
|
|
slots = 0;
|
|
}
|
|
|
|
if (useProvidedWindowTitle) {
|
|
title = LEGACY_TO_JSON.transform(wrapper, title);
|
|
} else {
|
|
title = LEGACY_TO_JSON_TRANSLATE.transform(wrapper, title);
|
|
}
|
|
|
|
wrapper.write(Type.STRING, inventoryName);
|
|
wrapper.write(Type.STRING, title);
|
|
wrapper.write(Type.UNSIGNED_BYTE, slots);
|
|
if (windowType == 11) wrapper.passthrough(Type.INT); // entity id
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SET_SLOT, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
handler(wrapper -> {
|
|
final short windowId = wrapper.read(Type.BYTE); // window id
|
|
wrapper.write(Type.UNSIGNED_BYTE, windowId); // actually wrong, should by BYTE but Via uses U_BYTE
|
|
short slot = wrapper.read(Type.SHORT); // slot
|
|
final short windowType = wrapper.user().get(WindowTracker.class).get(windowId);
|
|
if (windowType == 4/*enchanting_table*/ && slot >= 1) slot += 1;
|
|
wrapper.write(Type.SHORT, slot);
|
|
});
|
|
map(Types1_7_6.ITEM, Type.ITEM1_8); // item
|
|
handler(wrapper -> itemRewriter.handleItemToClient(wrapper.user(), wrapper.get(Type.ITEM1_8, 0)));
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.WINDOW_ITEMS, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
handler(wrapper -> {
|
|
final short windowId = wrapper.passthrough(Type.UNSIGNED_BYTE); // window id
|
|
final short windowType = wrapper.user().get(WindowTracker.class).get(windowId);
|
|
Item[] items = wrapper.read(Types1_7_6.ITEM_ARRAY); // items
|
|
if (windowType == 4/*enchanting_table*/) {
|
|
final Item[] old = items;
|
|
items = new Item[old.length + 1];
|
|
items[0] = old[0];
|
|
System.arraycopy(old, 1, items, 2, old.length - 1);
|
|
items[1] = new DataItem(351/*lapis_lazuli*/, (byte) 3, (short) 4, null);
|
|
}
|
|
for (Item item : items) {
|
|
itemRewriter.handleItemToClient(wrapper.user(), item);
|
|
}
|
|
wrapper.write(Type.ITEM1_8_SHORT_ARRAY, items);
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.WINDOW_PROPERTY, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.UNSIGNED_BYTE); // window id
|
|
map(Type.SHORT); // progress bar id
|
|
map(Type.SHORT); // progress bar value
|
|
handler(wrapper -> {
|
|
final short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
|
short progressBar = wrapper.get(Type.SHORT, 0);
|
|
final short windowType = wrapper.user().get(WindowTracker.class).get(windowId);
|
|
if (windowType == 2) { // furnace
|
|
switch (progressBar) {
|
|
case 0: { // cookTime
|
|
progressBar = 2;
|
|
final PacketWrapper windowProperty = PacketWrapper.create(ClientboundPackets1_8.WINDOW_PROPERTY, wrapper.user());
|
|
windowProperty.write(Type.UNSIGNED_BYTE, windowId);
|
|
windowProperty.write(Type.SHORT, (short) 3);
|
|
windowProperty.write(Type.SHORT, (short) 200);
|
|
windowProperty.send(Protocol1_8to1_7_6_10.class);
|
|
break;
|
|
}
|
|
case 1: { // furnaceBurnTime
|
|
progressBar = 0;
|
|
break;
|
|
}
|
|
case 2: { // currentItemBurnTime
|
|
progressBar = 1;
|
|
break;
|
|
}
|
|
}
|
|
wrapper.set(Type.SHORT, 0, progressBar);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.UPDATE_SIGN, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Types1_7_6.POSITION_SHORT, Type.POSITION1_8); // position
|
|
map(LEGACY_TO_JSON); // line 1
|
|
map(LEGACY_TO_JSON); // line 2
|
|
map(LEGACY_TO_JSON); // line 3
|
|
map(LEGACY_TO_JSON); // line 4
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.MAP_DATA, wrapper -> {
|
|
final int id = wrapper.passthrough(Type.VAR_INT); // map id
|
|
final byte[] data = wrapper.read(Type.SHORT_BYTE_ARRAY); // data
|
|
|
|
final MapStorage mapStorage = wrapper.user().get(MapStorage.class);
|
|
MapData mapData = mapStorage.getMapData(id);
|
|
if (mapData == null) mapStorage.putMapData(id, mapData = new MapData());
|
|
|
|
if (data[0] == 1) {
|
|
final int count = (data.length - 1) / 3;
|
|
mapData.mapIcons = new MapIcon[count];
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
mapData.mapIcons[i] = new MapIcon((byte) (data[i * 3 + 1] >> 4), (byte) (data[i * 3 + 1] & 0xF), data[i * 3 + 2], data[i * 3 + 3]);
|
|
}
|
|
} else if (data[0] == 2) {
|
|
mapData.scale = data[1];
|
|
}
|
|
|
|
wrapper.write(Type.BYTE, mapData.scale);
|
|
wrapper.write(Type.VAR_INT, mapData.mapIcons.length);
|
|
for (MapIcon mapIcon : mapData.mapIcons) {
|
|
wrapper.write(Type.BYTE, (byte) (mapIcon.direction << 4 | mapIcon.type & 0xF));
|
|
wrapper.write(Type.BYTE, mapIcon.x);
|
|
wrapper.write(Type.BYTE, mapIcon.z);
|
|
}
|
|
|
|
if (data[0] == 0) {
|
|
final byte x = data[1];
|
|
final byte z = data[2];
|
|
final int rows = data.length - 3;
|
|
final byte[] newData = new byte[rows];
|
|
System.arraycopy(data, 3, newData, 0, rows);
|
|
|
|
wrapper.write(Type.BYTE, (byte) 1);
|
|
wrapper.write(Type.BYTE, (byte) rows);
|
|
wrapper.write(Type.BYTE, x);
|
|
wrapper.write(Type.BYTE, z);
|
|
wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, newData);
|
|
} else {
|
|
wrapper.write(Type.BYTE, (byte) 0);
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.BLOCK_ENTITY_DATA, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Types1_7_6.POSITION_SHORT, Type.POSITION1_8); // position
|
|
map(Type.UNSIGNED_BYTE); // type
|
|
map(Types1_7_6.NBT, Type.NAMED_COMPOUND_TAG); // data
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.OPEN_SIGN_EDITOR, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Types1_7_6.POSITION_INT, Type.POSITION1_8); // position
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.PLAYER_INFO, wrapper -> {
|
|
final String name = wrapper.read(Type.STRING); // name
|
|
final boolean online = wrapper.read(Type.BOOLEAN); // online
|
|
final short ping = wrapper.read(Type.SHORT); // ping
|
|
|
|
final TablistStorage tablistStorage = wrapper.user().get(TablistStorage.class);
|
|
TabListEntry entry = tablistStorage.tablist.get(name);
|
|
|
|
if (entry == null && online) { // add entry
|
|
tablistStorage.tablist.put(name, entry = new TabListEntry(name, ping));
|
|
wrapper.write(Type.VAR_INT, 0); // action
|
|
wrapper.write(Type.VAR_INT, 1); // count
|
|
wrapper.write(Type.UUID, entry.gameProfile.uuid); // uuid
|
|
wrapper.write(Type.STRING, entry.gameProfile.userName); // name
|
|
wrapper.write(Type.VAR_INT, 0); // properties count
|
|
wrapper.write(Type.VAR_INT, 0); // gamemode
|
|
wrapper.write(Type.VAR_INT, entry.ping); // ping
|
|
wrapper.write(Type.OPTIONAL_STRING, null); // display name
|
|
} else if (entry != null && !online) { // remove entry
|
|
tablistStorage.tablist.remove(name);
|
|
wrapper.write(Type.VAR_INT, 4); // action
|
|
wrapper.write(Type.VAR_INT, 1); // count
|
|
wrapper.write(Type.UUID, entry.gameProfile.uuid); // uuid
|
|
} else if (entry != null) { // update ping
|
|
entry.ping = ping;
|
|
wrapper.write(Type.VAR_INT, 2); // action
|
|
wrapper.write(Type.VAR_INT, 1); // count
|
|
wrapper.write(Type.UUID, entry.gameProfile.uuid); // uuid
|
|
wrapper.write(Type.VAR_INT, entry.ping); // ping
|
|
} else {
|
|
wrapper.cancel();
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.SCOREBOARD_OBJECTIVE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.STRING); // name
|
|
handler(wrapper -> {
|
|
final String value = wrapper.read(Type.STRING); // value
|
|
final byte mode = wrapper.passthrough(Type.BYTE); // mode
|
|
|
|
if (mode == 0/*CREATE*/ || mode == 2/*UPDATE*/) {
|
|
wrapper.write(Type.STRING, value);
|
|
wrapper.write(Type.STRING, "integer");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.UPDATE_SCORE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.STRING); // name
|
|
map(Type.BYTE, Type.VAR_INT); // mode
|
|
handler(wrapper -> {
|
|
final int mode = wrapper.get(Type.VAR_INT, 0);
|
|
if (mode == 0/*UPDATE*/) {
|
|
wrapper.passthrough(Type.STRING); // objective
|
|
wrapper.write(Type.VAR_INT, wrapper.read(Type.INT)); // score
|
|
} else {
|
|
wrapper.write(Type.STRING, "");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.TEAMS, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.STRING); // name
|
|
handler(wrapper -> {
|
|
final byte mode = wrapper.passthrough(Type.BYTE); // mode
|
|
if (mode == 0 || mode == 2) {
|
|
wrapper.passthrough(Type.STRING); // display name
|
|
wrapper.passthrough(Type.STRING); // prefix
|
|
wrapper.passthrough(Type.STRING); // suffix
|
|
wrapper.passthrough(Type.BYTE); // flags
|
|
wrapper.write(Type.STRING, "always"); // nametag visibility
|
|
wrapper.write(Type.BYTE, (byte) 0); // color
|
|
}
|
|
if (mode == 0 || mode == 3 || mode == 4) {
|
|
final int count = wrapper.read(Type.SHORT); // count
|
|
final String[] playerNames = new String[count];
|
|
for (int i = 0; i < count; i++) {
|
|
playerNames[i] = wrapper.read(Type.STRING); // player name
|
|
}
|
|
wrapper.write(Type.STRING_ARRAY, playerNames);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerClientbound(ClientboundPackets1_7_2.PLUGIN_MESSAGE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.STRING); // channel
|
|
read(Type.UNSIGNED_SHORT); // length
|
|
handlerSoftFail(wrapper -> {
|
|
final String channel = wrapper.get(Type.STRING, 0);
|
|
switch (channel) {
|
|
case "MC|Brand": {
|
|
wrapper.write(Type.STRING, new String(wrapper.read(Type.REMAINING_BYTES), StandardCharsets.UTF_8)); // brand
|
|
break;
|
|
}
|
|
case "MC|TrList":
|
|
wrapper.passthrough(Type.INT); // window id
|
|
final int count = wrapper.passthrough(Type.UNSIGNED_BYTE); // count
|
|
for (int i = 0; i < count; i++) {
|
|
Item item = wrapper.read(Types1_7_6.ITEM);
|
|
itemRewriter.handleItemToClient(wrapper.user(), item);
|
|
wrapper.write(Type.ITEM1_8, item); // item 1
|
|
|
|
item = wrapper.read(Types1_7_6.ITEM);
|
|
itemRewriter.handleItemToClient(wrapper.user(), item);
|
|
wrapper.write(Type.ITEM1_8, item); // item 3
|
|
|
|
final boolean has3Items = wrapper.passthrough(Type.BOOLEAN); // has 3 items
|
|
if (has3Items) {
|
|
item = wrapper.read(Types1_7_6.ITEM);
|
|
itemRewriter.handleItemToClient(wrapper.user(), item);
|
|
wrapper.write(Type.ITEM1_8, item); // item 2
|
|
}
|
|
|
|
wrapper.passthrough(Type.BOOLEAN); // unavailable
|
|
wrapper.write(Type.INT, 0); // uses
|
|
wrapper.write(Type.INT, Integer.MAX_VALUE); // max uses
|
|
}
|
|
break;
|
|
case "MC|RPack": {
|
|
final String url = new String(wrapper.read(Type.REMAINING_BYTES), StandardCharsets.UTF_8); // url
|
|
wrapper.clearPacket();
|
|
wrapper.setPacketType(ClientboundPackets1_8.RESOURCE_PACK);
|
|
wrapper.write(Type.STRING, url); // url
|
|
wrapper.write(Type.STRING, "legacy"); // hash
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
handler(wrapper -> {
|
|
final String name = wrapper.passthrough(Type.STRING); // name
|
|
final ProtocolInfo info = wrapper.user().getProtocolInfo();
|
|
// Set the information early
|
|
if (info.getUsername() == null) {
|
|
info.setUsername(name);
|
|
}
|
|
if (info.getUuid() == null) {
|
|
info.setUuid(ViaLegacy.getConfig().isLegacySkinLoading() ? Via.getManager().getProviders().get(GameProfileFetcher.class).getMojangUUID(name) : new GameProfile(name).uuid);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY.getId(), ServerboundLoginPackets.ENCRYPTION_KEY.getId(), new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.BYTE_ARRAY_PRIMITIVE, Type.SHORT_BYTE_ARRAY); // shared secret
|
|
map(Type.BYTE_ARRAY_PRIMITIVE, Type.SHORT_BYTE_ARRAY); // verify token
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.KEEP_ALIVE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT, Type.INT); // key
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.INTERACT_ENTITY, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT, Type.INT); // entity id
|
|
handler(wrapper -> {
|
|
final int mode = wrapper.read(Type.VAR_INT); // mode
|
|
if (mode == 2) { // interactAt
|
|
wrapper.write(Type.BYTE, (byte) 0); // mode
|
|
wrapper.read(Type.FLOAT); // offsetX
|
|
wrapper.read(Type.FLOAT); // offsetY
|
|
wrapper.read(Type.FLOAT); // offsetZ
|
|
final EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
|
|
final EntityTypes1_10.EntityType entityType = entityTracker.getTrackedEntities().get(wrapper.get(Type.INT, 0));
|
|
if (entityType == null || !entityType.isOrHasParent(EntityTypes1_10.EntityType.ARMOR_STAND)) {
|
|
wrapper.cancel();
|
|
}
|
|
} else {
|
|
wrapper.write(Type.BYTE, (byte) mode); // mode
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.PLAYER_POSITION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.DOUBLE); // x
|
|
map(Type.DOUBLE); // y
|
|
handler(wrapper -> wrapper.write(Type.DOUBLE, wrapper.get(Type.DOUBLE, 1) + 1.62)); // stance
|
|
map(Type.DOUBLE); // z
|
|
map(Type.BOOLEAN); // onGround
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.PLAYER_POSITION_AND_ROTATION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.DOUBLE); // x
|
|
map(Type.DOUBLE); // y
|
|
handler(wrapper -> wrapper.write(Type.DOUBLE, wrapper.get(Type.DOUBLE, 1) + 1.62)); // stance
|
|
map(Type.DOUBLE); // z
|
|
map(Type.FLOAT); // yaw
|
|
map(Type.FLOAT); // pitch
|
|
map(Type.BOOLEAN); // onGround
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.PLAYER_DIGGING, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT, Type.UNSIGNED_BYTE); // status
|
|
map(Type.POSITION1_8, Types1_7_6.POSITION_UBYTE); // position
|
|
map(Type.UNSIGNED_BYTE); // direction
|
|
handler(wrapper -> {
|
|
final short status = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
|
if (status == 5) { // RELEASE_USE_ITEM
|
|
wrapper.set(Type.UNSIGNED_BYTE, 1, (short) 255);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.PLAYER_BLOCK_PLACEMENT, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.POSITION1_8, Types1_7_6.POSITION_UBYTE); // position
|
|
map(Type.UNSIGNED_BYTE); // direction
|
|
map(Type.ITEM1_8, Types1_7_6.ITEM); // item
|
|
map(Type.UNSIGNED_BYTE); // offset x
|
|
map(Type.UNSIGNED_BYTE); // offset y
|
|
map(Type.UNSIGNED_BYTE); // offset z
|
|
handler(wrapper -> {
|
|
final short direction = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
|
final Item item = wrapper.get(Types1_7_6.ITEM, 0);
|
|
itemRewriter.handleItemToServer(wrapper.user(), item);
|
|
|
|
if (item != null && item.identifier() == ItemList1_6.writtenBook.itemID && direction == 255) { // If placed item is a book then cancel it and send a MC|BOpen to the client
|
|
final PacketWrapper openBook = PacketWrapper.create(ClientboundPackets1_8.PLUGIN_MESSAGE, wrapper.user());
|
|
openBook.write(Type.STRING, "MC|BOpen"); // channel
|
|
openBook.send(Protocol1_8to1_7_6_10.class);
|
|
wrapper.cancel();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.ANIMATION, wrapper -> {
|
|
final EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
|
|
wrapper.write(Type.INT, entityTracker.getPlayerID()); // entity id
|
|
wrapper.write(Type.BYTE, (byte) 1); // animation
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.ENTITY_ACTION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.VAR_INT, Type.INT); // entity id
|
|
map(Type.VAR_INT, Type.BYTE, action -> (byte) (action + 1)); // action id
|
|
map(Type.VAR_INT, Type.INT); // action parameter
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.STEER_VEHICLE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.FLOAT); // sideways
|
|
map(Type.FLOAT); // forwards
|
|
handler(wrapper -> {
|
|
final byte flags = wrapper.read(Type.BYTE); // flags
|
|
wrapper.write(Type.BOOLEAN, (flags & 1) > 0); // jumping
|
|
wrapper.write(Type.BOOLEAN, (flags & 2) > 0); // sneaking
|
|
});
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.CLICK_WINDOW, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
handler(wrapper -> {
|
|
final short windowId = wrapper.read(Type.UNSIGNED_BYTE); // window id
|
|
wrapper.write(Type.BYTE, (byte) windowId); // actually wrong, should be BYTE but Via uses U_BYTE
|
|
final short slot = wrapper.passthrough(Type.SHORT); // slot
|
|
|
|
final short windowType = wrapper.user().get(WindowTracker.class).get(windowId);
|
|
if (windowType == 4/*enchanting_table*/) {
|
|
if (slot == 1) {
|
|
final PacketWrapper resetHandItem = PacketWrapper.create(ClientboundPackets1_8.SET_SLOT, wrapper.user());
|
|
resetHandItem.write(Type.UNSIGNED_BYTE, (short) -1); // window id
|
|
resetHandItem.write(Type.SHORT, (short) 0); // slot
|
|
resetHandItem.write(Type.ITEM1_8, new DataItem(-1, (byte) 0, (short) 0, null));
|
|
resetHandItem.send(Protocol1_8to1_7_6_10.class);
|
|
final PacketWrapper setLapisSlot = PacketWrapper.create(ClientboundPackets1_8.SET_SLOT, wrapper.user());
|
|
setLapisSlot.write(Type.UNSIGNED_BYTE, windowId);
|
|
setLapisSlot.write(Type.SHORT, slot);
|
|
setLapisSlot.write(Type.ITEM1_8, new DataItem(351/*lapis_lazuli*/, (byte) 3, (short) 4, null));
|
|
setLapisSlot.send(Protocol1_8to1_7_6_10.class);
|
|
wrapper.cancel();
|
|
} else if (slot > 1) {
|
|
wrapper.set(Type.SHORT, 0, (short) (slot - 1));
|
|
}
|
|
}
|
|
});
|
|
map(Type.BYTE); // button
|
|
map(Type.SHORT); // transaction id
|
|
map(Type.BYTE); // action
|
|
map(Type.ITEM1_8, Types1_7_6.ITEM); // item
|
|
handler(wrapper -> itemRewriter.handleItemToServer(wrapper.user(), wrapper.get(Types1_7_6.ITEM, 0)));
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.CREATIVE_INVENTORY_ACTION, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.SHORT); // slot
|
|
map(Type.ITEM1_8, Types1_7_6.ITEM); // item
|
|
handler(wrapper -> itemRewriter.handleItemToServer(wrapper.user(), wrapper.get(Types1_7_6.ITEM, 0)));
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.UPDATE_SIGN, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.POSITION1_8, Types1_7_6.POSITION_SHORT); // position
|
|
handler(wrapper -> {
|
|
for (int i = 0; i < 4; i++) {
|
|
final JsonElement component = wrapper.read(Type.COMPONENT); // line
|
|
String text = TextComponentSerializer.V1_8.deserialize(component).asLegacyFormatString();
|
|
if (text.length() > 15) text = text.substring(0, 15);
|
|
wrapper.write(Type.STRING, text);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.TAB_COMPLETE, wrapper -> {
|
|
final String text = wrapper.read(Type.STRING); // text
|
|
wrapper.clearPacket(); // remove optional blockpos
|
|
wrapper.write(Type.STRING, text);
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.CLIENT_SETTINGS, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
map(Type.STRING); // language
|
|
map(Type.BYTE); // view distance
|
|
map(Type.BYTE); // chat visibility
|
|
map(Type.BOOLEAN); // enable colors
|
|
create(Type.BYTE, (byte) 2); // difficulty (unused)
|
|
map(Type.UNSIGNED_BYTE, Type.BOOLEAN, flags -> (flags & 1) == 1); // skin flags -> show cape
|
|
}
|
|
});
|
|
this.registerServerbound(ServerboundPackets1_8.PLUGIN_MESSAGE, new PacketHandlers() {
|
|
@Override
|
|
public void register() {
|
|
handler(wrapper -> {
|
|
final String channel = wrapper.read(Type.STRING); // channel
|
|
|
|
if (ViaLegacy.getConfig().isIgnoreLong1_8ChannelNames() && channel.length() > 16) {
|
|
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
|
ViaLegacy.getPlatform().getLogger().warning("Ignoring serverbound plugin channel, as it is longer than 16 characters: '" + channel + "'");
|
|
}
|
|
wrapper.cancel();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
switch (channel) {
|
|
case "MC|BEdit":
|
|
case "MC|BSign":
|
|
final Item item = wrapper.read(Type.ITEM1_8); // book
|
|
itemRewriter.handleItemToServer(wrapper.user(), item);
|
|
wrapper.write(Types1_7_6.ITEM, item); // book
|
|
break;
|
|
case "MC|Brand":
|
|
case "MC|ItemName":
|
|
final String content = wrapper.read(Type.STRING); // client brand or item name
|
|
wrapper.write(Type.REMAINING_BYTES, content.getBytes(StandardCharsets.UTF_8)); // client brand or item name
|
|
break;
|
|
case "MC|AdvCdm":
|
|
final byte type = wrapper.passthrough(Type.BYTE); // command block type (0 = Block, 1 = Minecart)
|
|
if (type == 0) {
|
|
wrapper.passthrough(Type.INT); // x
|
|
wrapper.passthrough(Type.INT); // y
|
|
wrapper.passthrough(Type.INT); // z
|
|
} else if (type == 1) {
|
|
wrapper.passthrough(Type.INT); // entity id
|
|
} else {
|
|
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
|
ViaLegacy.getPlatform().getLogger().warning("Unknown 1.8 command block type: " + type);
|
|
}
|
|
wrapper.cancel();
|
|
return;
|
|
}
|
|
wrapper.passthrough(Type.STRING); // command
|
|
wrapper.read(Type.BOOLEAN); // track output
|
|
break;
|
|
case "REGISTER":
|
|
case "UNREGISTER":
|
|
byte[] channels = wrapper.read(Type.REMAINING_BYTES);
|
|
|
|
if (ViaLegacy.getConfig().isIgnoreLong1_8ChannelNames()) {
|
|
final String[] registeredChannels = new String(channels, StandardCharsets.UTF_8).split("\0");
|
|
final List<String> validChannels = new ArrayList<>(registeredChannels.length);
|
|
for (String registeredChannel : registeredChannels) {
|
|
if (registeredChannel.length() > 16) {
|
|
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
|
ViaLegacy.getPlatform().getLogger().warning("Ignoring serverbound plugin channel register of '" + registeredChannel + "', as it is longer than 16 characters");
|
|
}
|
|
continue;
|
|
}
|
|
validChannels.add(registeredChannel);
|
|
}
|
|
if (validChannels.isEmpty()) {
|
|
wrapper.cancel();
|
|
return;
|
|
}
|
|
channels = Joiner.on('\0').join(validChannels).getBytes(StandardCharsets.UTF_8);
|
|
}
|
|
|
|
wrapper.write(Type.REMAINING_BYTES, channels); // data
|
|
break;
|
|
}
|
|
} catch (Exception e) {
|
|
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
|
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to handle packet", e);
|
|
}
|
|
wrapper.cancel();
|
|
return;
|
|
}
|
|
|
|
final short length = (short) PacketUtil.calculateLength(wrapper);
|
|
wrapper.resetReader();
|
|
wrapper.write(Type.STRING, channel); // channel
|
|
wrapper.write(Type.SHORT, length); // length
|
|
});
|
|
}
|
|
});
|
|
this.cancelServerbound(ServerboundPackets1_8.SPECTATE);
|
|
this.cancelServerbound(ServerboundPackets1_8.RESOURCE_PACK_STATUS);
|
|
}
|
|
|
|
private float randomFloatClamp(Random rnd, float min, float max) {
|
|
return min >= max ? min : rnd.nextFloat() * (max - min) + min;
|
|
}
|
|
|
|
private int realignEntityY(final EntityTypes1_10.EntityType type, final int y) {
|
|
float yPos = y / 32F;
|
|
float yOffset = 0F;
|
|
if (type == EntityTypes1_10.ObjectType.FALLING_BLOCK.getType())
|
|
yOffset = 0.98F / 2F;
|
|
if (type == EntityTypes1_10.ObjectType.TNT_PRIMED.getType())
|
|
yOffset = 0.98F / 2F;
|
|
if (type == EntityTypes1_10.ObjectType.ENDER_CRYSTAL.getType())
|
|
yOffset = 1F;
|
|
else if (type == EntityTypes1_10.ObjectType.MINECART.getType())
|
|
yOffset = 0.7F / 2F;
|
|
else if (type == EntityTypes1_10.ObjectType.BOAT.getType())
|
|
yOffset = 0.6F / 2F;
|
|
else if (type == EntityTypes1_10.ObjectType.ITEM.getType())
|
|
yOffset = 0.25F / 2F;
|
|
else if (type == EntityTypes1_10.ObjectType.LEASH.getType())
|
|
yOffset = 0.5F;
|
|
else if (type == EntityTypes1_10.EntityType.EXPERIENCE_ORB)
|
|
yOffset = 0.5F / 2F;
|
|
return (int) Math.floor((yPos - yOffset) * 32F);
|
|
}
|
|
|
|
@Override
|
|
public void register(ViaProviders providers) {
|
|
providers.require(GameProfileFetcher.class);
|
|
}
|
|
|
|
@Override
|
|
public void init(UserConnection userConnection) {
|
|
userConnection.put(new TablistStorage(userConnection));
|
|
userConnection.put(new WindowTracker());
|
|
userConnection.put(new EntityTracker(userConnection));
|
|
userConnection.put(new MapStorage());
|
|
userConnection.put(new DimensionTracker());
|
|
userConnection.put(new ChunkTracker());
|
|
}
|
|
|
|
@Override
|
|
public LegacyItemRewriter<Protocol1_8to1_7_6_10> getItemRewriter() {
|
|
return this.itemRewriter;
|
|
}
|
|
|
|
public MetadataRewriter getMetadataRewriter() {
|
|
return this.metadataRewriter;
|
|
}
|
|
|
|
}
|