Compare commits

..
17 Commits
Author SHA1 Message Date
Myles 25a7915c7f 0.9.9 Version 2016-08-25 16:52:34 +01:00
Myles 822d582074 Deprecate isPorted, we port all players use getPlayerVersion instead. 2016-08-24 20:40:53 +01:00
Matsv f8a73d5fc2 Merge branch 'master' of https://github.com/Matsv/ViaVersion into upmaster 2016-08-22 21:38:19 +02:00
Matsv a0ad97947d Add the configuration to the dump command, also add a toString method to the ProtocolVersion class. 2016-08-22 21:37:51 +02:00
Myles 6ea5d0849d Missed a bit off the README 2016-08-21 15:52:59 +01:00
Myles eba512ef0b Update README with IRC 2016-08-21 15:51:21 +01:00
Matsv 0f96c24c78 Merge branch 'master' of https://github.com/Matsv/ViaVersion into dumpthemall 2016-08-20 16:21:19 +02:00
Matsv f2e4c37cd9 Add ViaVersion dump command to get all the relevant info we need by bug reports. 2016-08-20 16:19:44 +02:00
Myles f159a2250c SemVer compatibility, also change up the messages a bit. 2016-08-20 13:47:09 +01:00
Myles ed311e4059 Clean up some messages to be more understandable. 2016-08-20 12:03:23 +01:00
AlfieC 6aae98a8a9 typo (#485) 2016-08-17 23:32:21 +02:00
Matsv 0f3daa5dc4 Merge branch 'chunkFix' of https://github.com/Matsv/ViaVersion into upmaster 2016-08-08 18:00:40 +02:00
Matsv f258cf8c89 Stop depending on versions for the ChunkTypes. fix cast exceptions by using a ChunkType in front of it. 2016-08-08 17:38:11 +02:00
Matsv ca759c056e Add some missing sounds 2016-08-07 17:53:08 +02:00
Matsv d715607826 Implement 1_8 writing 2016-08-05 20:17:39 +02:00
inventivetalent afca92d122 update requests to use /v2 (#479) 2016-08-04 20:42:03 +01:00
Myles ae37b34692 Snapshot 2016-08-01 14:07:33 +01:00
23 changed files with 626 additions and 121 deletions

No files matched your search

+6 -30
View File
@@ -1,7 +1,9 @@
# ViaVersion 0.9.8
# ViaVersion 0.9.9
[![Build Status](https://travis-ci.org/MylesIsCool/ViaVersion.svg?branch=master)](https://travis-ci.org/MylesIsCool/ViaVersion)
[![Gitter](https://badges.gitter.im/MylesIsCool/ViaVersion.svg)](https://gitter.im/MylesIsCool/ViaVersion)
IRC: [#viaversion](http://buzz.spi.gt/iris/?channels=viaversion) on irc.spi.gt for Support.
**Allows the connection of higher client versions to lower server versions**
Allows 1.10, 1.9 on 1.8 server and 1.10 on a 1.9 server.
@@ -14,40 +16,14 @@ Allows 1.10, 1.9 on 1.8 server and 1.10 on a 1.9 server.
Sources:
--------
**wiki.vg** (Used for various information, we also contribute back)
**wiki.vg** (Protocol info, though I did have to find a lot myself)
**Burger** We use this tool to get protocol and other useful information for new / undocumented Minecraft versions
**Burger** (See [PAaaS](https://github.com/Matsv/Paaas))
**OpenNBT** (used for slot rewriting)
All Time Contributors:
--------
**Myself** (harhar)
**Matsv**
**HugoDaBosss**
**SanderGielisse**
**Paulomart**
**gigosaurus**
**fillefilip8**
**lenis0012**
**fuzzy_bot**
**joserobjr**
Releases / Dev Builds:
--------
You can find official releases here:
@@ -70,5 +46,5 @@ License:
MIT License, see LICENSE for more details.
Thanks!
Special thanks to all our [Contributors](https://github.com/MylesIsCool/ViaVersion/graphs/contributors)
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>0.9.8</version>
<version>0.9.9</version>
<packaging>jar</packaging>
<name>ViaVersion</name>
@@ -21,6 +21,7 @@ import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.api.command.ViaVersionCommand;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.boss.ViaBossBar;
import us.myles.ViaVersion.classgenerator.ClassGenerator;
import us.myles.ViaVersion.commands.ViaCommandHandler;
@@ -60,7 +61,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
protocolSupport = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null;
if (protocolSupport) {
getLogger().info("Patching to prevent concurrency issues...");
getLogger().info("Hooking into ProtocolSupport, to prevent issues!");
try {
patchLists();
} catch (Exception e) {
@@ -84,7 +85,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
}
} else {
getLogger().severe("ViaVersion is already loaded, this should work fine... Otherwise reboot the server!!!");
getLogger().severe("ViaVersion is already loaded, this should work fine. If you get any console errors, try rebooting.");
}
}
@@ -125,9 +126,9 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
gatherProtocolVersion();
// Check if there are any pipes to this version
if (ProtocolRegistry.SERVER_PROTOCOL != -1) {
getLogger().info("ViaVersion detected protocol version: " + ProtocolRegistry.SERVER_PROTOCOL);
getLogger().info("ViaVersion detected server version: " + ProtocolVersion.getProtocol(ProtocolRegistry.SERVER_PROTOCOL));
if (!ProtocolRegistry.isWorkingPipe()) {
getLogger().warning("ViaVersion will not function on the current protocol.");
getLogger().warning("ViaVersion does not have any compatible versions for this server version, please read our resource page carefully.");
}
}
ProtocolRegistry.refreshVersions();
@@ -151,7 +152,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
@Override
public void onDisable() {
getLogger().info("ViaVersion is disabling, if this is a reload it may not work.");
getLogger().info("ViaVersion is disabling, if this is a reload and you experience issues consider rebooting.");
uninject();
}
@@ -222,7 +223,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
try {
Object connection = getServerConnection();
if (connection == null) {
getLogger().warning("We failed to find the ServerConnection? :( What server are you running?");
getLogger().warning("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
return;
}
for (Field field : connection.getClass().getDeclaredFields()) {
@@ -256,7 +257,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
}
System.setProperty("ViaVersion", getDescription().getVersion());
} catch (Exception e) {
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
getLogger().severe("Unable to inject ViaVersion, please post these details on our GitHub and ensure you're using a compatible server version.");
e.printStackTrace();
}
}
@@ -265,7 +266,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
public void patchLists() throws Exception {
Object connection = getServerConnection();
if (connection == null) {
getLogger().warning("We failed to find the ServerConnection? :( What server are you running?");
getLogger().warning("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
return;
}
for (Field field : connection.getClass().getDeclaredFields()) {
@@ -325,12 +326,12 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
PluginDescriptionFile yaml = ReflectionUtil.get(cl, "description", PluginDescriptionFile.class);
throw new Exception("Unable to inject, due to " + bootstrapAcceptor.getClass().getName() + ", try without the plugin " + yaml.getName() + "?");
} else {
throw new Exception("Unable to find childHandler, weird server version? " + bootstrapAcceptor.getClass().getName());
throw new Exception("Unable to find core component 'childHandler', please check your plugins. issue: " + bootstrapAcceptor.getClass().getName());
}
}
} catch (Exception e) {
getLogger().severe("Have you got late-bind enabled with something else?");
getLogger().severe("We failed to inject ViaVersion, have you got late-bind enabled with something else?");
e.printStackTrace();
}
}
@@ -345,7 +346,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
ReflectionUtil.set(bootstrapAcceptor, "childHandler", ((ViaVersionInitializer) oldInit).getOriginal());
}
} catch (Exception e) {
System.out.println("Failed to remove injection... reload won't work with connections sorry");
System.out.println("Failed to remove injection handler, reload won't work with connections, please reboot!");
}
}
injectedFutures.clear();
@@ -357,7 +358,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
pair.getKey().set(pair.getValue(), ((ListWrapper) o).getOriginalList());
}
} catch (IllegalAccessException e) {
System.out.println("Failed to remove injection... reload might not work with connections sorry");
System.out.println("Failed to remove injection, reload won't work with connections, please reboot!");
}
}
@@ -17,6 +17,7 @@ public interface ViaVersionAPI {
*
* @param player Bukkit player object
* @return True if the client is modified (At the moment it also means version 1.9 and higher)
* @deprecated As of 0.9.9, because all players are ported use {@link #getPlayerVersion(Player)}
*/
boolean isPorted(Player player);
@@ -42,7 +43,9 @@ public interface ViaVersionAPI {
*
* @param playerUUID UUID of a player
* @return True if the client is on 1.9
* @deprecated As of 0.9.9, because all players are ported use {@link #getPlayerVersion(UUID)}
*/
@Deprecated
boolean isPorted(UUID playerUUID);
/**
@@ -116,9 +119,9 @@ public interface ViaVersionAPI {
/**
* Get the supported protocol versions
* This method removes any blocked protocol versions.
* @see ProtocolRegistry#getSupportedVersions() for full list.
*
* @return a list of protocol versions
* @see ProtocolRegistry#getSupportedVersions() for full list.
*/
SortedSet<Integer> getSupportedVersions();
@@ -1,5 +1,9 @@
package us.myles.ViaVersion.api.minecraft.chunks;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import java.util.List;
public interface Chunk {
int getX();
@@ -14,4 +18,6 @@ public interface Chunk {
byte[] getBiomeData();
int getBitmask();
List<CompoundTag> getBlockEntities();
}
@@ -91,4 +91,9 @@ public class ProtocolVersion {
public int hashCode() {
return id;
}
@Override
public String toString() {
return String.format("%s(%d)", this.getName(), this.getId());
}
}
@@ -19,7 +19,9 @@ public class Metadata1_8Type extends MetaTypeTemplate {
}
@Override
public void write(ByteBuf buffer, Metadata object) throws Exception {
throw new UnsupportedOperationException("1.8 Metadata writing is not implemented!");
public void write(ByteBuf buffer, Metadata meta) throws Exception {
byte item = (byte) (meta.getTypeID() << 5 | meta.getId() & 0x1F);
buffer.writeByte(item);
meta.getType().write(buffer, meta.getValue());
}
}
@@ -25,6 +25,8 @@ public class MetadataList1_8Type extends MetaListTypeTemplate {
@Override
public void write(ByteBuf buffer, List<Metadata> object) throws Exception {
throw new UnsupportedOperationException("1.8 MetadataList writing is not implemented");
for (Metadata data : object)
Types1_8.METADATA.write(buffer, data);
buffer.writeByte(127);
}
}
@@ -132,6 +132,7 @@ public class ViaCommandHandler implements ViaVersionCommand, CommandExecutor, Ta
registerSubCommand(new ListSubCmd());
registerSubCommand(new PPSSubCmd());
registerSubCommand(new DebugSubCmd());
registerSubCommand(new DumpSubCmd());
registerSubCommand(new DisplayLeaksSubCmd());
registerSubCommand(new DontBugMeSubCmd());
registerSubCommand(new AutoTeamSubCmd());
@@ -0,0 +1,94 @@
package us.myles.ViaVersion.commands.defaultsubs;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.dump.DumpTemplate;
import us.myles.ViaVersion.dump.PluginInfo;
import us.myles.ViaVersion.dump.VersionInfo;
import java.io.InputStreamReader;
import java.io.InvalidObjectException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
public class DumpSubCmd extends ViaSubCommand {
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
@Override
public String name() {
return "dump";
}
@Override
public String description() {
return "Dump information about your server, this is helpful if you report bugs.";
}
@Override
public boolean execute(final CommandSender sender, String[] args) {
VersionInfo version = new VersionInfo(
Bukkit.getServer().getVersion(),
Bukkit.getServer().getBukkitVersion(),
System.getProperty("java.version"),
System.getProperty("os.name"),
ProtocolRegistry.SERVER_PROTOCOL,
ProtocolRegistry.getSupportedVersions());
List<PluginInfo> plugins = new ArrayList<>();
for (Plugin p : Bukkit.getPluginManager().getPlugins())
plugins.add(new PluginInfo(p.isEnabled(), p.getDescription().getName(), p.getDescription().getVersion(), p.getDescription().getMain(), p.getDescription().getAuthors()));
Map<String, Object> configuration = ((ViaVersionPlugin) ViaVersion.getInstance()).getConfig().getValues(false);
final DumpTemplate template = new DumpTemplate(version, configuration, plugins);
Bukkit.getScheduler().runTaskAsynchronously((ViaVersionPlugin) ViaVersion.getInstance(), new Runnable() {
@Override
public void run() {
try {
HttpURLConnection con = (HttpURLConnection) new URL("http://hastebin.com/documents").openConnection();
con.setRequestProperty("Content-Type", "text/plain");
con.setRequestMethod("POST");
con.setDoOutput(true);
OutputStream out = con.getOutputStream();
out.write(gson.toJson(template).getBytes(Charset.forName("UTF-8")));
out.close();
JsonObject output = gson.fromJson(new InputStreamReader(con.getInputStream()), JsonObject.class);
con.getInputStream().close();
if (!output.has("key"))
throw new InvalidObjectException("Key is not given in Hastebin output");
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");
((ViaVersionPlugin) ViaVersion.getInstance()).getLogger().log(Level.WARNING, "Could not paste ViaVersion dump to Hastebin", e);
}
}
});
return true;
}
private String getUrl(String id) {
return String.format("http://hastebin.com/%s.json", id);
}
}
@@ -0,0 +1,15 @@
package us.myles.ViaVersion.dump;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
public class DumpTemplate {
private VersionInfo versionInfo;
private Map<String, Object> configuration;
private List<PluginInfo> plugins;
}
@@ -0,0 +1,16 @@
package us.myles.ViaVersion.dump;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
@Data
@AllArgsConstructor
public class PluginInfo {
private boolean enabled;
private String name;
private String version;
private String main;
private List<String> authors;
}
@@ -0,0 +1,18 @@
package us.myles.ViaVersion.dump;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
@Data
@AllArgsConstructor
public class VersionInfo {
private String version;
private String bukkitVersion;
private String javaVersion;
private String operatingSystem;
private int serverProtocol;
private Set<Integer> enabledPipelines;
}
@@ -11,11 +11,10 @@ import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks.BlockEntity;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks.Chunk1_9_3_4;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.types.Chunk1_9_3_4Type;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
public class Protocol1_9_1_2TO1_9_3_4 extends Protocol {
public static Type<Chunk> CHUNK = new Chunk1_9_3_4Type();
@Override
protected void registerPackets() {
@@ -60,8 +59,50 @@ public class Protocol1_9_1_2TO1_9_3_4 extends Protocol {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
Chunk chunk = wrapper.passthrough(CHUNK);
BlockEntity.handle(((Chunk1_9_3_4) chunk).getBlockEntities(), wrapper.user());
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
Chunk1_9_3_4Type type = new Chunk1_9_3_4Type(clientWorld);
Chunk chunk = wrapper.passthrough(type);
BlockEntity.handle(chunk.getBlockEntities(), wrapper.user());
}
});
}
});
// Join (save dimension id)
registerOutgoing(State.PLAY, 0x23, 0x23, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Entity ID
map(Type.UNSIGNED_BYTE); // 1 - Gamemode
map(Type.INT); // 2 - Dimension
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, 1);
clientChunks.setEnvironment(dimensionId);
}
});
}
});
// Respawn (save dimension id)
registerOutgoing(State.PLAY, 0x33, 0x33, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Dimension ID
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, 0);
clientWorld.setEnvironment(dimensionId);
}
});
}
@@ -70,6 +111,7 @@ public class Protocol1_9_1_2TO1_9_3_4 extends Protocol {
@Override
public void init(UserConnection userConnection) {
if (!userConnection.has(ClientWorld.class))
userConnection.put(new ClientWorld(userConnection));
}
}
@@ -15,15 +15,11 @@ public class Chunk1_9_3_4 implements Chunk {
private boolean groundUp;
private int bitmask;
private ChunkSection1_9_3_4[] sections;
List<CompoundTag> blockEntities;
private byte[] biomeData;
private List<CompoundTag> blockEntities;
@Override
public boolean isBiomeData() {
return false;
}
@Override
public byte[] getBiomeData() {
return new byte[0];
return biomeData != null;
}
}
@@ -1,41 +1,293 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks;
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
public class ChunkSection1_9_3_4 implements ChunkSection {
private final byte[] data;
/**
* Size (dimensions) of blocks in a chunks section.
*/
public static final int SIZE = 16 * 16 * 16; // width * depth * height
/**
* Length of the sky and block light nibble arrays.
*/
public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count)
/**
* Length of the block data array.
*/
@Getter
private final List<Integer> palette = Lists.newArrayList();
private final int[] blocks;
private final NibbleArray blockLight;
private NibbleArray skyLight;
public ChunkSection1_9_3_4(byte[] data) {
this.data = data;
public ChunkSection1_9_3_4() {
this.blocks = new int[SIZE];
this.blockLight = new NibbleArray(SIZE);
palette.add(0); // AIR
}
public byte[] getData() {
return data;
/**
* Set a block in the chunks
*
* @param x Block X
* @param y Block Y
* @param z Block Z
* @param type The type of the block
* @param data The data value of the block
*/
public void setBlock(int x, int y, int z, int type, int data) {
setBlock(index(x, y, z), type, data);
}
@Override
public int getBlockId(int x, int y, int z) {
throw new UnsupportedOperationException("Invalid chunk type!");
int index = blocks[index(x, y, z)];
return palette.get(index) >> 4;
}
@Override
/**
* Set a block in the chunks based on the index
*
* @param idx Index
* @param type The type of the block
* @param data The data value of the block
*/
public void setBlock(int idx, int type, int data) {
int hash = type << 4 | (data & 0xF);
int index = palette.indexOf(hash);
if (index == -1) {
index = palette.size();
palette.add(hash);
}
blocks[idx] = index;
}
/**
* Set the block light array
*
* @param data The value to set the block light to
*/
public void setBlockLight(byte[] data) {
blockLight.setHandle(data);
}
/**
* Set the sky light array
*
* @param data The value to set the sky light to
*/
public void setSkyLight(byte[] data) {
if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH);
this.skyLight = new NibbleArray(data);
}
private int index(int x, int y, int z) {
return y << 8 | z << 4 | x;
}
/**
* Read blocks from input stream.
* This reads all the block related data:
* <ul>
* <li>Block length/palette type</li>
* <li>Palette</li>
* <li>Block hashes/palette reference</li>
* </ul>
*
* @param input The buffer to read from.
* @throws Exception
*/
public void readBlocks(ByteBuf input) throws Exception {
palette.clear();
// Reaad bits per block
int bitsPerBlock = input.readUnsignedByte();
long maxEntryValue = (1L << bitsPerBlock) - 1;
if (bitsPerBlock == 0) {
bitsPerBlock = 13;
}
if (bitsPerBlock < 4) {
bitsPerBlock = 4;
}
if (bitsPerBlock > 8) {
bitsPerBlock = 13;
}
int paletteLength = Type.VAR_INT.read(input);
// Read palette
for (int i = 0; i < paletteLength; i++) {
if (bitsPerBlock != 13) {
palette.add(Type.VAR_INT.read(input));
} else {
Type.VAR_INT.read(input);
}
}
// Read blocks
Long[] blockData = Type.LONG_ARRAY.read(input);
if (blockData.length > 0) {
for (int i = 0; i < blocks.length; i++) {
int bitIndex = i * bitsPerBlock;
int startIndex = bitIndex / 64;
int endIndex = ((i + 1) * bitsPerBlock - 1) / 64;
int startBitSubIndex = bitIndex % 64;
int val;
if (startIndex == endIndex) {
val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue);
} else {
int endBitSubIndex = 64 - startBitSubIndex;
val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue);
}
if (bitsPerBlock == 13) {
int type = val >> 4;
int data = val & 0xF;
setBlock(i, type, data);
} else {
blocks[i] = val;
}
}
}
}
/**
* Read block light from buffer.
*
* @param input The buffer to read from
*/
public void readBlockLight(ByteBuf input) {
byte[] handle = new byte[LIGHT_LENGTH];
input.readBytes(handle);
blockLight.setHandle(handle);
}
/**
* Read sky light from buffer.
* Note: Only sent in overworld!
*
* @param input The buffer to read from
*/
public void readSkyLight(ByteBuf input) {
byte[] handle = new byte[LIGHT_LENGTH];
input.readBytes(handle);
if (skyLight != null) {
skyLight.setHandle(handle);
return;
}
this.skyLight = new NibbleArray(handle);
}
/**
* Write the blocks to a buffer.
*
* @param output The buffer to write to.
* @throws Exception Throws if it failed to write.
*/
public void writeBlocks(ByteBuf output) throws Exception {
throw new UnsupportedOperationException("Invalid chunk type!");
// Write bits per block
int bitsPerBlock = 4;
while (palette.size() > 1 << bitsPerBlock) {
bitsPerBlock += 1;
}
long maxEntryValue = (1L << bitsPerBlock) - 1;
output.writeByte(bitsPerBlock);
// Write pallet (or not)
Type.VAR_INT.write(output, palette.size());
for (int mappedId : palette) {
Type.VAR_INT.write(output, mappedId);
}
int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0);
Type.VAR_INT.write(output, length);
long[] data = new long[length];
for (int index = 0; index < blocks.length; index++) {
int value = blocks[index];
int bitIndex = index * bitsPerBlock;
int startIndex = bitIndex / 64;
int endIndex = ((index + 1) * bitsPerBlock - 1) / 64;
int startBitSubIndex = bitIndex % 64;
data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex;
if (startIndex != endIndex) {
int endBitSubIndex = 64 - startBitSubIndex;
data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex;
}
}
for (long l : data) {
Type.LONG.write(output, l);
}
}
@Override
public void writeBlockLight(ByteBuf output) throws Exception {
throw new UnsupportedOperationException("Invalid chunk type!");
/**
* Write the block light to a buffer
*
* @param output The buffer to write to
*/
public void writeBlockLight(ByteBuf output) {
output.writeBytes(blockLight.getHandle());
}
@Override
/**
* Write the sky light to a buffer
*
* @param output The buffer to write to
*/
public void writeSkyLight(ByteBuf output) {
output.writeBytes(skyLight.getHandle());
}
/**
* Check if sky light is present
*
* @return True if skylight is present
*/
public boolean hasSkyLight() {
throw new UnsupportedOperationException("Invalid chunk type!");
return skyLight != null;
}
@Override
public void writeSkyLight(ByteBuf output) throws Exception {
throw new UnsupportedOperationException("Invalid chunk type!");
/**
* Get expected size of this chunks section.
*
* @return Amount of bytes sent by this section
* @throws Exception If it failed to calculate bits properly
*/
public int getExpectedSize() throws Exception {
int bitsPerBlock = palette.size() > 255 ? 16 : 8;
int bytes = 1; // bits per block
bytes += paletteBytes(); // palette
bytes += countBytes(bitsPerBlock == 16 ? SIZE * 2 : SIZE); // block data length
bytes += (palette.size() > 255 ? 2 : 1) * SIZE; // block data
bytes += LIGHT_LENGTH; // block light
bytes += hasSkyLight() ? LIGHT_LENGTH : 0; // sky light
return bytes;
}
private int paletteBytes() throws Exception {
// Count bytes used by pallet
int bytes = countBytes(palette.size());
for (int mappedId : palette) {
bytes += countBytes(mappedId);
}
return bytes;
}
private int countBytes(int value) throws Exception {
// Count amount of bytes that would be sent if the value were sent as a VarInt
ByteBuf buf = Unpooled.buffer();
Type.VAR_INT.write(buf, value);
buf.readerIndex(0);
int bitCount = buf.readableBytes();
buf.release();
return bitCount;
}
}
@@ -1,56 +1,102 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.types;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.World;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
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.protocols.protocol1_9_1_2to1_9_3_4.chunks.Chunk1_9_3_4;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks.ChunkSection1_9_3_4;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
public class Chunk1_9_3_4Type extends BaseChunkType {
public Chunk1_9_3_4Type() {
super("1.9.3 Chunk");
public class Chunk1_9_3_4Type extends PartialType<Chunk, ClientWorld> {
public Chunk1_9_3_4Type(ClientWorld param) {
super(param, Chunk.class);
}
@Override
public Chunk read(ByteBuf input) throws Exception {
public Chunk read(ByteBuf input, ClientWorld world) throws Exception {
int chunkX = input.readInt();
int chunkZ = input.readInt();
boolean groundUp = input.readBoolean();
int primaryBitmask = Type.VAR_INT.read(input);
int size = Type.VAR_INT.read(input);
Type.VAR_INT.read(input);
byte[] sections = new byte[size];
input.readBytes(sections);
int blockEntities = Type.VAR_INT.read(input);
List<CompoundTag> nbtData = new ArrayList<>();
for (int i = 0; i < blockEntities; i++) {
nbtData.add(Type.NBT.read(input));
BitSet usedSections = new BitSet(16);
ChunkSection1_9_3_4[] sections = new ChunkSection1_9_3_4[16];
// Calculate section count from bitmask
for (int i = 0; i < 16; i++) {
if ((primaryBitmask & (1 << i)) != 0) {
usedSections.set(i);
}
}
return new Chunk1_9_3_4(chunkX, chunkZ, groundUp, primaryBitmask, new ChunkSection1_9_3_4[] {new ChunkSection1_9_3_4(sections)}, nbtData);
// Read sections
for (int i = 0; i < 16; i++) {
if (!usedSections.get(i)) continue; // Section not set
ChunkSection1_9_3_4 section = new ChunkSection1_9_3_4();
sections[i] = section;
section.readBlocks(input);
section.readBlockLight(input);
if (world.getEnvironment() == World.Environment.NORMAL) {
section.readSkyLight(input);
}
}
byte[] biomeData = groundUp ? new byte[256] : null;
if (groundUp) {
input.readBytes(biomeData);
}
List<CompoundTag> nbtData = Arrays.asList(Type.NBT_ARRAY.read(input));
return new Chunk1_9_3_4(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData);
}
@Override
public void write(ByteBuf buffer, Chunk input) throws Exception {
if (!(input instanceof Chunk1_9_3_4))
throw new Exception("Tried to send the wrong chunk type from 1.9.3-4 chunk: " + input.getClass());
Chunk1_9_3_4 chunk = (Chunk1_9_3_4) input;
public void write(ByteBuf output, ClientWorld world, Chunk chunk) throws Exception {
output.writeInt(chunk.getX());
output.writeInt(chunk.getZ());
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
output.writeBoolean(chunk.isGroundUp());
Type.VAR_INT.write(output, chunk.getBitmask());
buffer.writeBoolean(chunk.isGroundUp());
Type.VAR_INT.write(buffer, chunk.getBitmask());
ByteBuf buf = Unpooled.buffer();
for (int i = 0; i < 16; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null) continue; // Section not set
section.writeBlocks(buf);
section.writeBlockLight(buf);
Type.VAR_INT.write(buffer, chunk.getSections()[0].getData().length);
buffer.writeBytes(chunk.getSections()[0].getData());
if (!section.hasSkyLight()) continue; // No sky light, we're done here.
section.writeSkyLight(buf);
// no block entities as it's earlier
}
buf.readerIndex(0);
Type.VAR_INT.write(output, buf.readableBytes() + (chunk.isBiomeData() ? 256 : 0));
output.writeBytes(buf);
buf.release(); // release buffer
// Write biome data
if (chunk.isBiomeData()) {
output.writeBytes(chunk.getBiomeData());
}
// Don't write block entities
}
@Override
public Class<? extends Type> getBaseClass() {
return BaseChunkType.class;
}
}
@@ -142,6 +142,7 @@ public class Protocol1_9_3TO1_9_1_2 extends Protocol {
@Override
public void init(UserConnection user) {
user.put(new ClientWorld(user));
if (!user.has(ClientWorld.class))
user.put(new ClientWorld(user));
}
}
@@ -3,8 +3,12 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
import java.util.Collections;
import java.util.List;
@RequiredArgsConstructor
@Getter
@ToString
@@ -46,4 +50,9 @@ public class Chunk1_9to1_8 implements Chunk {
public int getBitmask() {
return primaryBitmask;
}
@Override
public List<CompoundTag> getBlockEntities() {
return Collections.emptyList();
}
}
@@ -18,7 +18,7 @@ public class PaperPatch extends ViaListener {
/*
This patch is applied when Paper is detected.
I'm unsure of what causes this but essentially,
placing blocks where your standing works?
placing blocks where you're standing works?
If there is a better fix then we'll replace this.
*/
@@ -35,7 +35,7 @@ public enum SoundEffect {
MOB_HORSE_ZOMBIE_DEATH("mob.horse.zombie.death", "entity.zombie_horse.death", SoundCategory.NEUTRAL),
MOB_SILVERFISH_KILL("mob.silverfish.kill", "entity.endermite.death", SoundCategory.HOSTILE),
MOB_WOLF_PANTING("mob.wolf.panting", "entity.wolf.pant", SoundCategory.NEUTRAL),
NOTE_BASS("note.bass", "null", SoundCategory.RECORD),
NOTE_BASS("note.bass", "block.note.bass", SoundCategory.RECORD),
DIG_STONE("dig.stone", "block.glass.place", SoundCategory.BLOCK),
MOB_ENDERMEN_STARE("mob.endermen.stare", "entity.endermen.stare", SoundCategory.HOSTILE),
GAME_PLAYER_SWIM_SPLASH("game.player.swim.splash", "entity.generic.splash", SoundCategory.BLOCK),
@@ -79,7 +79,7 @@ public enum SoundEffect {
CREEPER_PRIMED("creeper.primed", "entity.creeper.primed", SoundCategory.HOSTILE),
DIG_SAND("dig.sand", "block.sand.break", SoundCategory.BLOCK),
MOB_CHICKEN_SAY("mob.chicken.say", "entity.chicken.ambient", SoundCategory.NEUTRAL),
RANDOM_DOOR_CLOSE("random.door_close", "null", SoundCategory.BLOCK),
RANDOM_DOOR_CLOSE("random.door_close", "block.wooden_door.close", SoundCategory.BLOCK),
MOB_GUARDIAN_ELDER_DEATH("mob.guardian.elder.death", "entity.elder_guardian.death", SoundCategory.HOSTILE),
FIREWORKS_TWINKLE("fireworks.twinkle", "entity.firework.twinkle", SoundCategory.AMBIENT),
MOB_HORSE_SKELETON_DEATH("mob.horse.skeleton.death", "entity.skeleton_horse.death", SoundCategory.NEUTRAL),
@@ -177,7 +177,7 @@ public enum SoundEffect {
GAME_TNT_PRIMED("game.tnt.primed", "entity.creeper.primed", SoundCategory.BLOCK),
MOB_SHEEP_STEP("mob.sheep.step", "entity.sheep.step", SoundCategory.NEUTRAL),
MOB_ZOMBIE_DEATH("mob.zombie.death", "entity.zombie.death", SoundCategory.HOSTILE),
RANDOM_DOOR_OPEN("random.door_open", "null", SoundCategory.BLOCK),
RANDOM_DOOR_OPEN("random.door_open", "block.wooden_door.open", SoundCategory.BLOCK),
MOB_ENDERMEN_PORTAL("mob.endermen.portal", "entity.endermen.teleport", SoundCategory.HOSTILE),
MOB_HORSE_ANGRY("mob.horse.angry", "entity.horse.angry", SoundCategory.NEUTRAL),
MOB_WOLF_GROWL("mob.wolf.growl", "entity.wolf.growl", SoundCategory.NEUTRAL),
@@ -242,7 +242,7 @@ public enum SoundEffect {
MOB_RABBIT_IDLE("mob.rabbit.idle", "entity.rabbit.ambient", SoundCategory.NEUTRAL),
MUSIC_GAME_END("music.game.end", "music.end", SoundCategory.MUSIC),
MUSIC_GAME("music.game", "music.game", SoundCategory.MUSIC),
MOB_GUARDIAN_IDLE("mob.guardian.idle", "null", SoundCategory.HOSTILE),
MOB_GUARDIAN_IDLE("mob.guardian.idle", "entity.elder_guardian.ambient", SoundCategory.HOSTILE),
RECORDS_WARD("records.ward", "record.ward", SoundCategory.RECORD),
RECORDS_13("records.13", "record.13", SoundCategory.RECORD),
MOB_RABBIT_HOP("mob.rabbit.hop", "entity.rabbit.jump", SoundCategory.NEUTRAL),
@@ -21,8 +21,9 @@ import java.util.UUID;
public class UpdateUtil {
public final static String PREFIX = ChatColor.GREEN + "" + ChatColor.BOLD + "[ViaVersion] " + ChatColor.GREEN;
private final static String URL = "http://api.spiget.org/v1/resources/";
private final static String URL = "http://api.spiget.org/v2/resources/";
private final static int PLUGIN = 19254;
private final static String LATEST_VERSION = "/versions/latest";
public static void sendUpdateMessage(final UUID uuid, final Plugin plugin) {
new BukkitRunnable() {
@@ -81,20 +82,24 @@ public class UpdateUtil {
try {
current = new Version(ViaVersion.getInstance().getVersion());
} catch (IllegalArgumentException e) {
return "You are using a debug/custom version, consider updating.";
return "You are using a custom version, consider updating.";
}
Version newest = new Version(newestString);
if (current.compareTo(newest) < 0)
return "There is a newer version available: " + newest.toString();
return "There is a newer version available: " + newest.toString() + ", you're on: " + current.toString();
else if (console && current.compareTo(newest) != 0) {
return "You are running a newer version than is released!";
if (current.getTag().toLowerCase().startsWith("dev") || current.getTag().toLowerCase().startsWith("snapshot")) {
return "You are running a development version, please report any bugs to GitHub.";
} else {
return "You are running a newer version than is released!";
}
}
return null;
}
private static String getNewestVersion() {
try {
URL url = new URL(URL + PLUGIN + "?" + System.currentTimeMillis());
URL url = new URL(URL + PLUGIN + LATEST_VERSION + "?" + System.currentTimeMillis());
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(true);
connection.addRequestProperty("User-Agent", "ViaVersion " + ViaVersion.getInstance().getVersion());
@@ -114,7 +119,7 @@ public class UpdateUtil {
e.printStackTrace();
return null;
}
return (String) statistics.get("version");
return (String) statistics.get("name");
} catch (MalformedURLException e) {
return null;
} catch (IOException e) {
@@ -2,21 +2,26 @@ package us.myles.ViaVersion.update;
import org.apache.commons.lang.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Version implements Comparable<Version> {
private int[] parts;
private static Pattern semVer = Pattern.compile("(?<a>0|[1-9]\\d*)\\.(?<b>0|[1-9]\\d*)(?:\\.(?<c>0|[1-9]\\d*))?(?:-(?<tag>[A-z0-9.-]*))?");
private int[] parts = new int[3];
private String tag;
public Version(String value) {
if (value == null)
throw new IllegalArgumentException("Version can not be null");
if (!value.matches("^[0-9]+(\\.[0-9]+)*$"))
Matcher matcher = semVer.matcher(value);
if (!matcher.matches())
throw new IllegalArgumentException("Invalid version format");
parts[0] = Integer.parseInt(matcher.group("a"));
parts[1] = Integer.parseInt(matcher.group("b"));
parts[2] = matcher.group("c") == null ? 0 : Integer.parseInt(matcher.group("c"));
String[] split = value.split("\\.");
parts = new int[split.length];
for (int i = 0; i < split.length; i += 1)
parts[i] = Integer.parseInt(split[i]);
tag = matcher.group("tag") == null ? "" : matcher.group("tag");
}
public static int compare(Version verA, Version verB) {
@@ -33,6 +38,12 @@ public class Version implements Comparable<Version> {
if (partA > partB) return 1;
}
// Simple tag check
if (verA.tag.length() == 0 && verB.tag.length() > 0)
return 1;
if (verA.tag.length() > 0 && verB.tag.length() == 0)
return -1;
return 0;
}
@@ -47,7 +58,7 @@ public class Version implements Comparable<Version> {
for (int i = 0; i < parts.length; i += 1)
split[i] = String.valueOf(parts[i]);
return StringUtils.join(split, ".");
return StringUtils.join(split, ".") + (tag.length() != 0 ? "-" + tag : "");
}
@Override
@@ -59,4 +70,8 @@ public class Version implements Comparable<Version> {
public boolean equals(Object that) {
return that instanceof Version && equals(this, (Version) that);
}
public String getTag() {
return tag;
}
}