Compare commits

...
14 Commits
Author SHA1 Message Date
Matsv f7824e1df5 Bump version 2017-08-04 14:03:35 +02:00
Matsv 2168145d58 Prevent crash for now 2017-08-03 15:44:34 +02:00
Matsv ebb1323129 Prepare for 1.12.1 2017-08-02 14:08:37 +02:00
Matsv 34ca6324c5 Possibility to suppress type not found errors 2017-07-30 12:23:00 +02:00
Matsv 908931e174 Make metadata item rewrite check the Type instead of the MetaType fixes #17 2017-07-30 12:17:20 +02:00
Matsv 1f15c9e8f1 Back to snapshot 2017-07-30 12:14:59 +02:00
Matsv 9a0686685c Bump version 2017-07-29 14:11:43 +02:00
Matsv ccc63966c6 Change shulkerbox data fixes #15 2017-07-29 14:05:10 +02:00
Matsv 18d8ab068d Remove debug message 2017-07-29 13:32:03 +02:00
Matsv 227396d08a Format replacement items differently 2017-07-29 13:24:17 +02:00
Matsv dbc92572fd Fix NPE for unknown beds & keep original NBT data 2017-07-29 13:19:59 +02:00
Matsv ea2f603cf7 Possibility to hide warning using suppressMetadataErrors fixes #14 2017-07-04 21:12:09 +02:00
Matsv a5aa9e7281 Handle nulls in EntityRewriter (#11) 2017-06-21 19:30:48 +02:00
Matsv 0e5ee7063f Back to snapshot 2017-06-14 17:57:12 +02:00
19 changed files with 169 additions and 35 deletions

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@
<parent>
<artifactId>viabackwards-parent</artifactId>
<groupId>nl.matsv</groupId>
<version>2.1</version>
<version>2.2.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -15,7 +15,7 @@
<parent>
<artifactId>viabackwards-parent</artifactId>
<groupId>nl.matsv</groupId>
<version>2.1</version>
<version>2.2.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -15,7 +15,7 @@
<parent>
<artifactId>viabackwards-parent</artifactId>
<groupId>nl.matsv</groupId>
<version>2.1</version>
<version>2.2.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -15,7 +15,7 @@
<parent>
<artifactId>viabackwards-parent</artifactId>
<groupId>nl.matsv</groupId>
<version>2.1</version>
<version>2.2.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,10 +14,12 @@ import nl.matsv.viabackwards.ViaBackwards;
import nl.matsv.viabackwards.protocol.protocol1_10to1_11.Protocol1_10To1_11;
import nl.matsv.viabackwards.protocol.protocol1_11to1_11_1.Protocol1_11To1_11_1;
import nl.matsv.viabackwards.protocol.protocol1_12to1_11_1.Protocol1_11_1To1_12;
import nl.matsv.viabackwards.protocol.protocol1_12to1_12_1.Protocol1_12To1_12_1;
import nl.matsv.viabackwards.protocol.protocol1_9_4to1_10.Protocol1_9_4To1_10;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.logging.Logger;
@@ -33,6 +35,7 @@ public interface ViaBackwardsPlatform {
ProtocolRegistry.registerProtocol(new Protocol1_10To1_11(), Collections.singletonList(ProtocolVersion.v1_10.getId()), ProtocolVersion.v1_11.getId());
ProtocolRegistry.registerProtocol(new Protocol1_11To1_11_1(), Collections.singletonList(ProtocolVersion.v1_11.getId()), ProtocolVersion.v1_11_1.getId());
ProtocolRegistry.registerProtocol(new Protocol1_11_1To1_12(), Collections.singletonList(ProtocolVersion.v1_11_1.getId()), ProtocolVersion.v1_12.getId());
ProtocolRegistry.registerProtocol(new Protocol1_12To1_12_1(), Collections.singletonList(ProtocolVersion.v1_12.getId()), ProtocolVersion.v1_12_1.getId());
}
}
@@ -45,14 +48,16 @@ public interface ViaBackwardsPlatform {
// TODO remove or better implement later
default boolean isOutdated() {
Class<?> clazz = null;
boolean upToDate = false;
try {
clazz = Class.forName("us.myles.ViaVersion.api.type.types.version.Types1_12");
} catch (ClassNotFoundException e) {
e.printStackTrace();
Class<?> clazz = Class.forName("us.myles.ViaVersion.api.protocol.ProtocolVersion");
Field v1_12_1 = clazz.getField("v1_12_1");
upToDate = (v1_12_1 != null);
} catch (ClassNotFoundException | NoSuchFieldException ignored) {
}
if (clazz == null) {
if (!upToDate) {
getLogger().severe("================================");
getLogger().severe("YOUR VIAVERSION IS OUTDATED");
getLogger().severe("PLEASE USE THE LATEST VERSION");
@@ -19,6 +19,7 @@ import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
public class EntityTracker extends StoredObject {
@@ -51,12 +52,12 @@ public class EntityTracker extends StoredObject {
public AbstractEntityType getEntityType(int id) {
if (containsEntity(id))
return getEntity(id).getType();
return getEntity(id).get().getType();
return null;
}
public StoredEntity getEntity(int id) {
return entityMap.get(id);
public Optional<StoredEntity> getEntity(int id) {
return Optional.ofNullable(entityMap.get(id));
}
public boolean containsEntity(int id) {
@@ -13,6 +13,7 @@ package nl.matsv.viabackwards.api.entities.types;
import lombok.AllArgsConstructor;
import lombok.Getter;
import nl.matsv.viabackwards.ViaBackwards;
import us.myles.ViaVersion.api.Via;
import java.util.ArrayList;
import java.util.List;
@@ -30,7 +31,8 @@ public class EntityType1_10 {
type = EntityType.findById(typeID);
if (!type.isPresent()) {
ViaBackwards.getPlatform().getLogger().severe("[EntityType1_10] Could not find type id " + typeID + " isObject=" + isObject);
if (!Via.getConfig().isSuppressMetadataErrors())
ViaBackwards.getPlatform().getLogger().severe("[EntityType1_10] Could not find type id " + typeID + " isObject=" + isObject);
return EntityType.ENTITY; // Fall back to the basic ENTITY
}
@@ -13,6 +13,7 @@ package nl.matsv.viabackwards.api.entities.types;
import lombok.AllArgsConstructor;
import lombok.Getter;
import nl.matsv.viabackwards.ViaBackwards;
import us.myles.ViaVersion.api.Via;
import java.util.ArrayList;
import java.util.List;
@@ -29,7 +30,8 @@ public class EntityType1_11 {
type = EntityType.findById(typeID);
if (!type.isPresent()) {
ViaBackwards.getPlatform().getLogger().severe("[EntityType1_11] Could not find type id " + typeID + " isObject=" + isObject);
if (!Via.getConfig().isSuppressMetadataErrors())
ViaBackwards.getPlatform().getLogger().severe("[EntityType1_11] Could not find type id " + typeID + " isObject=" + isObject);
return EntityType.ENTITY; // Fall back to the basic ENTITY
}
@@ -13,6 +13,7 @@ package nl.matsv.viabackwards.api.entities.types;
import lombok.AllArgsConstructor;
import lombok.Getter;
import nl.matsv.viabackwards.ViaBackwards;
import us.myles.ViaVersion.api.Via;
import java.util.ArrayList;
import java.util.List;
@@ -29,7 +30,8 @@ public class EntityType1_12 {
type = EntityType.findById(typeID);
if (!type.isPresent()) {
ViaBackwards.getPlatform().getLogger().severe("[EntityType1_12] Could not find type id " + typeID + " isObject=" + isObject);
if (!Via.getConfig().isSuppressMetadataErrors())
ViaBackwards.getPlatform().getLogger().severe("[EntityType1_12] Could not find type id " + typeID + " isObject=" + isObject);
return EntityType.ENTITY; // Fall back to the basic ENTITY
}
@@ -14,6 +14,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import net.md_5.bungee.api.ChatColor;
import nl.matsv.viabackwards.api.BackwardsProtocol;
import nl.matsv.viabackwards.api.entities.blockitem.BlockItemSettings;
import nl.matsv.viabackwards.protocol.protocol1_12to1_11_1.data.BlockColors;
@@ -52,8 +53,15 @@ public abstract class BlockItemRewriter<T extends BackwardsProtocol> extends Rew
if (i.getTag() == null)
i.setTag(new CompoundTag(""));
// Backup data for toServer
i.getTag().put(createViaNBT(original));
// Keep original data
if (original.getTag() != null)
for (Tag ai : original.getTag())
i.getTag().put(ai);
// Handle colors
if (i.getTag().contains("display")) {
CompoundTag tag = i.getTag().get("display");
@@ -146,8 +154,10 @@ public abstract class BlockItemRewriter<T extends BackwardsProtocol> extends Rew
for (int z = 0; z < 16; z++) {
int block = section.getBlock(x, y, z);
int btype = block >> 4;
int meta = block & 15;
if (containsBlock(btype)) {
Block b = handleBlock(btype, block & 15); // Type / data
Block b = handleBlock(btype, meta); // Type / data
section.setBlock(x, y, z, b.getId(), b.getData());
}
// Entity Tags
@@ -198,7 +208,7 @@ public abstract class BlockItemRewriter<T extends BackwardsProtocol> extends Rew
protected CompoundTag getNamedTag(String text) {
CompoundTag tag = new CompoundTag("");
tag.put(new CompoundTag("display"));
((CompoundTag) tag.get("display")).put(new StringTag("Name", text));
((CompoundTag) tag.get("display")).put(new StringTag("Name", ChatColor.RESET + text));
return tag;
}
@@ -29,6 +29,7 @@ import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.metadata.MetaType;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_9;
import us.myles.ViaVersion.exception.CancelException;
import java.util.ArrayList;
import java.util.List;
@@ -98,7 +99,14 @@ public abstract class EntityRewriter<T extends BackwardsProtocol> extends Rewrit
}
protected MetaStorage handleMeta(UserConnection user, int entityId, MetaStorage storage) throws Exception {
EntityTracker.StoredEntity entity = getEntityTracker(user).getEntity(entityId);
Optional<EntityTracker.StoredEntity> optEntity = getEntityTracker(user).getEntity(entityId);
if (!optEntity.isPresent()) {
if (!Via.getConfig().isSuppressMetadataErrors())
ViaBackwards.getPlatform().getLogger().warning("Metadata for entity id: " + entityId + " not sent because the entity doesn't exist. " + storage);
throw new CancelException();
}
EntityTracker.StoredEntity entity = optEntity.get();
AbstractEntityType type = entity.getType();
List<Metadata> newList = new CopyOnWriteArrayList<>();
@@ -24,7 +24,6 @@ import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_9;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
@@ -381,7 +380,7 @@ public class BlockItemPackets1_11 extends BlockItemRewriter<Protocol1_10To1_11>
protocol.getEntityPackets().registerMetaHandler().handle(e -> {
Metadata data = e.getData();
if (data.getMetaType().equals(MetaType1_9.Slot)) // Is Item
if (data.getMetaType().getType().equals(Type.ITEM)) // Is Item
data.setValue(handleItemToClient((Item) data.getValue()));
return data;
@@ -394,7 +393,7 @@ public class BlockItemPackets1_11 extends BlockItemRewriter<Protocol1_10To1_11>
for (int i = 219; i < 235; i++)
rewrite(i)
.repItem(new Item((short) 130, (byte) 1, (short) 0, getNamedTag("1.11 " + BlockColors.get(i - 219) + " Shulker Box")))
.repBlock(new Block(130, 1))
.repBlock(new Block(130, 4)) // TODO investigate this
.blockEntityHandler((block, tag) -> {
tag.remove("id");
tag.put(new StringTag("id", "minecraft:chest"));
@@ -428,7 +427,8 @@ public class BlockItemPackets1_11 extends BlockItemRewriter<Protocol1_10To1_11>
WindowTracker tracker = user.get(WindowTracker.class);
if (tracker.getInventory() != null && tracker.getInventory().equals("EntityHorse")) {
EntityTracker.ProtocolEntityTracker entTracker = user.get(EntityTracker.class).get(getProtocol());
if (tracker.getEntityId() != -1 && entTracker.getEntity(tracker.getEntityId()).getType().is(EntityType1_11.EntityType.LIAMA))
Optional<EntityTracker.StoredEntity> optEntity = entTracker.getEntity(tracker.getEntityId());
if (optEntity.isPresent() && optEntity.get().getType().is(EntityType1_11.EntityType.LIAMA))
return true;
}
return false;
@@ -438,8 +438,9 @@ public class BlockItemPackets1_11 extends BlockItemRewriter<Protocol1_10To1_11>
WindowTracker tracker = user.get(WindowTracker.class);
if (tracker.getInventory() != null && tracker.getInventory().equals("EntityHorse")) {
EntityTracker.ProtocolEntityTracker entTracker = user.get(EntityTracker.class).get(getProtocol());
if (tracker.getEntityId() != -1)
return Optional.of(entTracker.getEntity(tracker.getEntityId()).get(ChestedHorseStorage.class));
Optional<EntityTracker.StoredEntity> optEntity = entTracker.getEntity(tracker.getEntityId());
if (optEntity.isPresent())
return Optional.of(optEntity.get().get(ChestedHorseStorage.class));
}
return Optional.empty();
}
@@ -15,7 +15,6 @@ import nl.matsv.viabackwards.protocol.protocol1_11to1_11_1.Protocol1_11To1_11_1;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_9;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
@@ -154,7 +153,7 @@ public class ItemPackets1_11_1 extends BlockItemRewriter<Protocol1_11To1_11_1> {
protocol.getEntityPackets().registerMetaHandler().handle(e -> {
Metadata data = e.getData();
if (data.getMetaType().equals(MetaType1_9.Slot)) // Is Item
if (data.getMetaType().getType().equals(Type.ITEM)) // Is Item
data.setValue(handleItemToClient((Item) data.getValue()));
return data;
@@ -45,6 +45,6 @@ public class BlockColors {
}
public static String get(Integer key) {
return colors.get(key);
return colors.getOrDefault(key, "Unknown color");
}
}
@@ -17,7 +17,6 @@ import nl.matsv.viabackwards.utils.Block;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_12;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
@@ -246,7 +245,7 @@ public class BlockItemPackets1_12 extends BlockItemRewriter<Protocol1_11_1To1_12
protocol.getEntityPackets().registerMetaHandler().handle(e -> {
Metadata data = e.getData();
if (data.getMetaType().equals(MetaType1_12.Slot)) // Is Item
if (data.getMetaType().getType().equals(Type.ITEM)) // Is Item
data.setValue(handleItemToClient((Item) data.getValue()));
return data;
@@ -0,0 +1,106 @@
/*
* Copyright (c) 2016 Matsv
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package nl.matsv.viabackwards.protocol.protocol1_12to1_12_1;
import nl.matsv.viabackwards.api.BackwardsProtocol;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.packets.State;
public class Protocol1_12To1_12_1 extends BackwardsProtocol {
@Override
protected void registerPackets() {
registerOutgoing(State.PLAY, 0x2b, -1, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
wrapper.cancel();
}
});
}
}); // TODO
registerOutgoing(State.PLAY, 0x2c, 0x2b);
registerOutgoing(State.PLAY, 0x2d, 0x2c);
registerOutgoing(State.PLAY, 0x2e, 0x2d);
registerOutgoing(State.PLAY, 0x2f, 0x2e);
registerOutgoing(State.PLAY, 0x30, 0x2f);
registerOutgoing(State.PLAY, 0x31, 0x30);
registerOutgoing(State.PLAY, 0x32, 0x31);
registerOutgoing(State.PLAY, 0x33, 0x32);
registerOutgoing(State.PLAY, 0x34, 0x33);
registerOutgoing(State.PLAY, 0x35, 0x34);
registerOutgoing(State.PLAY, 0x36, 0x35);
registerOutgoing(State.PLAY, 0x37, 0x36);
registerOutgoing(State.PLAY, 0x38, 0x37);
registerOutgoing(State.PLAY, 0x39, 0x38);
registerOutgoing(State.PLAY, 0x3a, 0x39);
registerOutgoing(State.PLAY, 0x3b, 0x3a);
registerOutgoing(State.PLAY, 0x3c, 0x3b);
registerOutgoing(State.PLAY, 0x3d, 0x3c);
registerOutgoing(State.PLAY, 0x3e, 0x3d);
registerOutgoing(State.PLAY, 0x3f, 0x3e);
registerOutgoing(State.PLAY, 0x40, 0x3f);
registerOutgoing(State.PLAY, 0x41, 0x40);
registerOutgoing(State.PLAY, 0x42, 0x41);
registerOutgoing(State.PLAY, 0x43, 0x42);
registerOutgoing(State.PLAY, 0x44, 0x43);
registerOutgoing(State.PLAY, 0x45, 0x44);
registerOutgoing(State.PLAY, 0x46, 0x45);
registerOutgoing(State.PLAY, 0x47, 0x46);
registerOutgoing(State.PLAY, 0x48, 0x47);
registerOutgoing(State.PLAY, 0x49, 0x48);
registerOutgoing(State.PLAY, 0x4a, 0x49);
registerOutgoing(State.PLAY, 0x4b, 0x4a);
registerOutgoing(State.PLAY, 0x4c, 0x4b);
registerOutgoing(State.PLAY, 0x4d, 0x4c);
registerOutgoing(State.PLAY, 0x4e, 0x4d);
registerOutgoing(State.PLAY, 0x4f, 0x4e);
registerIncoming(State.PLAY, -1, 0x1, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
wrapper.cancel();
}
});
}
}); // TODO
registerIncoming(State.PLAY, 0x1, 0x2);
registerIncoming(State.PLAY, 0x2, 0x3);
registerIncoming(State.PLAY, 0x3, 0x4);
registerIncoming(State.PLAY, 0x4, 0x5);
registerIncoming(State.PLAY, 0x5, 0x6);
registerIncoming(State.PLAY, 0x6, 0x7);
registerIncoming(State.PLAY, 0x7, 0x8);
registerIncoming(State.PLAY, 0x8, 0x9);
registerIncoming(State.PLAY, 0x9, 0xa);
registerIncoming(State.PLAY, 0xa, 0xb);
registerIncoming(State.PLAY, 0xb, 0xc);
registerIncoming(State.PLAY, 0xc, 0xd);
registerIncoming(State.PLAY, 0xd, 0xe);
registerIncoming(State.PLAY, 0xe, 0xf);
registerIncoming(State.PLAY, 0xf, 0x10);
registerIncoming(State.PLAY, 0x10, 0x11);
registerIncoming(State.PLAY, 0x11, 0x12);
registerIncoming(State.PLAY, 0x12, -1); // No sent by client, sad :(
}
@Override
public void init(UserConnection userConnection) {
}
}
@@ -16,7 +16,6 @@ import nl.matsv.viabackwards.utils.Block;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_9;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
@@ -219,11 +218,11 @@ public class BlockItemPackets1_10 extends BlockItemRewriter<Protocol1_9_4To1_10>
}
);
// Rewrite metadata items
protocol.getEntityPackets().registerMetaHandler().handle(e -> {
Metadata data = e.getData();
if (data.getMetaType().equals(MetaType1_9.Slot)) // Is Item
if (data.getMetaType().getType().equals(Type.ITEM)) // Is Item
data.setValue(handleItemToClient((Item) data.getValue()));
return data;
+2 -2
View File
@@ -16,7 +16,7 @@
<groupId>nl.matsv</groupId>
<artifactId>viabackwards-parent</artifactId>
<version>2.1</version>
<version>2.2.0</version>
<packaging>pom</packaging>
<description>Allow newer clients to join older server versions.</description>
@@ -65,7 +65,7 @@
<dependency>
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>1.1.1-SNAPSHOT</version>
<version>1.2.0-1_12_1-pre1</version>
<scope>provided</scope>
</dependency>
</dependencies>
+1 -1
View File
@@ -15,7 +15,7 @@
<parent>
<artifactId>viabackwards-parent</artifactId>
<groupId>nl.matsv</groupId>
<version>2.1</version>
<version>2.2.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>