Add support for long array nbt type

Fixes #648
This commit is contained in:
Dan Mulloy 2019-08-03 11:46:58 -04:00
parent 62e8d82e16
commit 916434251d
3 changed files with 418 additions and 413 deletions

View File

@ -1,368 +1,368 @@
/* /*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland * Copyright (C) 2012 Kristian S. Stangeland
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * 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 2 of * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * 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; * 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. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * 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; * You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.utility; package com.comphenix.protocol.utility;
import java.io.Serializable; import java.io.Serializable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolLibrary;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
/** /**
* Determine the current Minecraft version. * Determine the current Minecraft version.
* *
* @author Kristian * @author Kristian
*/ */
public class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable { public class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* Regular expression used to parse version strings. * Regular expression used to parse version strings.
*/ */
private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*"); private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*");
/** /**
* Version 1.14 - village and pillage update. * Version 1.14 - village and pillage update.
*/ */
public static final MinecraftVersion VILLAGE_UPDATE = new MinecraftVersion("1.14"); public static final MinecraftVersion VILLAGE_UPDATE = new MinecraftVersion("1.14");
/** /**
* Version 1.13 - update aquatic. * Version 1.13 - update aquatic.
*/ */
public static final MinecraftVersion AQUATIC_UPDATE = new MinecraftVersion("1.13"); public static final MinecraftVersion AQUATIC_UPDATE = new MinecraftVersion("1.13");
/** /**
* Version 1.12 - the world of color update. * Version 1.12 - the world of color update.
*/ */
public static final MinecraftVersion COLOR_UPDATE = new MinecraftVersion("1.12"); public static final MinecraftVersion COLOR_UPDATE = new MinecraftVersion("1.12");
/** /**
* Version 1.11 - the exploration update. * Version 1.11 - the exploration update.
*/ */
public static final MinecraftVersion EXPLORATION_UPDATE = new MinecraftVersion("1.11"); public static final MinecraftVersion EXPLORATION_UPDATE = new MinecraftVersion("1.11");
/** /**
* Version 1.10 - the frostburn update. * Version 1.10 - the frostburn update.
*/ */
public static final MinecraftVersion FROSTBURN_UPDATE = new MinecraftVersion("1.10"); public static final MinecraftVersion FROSTBURN_UPDATE = new MinecraftVersion("1.10");
/** /**
* Version 1.9 - the combat update. * Version 1.9 - the combat update.
*/ */
public static final MinecraftVersion COMBAT_UPDATE = new MinecraftVersion("1.9"); public static final MinecraftVersion COMBAT_UPDATE = new MinecraftVersion("1.9");
/** /**
* Version 1.8 - the "bountiful" update. * Version 1.8 - the "bountiful" update.
*/ */
public static final MinecraftVersion BOUNTIFUL_UPDATE = new MinecraftVersion("1.8"); public static final MinecraftVersion BOUNTIFUL_UPDATE = new MinecraftVersion("1.8");
/** /**
* Version 1.7.8 - the update that changed the skin format (and distribution - R.I.P. player disguise) * Version 1.7.8 - the update that changed the skin format (and distribution - R.I.P. player disguise)
*/ */
public static final MinecraftVersion SKIN_UPDATE = new MinecraftVersion("1.7.8"); public static final MinecraftVersion SKIN_UPDATE = new MinecraftVersion("1.7.8");
/** /**
* Version 1.7.2 - the update that changed the world. * Version 1.7.2 - the update that changed the world.
*/ */
public static final MinecraftVersion WORLD_UPDATE = new MinecraftVersion("1.7.2"); public static final MinecraftVersion WORLD_UPDATE = new MinecraftVersion("1.7.2");
/** /**
* Version 1.6.1 - the horse update. * Version 1.6.1 - the horse update.
*/ */
public static final MinecraftVersion HORSE_UPDATE = new MinecraftVersion("1.6.1"); public static final MinecraftVersion HORSE_UPDATE = new MinecraftVersion("1.6.1");
/** /**
* Version 1.5.0 - the redstone update. * Version 1.5.0 - the redstone update.
*/ */
public static final MinecraftVersion REDSTONE_UPDATE = new MinecraftVersion("1.5.0"); public static final MinecraftVersion REDSTONE_UPDATE = new MinecraftVersion("1.5.0");
/** /**
* Version 1.4.2 - the scary update (Wither Boss). * Version 1.4.2 - the scary update (Wither Boss).
*/ */
public static final MinecraftVersion SCARY_UPDATE = new MinecraftVersion("1.4.2"); public static final MinecraftVersion SCARY_UPDATE = new MinecraftVersion("1.4.2");
private final int major; private final int major;
private final int minor; private final int minor;
private final int build; private final int build;
// The development stage // The development stage
private final String development; private final String development;
// Snapshot? // Snapshot?
private final SnapshotVersion snapshot; private final SnapshotVersion snapshot;
/** /**
* Determine the current Minecraft version. * Determine the current Minecraft version.
* @param server - the Bukkit server that will be used to examine the MC version. * @param server - the Bukkit server that will be used to examine the MC version.
*/ */
public MinecraftVersion(Server server) { public MinecraftVersion(Server server) {
this(extractVersion(server.getVersion())); this(extractVersion(server.getVersion()));
} }
/** /**
* Construct a version object from the format major.minor.build, or the snapshot format. * Construct a version object from the format major.minor.build, or the snapshot format.
* @param versionOnly - the version in text form. * @param versionOnly - the version in text form.
*/ */
public MinecraftVersion(String versionOnly) { public MinecraftVersion(String versionOnly) {
this(versionOnly, true); this(versionOnly, true);
} }
/** /**
* Construct a version format from the standard release version or the snapshot verison. * Construct a version format from the standard release version or the snapshot verison.
* @param versionOnly - the version. * @param versionOnly - the version.
* @param parseSnapshot - TRUE to parse the snapshot, FALSE otherwise. * @param parseSnapshot - TRUE to parse the snapshot, FALSE otherwise.
*/ */
private MinecraftVersion(String versionOnly, boolean parseSnapshot) { private MinecraftVersion(String versionOnly, boolean parseSnapshot) {
String[] section = versionOnly.split("-"); String[] section = versionOnly.split("-");
SnapshotVersion snapshot = null; SnapshotVersion snapshot = null;
int[] numbers = new int[3]; int[] numbers = new int[3];
try { try {
numbers = parseVersion(section[0]); numbers = parseVersion(section[0]);
} catch (NumberFormatException cause) { } catch (NumberFormatException cause) {
// Skip snapshot parsing // Skip snapshot parsing
if (!parseSnapshot) if (!parseSnapshot)
throw cause; throw cause;
try { try {
// Determine if the snapshot is newer than the current release version // Determine if the snapshot is newer than the current release version
snapshot = new SnapshotVersion(section[0]); snapshot = new SnapshotVersion(section[0]);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
MinecraftVersion latest = new MinecraftVersion(ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION, false); MinecraftVersion latest = new MinecraftVersion(ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION, false);
boolean newer = snapshot.getSnapshotDate().compareTo( boolean newer = snapshot.getSnapshotDate().compareTo(
format.parse(ProtocolLibrary.MINECRAFT_LAST_RELEASE_DATE)) > 0; format.parse(ProtocolLibrary.MINECRAFT_LAST_RELEASE_DATE)) > 0;
numbers[0] = latest.getMajor(); numbers[0] = latest.getMajor();
numbers[1] = latest.getMinor() + (newer ? 1 : -1); numbers[1] = latest.getMinor() + (newer ? 1 : -1);
numbers[2] = 0; numbers[2] = 0;
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException("Cannot parse " + section[0], e); throw new IllegalStateException("Cannot parse " + section[0], e);
} }
} }
this.major = numbers[0]; this.major = numbers[0];
this.minor = numbers[1]; this.minor = numbers[1];
this.build = numbers[2]; this.build = numbers[2];
this.development = section.length > 1 ? section[1] : (snapshot != null ? "snapshot" : null); this.development = section.length > 1 ? section[1] : (snapshot != null ? "snapshot" : null);
this.snapshot = snapshot; this.snapshot = snapshot;
} }
/** /**
* Construct a version object directly. * Construct a version object directly.
* @param major - major version number. * @param major - major version number.
* @param minor - minor version number. * @param minor - minor version number.
* @param build - build version number. * @param build - build version number.
*/ */
public MinecraftVersion(int major, int minor, int build) { public MinecraftVersion(int major, int minor, int build) {
this(major, minor, build, null); this(major, minor, build, null);
} }
/** /**
* Construct a version object directly. * Construct a version object directly.
* @param major - major version number. * @param major - major version number.
* @param minor - minor version number. * @param minor - minor version number.
* @param build - build version number. * @param build - build version number.
* @param development - development stage. * @param development - development stage.
*/ */
public MinecraftVersion(int major, int minor, int build, String development) { public MinecraftVersion(int major, int minor, int build, String development) {
this.major = major; this.major = major;
this.minor = minor; this.minor = minor;
this.build = build; this.build = build;
this.development = development; this.development = development;
this.snapshot = null; this.snapshot = null;
} }
private int[] parseVersion(String version) { private int[] parseVersion(String version) {
String[] elements = version.split("\\."); String[] elements = version.split("\\.");
int[] numbers = new int[3]; int[] numbers = new int[3];
// Make sure it's even a valid version // Make sure it's even a valid version
if (elements.length < 1) if (elements.length < 1)
throw new IllegalStateException("Corrupt MC version: " + version); throw new IllegalStateException("Corrupt MC version: " + version);
// The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively. // The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively.
for (int i = 0; i < Math.min(numbers.length, elements.length); i++) for (int i = 0; i < Math.min(numbers.length, elements.length); i++)
numbers[i] = Integer.parseInt(elements[i].trim()); numbers[i] = Integer.parseInt(elements[i].trim());
return numbers; return numbers;
} }
/** /**
* Major version number * Major version number
* @return Current major version number. * @return Current major version number.
*/ */
public int getMajor() { public int getMajor() {
return major; return major;
} }
/** /**
* Minor version number * Minor version number
* @return Current minor version number. * @return Current minor version number.
*/ */
public int getMinor() { public int getMinor() {
return minor; return minor;
} }
/** /**
* Build version number * Build version number
* @return Current build version number. * @return Current build version number.
*/ */
public int getBuild() { public int getBuild() {
return build; return build;
} }
/** /**
* Retrieve the development stage. * Retrieve the development stage.
* @return Development stage, or NULL if this is a release. * @return Development stage, or NULL if this is a release.
*/ */
public String getDevelopmentStage() { public String getDevelopmentStage() {
return development; return development;
} }
/** /**
* Retrieve the snapshot version, or NULL if this is a release. * Retrieve the snapshot version, or NULL if this is a release.
* @return The snapshot version. * @return The snapshot version.
*/ */
public SnapshotVersion getSnapshot() { public SnapshotVersion getSnapshot() {
return snapshot; return snapshot;
} }
/** /**
* Determine if this version is a snapshot. * Determine if this version is a snapshot.
* @return The snapshot version. * @return The snapshot version.
*/ */
public boolean isSnapshot() { public boolean isSnapshot() {
return snapshot != null; return snapshot != null;
} }
/** /**
* Retrieve the version String (major.minor.build) only. * Retrieve the version String (major.minor.build) only.
* @return A normal version string. * @return A normal version string.
*/ */
public String getVersion() { public String getVersion() {
if (getDevelopmentStage() == null) if (getDevelopmentStage() == null)
return String.format("%s.%s.%s", getMajor(), getMinor(), getBuild()); return String.format("%s.%s.%s", getMajor(), getMinor(), getBuild());
else else
return String.format("%s.%s.%s-%s%s", getMajor(), getMinor(), getBuild(), return String.format("%s.%s.%s-%s%s", getMajor(), getMinor(), getBuild(),
getDevelopmentStage(), isSnapshot() ? snapshot : ""); getDevelopmentStage(), isSnapshot() ? snapshot : "");
} }
@Override @Override
public int compareTo(MinecraftVersion o) { public int compareTo(MinecraftVersion o) {
if (o == null) if (o == null)
return 1; return 1;
return ComparisonChain.start(). return ComparisonChain.start().
compare(getMajor(), o.getMajor()). compare(getMajor(), o.getMajor()).
compare(getMinor(), o.getMinor()). compare(getMinor(), o.getMinor()).
compare(getBuild(), o.getBuild()). compare(getBuild(), o.getBuild()).
// No development String means it's a release // No development String means it's a release
compare(getDevelopmentStage(), o.getDevelopmentStage(), Ordering.natural().nullsLast()). compare(getDevelopmentStage(), o.getDevelopmentStage(), Ordering.natural().nullsLast()).
compare(getSnapshot(), o.getSnapshot(), Ordering.natural().nullsFirst()). compare(getSnapshot(), o.getSnapshot(), Ordering.natural().nullsFirst()).
result(); result();
} }
public boolean isAtLeast(MinecraftVersion other) { public boolean isAtLeast(MinecraftVersion other) {
if (other == null) if (other == null)
return false; return false;
return compareTo(other) >= 0; return compareTo(other) >= 0;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null) if (obj == null)
return false; return false;
if (obj == this) if (obj == this)
return true; return true;
if (obj instanceof MinecraftVersion) { if (obj instanceof MinecraftVersion) {
MinecraftVersion other = (MinecraftVersion) obj; MinecraftVersion other = (MinecraftVersion) obj;
return getMajor() == other.getMajor() && return getMajor() == other.getMajor() &&
getMinor() == other.getMinor() && getMinor() == other.getMinor() &&
getBuild() == other.getBuild() && getBuild() == other.getBuild() &&
Objects.equal(getDevelopmentStage(), other.getDevelopmentStage()); Objects.equal(getDevelopmentStage(), other.getDevelopmentStage());
} }
return false; return false;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(getMajor(), getMinor(), getBuild()); return Objects.hashCode(getMajor(), getMinor(), getBuild());
} }
@Override @Override
public String toString() { public String toString() {
// Convert to a String that we can parse back again // Convert to a String that we can parse back again
return String.format("(MC: %s)", getVersion()); return String.format("(MC: %s)", getVersion());
} }
/** /**
* Extract the Minecraft version from CraftBukkit itself. * Extract the Minecraft version from CraftBukkit itself.
* @param text - the server version in text form. * @param text - the server version in text form.
* @return The underlying MC version. * @return The underlying MC version.
* @throws IllegalStateException If we could not parse the version string. * @throws IllegalStateException If we could not parse the version string.
*/ */
public static String extractVersion(String text) { public static String extractVersion(String text) {
Matcher version = VERSION_PATTERN.matcher(text); Matcher version = VERSION_PATTERN.matcher(text);
if (version.matches() && version.group(1) != null) { if (version.matches() && version.group(1) != null) {
return version.group(1); return version.group(1);
} else { } else {
throw new IllegalStateException("Cannot parse version String '" + text + "'"); throw new IllegalStateException("Cannot parse version String '" + text + "'");
} }
} }
/** /**
* Parse the given server version into a Minecraft version. * Parse the given server version into a Minecraft version.
* @param serverVersion - the server version. * @param serverVersion - the server version.
* @return The resulting Minecraft version. * @return The resulting Minecraft version.
*/ */
public static MinecraftVersion fromServerVersion(String serverVersion) { public static MinecraftVersion fromServerVersion(String serverVersion) {
return new MinecraftVersion(extractVersion(serverVersion)); return new MinecraftVersion(extractVersion(serverVersion));
} }
private static MinecraftVersion currentVersion; private static MinecraftVersion currentVersion;
public static void setCurrentVersion(MinecraftVersion version) { public static void setCurrentVersion(MinecraftVersion version) {
currentVersion = version; currentVersion = version;
} }
public static MinecraftVersion getCurrentVersion() { public static MinecraftVersion getCurrentVersion() {
if (currentVersion == null) { if (currentVersion == null) {
currentVersion = fromServerVersion(Bukkit.getVersion()); currentVersion = fromServerVersion(Bukkit.getVersion());
} }
return currentVersion; return currentVersion;
} }
public static boolean atOrAbove(MinecraftVersion version) { public static boolean atOrAbove(MinecraftVersion version) {
return getCurrentVersion().isAtLeast(version); return getCurrentVersion().isAtLeast(version);
} }
} }

