3
0
Mirror von https://github.com/ViaVersion/ViaVersion.git synchronisiert 2024-11-19 14:30:16 +01:00
Dieser Commit ist enthalten in:
KennyTV 2020-07-08 21:01:18 +02:00
Ursprung 58e7455cd9
Commit 7171802b78
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 6BE3B555EBC5982B
29 geänderte Dateien mit 562 neuen und 89 gelöschten Zeilen

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

Datei anzeigen

@ -14,6 +14,7 @@ import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URL;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -205,7 +206,11 @@ public class MappingDataLoader {
return null; return null;
} }
private static InputStream getResource(String name) { public static InputStream getResource(String name) {
return MappingDataLoader.class.getClassLoader().getResourceAsStream("assets/viaversion/data/" + name); return MappingDataLoader.class.getClassLoader().getResourceAsStream("assets/viaversion/data/" + name);
} }
public static URL getResourceUrl(String name) {
return MappingDataLoader.class.getClassLoader().getResource("assets/viaversion/data/" + name);
}
} }

Datei anzeigen

@ -1,29 +1,38 @@
package us.myles.ViaVersion.api.minecraft; package us.myles.ViaVersion.api.minecraft;
public class BlockChangeRecord { public interface BlockChangeRecord {
private final short horizontal;
private final short y;
private int blockId;
public BlockChangeRecord(short horizontal, short y, int blockId) { /**
this.horizontal = horizontal; * @return relative x coordinate within the chunk section
this.y = y; */
this.blockId = blockId; byte getSectionX();
/**
* @return relative y coordinate within the chunk section
*/
byte getSectionY();
/**
* @return relative z coordinate within the chunk section
*/
byte getSectionZ();
/**
* @param chunkSectionY chunk section
* @return absolute y coordinate
*/
short getY(int chunkSectionY);
/**
* @return absolute y coordinate
* @deprecated 1.16+ stores the relative y coordinate
*/
@Deprecated
default short getY() {
return getY(-1);
} }
public short getHorizontal() { int getBlockId();
return horizontal;
}
public short getY() { void setBlockId(int blockId);
return y;
}
public int getBlockId() {
return blockId;
}
public void setBlockId(int blockId) {
this.blockId = blockId;
}
} }

Datei anzeigen

@ -0,0 +1,50 @@
package us.myles.ViaVersion.api.minecraft;
import com.google.common.base.Preconditions;
public class BlockChangeRecord1_16_2 implements BlockChangeRecord {
private final byte sectionX;
private final byte sectionY;
private final byte sectionZ;
private int blockId;
public BlockChangeRecord1_16_2(byte sectionX, byte sectionY, byte sectionZ, int blockId) {
this.sectionX = sectionX;
this.sectionY = sectionY;
this.sectionZ = sectionZ;
this.blockId = blockId;
}
public BlockChangeRecord1_16_2(int sectionX, int sectionY, int sectionZ, int blockId) {
this((byte) sectionX, (byte) sectionY, (byte) sectionZ, blockId);
}
@Override
public byte getSectionX() {
return sectionX;
}
@Override
public byte getSectionY() {
return sectionY;
}
@Override
public byte getSectionZ() {
return sectionZ;
}
@Override
public short getY(int chunkSectionY) {
Preconditions.checkArgument(chunkSectionY >= 0 && chunkSectionY < 16);
return (short) ((chunkSectionY << 4) + sectionY);
}
public int getBlockId() {
return blockId;
}
public void setBlockId(int blockId) {
this.blockId = blockId;
}
}

Datei anzeigen

@ -0,0 +1,54 @@
package us.myles.ViaVersion.api.minecraft;
public class BlockChangeRecord1_8 implements BlockChangeRecord {
private final byte sectionX;
private final short y;
private final byte sectionZ;
private int blockId;
public BlockChangeRecord1_8(byte sectionX, short y, byte sectionZ, int blockId) {
this.sectionX = sectionX;
this.y = y;
this.sectionZ = sectionZ;
this.blockId = blockId;
}
public BlockChangeRecord1_8(int sectionX, int y, int sectionZ, int blockId) {
this((byte) sectionX, (short) y, (byte) sectionZ, blockId);
}
/**
* @return x coordinate within the chunk section
*/
public byte getSectionX() {
return sectionX;
}
@Override
public byte getSectionY() {
return (byte) (y & 0xF);
}
/**
* @return y coordinate
*/
@Override
public short getY(int chunkSectionY) {
return y;
}
/**
* @return z coordinate within the chunk section
*/
public byte getSectionZ() {
return sectionZ;
}
public int getBlockId() {
return blockId;
}
public void setBlockId(int blockId) {
this.blockId = blockId;
}
}

Datei anzeigen

