diff --git a/LICENSE b/LICENSE index 4ddc63b9a..15bc72f8d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,9 +1,6 @@ -License: --------- - MIT License -Copyright (c) 2017 +Copyright (c) 2019 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/protocol1_9to1_8/ArmorListener.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/protocol1_9to1_8/ArmorListener.java index 2880f47e4..cddf4fe82 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/protocol1_9to1_8/ArmorListener.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/protocol1_9to1_8/ArmorListener.java @@ -9,6 +9,7 @@ import org.bukkit.event.block.Action; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemBreakEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.inventory.CraftingInventory; @@ -91,6 +92,11 @@ public class ArmorListener extends ViaBukkitListener { } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onItemBreak(PlayerItemBreakEvent e) { + sendDelayedArmorUpdate(e.getPlayer()); + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onJoin(PlayerJoinEvent e) { sendDelayedArmorUpdate(e.getPlayer()); diff --git a/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeChannelInitializer.java b/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeChannelInitializer.java index ceea247f9..dce420c08 100644 --- a/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeChannelInitializer.java +++ b/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeChannelInitializer.java @@ -30,6 +30,9 @@ public class BungeeChannelInitializer extends ChannelInitializer new ProtocolPipeline(info); // Add originals this.method.invoke(this.original, socketChannel); + + if (socketChannel.pipeline().get("packet-encoder") == null) return; // Don't inject if no packet-encoder + if (socketChannel.pipeline().get("packet-decoder") == null) return; // Don't inject if no packet-decoder // Add our transformers BungeeEncodeHandler encoder = new BungeeEncodeHandler(info); BungeeDecodeHandler decoder = new BungeeDecodeHandler(info); diff --git a/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/NibbleArray.java b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/NibbleArray.java index 8245d2a8c..4cfeddccc 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/NibbleArray.java +++ b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/NibbleArray.java @@ -67,11 +67,12 @@ public class NibbleArray { * @param value The desired value */ public void set(int index, int value) { - index /= 2; if (index % 2 == 0) { - handle[index] = (byte) (handle[index] & 0xF0 | value & 0xF); + index /= 2; + handle[index] = (byte) ((handle[index] & 0xF0) | (value & 0xF)); } else { - handle[index] = (byte) (handle[index] & 0xF | (value & 0xF) << 4); + index /= 2; + handle[index] = (byte) ((handle[index] & 0xF) | ((value & 0xF) << 4)); } } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/MetadataRewriter.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/MetadataRewriter.java index a838d96a1..431bccf94 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/MetadataRewriter.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/MetadataRewriter.java @@ -98,7 +98,9 @@ public class MetadataRewriter { // Handle AreaEffectCloud outside the loop if (type != null && type.is(Entity1_13Types.EntityType.AREA_EFFECT_CLOUD) && particleId != -1) { Particle particle = ParticleRewriter.rewriteParticle(particleId, new Integer[]{parameter1, parameter2}); - metadatas.add(new Metadata(9, MetaType1_13.PARTICLE, particle)); + if (particle != null && particle.getId() != -1) { + metadatas.add(new Metadata(9, MetaType1_13.PARTICLE, particle)); + } } } } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/blockconnections/ConnectionData.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/blockconnections/ConnectionData.java index 95b4655a5..aa2e7cc1b 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/blockconnections/ConnectionData.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/blockconnections/ConnectionData.java @@ -162,7 +162,6 @@ public class ConnectionData { List initActions = new ArrayList<>(); initActions.add(PumpkinConnectionHandler.init()); - initActions.add(MelonConnectionHandler.init()); initActions.addAll(BasicFenceConnectionHandler.init()); initActions.add(NetherFenceConnectionHandler.init()); initActions.addAll(WallConnectionHandler.init()); @@ -175,6 +174,7 @@ public class ConnectionData { initActions.add(FlowerConnectionHandler.init()); initActions.addAll(ChorusPlantConnectionHandler.init()); initActions.add(TripwireConnectionHandler.init()); + initActions.add(SnowyGrassConnectionHandler.init()); for (String key : keyToId.keySet()) { WrappedBlockData wrappedBlockData = WrappedBlockData.fromString(key); for (ConnectorInitAction action : initActions) { diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/blockconnections/SnowyGrassConnectionHandler.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/blockconnections/SnowyGrassConnectionHandler.java new file mode 100644 index 000000000..9d20d4168 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/blockconnections/SnowyGrassConnectionHandler.java @@ -0,0 +1,51 @@ +package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections; + +import us.myles.ViaVersion.api.Pair; +import us.myles.ViaVersion.api.data.UserConnection; +import us.myles.ViaVersion.api.minecraft.BlockFace; +import us.myles.ViaVersion.api.minecraft.Position; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class SnowyGrassConnectionHandler extends ConnectionHandler { + private static Map, Integer> grassBlocks = new HashMap<>(); + private static Set snows = new HashSet<>(); + + static ConnectionData.ConnectorInitAction init() { + final Set snowyGrassBlocks = new HashSet<>(); + snowyGrassBlocks.add("minecraft:grass_block"); + snowyGrassBlocks.add("minecraft:podzol"); + snowyGrassBlocks.add("minecraft:mycelium"); + + final SnowyGrassConnectionHandler handler = new SnowyGrassConnectionHandler(); + return new ConnectionData.ConnectorInitAction() { + @Override + public void check(WrappedBlockData blockData) { + if (snowyGrassBlocks.contains(blockData.getMinecraftKey())) { + ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), handler); + blockData.set("snowy", "true"); + grassBlocks.put(new Pair<>(blockData.getSavedBlockStateId(), true), blockData.getBlockStateId()); + blockData.set("snowy", "false"); + grassBlocks.put(new Pair<>(blockData.getSavedBlockStateId(), false), blockData.getBlockStateId()); + } + if (blockData.getMinecraftKey().equals("minecraft:snow") || blockData.getMinecraftKey().equals("minecraft:snow_block")) { + ConnectionData.connectionHandlerMap.put(blockData.getSavedBlockStateId(), handler); + snows.add(blockData.getSavedBlockStateId()); + } + } + }; + } + + @Override + public int connect(UserConnection user, Position position, int blockState) { + int blockUpId = getBlockData(user, position.getRelative(BlockFace.TOP)); + Integer newId = grassBlocks.get(new Pair<>(blockState, snows.contains(blockUpId))); + if (newId != null) { + return newId; + } + return blockState; + } +} \ No newline at end of file diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/data/MappingData.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/data/MappingData.java index 0e9322060..8dcbff56a 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/data/MappingData.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/data/MappingData.java @@ -67,7 +67,7 @@ public class MappingData { String[] keyAndTranslation = line.split("=", 2); if (keyAndTranslation.length != 2) continue; String key = keyAndTranslation[0]; - String translation = keyAndTranslation[1]; + String translation = keyAndTranslation[1].replaceAll("%(\\d\\$)?d", "%$1s"); if (!translateData.containsKey(key)) { translateMapping.put(key, translation); } else { diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/data/ParticleRewriter.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/data/ParticleRewriter.java index 804c09f12..e700ac779 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/data/ParticleRewriter.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/data/ParticleRewriter.java @@ -11,11 +11,10 @@ import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.packets.WorldPackets; import java.util.Arrays; import java.util.LinkedList; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class ParticleRewriter { private static List particles = new LinkedList<>(); - private static Random rand = new Random(); static { add(34); // (0->34) explode -> minecraft:poof @@ -108,17 +107,17 @@ public class ParticleRewriter { return new ParticleDataHandler() { @Override public Particle handler(Particle particle, Integer[] data) { - particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, randomFloat())); // Red 0 - 1 - particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, randomFloat())); // Green 0 - 1 - particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, randomFloat())); // Blue 0 - 1 - particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, 1));// Scale 0.01 - 4 + particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, randomBool() ? 1f : 0f)); // Red 0 - 1 + particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, 0f)); // Green 0 - 1 + particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, randomBool() ? 1f : 0f)); // Blue 0 - 1 + particle.getArguments().add(new Particle.ParticleData(Type.FLOAT, 1f));// Scale 0.01 - 4 return particle; } }; } - private static float randomFloat() { - return rand.nextFloat(); + private static boolean randomBool() { + return ThreadLocalRandom.current().nextBoolean(); } // Rewrite IconCrack items to new format :) diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java index 2b1866c1a..cf4312d22 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java @@ -615,7 +615,7 @@ public class InventoryPackets { ench.add(enchEntry); } } - tag.remove("Enchantment"); + tag.remove("Enchantments"); tag.put(ench); } if (tag.get("StoredEnchantments") instanceof ListTag) { diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/WorldPackets.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/WorldPackets.java index 0c932eaf6..5593028f0 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/WorldPackets.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/WorldPackets.java @@ -175,12 +175,13 @@ public class WorldPackets { if (Via.getConfig().isServersideBlockConnections()) { UserConnection userConnection = wrapper.user(); + + ConnectionData.updateBlockStorage(userConnection, position, newId); + if (ConnectionData.connects(newId)) { newId = ConnectionData.connect(userConnection, position, newId); } - ConnectionData.updateBlockStorage(userConnection, position, newId); - ConnectionData.update(userConnection, position); } @@ -415,15 +416,20 @@ public class WorldPackets { if (particle.getId() == 11) { int count = wrapper.get(Type.INT, 1); float speed = wrapper.get(Type.FLOAT, 6); - // Only handle for count = 0 & speed = 1 - if (count == 0 && speed == 1) { + // Only handle for count = 0 + if (count == 0) { wrapper.set(Type.INT, 1, 1); wrapper.set(Type.FLOAT, 6, 0f); List arguments = particle.getArguments(); for (int i = 0; i < 3; i++) { //RGB values are represented by the X/Y/Z offset - arguments.get(i).setValue(wrapper.get(Type.FLOAT, i + 3)); + float colorValue = wrapper.get(Type.FLOAT, i + 3) * speed; + if (colorValue == 0 && i == 0) { + // https://minecraft.gamepedia.com/User:Alphappy/reddust + colorValue = 1; + } + arguments.get(i).setValue(colorValue); wrapper.set(Type.FLOAT, i + 3, 0f); } } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/storage/BlockConnectionStorage.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/storage/BlockConnectionStorage.java index ad0a9e595..1694e2af9 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/storage/BlockConnectionStorage.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/storage/BlockConnectionStorage.java @@ -1,42 +1,88 @@ package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage; -import lombok.Data; -import lombok.EqualsAndHashCode; import us.myles.ViaVersion.api.Pair; +import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.StoredObject; import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.minecraft.Position; +import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray; +import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData; +import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.packets.WorldPackets; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; public class BlockConnectionStorage extends StoredObject { - private Map, Map> blockStorage = new HashMap<>(); + private Map> blockStorage = createLongObjectMap(); + + private static Constructor fastUtilLongObjectHashMap; + private static HashMap reverseBlockMappings; + + static { + try { + fastUtilLongObjectHashMap = Class.forName("it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap").getConstructor(); + Via.getPlatform().getLogger().info("Using FastUtil Long2ObjectOpenHashMap for block connections"); + } catch (ClassNotFoundException | NoSuchMethodException ignored) { + } + reverseBlockMappings = new HashMap<>(); + for (int i = 0; i < 4096; i++) { + int newBlock = MappingData.blockMappings.getNewBlock(i); + if (newBlock != -1) reverseBlockMappings.put((short) newBlock, (short) i); + } + } public BlockConnectionStorage(UserConnection user) { super(user); } public void store(Position position, int blockState) { - Pair pair = getPair(position); - Map map = getChunkMap(pair); - map.put(new BlockPositon(position), blockState); + Short mapping = reverseBlockMappings.get((short) blockState); + if (mapping == null) return; + blockState = mapping; + long pair = getChunkSectionIndex(position); + Pair map = getChunkSection(pair, (blockState & 0xF) != 0); + int blockIndex = encodeBlockPos(position); + map.getKey()[blockIndex] = (byte) (blockState >> 4); + NibbleArray nibbleArray = map.getValue(); + if (nibbleArray != null) nibbleArray.set(blockIndex, blockState); } public int get(Position position) { - Pair pair = getPair(position); - Map map = getChunkMap(pair); - BlockPositon blockPositon = new BlockPositon(position); - return map.containsKey(blockPositon) ? map.get(blockPositon) : 0; + long pair = getChunkSectionIndex(position); + Pair map = blockStorage.get(pair); + if (map == null) return 0; + short blockPosition = encodeBlockPos(position); + NibbleArray nibbleArray = map.getValue(); + return WorldPackets.toNewId( + ((map.getKey()[blockPosition] & 0xFF) << 4) + | (nibbleArray == null ? 0 : nibbleArray.get(blockPosition)) + ); } public void remove(Position position) { - Pair pair = getPair(position); - Map map = getChunkMap(pair); - map.remove(new BlockPositon(position)); - if (map.isEmpty()) { - blockStorage.remove(pair); + long pair = getChunkSectionIndex(position); + Pair map = blockStorage.get(pair); + if (map == null) return; + int blockIndex = encodeBlockPos(position); + NibbleArray nibbleArray = map.getValue(); + if (nibbleArray != null) { + nibbleArray.set(blockIndex, 0); + boolean allZero = true; + for (int i = 0; i < 4096; i++) { + if (nibbleArray.get(i) != 0) { + allZero = false; + break; + } + } + if (allZero) map.setValue(null); } + map.getKey()[blockIndex] = 0; + for (short entry : map.getKey()) { + if (entry != 0) return; + } + blockStorage.remove(pair); } public void clear() { @@ -44,33 +90,47 @@ public class BlockConnectionStorage extends StoredObject { } public void unloadChunk(int x, int z) { - blockStorage.remove(new Pair<>(x, z)); + for (int y = 0; y < 256; y += 16) { + blockStorage.remove(getChunkSectionIndex(x, y, z)); + } } - private Map getChunkMap(Pair pair) { - Map map = blockStorage.get(pair); + private Pair getChunkSection(long index, boolean requireNibbleArray) { + Pair map = blockStorage.get(index); if (map == null) { - map = new HashMap<>(); - blockStorage.put(pair, map); + map = new Pair<>(new byte[4096], null); + blockStorage.put(index, map); + } + if (map.getValue() == null && requireNibbleArray) { + map.setValue(new NibbleArray(4096)); } return map; } - private Pair getPair(Position position) { - int chunkX = (int) (position.getX() >> 4); - int chunkZ = (int) (position.getZ() >> 4); - return new Pair<>(chunkX, chunkZ); + private long getChunkSectionIndex(int x, int y, int z) { + return (((x >> 4) & 0x3FFFFFFL) << 38) | (((y >> 4) & 0xFFFL) << 26) | ((z >> 4) & 0x3FFFFFFL); } - @EqualsAndHashCode - @Data - private class BlockPositon { - int x, y, z; + private long getChunkSectionIndex(Position position) { + return getChunkSectionIndex(position.getX().intValue(), position.getY().intValue(), position.getZ().intValue()); + } - public BlockPositon(Position position) { - x = position.getX().intValue(); - y = position.getY().intValue(); - z = position.getZ().intValue(); + private short encodeBlockPos(int x, int y, int z) { + return (short) (((y & 0xF) << 8) | ((x & 0xF) << 4) | (z & 0xF)); + } + + private short encodeBlockPos(Position pos) { + return encodeBlockPos(pos.getX().intValue(), pos.getY().intValue(), pos.getZ().intValue()); + } + + private Map createLongObjectMap() { + if (fastUtilLongObjectHashMap != null) { + try { + return (Map) fastUtilLongObjectHashMap.newInstance(); + } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { + e.printStackTrace(); + } } + return new HashMap<>(); } }