View File

@ -87,7 +87,12 @@ public enum NbtType {
/** /**
* A list of fully formed tags, including their IDs, names, and payloads. No two tags may have the same name. * A list of fully formed tags, including their IDs, names, and payloads. No two tags may have the same name.
*/ */
TAG_COMPOUND(10, Map.class); TAG_COMPOUND(10, Map.class),
/**
* An array of longs
*/
TAG_LONG_ARRAY(12, long[].class);
private int rawID; private int rawID;
private Class<?> valueType; private Class<?> valueType;

View File

@ -1,45 +1,45 @@
name: ProtocolLib name: ProtocolLib
version: 4.5.0-SNAPSHOT version: 4.5.0-SNAPSHOT
description: Provides read/write access to the Minecraft protocol. description: Provides read/write access to the Minecraft protocol.
authors: [dmulloy2, comphenix] authors: [dmulloy2, comphenix]
main: com.comphenix.protocol.ProtocolLib main: com.comphenix.protocol.ProtocolLib
load: STARTUP load: STARTUP
database: false database: false
api-version: "1.13" api-version: "1.13"
commands: commands:
protocol: protocol:
description: Performs administrative tasks regarding ProtocolLib. description: Performs administrative tasks regarding ProtocolLib.
usage: /<command> config|check|update|timings|listeners|version|dump usage: /<command> config|check|update|timings|listeners|version|dump
permission: protocol.admin permission: protocol.admin
permission-message: You don't have <permission> permission-message: You don't have <permission>
packet: packet:
description: Add or remove a simple packet listener. description: Add or remove a simple packet listener.
usage: /<command> add|remove|names client|server [ID start]-[ID stop] [detailed] usage: /<command> add|remove|names client|server [ID start]-[ID stop] [detailed]
permission: protocol.admin permission: protocol.admin
permission-message: You don't have <permission> permission-message: You don't have <permission>
filter: filter:
description: Add or remove programmable filters to the packet listeners. description: Add or remove programmable filters to the packet listeners.
usage: /<command> add|remove name [ID start]-[ID stop] usage: /<command> add|remove name [ID start]-[ID stop]
aliases: [packet_filter] aliases: [packet_filter]
permission: protocol.admin permission: protocol.admin
permission-message: You don't have <permission> permission-message: You don't have <permission>
packetlog: packetlog:
description: Logs hex representations of packets to a file or console description: Logs hex representations of packets to a file or console
usage: /<command> <protocol> <sender> <packet> [location] usage: /<command> <protocol> <sender> <packet> [location]
permission: protocol.admin permission: protocol.admin
permission-message: You don't have <permission> permission-message: You don't have <permission>
permissions: permissions:
protocol.*: protocol.*:
description: Gives access to everything. description: Gives access to everything.
children: children:
protocol.admin: true protocol.admin: true
protocol.info: true protocol.info: true
protocol.admin: protocol.admin:
description: Able to initiate the update process, and can configure debug mode. description: Able to initiate the update process, and can configure debug mode.
default: op default: op
protocol.info: protocol.info:
description: Can read update notifications and error reports. description: Can read update notifications and error reports.
default: op default: op