@ -84,7 +84,7 @@ public class ProtocolVersion {
register(v1_15_2 = new ProtocolVersion(578, "1.15.2")); register(v1_15_2 = new ProtocolVersion(578, "1.15.2"));
register(v1_16 = new ProtocolVersion(735, "1.16")); register(v1_16 = new ProtocolVersion(735, "1.16"));
register(v1_16_1 = new ProtocolVersion(736, "1.16.1")); register(v1_16_1 = new ProtocolVersion(736, "1.16.1"));
register(v1_16_2 = new ProtocolVersion(738, "1.16.2")); register(v1_16_2 = new ProtocolVersion(740, "1.16.2"));
register(unknown = new ProtocolVersion(-1, "UNKNOWN")); register(unknown = new ProtocolVersion(-1, "UNKNOWN"));
} }

Datei anzeigen

@ -63,9 +63,22 @@ public class BlockRewriter {
public void registerMap() { public void registerMap() {
map(Type.INT); // 0 - Chunk X map(Type.INT); // 0 - Chunk X
map(Type.INT); // 1 - Chunk Z map(Type.INT); // 1 - Chunk Z
map(Type.BLOCK_CHANGE_RECORD_ARRAY); // 2 - Records
handler(wrapper -> { handler(wrapper -> {
for (BlockChangeRecord record : wrapper.get(Type.BLOCK_CHANGE_RECORD_ARRAY, 0)) { for (BlockChangeRecord record : wrapper.passthrough(Type.BLOCK_CHANGE_RECORD_ARRAY)) {
record.setBlockId(blockStateRewriter.rewrite(record.getBlockId()));
}
});
}
});
}
public void registerVarLongMultiBlockChange(ClientboundPacketType packetType) {
protocol.registerOutgoing(packetType, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.LONG); // Chunk position
handler(wrapper -> {
for (BlockChangeRecord record : wrapper.passthrough(Type.VAR_LONG_BLOCK_CHANGE_RECORD_ARRAY)) {
record.setBlockId(blockStateRewriter.rewrite(record.getBlockId())); record.setBlockId(blockStateRewriter.rewrite(record.getBlockId()));
} }
}); });

Datei anzeigen

@ -3,10 +3,51 @@ package us.myles.ViaVersion.api.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import us.myles.ViaVersion.api.minecraft.*; import us.myles.ViaVersion.api.minecraft.BlockChangeRecord;
import us.myles.ViaVersion.api.minecraft.EulerAngle;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.minecraft.Vector;
import us.myles.ViaVersion.api.minecraft.VillagerData;
import us.myles.ViaVersion.api.minecraft.item.Item; import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.type.types.*; import us.myles.ViaVersion.api.type.types.ArrayType;
import us.myles.ViaVersion.api.type.types.minecraft.*; import us.myles.ViaVersion.api.type.types.BooleanType;
import us.myles.ViaVersion.api.type.types.ByteArrayType;
import us.myles.ViaVersion.api.type.types.ByteType;
import us.myles.ViaVersion.api.type.types.ComponentType;
import us.myles.ViaVersion.api.type.types.DoubleType;
import us.myles.ViaVersion.api.type.types.FloatType;
import us.myles.ViaVersion.api.type.types.IntType;
import us.myles.ViaVersion.api.type.types.LongType;
import us.myles.ViaVersion.api.type.types.RemainingBytesType;
import us.myles.ViaVersion.api.type.types.ShortType;
import us.myles.ViaVersion.api.type.types.StringType;
import us.myles.ViaVersion.api.type.types.UUIDIntArrayType;
import us.myles.ViaVersion.api.type.types.UUIDType;
import us.myles.ViaVersion.api.type.types.UnsignedByteType;
import us.myles.ViaVersion.api.type.types.UnsignedShortType;
import us.myles.ViaVersion.api.type.types.VarIntArrayType;
import us.myles.ViaVersion.api.type.types.VarIntType;
import us.myles.ViaVersion.api.type.types.VarLongType;
import us.myles.ViaVersion.api.type.types.VoidType;
import us.myles.ViaVersion.api.type.types.minecraft.BlockChangeRecordType;
import us.myles.ViaVersion.api.type.types.minecraft.EulerAngleType;
import us.myles.ViaVersion.api.type.types.minecraft.FlatItemArrayType;
import us.myles.ViaVersion.api.type.types.minecraft.FlatItemType;
import us.myles.ViaVersion.api.type.types.minecraft.FlatVarIntItemArrayType;
import us.myles.ViaVersion.api.type.types.minecraft.FlatVarIntItemType;
import us.myles.ViaVersion.api.type.types.minecraft.ItemArrayType;
import us.myles.ViaVersion.api.type.types.minecraft.ItemType;
import us.myles.ViaVersion.api.type.types.minecraft.NBTType;
import us.myles.ViaVersion.api.type.types.minecraft.OptPosition1_14Type;
import us.myles.ViaVersion.api.type.types.minecraft.OptPositionType;
import us.myles.ViaVersion.api.type.types.minecraft.OptUUIDType;
import us.myles.ViaVersion.api.type.types.minecraft.OptionalComponentType;
import us.myles.ViaVersion.api.type.types.minecraft.OptionalVarIntType;
import us.myles.ViaVersion.api.type.types.minecraft.Position1_14Type;
import us.myles.ViaVersion.api.type.types.minecraft.PositionType;
import us.myles.ViaVersion.api.type.types.minecraft.VarLongBlockChangeRecordType;
import us.myles.ViaVersion.api.type.types.minecraft.VectorType;
import us.myles.ViaVersion.api.type.types.minecraft.VillagerDataType;
import java.util.UUID; import java.util.UUID;
@ -94,7 +135,7 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public static final Type<Integer[]> VAR_INT_ARRAY = new ArrayType<>(Type.VAR_INT); public static final Type<Integer[]> VAR_INT_ARRAY = new ArrayType<>(Type.VAR_INT);
public static final Type<int[]> VAR_INT_ARRAY_PRIMITIVE = new VarIntArrayType(); public static final Type<int[]> VAR_INT_ARRAY_PRIMITIVE = new VarIntArrayType();
public static final Type<Integer> OPTIONAL_VAR_INT = new OptionalVarIntType(); public static final Type<Integer> OPTIONAL_VAR_INT = new OptionalVarIntType();
public static final Type<Long> VAR_LONG = new VarLongType(); public static final VarLongType VAR_LONG = new VarLongType();
/** /**
* @deprecated unreasonable overhead * @deprecated unreasonable overhead
*/ */
@ -121,6 +162,9 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public static final Type<BlockChangeRecord> BLOCK_CHANGE_RECORD = new BlockChangeRecordType(); 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); public static final Type<BlockChangeRecord[]> BLOCK_CHANGE_RECORD_ARRAY = new ArrayType<>(Type.BLOCK_CHANGE_RECORD);
public static final Type<BlockChangeRecord> VAR_LONG_BLOCK_CHANGE_RECORD = new VarLongBlockChangeRecordType();
public static final Type<BlockChangeRecord[]> VAR_LONG_BLOCK_CHANGE_RECORD_ARRAY = new ArrayType<>(Type.VAR_LONG_BLOCK_CHANGE_RECORD);
public static final Type<VillagerData> VILLAGER_DATA = new VillagerDataType(); public static final Type<VillagerData> VILLAGER_DATA = new VillagerDataType();
/* 1.13 Flat Item (no data) */ /* 1.13 Flat Item (no data) */

