diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 093afb9ec..32383cfce 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -5,7 +5,7 @@
viaversion-parent
us.myles
- 1.4.0-18w11a
+ 1.4.0-18w14a
4.0.0
diff --git a/bungee/pom.xml b/bungee/pom.xml
index 56c3a1cc2..7e948a118 100644
--- a/bungee/pom.xml
+++ b/bungee/pom.xml
@@ -5,7 +5,7 @@
viaversion-parent
us.myles
- 1.4.0-18w11a
+ 1.4.0-18w14a
4.0.0
diff --git a/common/pom.xml b/common/pom.xml
index 90b0e887d..4e394266b 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -5,7 +5,7 @@
viaversion-parent
us.myles
- 1.4.0-18w11a
+ 1.4.0-18w14a
4.0.0
diff --git a/common/src/main/java/us/myles/ViaVersion/api/minecraft/metadata/types/MetaType1_13.java b/common/src/main/java/us/myles/ViaVersion/api/minecraft/metadata/types/MetaType1_13.java
index 2a311e569..6638deeea 100644
--- a/common/src/main/java/us/myles/ViaVersion/api/minecraft/metadata/types/MetaType1_13.java
+++ b/common/src/main/java/us/myles/ViaVersion/api/minecraft/metadata/types/MetaType1_13.java
@@ -4,6 +4,7 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import us.myles.ViaVersion.api.minecraft.metadata.MetaType;
import us.myles.ViaVersion.api.type.Type;
+import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.ProtocolSnapshotTo1_12_2;
@RequiredArgsConstructor
@Getter
@@ -23,7 +24,7 @@ public enum MetaType1_13 implements MetaType {
OptUUID(12, Type.OPTIONAL_UUID),
BlockID(13, Type.VAR_INT),
NBTTag(14, Type.NBT),
- UNKNOWN(15, null), // TODO do research
+ PARTICLE(15, ProtocolSnapshotTo1_12_2.PARTICLE_TYPE),
Discontinued(99, null);
private final int typeID;
diff --git a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolVersion.java b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolVersion.java
index 89601a095..caed37129 100644
--- a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolVersion.java
+++ b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolVersion.java
@@ -62,7 +62,7 @@ public class ProtocolVersion {
register(v1_12 = new ProtocolVersion(335, "1.12"));
register(v1_12_1 = new ProtocolVersion(338, "1.12.1"));
register(v1_12_2 = new ProtocolVersion(340, "1.12.2"));
- register(v1_13 = new ProtocolVersion(368, "18w11a"));
+ register(v1_13 = new ProtocolVersion(369, "18w14a"));
register(unknown = new ProtocolVersion(-1, "UNKNOWN"));
}
diff --git a/common/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DumpSubCmd.java b/common/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DumpSubCmd.java
index 5892716a1..c36822a2e 100644
--- a/common/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DumpSubCmd.java
+++ b/common/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DumpSubCmd.java
@@ -33,9 +33,10 @@ public class DumpSubCmd extends ViaSubCommand {
return "Dump information about your server, this is helpful if you report bugs.";
}
+
@Override
public boolean execute(final ViaCommandSender sender, String[] args) {
- VersionInfo version = new VersionInfo(
+ final VersionInfo version = new VersionInfo(
System.getProperty("java.version"),
System.getProperty("os.name"),
ProtocolRegistry.SERVER_PROTOCOL,
@@ -53,58 +54,47 @@ public class DumpSubCmd extends ViaSubCommand {
@Override
public void run() {
- HttpURLConnection con;
+ HttpURLConnection con = null;
try {
- con = (HttpURLConnection) new URL("https://api.github.com/gists").openConnection();
+ con = (HttpURLConnection) new URL("https://dump.viaversion.com/documents").openConnection();
} catch (IOException e) {
sender.sendMessage(ChatColor.RED + "Failed to dump, please check the console for more information");
- Via.getPlatform().getLogger().log(Level.WARNING, "Could not paste ViaVersion dump to Gist", e);
+ Via.getPlatform().getLogger().log(Level.WARNING, "Could not paste ViaVersion dump to ViaVersion Dump", e);
return;
}
try {
- con.setRequestProperty("Content-Type", "application/json");
- con.addRequestProperty("User-Agent", "ViaVersion");
+ con.setRequestProperty("Content-Type", "text/plain");
+ con.addRequestProperty("User-Agent", "ViaVersion/" + version.getPluginVersion());
con.setRequestMethod("POST");
con.setDoOutput(true);
OutputStream out = con.getOutputStream();
- String contents = GsonUtil.getGsonBuilder().setPrettyPrinting().create().toJson(template);
- // Create payload
- JsonObject payload = new JsonObject();
- payload.addProperty("description", "ViaVersion Dump");
- payload.addProperty("public", "false");
- // Create file contents
- JsonObject file = new JsonObject();
- file.addProperty("content", contents);
- // Create file list
- JsonObject files = new JsonObject();
- files.add("dump.json", file);
- payload.add("files", files);
- // Write to stream
- out.write(GsonUtil.getGson().toJson(payload).getBytes(Charset.forName("UTF-8")));
+ out.write(GsonUtil.getGsonBuilder().setPrettyPrinting().create().toJson(template).getBytes(Charset.forName("UTF-8")));
out.close();
+ if (con.getResponseCode() == 429) {
+ sender.sendMessage(ChatColor.RED + "You can only paste ones every minute to protect our systems.");
+ return;
+ }
+
String rawOutput = CharStreams.toString(new InputStreamReader(con.getInputStream()));
con.getInputStream().close();
+
JsonObject output = GsonUtil.getGson().fromJson(rawOutput, JsonObject.class);
+ if (!output.has("key"))
+ throw new InvalidObjectException("Key is not given in Hastebin output");
- if (!output.has("html_url"))
- throw new InvalidObjectException("URL is not given in Gist output");
-
- sender.sendMessage(ChatColor.GREEN + "We've made a dump with useful information, report your issue and provide this url: " + output.get("html_url").getAsString());
+ sender.sendMessage(ChatColor.GREEN + "We've made a dump with useful information, report your issue and provide this url: " + getUrl(output.get("key").getAsString()));
} catch (Exception e) {
sender.sendMessage(ChatColor.RED + "Failed to dump, please check the console for more information");
+ Via.getPlatform().getLogger().log(Level.WARNING, "Could not paste ViaVersion dump to Hastebin", e);
try {
- if (con.getResponseCode() == 403) {
- // Ensure 403 is due to rate limit being hit
- if("0".equals(con.getHeaderField("X-RateLimit-Remaining"))) {
- Via.getPlatform().getLogger().log(Level.WARNING, "You may only create 60 dumps per hour, please try again later.");
- return;
- }
+ if (con.getResponseCode() < 200 || con.getResponseCode() > 400) {
+ String rawOutput = CharStreams.toString(new InputStreamReader(con.getErrorStream()));
+ con.getErrorStream().close();
+ Via.getPlatform().getLogger().log(Level.WARNING, "Page returned: " + rawOutput);
}
- Via.getPlatform().getLogger().log(Level.WARNING, "Could not paste ViaVersion dump to Gist", e);
-
} catch (IOException e1) {
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to capture further info", e1);
}
@@ -114,4 +104,8 @@ public class DumpSubCmd extends ViaSubCommand {
return true;
}
+
+ private String getUrl(String id) {
+ return String.format("https://dump.viaversion.com/%s", id);
+ }
}
diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/ProtocolSnapshotTo1_12_2.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/ProtocolSnapshotTo1_12_2.java
index ae2653b42..255d642a1 100644
--- a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/ProtocolSnapshotTo1_12_2.java
+++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/ProtocolSnapshotTo1_12_2.java
@@ -21,9 +21,11 @@ import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.providers.Painting
import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.storage.BlockStorage;
import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.storage.EntityTracker;
import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.storage.TabCompleteTracker;
+import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.type.Particle1_13Type;
// Development of 1.13 support!
public class ProtocolSnapshotTo1_12_2 extends Protocol {
+ public static final Particle1_13Type PARTICLE_TYPE = new Particle1_13Type();
static {
MappingData.init();
diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/data/Particle.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/data/Particle.java
new file mode 100644
index 000000000..2206bcab2
--- /dev/null
+++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/data/Particle.java
@@ -0,0 +1,25 @@
+package us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import us.myles.ViaVersion.api.type.Type;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+@Data
+public class Particle {
+ private int id;
+ private Set arguments = new TreeSet<>();
+
+ public Particle(int id) {
+ this.id = id;
+ }
+
+ @lombok.Data
+ @AllArgsConstructor
+ public static class ParticleData {
+ private Type type;
+ private Object value;
+ }
+}
diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/data/ParticleRewriter.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/data/ParticleRewriter.java
new file mode 100644
index 000000000..bfbb3fa36
--- /dev/null
+++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/data/ParticleRewriter.java
@@ -0,0 +1,182 @@
+package us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.data;
+
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import us.myles.ViaVersion.api.Via;
+import us.myles.ViaVersion.api.minecraft.item.Item;
+import us.myles.ViaVersion.api.type.Type;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ParticleRewriter {
+ private static List particles = new LinkedList<>();
+
+ static {
+ add(34); // (0->34) explode -> minecraft:poof
+ add(19); // (1->19) largeexplode -> minecraft:explosion
+ add(18); // (2->18) hugeexplosion -> minecraft:explosion_emitter
+ add(21); // (3->21) fireworksSpark -> minecraft:firework
+ add(4); // (4->4) bubble -> minecraft:bubble
+ add(43); // (5->43) splash -> minecraft:splash
+ add(22); // (6->22) wake -> minecraft:fishing
+ add(42); // (7->42) suspended -> minecraft:underwater
+ add(42); // (8->42) depthsuspend -> minecraft:underwater (COMPLETELY REMOVED)
+ add(6); // (9->6) crit -> minecraft:crit
+ add(14); // (10->14) magicCrit -> minecraft:enchanted_hit
+ add(37); // (11->37) smoke -> minecraft:smoke
+ add(30); // (12->30) largesmoke -> minecraft:large_smoke
+ add(12); // (13->12) spell -> minecraft:effect
+ add(26); // (14->26) instantSpell -> minecraft:instant_effect
+ add(17); // (15->17) mobSpell -> minecraft:entity_effect
+ add(0); // (16->0) mobSpellAmbient -> minecraft:ambient_entity_effect
+ add(44); // (17->44) witchMagic -> minecraft:witch
+ add(10); // (18->10) dripWater -> minecraft:dripping_water
+ add(9); // (19->9) dripLava -> minecraft:dripping_lava
+ add(1); // (20->1) angryVillager -> minecraft:angry_villager
+ add(24); // (21->24) happyVillager -> minecraft:happy_villager
+ add(32); // (22->32) townaura -> minecraft:mycelium
+ add(33); // (23->33) note -> minecraft:note
+ add(35); // (24->35) portal -> minecraft:portal
+ add(15); // (25->15) enchantmenttable -> minecraft:enchant
+ add(23); // (26->23) flame -> minecraft:flame
+ add(31); // (27->31) lava -> minecraft:lava
+ add(-1); // (28->-1) footstap -> REMOVED (TODO REPLACEMENT/CLIENT_SIDED?)
+ add(5); // (29->5) cloud -> minecraft:cloud
+ add(11, reddustHandler()); // (30->11) reddust -> minecraft:dust
+ // Red Float Red value, 0-1
+ // Green Float Green value, 0-1
+ // Blue Float Blue value, 0-1
+ // Scale Float The scale, will be clamped between 0.01 and 4.
+ add(29); // (31->29) snowballpoof -> minecraft:item_snowball
+ add(34); // (32->34) snowshovel -> minecraft:poof
+ add(28); // (33->28) slime -> minecraft:item_slime
+ add(25); // (34->25) heart -> minecraft:heart
+ add(2); // (35->2) barrier -> minecraft:barrier
+ add(27, iconcrackHandler()); // (36->27) iconcrack_(id)_(data) -> minecraft:item
+ // Item Slot The item that will be used.
+ add(3, blockHandler()); // (37->3) blockcrack_(id+(data<<12)) -> minecraft:block
+ add(3, blockdustHandler()); // (38->3) blockdust_(id) -> minecraft:block
+ // BlockState VarInt The ID of the block state.
+ add(36); // (39->36) droplet -> minecraft:rain
+ add(-1); // (40->-1) take -> REMOVED (TODO REPLACENT/CLIENT_SIDED?)
+ add(13); // (41->13) mobappearance -> minecraft:elder_guardian
+ add(8); // (42->8) dragonbreath -> minecraft:dragon_breath
+ add(16); // (43->16) endrod -> minecraft:end_rod
+ add(7); // (44->7) damageindicator -> minecraft:damage_indicator
+ add(40); // (45->40) sweepattack -> minecraft:sweep_attack
+ add(20, fallingdustHandler()); // (46->20) fallingdust -> minecraft:falling_dust
+ // BlockState VarInt The ID of the block state.
+ add(41); // (47->41) totem -> minecraft:totem_of_undying
+ add(38); // (48->38) spit -> minecraft:spit
+
+ /*
+ NEW particles
+ minecraft:squid_ink 39 None
+ minecraft:bubble_pop 45 None
+ minecraft:current_down 46 None
+ minecraft:bubble_column_up 47 None
+ */
+ }
+
+ public static Particle rewriteParticle(int particleId, int[] data) {
+ if (particles.size() >= particleId) {
+ Via.getPlatform().getLogger().severe("Failed to transform particles with id " + particleId + " and data " + Arrays.toString(data));
+ return null;
+ }
+
+ NewParticle rewrite = particles.get(particleId);
+ return rewrite.handle(new Particle(rewrite.getId()), data);
+ }
+
+ private static void add(int newId) {
+ particles.add(new NewParticle(newId, null));
+ }
+
+ private static void add(int newId, ParticleDataHandler dataHandler) {
+ particles.add(new NewParticle(newId, dataHandler));
+ }
+
+ interface ParticleDataHandler {
+ Particle handler(Particle particle, int[] data);
+ }
+
+ // TODO TEST
+ private static ParticleDataHandler reddustHandler() {
+ return new ParticleDataHandler() {
+ @Override
+ public Particle handler(Particle particle, int[] data) {
+ particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, 1)); // Red 0 - 1
+ particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, 0)); // Green 0 - 1
+ particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, 0)); // Blue 0 - 1
+ particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, 1));// Scale 0.01 - 4 TODO test scale
+ return particle;
+ }
+ };
+ }
+
+ // TODO TEST
+ private static ParticleDataHandler iconcrackHandler() {
+ return new ParticleDataHandler() {
+ @Override
+ public Particle handler(Particle particle, int[] data) {
+ Item item;
+ if (data.length == 1)
+ item = new Item((short) data[0], (byte) 1, (short) 0, null);
+ else if (data.length == 2)
+ item = new Item((short) data[0], (byte) 1, (short) data[1], null);
+ else
+ return particle;
+
+ particle.getArguments().add(new Particle.ParticleData(Type.FLAT_ITEM, item));
+ return particle;
+ }
+ };
+ }
+
+ // TODO HANDLE
+ private static ParticleDataHandler blockHandler() {
+ return new ParticleDataHandler() {
+ @Override
+ public Particle handler(Particle particle, int[] data) {
+ return particle;
+ }
+ };
+ }
+
+ // TODO HANDLE
+ private static ParticleDataHandler blockdustHandler() {
+ return new ParticleDataHandler() {
+ @Override
+ public Particle handler(Particle particle, int[] data) {
+ return particle;
+ }
+ };
+ }
+
+ // TODO HANDLE
+ private static ParticleDataHandler fallingdustHandler() {
+ return new ParticleDataHandler() {
+ @Override
+ public Particle handler(Particle particle, int[] data) {
+ return particle;
+ }
+ };
+ }
+
+ @Data
+ @RequiredArgsConstructor
+ private static class NewParticle {
+ private final int id;
+ private final ParticleDataHandler handler;
+
+ public Particle handle(Particle particle, int[] data) {
+ if (handler != null)
+ return handler.handler(particle, data);
+ return particle;
+ }
+ }
+
+
+}
diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/providers/BlockEntityProvider.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/providers/BlockEntityProvider.java
index f508f384a..c495721c1 100644
--- a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/providers/BlockEntityProvider.java
+++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/providers/BlockEntityProvider.java
@@ -63,7 +63,7 @@ public class BlockEntityProvider implements Provider {
wrapper.write(Type.POSITION, position);
wrapper.write(Type.VAR_INT, blockId);
- wrapper.send(ProtocolSnapshotTo1_12_2.class);
+ wrapper.send(ProtocolSnapshotTo1_12_2.class, true, true);
}
diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/type/Particle1_13Type.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/type/Particle1_13Type.java
new file mode 100644
index 000000000..b61195da7
--- /dev/null
+++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/type/Particle1_13Type.java
@@ -0,0 +1,45 @@
+package us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.type;
+
+import io.netty.buffer.ByteBuf;
+import us.myles.ViaVersion.api.type.Type;
+import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.data.Particle;
+
+// TODO make future proof
+public class Particle1_13Type extends Type {
+ public Particle1_13Type() {
+ super("Particle", Particle.class);
+ }
+
+ @Override
+ public void write(ByteBuf buffer, Particle object) throws Exception {
+ Type.VAR_INT.write(buffer, object.getId());
+ for (Particle.ParticleData data : object.getArguments())
+ data.getType().write(buffer, data.getValue());
+ }
+
+ @Override
+ public Particle read(ByteBuf buffer) throws Exception {
+ int type = Type.VAR_INT.read(buffer);
+ Particle particle = new Particle(type);
+
+ switch (type) {
+ // Block / Falling Dust /
+ case 3:
+ case 20:
+ particle.getArguments().add(new Particle.ParticleData(Type.VAR_INT, Type.VAR_INT.read(buffer))); // Flat Block
+ break;
+ // Dust
+ case 11:
+ particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, Type.FLOAT.read(buffer))); // Red 0 - 1
+ particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, Type.FLOAT.read(buffer))); // Green 0 - 1
+ particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, Type.FLOAT.read(buffer))); // Blue 0 - 1
+ particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, Type.FLOAT.read(buffer)));// Scale 0.01 - 4
+ break;
+ // Item
+ case 27:
+ particle.getArguments().add(new Particle.ParticleData(Type.FLAT_ITEM, Type.FLAT_ITEM.read(buffer))); // Flat item
+ break;
+ }
+ return particle;
+ }
+}
diff --git a/common/src/main/resources/assets/viaversion/data/mapping-1.12.json b/common/src/main/resources/assets/viaversion/data/mapping-1.12.json
index 4d45db38f..b7fc7d598 100644
--- a/common/src/main/resources/assets/viaversion/data/mapping-1.12.json
+++ b/common/src/main/resources/assets/viaversion/data/mapping-1.12.json
@@ -892,8 +892,8 @@
"2204": "minecraft:command_block[conditional=true,facing=west]",
"2205": "minecraft:command_block[conditional=true,facing=east]",
"2208": "minecraft:beacon",
- "2224": "minecraft:cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false]",
- "2225": "minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false]",
+ "2224": "minecraft:cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]",
+ "2225": "minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]",
"2240": "minecraft:flower_pot",
"2241": "minecraft:flower_pot",
"2242": "minecraft:flower_pot",
diff --git a/jar/pom.xml b/jar/pom.xml
index 24a9f4137..c48f5d522 100644
--- a/jar/pom.xml
+++ b/jar/pom.xml
@@ -5,7 +5,7 @@
viaversion-parent
us.myles
- 1.4.0-18w11a
+ 1.4.0-18w14a
4.0.0
viaversion-jar
diff --git a/pom.xml b/pom.xml
index 46183b746..2853c2084 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
us.myles
viaversion-parent
- 1.4.0-18w11a
+ 1.4.0-18w14a
pom
viaversion-parent
diff --git a/sponge-legacy/pom.xml b/sponge-legacy/pom.xml
index b59394da9..4e6d69c07 100644
--- a/sponge-legacy/pom.xml
+++ b/sponge-legacy/pom.xml
@@ -5,7 +5,7 @@
viaversion-parent
us.myles
- 1.4.0-18w11a
+ 1.4.0-18w14a
4.0.0
diff --git a/sponge/pom.xml b/sponge/pom.xml
index 1bb897583..1808e0f75 100644
--- a/sponge/pom.xml
+++ b/sponge/pom.xml
@@ -5,7 +5,7 @@
viaversion-parent
us.myles
- 1.4.0-18w11a
+ 1.4.0-18w14a
4.0.0