Datei anzeigen

@ -10,10 +10,25 @@ public class VarLongType extends Type<Long> implements TypeConverter<Long> {
super("VarLong", Long.class); super("VarLong", Long.class);
} }
@Override public long readPrimitive(ByteBuf buffer) {
public void write(ByteBuf buffer, Long object) { long out = 0;
int bytes = 0;
byte in;
do {
in = buffer.readByte();
out |= (long) (in & 0x7F) << (bytes++ * 7);
if (bytes > 10) { // 10 is maxBytes
throw new RuntimeException("VarLong too big");
}
} while ((in & 0x80) == 0x80);
return out;
}
public void writePrimitive(ByteBuf buffer, long object) {
int part; int part;
while (true) { do {
part = (int) (object & 0x7F); part = (int) (object & 0x7F);
object >>>= 7; object >>>= 7;
@ -22,35 +37,26 @@ public class VarLongType extends Type<Long> implements TypeConverter<Long> {
} }
buffer.writeByte(part); buffer.writeByte(part);
} while (object != 0);
if (object == 0) {
break;
}
}
} }
/**
* @deprecated use {@link #readPrimitive(ByteBuf)} for manual reading to avoid wrapping
*/
@Override @Override
@Deprecated
public Long read(ByteBuf buffer) { public Long read(ByteBuf buffer) {
long out = 0; return readPrimitive(buffer);
int bytes = 0;
byte in;
while (true) {
in = buffer.readByte();
out |= (in & 0x7F) << (bytes++ * 7);
if (bytes > 10) { // 10 is maxBytes
throw new RuntimeException("VarLong too big");
}
if ((in & 0x80) != 0x80) {
break;
}
}
return out;
} }
/**
* @deprecated use {@link #writePrimitive(ByteBuf, long)} for manual reading to avoid wrapping
*/
@Override
@Deprecated
public void write(ByteBuf buffer, Long object) {
writePrimitive(buffer, object);
}
@Override @Override
public Long from(Object o) { public Long from(Object o) {

Datei anzeigen

@ -2,26 +2,25 @@ package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.BlockChangeRecord; import us.myles.ViaVersion.api.minecraft.BlockChangeRecord;
import us.myles.ViaVersion.api.minecraft.BlockChangeRecord1_8;
import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.Type;
public class BlockChangeRecordType extends Type<BlockChangeRecord> { public class BlockChangeRecordType extends Type<BlockChangeRecord> {
public BlockChangeRecordType() { public BlockChangeRecordType() {
super(BlockChangeRecord.class); super(BlockChangeRecord.class);
} }
@Override @Override
public BlockChangeRecord read(ByteBuf buffer) throws Exception { public BlockChangeRecord read(ByteBuf buffer) throws Exception {
short horizontal = Type.UNSIGNED_BYTE.read(buffer); short position = Type.SHORT.readPrimitive(buffer);
short y = Type.UNSIGNED_BYTE.read(buffer);
int blockId = Type.VAR_INT.readPrimitive(buffer); int blockId = Type.VAR_INT.readPrimitive(buffer);
return new BlockChangeRecord1_8(position >> 12 & 0xF, position & 0xFF, position >> 8 & 0xF, blockId);
return new BlockChangeRecord(horizontal, y, blockId);
} }
@Override @Override
public void write(ByteBuf buffer, BlockChangeRecord object) throws Exception { public void write(ByteBuf buffer, BlockChangeRecord object) throws Exception {
Type.UNSIGNED_BYTE.write(buffer, object.getHorizontal()); Type.SHORT.writePrimitive(buffer, (short) (object.getSectionX() << 12 | object.getSectionZ() << 8 | object.getY()));
Type.UNSIGNED_BYTE.write(buffer, object.getY());
Type.VAR_INT.writePrimitive(buffer, object.getBlockId()); Type.VAR_INT.writePrimitive(buffer, object.getBlockId());
} }
} }

Datei anzeigen

@ -0,0 +1,26 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.BlockChangeRecord;
import us.myles.ViaVersion.api.minecraft.BlockChangeRecord1_16_2;
import us.myles.ViaVersion.api.type.Type;
public class VarLongBlockChangeRecordType extends Type<BlockChangeRecord> {
public VarLongBlockChangeRecordType() {
super(BlockChangeRecord.class);
}
@Override
public BlockChangeRecord read(ByteBuf buffer) throws Exception {
long data = Type.VAR_LONG.readPrimitive(buffer);
short position = (short) (data & 0xFFFL);
return new BlockChangeRecord1_16_2(position >>> 8 & 0xF, position & 0xF, position >>> 4 & 0xF, (int) (data >>> 12));
}
@Override
public void write(ByteBuf buffer, BlockChangeRecord object) throws Exception {
short position = (short) (object.getSectionX() << 8 | object.getSectionZ() << 4 | object.getSectionY());
Type.VAR_LONG.writePrimitive(buffer, (long) object.getBlockId() << 12 | position);
}
}

Datei anzeigen

@ -11,7 +11,7 @@ import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.MappingDataLoader; import us.myles.ViaVersion.api.data.MappingDataLoader;
import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.BlockChangeRecord; import us.myles.ViaVersion.api.minecraft.BlockChangeRecord1_8;
import us.myles.ViaVersion.api.minecraft.BlockFace; import us.myles.ViaVersion.api.minecraft.BlockFace;
import us.myles.ViaVersion.api.minecraft.Position; import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.minecraft.chunks.Chunk; import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
@ -29,7 +29,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
public class ConnectionData { public class ConnectionData {
private static final BlockChangeRecord[] EMPTY_RECORDS = new BlockChangeRecord[0]; private static final BlockChangeRecord1_8[] EMPTY_RECORDS = new BlockChangeRecord1_8[0];
public static BlockConnectionProvider blockConnectionProvider; public static BlockConnectionProvider blockConnectionProvider;
static Int2ObjectMap<String> idToKey = new Int2ObjectOpenHashMap<>(8582, 1F); static Int2ObjectMap<String> idToKey = new Int2ObjectOpenHashMap<>(8582, 1F);
static Map<String, Integer> keyToId = new HashMap<>(8582, 1F); static Map<String, Integer> keyToId = new HashMap<>(8582, 1F);
@ -61,7 +61,7 @@ public class ConnectionData {
for (int chunkDeltaZ = -1; chunkDeltaZ <= 1; chunkDeltaZ++) { for (int chunkDeltaZ = -1; chunkDeltaZ <= 1; chunkDeltaZ++) {
if (Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ) == 0) continue; if (Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ) == 0) continue;
List<BlockChangeRecord> updates = new ArrayList<>(); List<BlockChangeRecord1_8> updates = new ArrayList<>();
if (Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ) == 2) { // Corner if (Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ) == 2) { // Corner
for (int blockY = chunkSectionY * 16; blockY < chunkSectionY * 16 + 16; blockY++) { for (int blockY = chunkSectionY * 16; blockY < chunkSectionY * 16 + 16; blockY++) {
@ -132,13 +132,13 @@ public class ConnectionData {
} }
} }
public static void updateBlock(UserConnection user, Position pos, List<BlockChangeRecord> records) { public static void updateBlock(UserConnection user, Position pos, List<BlockChangeRecord1_8> records) {
int blockState = blockConnectionProvider.getBlockData(user, pos.getX(), pos.getY(), pos.getZ()); int blockState = blockConnectionProvider.getBlockData(user, pos.getX(), pos.getY(), pos.getZ());
ConnectionHandler handler = getConnectionHandler(blockState); ConnectionHandler handler = getConnectionHandler(blockState);
if (handler == null) return; if (handler == null) return;
int newBlockState = handler.connect(user, pos, blockState); int newBlockState = handler.connect(user, pos, blockState);
records.add(new BlockChangeRecord((short) (((pos.getX() & 0xF) << 4) | (pos.getZ() & 0xF)), pos.getY(), newBlockState)); records.add(new BlockChangeRecord1_8(pos.getX() & 0xF, pos.getY(), pos.getZ() & 0xF, newBlockState));
} }
public static void updateBlockStorage(UserConnection userConnection, int x, int y, int z, int blockState) { public static void updateBlockStorage(UserConnection userConnection, int x, int y, int z, int blockState) {

Datei anzeigen

@ -207,9 +207,9 @@ public class WorldPackets {
for (BlockChangeRecord record : records) { for (BlockChangeRecord record : records) {
int newBlock = toNewId(record.getBlockId()); int newBlock = toNewId(record.getBlockId());
Position position = new Position( Position position = new Position(
(record.getHorizontal() >> 4 & 15) + (chunkX * 16), record.getSectionX() + (chunkX * 16),
record.getY(), record.getY(),
(record.getHorizontal() & 15) + (chunkZ * 16)); record.getSectionZ() + (chunkZ * 16));
if (Via.getConfig().isServersideBlockConnections()) { if (Via.getConfig().isServersideBlockConnections()) {
ConnectionData.updateBlockStorage(userConnection, position.getX(), position.getY(), position.getZ(), newBlock); ConnectionData.updateBlockStorage(userConnection, position.getX(), position.getY(), position.getZ(), newBlock);
@ -222,9 +222,9 @@ public class WorldPackets {
int blockState = record.getBlockId(); int blockState = record.getBlockId();
Position position = new Position( Position position = new Position(
(record.getHorizontal() >> 4 & 15) + (chunkX * 16), record.getSectionX() + (chunkX * 16),
record.getY(), record.getY(),
(record.getHorizontal() & 15) + (chunkZ * 16)); record.getSectionZ() + (chunkZ * 16));
ConnectionHandler handler = ConnectionData.getConnectionHandler(blockState); ConnectionHandler handler = ConnectionData.getConnectionHandler(blockState);
if (handler != null) { if (handler != null) {
@ -238,9 +238,9 @@ public class WorldPackets {
for (BlockChangeRecord record : records) { for (BlockChangeRecord record : records) {
Position position = new Position( Position position = new Position(
(record.getHorizontal() >> 4 & 15) + (chunkX * 16), record.getSectionX() + (chunkX * 16),
record.getY(), record.getY(),
(record.getHorizontal() & 15) + (chunkZ * 16)); record.getSectionZ() + (chunkZ * 16));
ConnectionData.update(userConnection, position); ConnectionData.update(userConnection, position);
} }
} }

Datei anzeigen

@ -0,0 +1,99 @@
package us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1;
import us.myles.ViaVersion.api.protocol.ClientboundPacketType;
public enum ClientboundPackets1_16_2 implements ClientboundPacketType {
SPAWN_ENTITY, // 0x00
SPAWN_EXPERIENCE_ORB, // 0x01
SPAWN_MOB, // 0x02
SPAWN_PAINTING, // 0x03
SPAWN_PLAYER, // 0x04
ENTITY_ANIMATION, // 0x05
STATISTICS, // 0x06
ACKNOWLEDGE_PLAYER_DIGGING, // 0x07
BLOCK_BREAK_ANIMATION, // 0x08
BLOCK_ENTITY_DATA, // 0x09
BLOCK_ACTION, // 0x0A
BLOCK_CHANGE, // 0x0B
BOSSBAR, // 0x0C
SERVER_DIFFICULTY, // 0x0D
CHAT_MESSAGE, // 0x0E
TAB_COMPLETE, // 0x0F
DECLARE_COMMANDS, // 0x10
WINDOW_CONFIRMATION, // 0x11
CLOSE_WINDOW, // 0x12
WINDOW_ITEMS, // 0x13
WINDOW_PROPERTY, // 0x14
SET_SLOT, // 0x15
COOLDOWN, // 0x16
PLUGIN_MESSAGE, // 0x17
NAMED_SOUND, // 0x18
DISCONNECT, // 0x19
ENTITY_STATUS, // 0x1A
EXPLOSION, // 0x1B
UNLOAD_CHUNK, // 0x1C
GAME_EVENT, // 0x1D
OPEN_HORSE_WINDOW, // 0x1E
KEEP_ALIVE, // 0x1F
CHUNK_DATA, // 0x20
EFFECT, // 0x21
SPAWN_PARTICLE, // 0x22
UPDATE_LIGHT, // 0x23
JOIN_GAME, // 0x24
MAP_DATA, // 0x25
TRADE_LIST, // 0x26
ENTITY_POSITION, // 0x27
ENTITY_POSITION_AND_ROTATION, // 0x28
ENTITY_ROTATION, // 0x29
ENTITY_MOVEMENT, // 0x2A
VEHICLE_MOVE, // 0x2B
OPEN_BOOK, // 0x2C
OPEN_WINDOW, // 0x2D
OPEN_SIGN_EDITOR, // 0x2E
CRAFT_RECIPE_RESPONSE, // 0x2F
PLAYER_ABILITIES, // 0x30
COMBAT_EVENT, // 0x31
PLAYER_INFO, // 0x32
FACE_PLAYER, // 0x33
PLAYER_POSITION, // 0x34
UNLOCK_RECIPES, // 0x35
DESTROY_ENTITIES, // 0x36
REMOVE_ENTITY_EFFECT, // 0x37
RESOURCE_PACK, // 0x38
RESPAWN, // 0x39
ENTITY_HEAD_LOOK, // 0x3A
MULTI_BLOCK_CHANGE, // 0x3B
SELECT_ADVANCEMENTS_TAB, // 0x3C
WORLD_BORDER, // 0x3D
CAMERA, // 0x3E
HELD_ITEM_CHANGE, // 0x3F
UPDATE_VIEW_POSITION, // 0x40
UPDATE_VIEW_DISTANCE, // 0x41
SPAWN_POSITION, // 0x42
DISPLAY_SCOREBOARD, // 0x43
ENTITY_METADATA, // 0x44
ATTACH_ENTITY, // 0x45
ENTITY_VELOCITY, // 0x46
ENTITY_EQUIPMENT, // 0x47
SET_EXPERIENCE, // 0x48
UPDATE_HEALTH, // 0x49
SCOREBOARD_OBJECTIVE, // 0x4A
SET_PASSENGERS, // 0x4B
TEAMS, // 0x4C
UPDATE_SCORE, // 0x4D
TIME_UPDATE, // 0x4E
TITLE, // 0x4F
ENTITY_SOUND, // 0x50
SOUND, // 0x51
STOP_SOUND, // 0x52
TAB_LIST, // 0x53
NBT_QUERY, // 0x54
COLLECT_ITEM, // 0x55
ENTITY_TELEPORT, // 0x56
ADVANCEMENTS, // 0x57
ENTITY_PROPERTIES, // 0x58
ENTITY_EFFECT, // 0x59
DECLARE_RECIPES, // 0x5A
TAGS, // 0x5B
}

Datei anzeigen

@ -18,12 +18,12 @@ import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16
import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.ServerboundPackets1_16; import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.ServerboundPackets1_16;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld; import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
public class Protocol1_16_2To1_16_1 extends Protocol<ClientboundPackets1_16, ClientboundPackets1_16, ServerboundPackets1_16, ServerboundPackets1_16_2> { public class Protocol1_16_2To1_16_1 extends Protocol<ClientboundPackets1_16, ClientboundPackets1_16_2, ServerboundPackets1_16, ServerboundPackets1_16_2> {
private TagRewriter tagRewriter; private TagRewriter tagRewriter;
public Protocol1_16_2To1_16_1() { public Protocol1_16_2To1_16_1() {
super(ClientboundPackets1_16.class, ClientboundPackets1_16.class, ServerboundPackets1_16.class, ServerboundPackets1_16_2.class, true); super(ClientboundPackets1_16.class, ClientboundPackets1_16_2.class, ServerboundPackets1_16.class, ServerboundPackets1_16_2.class, true);
} }
@Override @Override

Datei anzeigen

@ -1,12 +1,18 @@
package us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.data; package us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.data;
import com.github.steveice10.opennbt.NBTIO;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.MappingDataLoader; import us.myles.ViaVersion.api.data.MappingDataLoader;
import us.myles.ViaVersion.api.data.Mappings; import us.myles.ViaVersion.api.data.Mappings;
import us.myles.ViaVersion.util.Int2IntBiMap; import us.myles.ViaVersion.util.Int2IntBiMap;
import java.io.File;
import java.io.IOException;
public class MappingData { public class MappingData {
public static CompoundTag dimensionRegistry;
public static Int2IntBiMap oldToNewItems = new Int2IntBiMap(); public static Int2IntBiMap oldToNewItems = new Int2IntBiMap();
public static Mappings blockMappings; public static Mappings blockMappings;
public static Mappings blockStateMappings; public static Mappings blockStateMappings;
@ -17,6 +23,13 @@ public class MappingData {
JsonObject mapping1_16 = MappingDataLoader.loadData("mapping-1.16.json", true); JsonObject mapping1_16 = MappingDataLoader.loadData("mapping-1.16.json", true);
JsonObject mapping1_16_2 = MappingDataLoader.loadData("mapping-1.16.2.json", true); JsonObject mapping1_16_2 = MappingDataLoader.loadData("mapping-1.16.2.json", true);
try {
dimensionRegistry = NBTIO.readFile(new File(MappingDataLoader.getResourceUrl("dimenstion-registry-1.16.2.nbt").getFile()));
} catch (IOException e) {
Via.getPlatform().getLogger().severe("Error loading dimenstion registry:");
e.printStackTrace();
}
oldToNewItems.defaultReturnValue(-1); oldToNewItems.defaultReturnValue(-1);
blockStateMappings = new Mappings(mapping1_16.getAsJsonObject("blockstates"), mapping1_16_2.getAsJsonObject("blockstates")); blockStateMappings = new Mappings(mapping1_16.getAsJsonObject("blockstates"), mapping1_16_2.getAsJsonObject("blockstates"));
blockMappings = new Mappings(mapping1_16.getAsJsonObject("blocks"), mapping1_16_2.getAsJsonObject("blocks")); blockMappings = new Mappings(mapping1_16.getAsJsonObject("blocks"), mapping1_16_2.getAsJsonObject("blocks"));

Datei anzeigen

@ -5,6 +5,7 @@ import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.types.version.Types1_14; import us.myles.ViaVersion.api.type.types.version.Types1_14;
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.Protocol1_16_2To1_16_1; import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.Protocol1_16_2To1_16_1;
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.data.MappingData;
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.metadata.MetadataRewriter1_16_2To1_16_1; import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.metadata.MetadataRewriter1_16_2To1_16_1;
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.storage.EntityTracker1_16_2; import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.storage.EntityTracker1_16_2;
import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16; import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16;
@ -35,7 +36,11 @@ public class EntityPackets {
}); });
map(Type.BYTE); // Previous Gamemode map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // World List map(Type.STRING_ARRAY); // World List
map(Type.NBT); // Dimension Registry handler(wrapper -> {
// Throw away the old dimension registry, extra conversion would be too hard of a hit
wrapper.read(Type.NBT);
wrapper.write(Type.NBT, MappingData.dimensionRegistry);
});
map(Type.STRING); // Dimension Type map(Type.STRING); // Dimension Type
map(Type.STRING); // Dimension map(Type.STRING); // Dimension
map(Type.LONG); // Seed map(Type.LONG); // Seed

Datei anzeigen

@ -1,5 +1,6 @@
package us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.packets; package us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.packets;
import us.myles.ViaVersion.api.minecraft.BlockChangeRecord;
import us.myles.ViaVersion.api.minecraft.chunks.Chunk; import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
import us.myles.ViaVersion.api.protocol.Protocol; import us.myles.ViaVersion.api.protocol.Protocol;
@ -7,6 +8,7 @@ import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.rewriters.BlockRewriter; import us.myles.ViaVersion.api.rewriters.BlockRewriter;
import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.Protocol1_16_2To1_16_1; import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.Protocol1_16_2To1_16_1;
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.types.Chunk1_16_2Type;
import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16; import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16;
import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.types.Chunk1_16Type; import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.types.Chunk1_16Type;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld; import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
@ -18,7 +20,6 @@ public class WorldPackets {
blockRewriter.registerBlockAction(ClientboundPackets1_16.BLOCK_ACTION); blockRewriter.registerBlockAction(ClientboundPackets1_16.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_16.BLOCK_CHANGE); blockRewriter.registerBlockChange(ClientboundPackets1_16.BLOCK_CHANGE);
blockRewriter.registerMultiBlockChange(ClientboundPackets1_16.MULTI_BLOCK_CHANGE);
blockRewriter.registerAcknowledgePlayerDigging(ClientboundPackets1_16.ACKNOWLEDGE_PLAYER_DIGGING); blockRewriter.registerAcknowledgePlayerDigging(ClientboundPackets1_16.ACKNOWLEDGE_PLAYER_DIGGING);
protocol.registerOutgoing(ClientboundPackets1_16.CHUNK_DATA, new PacketRemapper() { protocol.registerOutgoing(ClientboundPackets1_16.CHUNK_DATA, new PacketRemapper() {
@ -26,7 +27,9 @@ public class WorldPackets {
public void registerMap() { public void registerMap() {
handler(wrapper -> { handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class); ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
Chunk chunk = wrapper.passthrough(new Chunk1_16Type(clientWorld)); Chunk chunk = wrapper.read(new Chunk1_16Type(clientWorld));
wrapper.write(new Chunk1_16_2Type(clientWorld), chunk);
for (int s = 0; s < 16; s++) { for (int s = 0; s < 16; s++) {
ChunkSection section = chunk.getSections()[s]; ChunkSection section = chunk.getSections()[s];
if (section == null) continue; if (section == null) continue;
@ -39,8 +42,49 @@ public class WorldPackets {
} }
}); });
protocol.registerOutgoing(ClientboundPackets1_16.MULTI_BLOCK_CHANGE, new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
wrapper.cancel();
int chunkX = wrapper.read(Type.INT);
int chunkZ = wrapper.read(Type.INT);
wrapper.write(Type.LONG, asLong(chunkX, 0, chunkZ)); //TODO
BlockChangeRecord[] blockChangeRecord = wrapper.read(Type.BLOCK_CHANGE_RECORD_ARRAY);
wrapper.write(Type.VAR_LONG_BLOCK_CHANGE_RECORD_ARRAY, blockChangeRecord);
for (BlockChangeRecord record : blockChangeRecord) {
record.setBlockId(Protocol1_16_2To1_16_1.getNewBlockId(record.getBlockId()));
}
});
}
});
blockRewriter.registerEffect(ClientboundPackets1_16.EFFECT, 1010, 2001, InventoryPackets::getNewItemId); blockRewriter.registerEffect(ClientboundPackets1_16.EFFECT, 1010, 2001, InventoryPackets::getNewItemId);
blockRewriter.registerSpawnParticle(ClientboundPackets1_16.SPAWN_PARTICLE, 3, 23, 34, blockRewriter.registerSpawnParticle(ClientboundPackets1_16.SPAWN_PARTICLE, 3, 23, 34,
null, InventoryPackets::toClient, Type.FLAT_VAR_INT_ITEM, Type.DOUBLE); null, InventoryPackets::toClient, Type.FLAT_VAR_INT_ITEM, Type.DOUBLE);
} }
//TODO to chunk coordinates
public static int x(final long long1) {
return (int) (long1 >> 42);
}
public static int y(final long long1) {
return (int) (long1 << 44 >> 44);
}
public static int z(final long long1) {
return (int) (long1 << 22 >> 42);
}
public static long asLong(final int x, final int y, final int z) {
long long4 = 0L;
long4 |= (x & 0x3FFFFFL) << 42;
long4 |= (y & 0xFFFFFL);
long4 |= (z & 0x3FFFFFL) << 20;
return long4;
}
} }

Datei anzeigen

@ -0,0 +1,106 @@
package us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.types;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.minecraft.chunks.BaseChunk;
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
import us.myles.ViaVersion.api.type.PartialType;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType;
import us.myles.ViaVersion.api.type.types.version.Types1_16;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Chunk1_16_2Type extends PartialType<Chunk, ClientWorld> {
private static final CompoundTag[] EMPTY_COMPOUNDS = new CompoundTag[0];
public Chunk1_16_2Type(ClientWorld param) {
super(param, Chunk.class);
}
@Override
public Chunk read(ByteBuf input, ClientWorld world) throws Exception {
int chunkX = input.readInt();
int chunkZ = input.readInt();
boolean fullChunk = input.readBoolean();
boolean ignoreOldLightData = input.readBoolean();
int primaryBitmask = Type.VAR_INT.readPrimitive(input);
CompoundTag heightMap = Type.NBT.read(input);
int[] biomeData = null;
if (fullChunk) {
biomeData = Type.VAR_INT_ARRAY_PRIMITIVE.read(input);
}
Type.VAR_INT.readPrimitive(input); // data size in bytes
// Read sections
ChunkSection[] sections = new ChunkSection[16];
for (int i = 0; i < 16; i++) {
if ((primaryBitmask & (1 << i)) == 0) continue; // Section not set
short nonAirBlocksCount = input.readShort();
ChunkSection section = Types1_16.CHUNK_SECTION.read(input);
section.setNonAirBlocksCount(nonAirBlocksCount);
sections[i] = section;
}
List<CompoundTag> nbtData = new ArrayList<>(Arrays.asList(Type.NBT_ARRAY.read(input)));
// Read all the remaining bytes (workaround for #681)
if (input.readableBytes() > 0) {
byte[] array = Type.REMAINING_BYTES.read(input);
if (Via.getManager().isDebug()) {
Via.getPlatform().getLogger().warning("Found " + array.length + " more bytes than expected while reading the chunk: " + chunkX + "/" + chunkZ);
}
}
return new BaseChunk(chunkX, chunkZ, fullChunk, ignoreOldLightData, primaryBitmask, sections, biomeData, heightMap, nbtData);
}
@Override
public void write(ByteBuf output, ClientWorld world, Chunk chunk) throws Exception {
output.writeInt(chunk.getX());
output.writeInt(chunk.getZ());
output.writeBoolean(chunk.isFullChunk());
output.writeBoolean(chunk.isIgnoreOldLightData());
Type.VAR_INT.writePrimitive(output, chunk.getBitmask());
Type.NBT.write(output, chunk.getHeightMap());
// Write biome data
if (chunk.isBiomeData()) {
Type.VAR_INT_ARRAY_PRIMITIVE.write(output, chunk.getBiomeData());
}
ByteBuf buf = output.alloc().buffer();
try {
for (int i = 0; i < 16; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null) continue; // Section not set
buf.writeShort(section.getNonAirBlocksCount());
Types1_16.CHUNK_SECTION.write(buf, section);
}
buf.readerIndex(0);
Type.VAR_INT.writePrimitive(output, buf.readableBytes());
output.writeBytes(buf);
} finally {
buf.release(); // release buffer
}
// Write Block Entities
Type.NBT_ARRAY.write(output, chunk.getBlockEntities().toArray(EMPTY_COMPOUNDS));
}
@Override
public Class<? extends Type> getBaseClass() {
return BaseChunkType.class;
}
}

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<name>viaversion-jar</name> <name>viaversion-jar</name>

Datei anzeigen

@ -6,7 +6,7 @@
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>viaversion-parent</name> <name>viaversion-parent</name>

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

Datei anzeigen

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>viaversion-parent</artifactId> <artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<version>3.0.2-20w27a</version> <version>3.0.2-20w28a</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>