mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-29 13:36:16 +01:00
Serverside block-connections!
This commit is contained in:
parent
73dccbaf24
commit
9a13eb36b3
@ -219,4 +219,19 @@ public class BukkitViaConfig extends Config implements ViaVersionConfig {
|
||||
public boolean isDisable1_13AutoComplete() {
|
||||
return getBoolean("disable-1_13-auto-complete", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServersideBlockConnections() {
|
||||
return getBoolean("serverside-blockconnections", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockConnectionMethod() {
|
||||
return getString("blockconnection-method", "world");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedueBlockStorageMemory() {
|
||||
return getBoolean("reduce-blockstorage-memory", false);
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,14 @@ import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.bukkit.listeners.UpdateListener;
|
||||
import us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8.*;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitBlockConnectionProvider;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitInventoryQuickMoveProvider;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitViaBulkChunkTranslator;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitViaMovementTransmitter;
|
||||
import us.myles.ViaVersion.bukkit.classgenerator.ClassGenerator;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers.InventoryQuickMoveProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.HandItemProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
@ -92,6 +94,9 @@ public class BukkitViaLoader implements ViaPlatformLoader {
|
||||
if (plugin.getConf().is1_12QuickMoveActionFix()) {
|
||||
Via.getManager().getProviders().use(InventoryQuickMoveProvider.class, new BukkitInventoryQuickMoveProvider());
|
||||
}
|
||||
if (Via.getConfig().getBlockConnectionMethod().equalsIgnoreCase("world")) {
|
||||
Via.getManager().getProviders().use(BlockConnectionProvider.class, new BukkitBlockConnectionProvider());
|
||||
}
|
||||
Via.getManager().getProviders().use(HandItemProvider.class, new HandItemProvider() {
|
||||
@Override
|
||||
public Item getHandItem(final UserConnection info) {
|
||||
|
@ -0,0 +1,41 @@
|
||||
package us.myles.ViaVersion.bukkit.providers;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitBlockConnectionProvider extends BlockConnectionProvider {
|
||||
private Chunk lastChunk;
|
||||
|
||||
@Override
|
||||
public int getWorldBlockData(UserConnection user, Position position) {
|
||||
UUID uuid = user.get(ProtocolInfo.class).getUuid();
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
World world = player.getWorld();
|
||||
int x = (int) (position.getX() >> 4);
|
||||
int z = (int) (position.getZ() >> 4);
|
||||
if (world.isChunkLoaded(x, z)) {
|
||||
Chunk c = getChunk(world, x, z);
|
||||
Block b = c.getBlock(position.getX().intValue(), position.getY().intValue(), position.getZ().intValue());
|
||||
return b.getTypeId() << 4 | b.getData();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Chunk getChunk(World world, int x, int z) {
|
||||
if (lastChunk != null && lastChunk.getX() == x && lastChunk.getZ() == z) {
|
||||
return lastChunk;
|
||||
}
|
||||
return lastChunk = world.getChunkAt(x, z);
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
public class BungeeViaConfig extends Config implements ViaVersionConfig {
|
||||
private static List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch", "quick-move-action-fix", "velocity-ping-interval", "velocity-ping-save", "velocity-servers");
|
||||
private static List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch", "quick-move-action-fix", "velocity-ping-interval", "velocity-ping-save", "velocity-servers", "blockconnection-method");
|
||||
|
||||
public BungeeViaConfig(File configFile) {
|
||||
super(new File(configFile, "config.yml"));
|
||||
@ -272,4 +272,19 @@ public class BungeeViaConfig extends Config implements ViaVersionConfig {
|
||||
public boolean isDisable1_13AutoComplete() {
|
||||
return getBoolean("disable-1_13-auto-complete", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServersideBlockConnections() {
|
||||
return getBoolean("serverside-blockconnections", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockConnectionMethod() {
|
||||
return "packet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedueBlockStorageMemory() {
|
||||
return getBoolean("reduce-blockstorage-memory", false);
|
||||
}
|
||||
}
|
||||
|
@ -266,4 +266,25 @@ public interface ViaVersionConfig {
|
||||
* @return True if enabled
|
||||
*/
|
||||
boolean isMinimizeCooldown();
|
||||
|
||||
/**
|
||||
* Enable the serverside blockconnections for 1.13+ clients
|
||||
*
|
||||
* @return True if enabled
|
||||
*/
|
||||
boolean isServersideBlockConnections();
|
||||
|
||||
/**
|
||||
* Get the type of block-connection provider which should be used
|
||||
*
|
||||
* @return String world for world-level or packet for packet-level
|
||||
*/
|
||||
String getBlockConnectionMethod();
|
||||
|
||||
/**
|
||||
* When activated, only the most important blocks are saved in the BlockStorage.
|
||||
*
|
||||
* @return True if enabled
|
||||
*/
|
||||
boolean isRedueBlockStorageMemory();
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
package us.myles.ViaVersion.api.minecraft;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BlockFace {
|
||||
NORTH(0, 0, -1, EnumAxis.Z), SOUTH(0, 0, 1, EnumAxis.Z), EAST(1, 0, 0, EnumAxis.X), WEST(-1, 0, 0, EnumAxis.X), TOP(0, 1, 0, EnumAxis.Y), BOTTOM(0, -1, 0, EnumAxis.Y);
|
||||
|
||||
private static Map<BlockFace, BlockFace> opposites = new HashMap<>();
|
||||
static {
|
||||
opposites.put(BlockFace.NORTH, BlockFace.SOUTH);
|
||||
opposites.put(BlockFace.SOUTH, BlockFace.NORTH);
|
||||
opposites.put(BlockFace.EAST, BlockFace.WEST);
|
||||
opposites.put(BlockFace.WEST, BlockFace.EAST);
|
||||
opposites.put(BlockFace.TOP, BlockFace.BOTTOM);
|
||||
opposites.put(BlockFace.BOTTOM, BlockFace.TOP);
|
||||
}
|
||||
|
||||
private int modX, modY, modZ;
|
||||
private EnumAxis axis;
|
||||
|
||||
public BlockFace opposite() {
|
||||
return opposites.get(this);
|
||||
}
|
||||
|
||||
public enum EnumAxis {
|
||||
X, Y, Z;
|
||||
}
|
||||
}
|
@ -13,4 +13,15 @@ public class Position {
|
||||
private Long x;
|
||||
private Long y;
|
||||
private Long z;
|
||||
|
||||
public Position getRelative(BlockFace face) {
|
||||
return new Position(this.x + face.getModX(), this.y + face.getModY(), this.z + face.getModZ());
|
||||
}
|
||||
|
||||
public Position shift(BlockFace face) {
|
||||
this.x += face.getModX();
|
||||
this.y += face.getModY();
|
||||
this.z += face.getModZ();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import us.myles.ViaVersion.api.remapper.ValueCreator;
|
||||
import us.myles.ViaVersion.api.remapper.ValueTransformer;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.ConnectionData;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.packets.EntityPackets;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.packets.InventoryPackets;
|
||||
@ -484,6 +485,10 @@ public class Protocol1_13To1_12_2 extends Protocol {
|
||||
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
|
||||
int dimensionId = wrapper.get(Type.INT, 0);
|
||||
clientWorld.setEnvironment(dimensionId);
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
ConnectionData.clearBlockStorage(wrapper.user());
|
||||
}
|
||||
}
|
||||
});
|
||||
handler(SEND_DECLARE_COMMANDS_AND_TAGS);
|
||||
|
@ -0,0 +1,60 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import lombok.Getter;
|
||||
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 abstract class AbstractFenceConnectionHandler extends ConnectionHandler {
|
||||
private final String blockConnections;
|
||||
@Getter
|
||||
private Set<Integer> blockStates = new HashSet<>();
|
||||
private Map<Byte, Integer> connectedBlockStates = new HashMap<>();
|
||||
|
||||
public AbstractFenceConnectionHandler(String blockConnections, String key){
|
||||
this.blockConnections = blockConnections;
|
||||
|
||||
for (Map.Entry<String, Integer> blockState : ConnectionData.keyToId.entrySet()) {
|
||||
if (key.equals(blockState.getKey().split("\\[")[0])) {
|
||||
blockStates.add(blockState.getValue());
|
||||
ConnectionData.connectionHandlerMap.put(blockState.getValue(), this);
|
||||
WrappedBlockData blockData = WrappedBlockData.fromString(blockState.getKey());
|
||||
connectedBlockStates.put(getStates(blockData), blockState.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected byte getStates(WrappedBlockData blockData) {
|
||||
byte states = 0;
|
||||
if (blockData.getValue("east").equals("true")) states |= 1;
|
||||
if (blockData.getValue("north").equals("true")) states |= 2;
|
||||
if (blockData.getValue("south").equals("true")) states |= 4;
|
||||
if (blockData.getValue("west").equals("true")) states |= 8;
|
||||
if (blockData.hasData("waterlogged") && blockData.getValue("waterlogged").equals("true")) states |= 16;
|
||||
return states;
|
||||
}
|
||||
|
||||
protected byte getStates(UserConnection user, Position position, int blockState) {
|
||||
byte states = 0;
|
||||
if (connects(BlockFace.EAST, getBlockData(user, position.getRelative(BlockFace.EAST)))) states |= 1;
|
||||
if (connects(BlockFace.NORTH, getBlockData(user, position.getRelative(BlockFace.NORTH)))) states |= 2;
|
||||
if (connects(BlockFace.SOUTH, getBlockData(user, position.getRelative(BlockFace.SOUTH)))) states |= 4;
|
||||
if (connects(BlockFace.WEST, getBlockData(user, position.getRelative(BlockFace.WEST)))) states |= 8;
|
||||
return states;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
final Integer newBlockState = connectedBlockStates.get(getStates(user, position, blockState));
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
}
|
||||
|
||||
protected boolean connects(BlockFace side, int blockState) {
|
||||
return blockStates.contains(blockState) || blockConnections != null && ConnectionData.blockConnectionData.containsKey(blockState) && ConnectionData.blockConnectionData.get(blockState).connectsTo(blockConnections, side.opposite());
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
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 AbstractStempConnectionHandler extends ConnectionHandler {
|
||||
private static final BlockFace[] BLOCK_FACES = {BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST};
|
||||
|
||||
private int baseStateId;
|
||||
private Set<Integer> blockId = new HashSet<>();
|
||||
|
||||
private Map<BlockFace, Integer> stemps = new HashMap<>();
|
||||
|
||||
public AbstractStempConnectionHandler(String baseStateId, String blockId, String toKey) {
|
||||
this.baseStateId = ConnectionData.getId(baseStateId);
|
||||
|
||||
for (Map.Entry<String, Integer> entry : ConnectionData.keyToId.entrySet()) {
|
||||
String key = entry.getKey().split("\\[")[0];
|
||||
if (entry.getValue() == this.baseStateId || blockId.equals(key)) {
|
||||
if (entry.getValue() != this.baseStateId) {
|
||||
this.blockId.add(entry.getValue());
|
||||
}
|
||||
ConnectionData.connectionHandlerMap.put(entry.getValue(), this);
|
||||
}
|
||||
if (key.equals(toKey)) {
|
||||
WrappedBlockData data = WrappedBlockData.fromString(entry.getKey());
|
||||
String facing = data.getValue("facing").toUpperCase();
|
||||
stemps.put(BlockFace.valueOf(facing), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
if (blockState != baseStateId) {
|
||||
return blockState;
|
||||
}
|
||||
for (BlockFace blockFace : BLOCK_FACES) {
|
||||
if (blockId.contains(getBlockData(user, position.getRelative(blockFace)))) {
|
||||
return stemps.get(blockFace);
|
||||
}
|
||||
}
|
||||
return baseStateId;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
public class BasicFenceConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
|
||||
static void init() {
|
||||
new BasicFenceConnectionHandler("fenceConnections", "minecraft:oak_fence");
|
||||
new BasicFenceConnectionHandler("fenceConnections", "minecraft:birch_fence");
|
||||
new BasicFenceConnectionHandler("fenceConnections", "minecraft:jungle_fence");
|
||||
new BasicFenceConnectionHandler("fenceConnections", "minecraft:dark_oak_fence");
|
||||
new BasicFenceConnectionHandler("fenceConnections", "minecraft:acacia_fence");
|
||||
new BasicFenceConnectionHandler("fenceConnections", "minecraft:spruce_fence");
|
||||
}
|
||||
|
||||
public BasicFenceConnectionHandler(String blockConnections, String key) {
|
||||
super(blockConnections, key);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import us.myles.ViaVersion.api.minecraft.BlockFace;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BlockData {
|
||||
private Map<String, Boolean[]> connectData = new HashMap<>();
|
||||
|
||||
public void put(String key, Boolean[] booleans){
|
||||
connectData.put(key, booleans);
|
||||
}
|
||||
|
||||
public boolean connectsTo(String blockConnection, BlockFace face){
|
||||
final Boolean[] booleans = connectData.get(blockConnection);
|
||||
return booleans != null && booleans[face.ordinal()];
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
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;
|
||||
|
||||
class ChestConnectionHandler extends ConnectionHandler {
|
||||
private static Map<Integer, BlockFace> chestFacings = new HashMap<>();
|
||||
private static Map<Byte, Integer> connectedStates = new HashMap<>();
|
||||
private static Set<Integer> trappedChests = new HashSet<>();
|
||||
|
||||
static void init() {
|
||||
ChestConnectionHandler connectionHandler = new ChestConnectionHandler();
|
||||
for (Map.Entry<String, Integer> blockState : ConnectionData.keyToId.entrySet()) {
|
||||
String key = blockState.getKey().split("\\[")[0];
|
||||
if (!key.equals("minecraft:chest") && !key.equals("minecraft:trapped_chest")) continue;
|
||||
WrappedBlockData blockData = WrappedBlockData.fromString(blockState.getKey());
|
||||
if (blockData.getValue("waterlogged").equals("true")) continue;
|
||||
chestFacings.put(blockState.getValue(), BlockFace.valueOf(blockData.getValue("facing").toUpperCase()));
|
||||
if (key.equalsIgnoreCase("minecraft:trapped_chest")) trappedChests.add(blockState.getValue());
|
||||
connectedStates.put(getStates(blockData), blockState.getValue());
|
||||
ConnectionData.connectionHandlerMap.put(blockState.getValue(), connectionHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private static Byte getStates(WrappedBlockData blockData) {
|
||||
byte states = 0;
|
||||
String type = blockData.getValue("type");
|
||||
if (type.equals("left")) states |= 1;
|
||||
if (type.equals("right")) states |= 2;
|
||||
states |= (BlockFace.valueOf(blockData.getValue("facing").toUpperCase()).ordinal() << 2);
|
||||
if (blockData.getMinecraftKey().equals("minecraft:trapped_chest")) states |= 16;
|
||||
return states;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
BlockFace facing = chestFacings.get(blockState);
|
||||
byte states = 0;
|
||||
states |= (facing.ordinal() << 2);
|
||||
boolean trapped = trappedChests.contains(blockState);
|
||||
if (trapped) states |= 16;
|
||||
int relative;
|
||||
if (chestFacings.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.NORTH))) && trapped == trappedChests.contains(relative)) {
|
||||
states |= facing == BlockFace.WEST ? 1 : 2;
|
||||
} else if (chestFacings.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.SOUTH))) && trapped == trappedChests.contains(relative)) {
|
||||
states |= facing == BlockFace.EAST ? 1 : 2;
|
||||
} else if (chestFacings.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.WEST))) && trapped == trappedChests.contains(relative)) {
|
||||
states |= facing == BlockFace.NORTH ? 2 : 1;
|
||||
} else if (chestFacings.containsKey(relative = getBlockData(user, position.getRelative(BlockFace.EAST))) && trapped == trappedChests.contains(relative)) {
|
||||
states |= facing == BlockFace.SOUTH ? 2 : 1;
|
||||
}
|
||||
Integer newBlockState = connectedStates.get(states);
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.BlockFace;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ChorusPlantConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
private int endstone;
|
||||
|
||||
static void init() {
|
||||
new ChorusPlantConnectionHandler("minecraft:chorus_plant");
|
||||
}
|
||||
|
||||
public ChorusPlantConnectionHandler(String key) {
|
||||
super(null, key);
|
||||
endstone = ConnectionData.getId("minecraft:end_stone");
|
||||
for (Map.Entry<String, Integer> entry : ConnectionData.keyToId.entrySet()) {
|
||||
if (entry.getKey().split("\\[")[0].equals("minecraft:chorus_flower")) {
|
||||
getBlockStates().add(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getStates(WrappedBlockData blockData) {
|
||||
byte states = super.getStates(blockData);
|
||||
if (blockData.getValue("up").equals("true")) states |= 16;
|
||||
if (blockData.getValue("down").equals("true")) states |= 32;
|
||||
return states;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getStates(UserConnection user, Position position, int blockState) {
|
||||
byte states = super.getStates(user, position, blockState);
|
||||
if (connects(BlockFace.TOP, getBlockData(user, position.getRelative(BlockFace.TOP)))) states |= 16;
|
||||
if (connects(BlockFace.BOTTOM, getBlockData(user, position.getRelative(BlockFace.BOTTOM)))) states |= 32;
|
||||
return states;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean connects(BlockFace side, int blockState) {
|
||||
return getBlockStates().contains(blockState) || (side == BlockFace.BOTTOM && blockState == endstone);
|
||||
}
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.BlockFace;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.PacketBlockConnectionProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class ConnectionData {
|
||||
static Map<Integer, String> idToKey = new HashMap<>();
|
||||
static Map<String, Integer> keyToId = new HashMap<>();
|
||||
static Map<Integer, ConnectionHandler> connectionHandlerMap = new HashMap<>();
|
||||
static Map<Integer, BlockData> blockConnectionData = new HashMap<>();
|
||||
static Set<Integer> occludingStates = new HashSet<>();
|
||||
|
||||
public static void update(UserConnection user, Position position) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
if (Math.abs(x) + Math.abs(y) + Math.abs(z) != 1) continue;
|
||||
Position pos = new Position(position.getX() + x, position.getY() + y, position.getZ() + z);
|
||||
int blockState = Via.getManager().getProviders().get(BlockConnectionProvider.class).getBlockdata(user, pos);
|
||||
if (!connects(blockState)) continue;
|
||||
int newBlockState = connect(user, pos, blockState);
|
||||
if (newBlockState == blockState) continue;
|
||||
|
||||
PacketWrapper blockUpdatePacket = new PacketWrapper(0x0B, null, user);
|
||||
blockUpdatePacket.write(Type.POSITION, pos);
|
||||
blockUpdatePacket.write(Type.VAR_INT, newBlockState);
|
||||
try {
|
||||
blockUpdatePacket.send(Protocol1_13To1_12_2.class, true, false);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockConnectionProvider getProvider() {
|
||||
return Via.getManager().getProviders().get(BlockConnectionProvider.class);
|
||||
}
|
||||
|
||||
public static void updateBlockStorage(UserConnection userConnection, Position position, int blockState) {
|
||||
if (!needStoreBlocks()) return;
|
||||
if (ConnectionData.isWelcome(blockState)) {
|
||||
ConnectionData.getProvider().storeBlock(userConnection, position, blockState);
|
||||
} else {
|
||||
ConnectionData.getProvider().removeBlock(userConnection, position);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearBlockStorage(UserConnection connection) {
|
||||
if (!needStoreBlocks()) return;
|
||||
getProvider().clearStorage(connection);
|
||||
}
|
||||
|
||||
public static boolean needStoreBlocks() {
|
||||
return getProvider().storesBlocks();
|
||||
}
|
||||
|
||||
public static void connectBlocks(UserConnection user, Chunk chunk) {
|
||||
long xOff = chunk.getX() << 4;
|
||||
long zOff = chunk.getZ() << 4;
|
||||
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
if (section == null) continue;
|
||||
|
||||
boolean willConnect = false;
|
||||
|
||||
for (int p = 0; p < section.getPaletteSize(); p++) {
|
||||
int id = section.getPaletteEntry(p);
|
||||
if (ConnectionData.connects(id)) {
|
||||
willConnect = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!willConnect) continue;
|
||||
|
||||
long yOff = i << 4;
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int block = section.getFlatBlock(x, y, z);
|
||||
|
||||
if (ConnectionData.connects(block)) {
|
||||
block = ConnectionData.connect(user, new Position(xOff + x, yOff + y, zOff + z), block);
|
||||
section.setFlatBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
if (x == 0) {
|
||||
update(user, new Position(xOff - 1, yOff + y, zOff + z));
|
||||
} else if (x == 15) {
|
||||
update(user, new Position(xOff + 16, yOff + y, zOff + z));
|
||||
}
|
||||
if (z == 0) {
|
||||
update(user, new Position(xOff + x, yOff + y, zOff - 1));
|
||||
} else if (z == 15) {
|
||||
update(user, new Position(xOff + x, yOff + y, zOff + 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
if (!Via.getConfig().isServersideBlockConnections()) return;
|
||||
Via.getPlatform().getLogger().info("Loading block connection mappings ...");
|
||||
JsonObject mapping1_13 = MappingData.loadData("mapping-1.13.json");
|
||||
JsonObject blocks1_13 = mapping1_13.getAsJsonObject("blocks");
|
||||
for (Entry<String, JsonElement> blockState : blocks1_13.entrySet()) {
|
||||
Integer id = Integer.parseInt(blockState.getKey());
|
||||
String key = blockState.getValue().getAsString();
|
||||
idToKey.put(id, key);
|
||||
keyToId.put(key, id);
|
||||
}
|
||||
|
||||
if (!Via.getConfig().isRedueBlockStorageMemory()) {
|
||||
JsonObject mappingBlockConnections = MappingData.loadData("blockConnections.json");
|
||||
for (Entry<String, JsonElement> entry : mappingBlockConnections.entrySet()) {
|
||||
int id = keyToId.get(entry.getKey());
|
||||
BlockData blockData = new BlockData();
|
||||
for (Entry<String, JsonElement> type : entry.getValue().getAsJsonObject().entrySet()) {
|
||||
String name = type.getKey();
|
||||
JsonObject object = type.getValue().getAsJsonObject();
|
||||
Boolean[] data = new Boolean[6];
|
||||
for (BlockFace value : BlockFace.values()) {
|
||||
String face = value.toString().toLowerCase();
|
||||
if (object.has(face)) {
|
||||
data[value.ordinal()] = object.getAsJsonPrimitive(face).getAsBoolean();
|
||||
} else {
|
||||
data[value.ordinal()] = false;
|
||||
}
|
||||
}
|
||||
blockData.put(name, data);
|
||||
}
|
||||
blockConnectionData.put(id, blockData);
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject blockData = MappingData.loadData("blockData.json");
|
||||
JsonArray occluding = blockData.getAsJsonArray("occluding");
|
||||
for (JsonElement jsonElement : occluding) {
|
||||
occludingStates.add(keyToId.get(jsonElement.getAsString()));
|
||||
}
|
||||
|
||||
PumpkinConnectionHandler.init();
|
||||
MelonConnectionHandler.init();
|
||||
BasicFenceConnectionHandler.init();
|
||||
NetherFenceConnectionHandler.init();
|
||||
WallConnectionHandler.init();
|
||||
MelonConnectionHandler.init();
|
||||
GlassConnectionHandler.init();
|
||||
ChestConnectionHandler.init();
|
||||
DoorConnectionHandler.init();
|
||||
RedstoneConnectionHandler.init();
|
||||
StairConnectionHandler.init();
|
||||
FlowerConnectionHandler.init();
|
||||
ChorusPlantConnectionHandler.init();
|
||||
|
||||
if (Via.getConfig().getBlockConnectionMethod().equalsIgnoreCase("packet")) {
|
||||
Via.getManager().getProviders().register(BlockConnectionProvider.class, new PacketBlockConnectionProvider());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWelcome(int blockState) {
|
||||
return blockConnectionData.containsKey(blockState) || connectionHandlerMap.containsKey(blockState);
|
||||
}
|
||||
|
||||
public static boolean connects(int blockState) {
|
||||
return connectionHandlerMap.containsKey(blockState);
|
||||
}
|
||||
|
||||
public static int connect(UserConnection user, Position position, int blockState) {
|
||||
if (connectionHandlerMap.containsKey(blockState)) {
|
||||
ConnectionHandler handler = connectionHandlerMap.get(blockState);
|
||||
return handler.connect(user, position, blockState);
|
||||
} else {
|
||||
return blockState;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getId(String key) {
|
||||
return keyToId.containsKey(key) ? keyToId.get(key) : -1;
|
||||
}
|
||||
|
||||
public static String getKey(int id) {
|
||||
return idToKey.get(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
|
||||
public abstract class ConnectionHandler {
|
||||
public abstract int connect(UserConnection connection, Position position, int blockState);
|
||||
|
||||
public int getBlockData(UserConnection connection, Position position) {
|
||||
return Via.getManager().getProviders().get(BlockConnectionProvider.class).getBlockdata(connection, position);
|
||||
}
|
||||
|
||||
public boolean canConnect(int id) {
|
||||
ConnectionHandler handler = ConnectionData.connectionHandlerMap.get(id);
|
||||
return handler != null && handler == this;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
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.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DoorConnectionHandler extends ConnectionHandler {
|
||||
private static Map<Integer, DoorData> doorDataMap = new HashMap<>();
|
||||
private static Map<Short, Integer> connectedStates = new HashMap<>();
|
||||
|
||||
static void init() {
|
||||
List<String> baseDoors = new LinkedList<>();
|
||||
baseDoors.add("minecraft:oak_door");
|
||||
baseDoors.add("minecraft:birch_door");
|
||||
baseDoors.add("minecraft:jungle_door");
|
||||
baseDoors.add("minecraft:dark_oak_door");
|
||||
baseDoors.add("minecraft:acacia_door");
|
||||
baseDoors.add("minecraft:spruce_door");
|
||||
baseDoors.add("minecraft:iron_door");
|
||||
|
||||
DoorConnectionHandler connectionHandler = new DoorConnectionHandler();
|
||||
for (Map.Entry<String, Integer> blockState : ConnectionData.keyToId.entrySet()) {
|
||||
String key = blockState.getKey().split("\\[")[0];
|
||||
int type = baseDoors.indexOf(key);
|
||||
if (type == -1) continue;
|
||||
|
||||
WrappedBlockData blockData = WrappedBlockData.fromString(blockState.getKey());
|
||||
int id = blockState.getValue();
|
||||
|
||||
DoorData doorData = new DoorData(
|
||||
blockData.getValue("half").equals("lower"),
|
||||
blockData.getValue("hinge").equals("right"),
|
||||
blockData.getValue("powered").equals("true"),
|
||||
blockData.getValue("open").equals("true"),
|
||||
BlockFace.valueOf(blockData.getValue("facing").toUpperCase()),
|
||||
type
|
||||
);
|
||||
|
||||
doorDataMap.put(id, doorData);
|
||||
|
||||
connectedStates.put(getStates(doorData), id);
|
||||
|
||||
ConnectionData.connectionHandlerMap.put(id, connectionHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private static short getStates(DoorData doorData) {
|
||||
short s = 0;
|
||||
if (doorData.isLower()) s |= 1;
|
||||
if (doorData.isOpen()) s |= 2;
|
||||
if (doorData.isPowered()) s |= 4;
|
||||
if (doorData.isRightHinge()) s |= 8;
|
||||
s |= doorData.getFacing().ordinal() << 4;
|
||||
s |= (doorData.getType() & 0x7) << 6;
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
DoorData doorData = doorDataMap.get(blockState);
|
||||
if (doorData == null) return blockState;
|
||||
short s = 0;
|
||||
s |= (doorData.getType() & 0x7) << 6;
|
||||
if (doorData.isLower()) {
|
||||
DoorData upperHalf = doorDataMap.get(getBlockData(user, position.getRelative(BlockFace.TOP)));
|
||||
if (upperHalf == null) return blockState;
|
||||
s |= 1;
|
||||
if (doorData.isOpen()) s |= 2;
|
||||
if (upperHalf.isPowered()) s |= 4;
|
||||
if (upperHalf.isRightHinge()) s |= 8;
|
||||
s |= doorData.getFacing().ordinal() << 4;
|
||||
} else {
|
||||
DoorData lowerHalf = doorDataMap.get(getBlockData(user, position.getRelative(BlockFace.BOTTOM)));
|
||||
if (lowerHalf == null) return blockState;
|
||||
if (lowerHalf.isOpen()) s |= 2;
|
||||
if (doorData.isPowered()) s |= 4;
|
||||
if (doorData.isRightHinge()) s |= 8;
|
||||
s |= lowerHalf.getFacing().ordinal() << 4;
|
||||
}
|
||||
Integer newBlockState = connectedStates.get(s);
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
private static class DoorData {
|
||||
private final boolean lower, rightHinge, powered, open;
|
||||
private final BlockFace facing;
|
||||
private int type;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
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 FlowerConnectionHandler extends ConnectionHandler {
|
||||
private static Set<String> baseFlower = new HashSet<>();
|
||||
private static Map<Integer, Integer> flowers = new HashMap<>();
|
||||
|
||||
static void init() {
|
||||
baseFlower.add("minecraft:rose_bush");
|
||||
baseFlower.add("minecraft:sunflower");
|
||||
baseFlower.add("minecraft:peony");
|
||||
baseFlower.add("minecraft:tall_grass");
|
||||
baseFlower.add("minecraft:large_fern");
|
||||
baseFlower.add("minecraft:lilac");
|
||||
|
||||
|
||||
FlowerConnectionHandler handler = new FlowerConnectionHandler();
|
||||
|
||||
for (Map.Entry<String, Integer> blockState : ConnectionData.keyToId.entrySet()) {
|
||||
WrappedBlockData data = WrappedBlockData.fromString(blockState.getKey());
|
||||
if (baseFlower.contains(data.getMinecraftKey())) {
|
||||
ConnectionData.connectionHandlerMap.put(blockState.getValue(), handler);
|
||||
if (data.getValue("half").equals("lower")) {
|
||||
data.set("half", "upper");
|
||||
flowers.put(blockState.getValue(), data.getBlockStateId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
int blockBelowId = getBlockData(user, position.getRelative(BlockFace.BOTTOM));
|
||||
if (flowers.containsKey(blockBelowId) && !flowers.containsKey(getBlockData(user, position.getRelative(BlockFace.TOP)))) {
|
||||
return flowers.get(blockBelowId);
|
||||
}
|
||||
return blockState;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
|
||||
public class GlassConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
|
||||
static void init() {
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:white_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:orange_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:magenta_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:light_blue_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:yellow_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:lime_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:pink_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:gray_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:light_gray_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:cyan_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:purple_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:blue_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:brown_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:green_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:red_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:black_stained_glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:glass_pane");
|
||||
new GlassConnectionHandler("paneConnections", "minecraft:iron_bars");
|
||||
}
|
||||
|
||||
public GlassConnectionHandler(String blockConnections, String key) {
|
||||
super(blockConnections, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getStates(UserConnection user, Position position, int blockState) {
|
||||
byte states = super.getStates(user, position, blockState);
|
||||
return states == 0 && (ProtocolRegistry.SERVER_PROTOCOL <= 47 && ProtocolRegistry.SERVER_PROTOCOL != -1) ? 0xF : states;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
public class MelonConnectionHandler extends AbstractStempConnectionHandler {
|
||||
|
||||
public MelonConnectionHandler(String baseStateId, String blockId, String toKey) {
|
||||
super(baseStateId, blockId, toKey);
|
||||
}
|
||||
|
||||
static void init() {
|
||||
new MelonConnectionHandler("minecraft:melon_stem[age=7]", "minecraft:melon", "minecraft:attached_melon_stem");
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
public class NetherFenceConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
|
||||
static void init() {
|
||||
new NetherFenceConnectionHandler("netherFenceConnections", "minecraft:nether_brick_fence");
|
||||
}
|
||||
|
||||
public NetherFenceConnectionHandler(String blockConnections, String key) {
|
||||
super(blockConnections, key);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
public class PumpkinConnectionHandler extends AbstractStempConnectionHandler {
|
||||
|
||||
static void init() {
|
||||
new PumpkinConnectionHandler("minecraft:pumpkin_stem[age=7]", "minecraft:carved_pumpkin", "minecraft:attached_pumpkin_stem");
|
||||
}
|
||||
|
||||
public PumpkinConnectionHandler(String baseStateId, String blockId, String toKey) {
|
||||
super(baseStateId, blockId, toKey);
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
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 RedstoneConnectionHandler extends ConnectionHandler {
|
||||
private static Set<Integer> redstone = new HashSet<>();
|
||||
private static Map<Short, Integer> connectedBlockStates = new HashMap<>();
|
||||
private static Map<Integer, Integer> powerMappings = new HashMap<>();
|
||||
|
||||
static void init() {
|
||||
RedstoneConnectionHandler connectionHandler = new RedstoneConnectionHandler();
|
||||
String redstoneKey = "minecraft:redstone_wire";
|
||||
for (Map.Entry<String, Integer> blockState : ConnectionData.keyToId.entrySet()) {
|
||||
String key = blockState.getKey().split("\\[")[0];
|
||||
if (!redstoneKey.equals(key)) continue;
|
||||
redstone.add(blockState.getValue());
|
||||
ConnectionData.connectionHandlerMap.put(blockState.getValue(), connectionHandler);
|
||||
WrappedBlockData blockData = WrappedBlockData.fromStateId(blockState.getValue());
|
||||
connectedBlockStates.put(getStates(blockData), blockData.getBlockStateId());
|
||||
powerMappings.put(blockData.getBlockStateId(), Integer.valueOf(blockData.getValue("power")));
|
||||
}
|
||||
}
|
||||
|
||||
private static short getStates(WrappedBlockData data) {
|
||||
short b = 0;
|
||||
b |= getState(data.getValue("east"));
|
||||
b |= getState(data.getValue("north")) << 2;
|
||||
b |= getState(data.getValue("south")) << 4;
|
||||
b |= getState(data.getValue("west")) << 6;
|
||||
b |= Integer.valueOf(data.getValue("power")) << 8;
|
||||
return b;
|
||||
}
|
||||
|
||||
private static int getState(String value) {
|
||||
switch (value){
|
||||
case "none": return 0;
|
||||
case "side" : return 1;
|
||||
case "up" : return 2;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
short b = 0;
|
||||
b |= connects(user, position, BlockFace.EAST);
|
||||
b |= connects(user, position, BlockFace.NORTH) << 2;
|
||||
b |= connects(user, position, BlockFace.SOUTH) << 4;
|
||||
b |= connects(user, position, BlockFace.WEST) << 6;
|
||||
b |= powerMappings.get(blockState) << 8;
|
||||
final Integer newBlockState = connectedBlockStates.get(b);
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
}
|
||||
|
||||
private int connects(UserConnection user, Position position, BlockFace side) {
|
||||
final Position relative = position.getRelative(side);
|
||||
int blockState = getBlockData(user, relative);
|
||||
if (connects(side, blockState)) {
|
||||
return 1; //side
|
||||
}
|
||||
int up = getBlockData(user, relative.getRelative(BlockFace.TOP));
|
||||
if (redstone.contains(up) && !ConnectionData.occludingStates.contains(getBlockData(user, position.getRelative(BlockFace.TOP)))) {
|
||||
return 2; //"up"
|
||||
}
|
||||
int down = getBlockData(user, relative.getRelative(BlockFace.BOTTOM));
|
||||
if (redstone.contains(down) && !ConnectionData.occludingStates.contains(getBlockData(user, relative))) {
|
||||
return 1; //side
|
||||
}
|
||||
return 0; //none
|
||||
}
|
||||
|
||||
private boolean connects(BlockFace side, int blockState) {
|
||||
final BlockData blockData = ConnectionData.blockConnectionData.get(blockState);
|
||||
return blockData != null && blockData.connectsTo("redstoneConnections", side.opposite());
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
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.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StairConnectionHandler extends ConnectionHandler {
|
||||
private static Map<Integer, StairData> stairDataMap = new HashMap<>();
|
||||
private static Map<Short, Integer> connectedBlocks = new HashMap<>();
|
||||
|
||||
static void init() {
|
||||
List<String> baseStairs = new LinkedList<>();
|
||||
baseStairs.add("minecraft:oak_stairs");
|
||||
baseStairs.add("minecraft:cobblestone_stairs");
|
||||
baseStairs.add("minecraft:brick_stairs");
|
||||
baseStairs.add("minecraft:stone_brick_stairs");
|
||||
baseStairs.add("minecraft:nether_brick_stairs");
|
||||
baseStairs.add("minecraft:sandstone_stairs");
|
||||
baseStairs.add("minecraft:spruce_stairs");
|
||||
baseStairs.add("minecraft:birch_stairs");
|
||||
baseStairs.add("minecraft:jungle_stairs");
|
||||
baseStairs.add("minecraft:quartz_stairs");
|
||||
baseStairs.add("minecraft:acacia_stairs");
|
||||
baseStairs.add("minecraft:dark_oak_stairs");
|
||||
baseStairs.add("minecraft:red_sandstone_stairs");
|
||||
baseStairs.add("minecraft:purpur_stairs");
|
||||
baseStairs.add("minecraft:prismarine_stairs");
|
||||
baseStairs.add("minecraft:prismarine_brick_stairs");
|
||||
baseStairs.add("minecraft:dark_prismarine_stairs");
|
||||
|
||||
StairConnectionHandler connectionHandler = new StairConnectionHandler();
|
||||
for (Map.Entry<String, Integer> blockState : ConnectionData.keyToId.entrySet()) {
|
||||
String key = blockState.getKey().split("\\[")[0];
|
||||
int type = baseStairs.indexOf(key);
|
||||
if (type == -1) continue;
|
||||
|
||||
WrappedBlockData blockData = WrappedBlockData.fromString(blockState.getKey());
|
||||
if (blockData.getValue("waterlogged").equals("true")) continue;
|
||||
|
||||
byte shape;
|
||||
switch (blockData.getValue("shape")) {
|
||||
case "straight": shape = 0; break;
|
||||
case "inner_left": shape = 1; break;
|
||||
case "inner_right": shape = 2; break;
|
||||
case "outer_left": shape = 3; break;
|
||||
case "outer_right": shape = 4; break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
StairData stairData = new StairData(
|
||||
blockData.getValue("half").equals("bottom"),
|
||||
shape, (byte) type,
|
||||
BlockFace.valueOf(blockData.getValue("facing").toUpperCase())
|
||||
);
|
||||
|
||||
stairDataMap.put(blockState.getValue(), stairData);
|
||||
connectedBlocks.put(getStates(stairData), blockState.getValue());
|
||||
|
||||
ConnectionData.connectionHandlerMap.put(blockState.getValue(), connectionHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private static short getStates(StairData stairData) {
|
||||
short s = 0;
|
||||
if (stairData.isBottom()) s |= 1;
|
||||
s |= stairData.getShape() << 1;
|
||||
s |= stairData.getType() << 4;
|
||||
s |= stairData.getFacing().ordinal() << 9;
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int connect(UserConnection user, Position position, int blockState) {
|
||||
StairData stairData = stairDataMap.get(blockState);
|
||||
if (stairData == null) return blockState;
|
||||
|
||||
short s = 0;
|
||||
if (stairData.isBottom()) s |= 1;
|
||||
s |= getShape(user, position, stairData) << 1;
|
||||
s |= stairData.getType() << 4;
|
||||
s |= stairData.getFacing().ordinal() << 9;
|
||||
|
||||
Integer newBlockState = connectedBlocks.get(s);
|
||||
return newBlockState == null ? blockState : newBlockState;
|
||||
}
|
||||
|
||||
private int getShape(UserConnection user, Position position, StairData stair) {
|
||||
BlockFace facing = stair.getFacing();
|
||||
|
||||
StairData relativeStair = stairDataMap.get(getBlockData(user, position.getRelative(facing)));
|
||||
if (relativeStair != null && relativeStair.isBottom() == stair.isBottom()) {
|
||||
BlockFace facing2 = relativeStair.getFacing();
|
||||
if (facing.getAxis() != facing2.getAxis() && checkOpposite(user, stair, position, facing2.opposite())){
|
||||
return facing2 == rotateAntiClockwise(facing) ? 3 : 4; // outer_left : outer_right
|
||||
}
|
||||
}
|
||||
|
||||
relativeStair = stairDataMap.get(getBlockData(user, position.getRelative(facing.opposite())));
|
||||
if(relativeStair != null && relativeStair.isBottom() == stair.isBottom()) {
|
||||
BlockFace facing2 = relativeStair.getFacing();
|
||||
if (facing.getAxis() != facing2.getAxis() && checkOpposite(user, stair, position, facing2)){
|
||||
return facing2 == rotateAntiClockwise(facing) ? 1 : 2; // inner_left : inner_right
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // straight
|
||||
}
|
||||
|
||||
private boolean checkOpposite(UserConnection user, StairData stair, Position position, BlockFace face) {
|
||||
StairData relativeStair = stairDataMap.get(getBlockData(user, position.getRelative(face)));
|
||||
return relativeStair == null || relativeStair.getFacing() != stair.getFacing() || relativeStair.isBottom() != stair.isBottom();
|
||||
}
|
||||
|
||||
private BlockFace rotateAntiClockwise(BlockFace face) {
|
||||
switch (face) {
|
||||
case NORTH:
|
||||
return BlockFace.WEST;
|
||||
case SOUTH:
|
||||
return BlockFace.EAST;
|
||||
case EAST:
|
||||
return BlockFace.NORTH;
|
||||
case WEST:
|
||||
return BlockFace.SOUTH;
|
||||
default:
|
||||
return face;
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
private static class StairData {
|
||||
private final boolean bottom;
|
||||
private final byte shape, type;
|
||||
private final BlockFace facing;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.BlockFace;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
|
||||
public class WallConnectionHandler extends AbstractFenceConnectionHandler {
|
||||
private static final BlockFace[] BLOCK_FACES = { BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST };
|
||||
private static final int[] OPPOSITES = { 3, 2, 1, 0 };
|
||||
|
||||
static void init() {
|
||||
new WallConnectionHandler("cobbleWallConnections", "minecraft:cobblestone_wall");
|
||||
new WallConnectionHandler("cobbleWallConnections", "minecraft:mossy_cobblestone_wall");
|
||||
}
|
||||
|
||||
|
||||
public WallConnectionHandler(String blockConnections, String key) {
|
||||
super(blockConnections, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getStates(WrappedBlockData blockData) {
|
||||
byte states = super.getStates(blockData);
|
||||
if (blockData.getValue("up").equals("true")) states |= 32;
|
||||
return states;
|
||||
}
|
||||
|
||||
protected byte getStates(UserConnection user, Position position, int blockState) {
|
||||
byte states = super.getStates(user, position, blockState);
|
||||
if (up(user, position)) states |= 32;
|
||||
return states;
|
||||
}
|
||||
|
||||
public boolean up(UserConnection user, Position position) {
|
||||
if(isWall(getBlockData(user, position.getRelative(BlockFace.BOTTOM))) || isWall(getBlockData(user, position.getRelative(BlockFace.TOP))))return true;
|
||||
int blockFaces = getBlockFaces(user, position);
|
||||
if (blockFaces == 0 || blockFaces == 0xF) return true;
|
||||
for (int i = 0; i < BLOCK_FACES.length; i++) {
|
||||
if ((blockFaces & (1 << i)) != 0 && (blockFaces & (1 << OPPOSITES[i])) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int getBlockFaces(UserConnection user, Position position) {
|
||||
int blockFaces = 0;
|
||||
for (int i = 0; i < BLOCK_FACES.length; i++) {
|
||||
if (isWall(getBlockData(user, position.getRelative(BLOCK_FACES[i])))) {
|
||||
blockFaces |= 1 << i;
|
||||
}
|
||||
}
|
||||
return blockFaces;
|
||||
}
|
||||
|
||||
private boolean isWall(int id){
|
||||
return getBlockStates().contains(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections;
|
||||
|
||||
import lombok.Getter;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class WrappedBlockData {
|
||||
@Getter
|
||||
private String minecraftKey;
|
||||
private LinkedHashMap<String, String> blockData = new LinkedHashMap<>();
|
||||
|
||||
public static WrappedBlockData fromString(String s) {
|
||||
String[] array = s.split("\\[");
|
||||
String key = array[0];
|
||||
WrappedBlockData wrappedBlockdata = new WrappedBlockData(key);
|
||||
if (array.length > 1) {
|
||||
String blockData = array[1];
|
||||
blockData = blockData.replace("]", "");
|
||||
String[] data = blockData.split(",");
|
||||
for (String d : data) {
|
||||
String[] a = d.split("=");
|
||||
wrappedBlockdata.blockData.put(a[0], a[1]);
|
||||
}
|
||||
}
|
||||
return wrappedBlockdata;
|
||||
}
|
||||
|
||||
public static WrappedBlockData fromStateId(int id) {
|
||||
String blockData = ConnectionData.getKey(id);
|
||||
if (blockData != null) {
|
||||
return fromString(blockData);
|
||||
}
|
||||
Via.getPlatform().getLogger().info("Unable to get blockdata from " + id);
|
||||
return fromString("minecraft:air");
|
||||
}
|
||||
|
||||
private WrappedBlockData(String key) {
|
||||
minecraftKey = key;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(minecraftKey + "[");
|
||||
for (Entry<String, String> entry : blockData.entrySet()) {
|
||||
sb.append(entry.getKey()).append('=').append(entry.getValue()).append(',');
|
||||
}
|
||||
return sb.substring(0, sb.length()-1) + "]";
|
||||
}
|
||||
|
||||
public int getBlockStateId() {
|
||||
return ConnectionData.getId(toString());
|
||||
}
|
||||
|
||||
public WrappedBlockData set(String data, Object value) {
|
||||
if (!hasData(data)) throw new UnsupportedOperationException("No blockdata found for " + data + " at " + minecraftKey);
|
||||
blockData.put(data, value.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getValue(String data) {
|
||||
return blockData.get(data);
|
||||
}
|
||||
|
||||
public boolean hasData(String key) {
|
||||
return blockData.containsKey(key);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers;
|
||||
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.api.platform.providers.Provider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData;
|
||||
|
||||
public class BlockConnectionProvider implements Provider {
|
||||
|
||||
public int getBlockdata(UserConnection connection, Position position) {
|
||||
int oldId = getWorldBlockData(connection, position);
|
||||
return MappingData.blockMappings.getNewBlock(oldId);
|
||||
}
|
||||
|
||||
public int getWorldBlockData(UserConnection connection, Position position) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void storeBlock(UserConnection connection, Position position, int blockState) {};
|
||||
|
||||
public void removeBlock(UserConnection connection, Position position) {};
|
||||
|
||||
public void storeBlock(UserConnection connection, long x, long y, long z, int blockState) {
|
||||
storeBlock(connection, new Position(x, y, z), blockState);
|
||||
}
|
||||
|
||||
public void clearStorage(UserConnection connection) {};
|
||||
|
||||
public void unloadChunk(UserConnection connection, int x, int z) {};
|
||||
|
||||
public boolean storesBlocks(){
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers;
|
||||
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockConnectionStorage;
|
||||
|
||||
public class PacketBlockConnectionProvider extends BlockConnectionProvider {
|
||||
|
||||
@Override
|
||||
public void storeBlock(UserConnection connection, Position position, int blockState) {
|
||||
connection.get(BlockConnectionStorage.class).store(position, blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBlock(UserConnection connection, Position position) {
|
||||
connection.get(BlockConnectionStorage.class).remove(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockdata(UserConnection connection, Position position) {
|
||||
return connection.get(BlockConnectionStorage.class).get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearStorage(UserConnection connection) {
|
||||
connection.get(BlockConnectionStorage.class).clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(UserConnection connection, int x, int z) {
|
||||
connection.get(BlockConnectionStorage.class).unloadChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storesBlocks() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ 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_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.ConnectionData;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.NamedSoundRewriter;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.Particle;
|
||||
@ -173,6 +174,17 @@ public class WorldPackets {
|
||||
Position position = wrapper.get(Type.POSITION, 0);
|
||||
int newId = toNewId(wrapper.get(Type.VAR_INT, 0));
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
UserConnection userConnection = wrapper.user();
|
||||
if (ConnectionData.connects(newId)) {
|
||||
newId = ConnectionData.connect(userConnection, position, newId);
|
||||
}
|
||||
|
||||
ConnectionData.updateBlockStorage(userConnection, position, newId);
|
||||
|
||||
ConnectionData.update(userConnection, position);
|
||||
}
|
||||
|
||||
wrapper.set(Type.VAR_INT, 0, checkStorage(wrapper.user(), position, newId));
|
||||
}
|
||||
});
|
||||
@ -191,6 +203,7 @@ public class WorldPackets {
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
int chunkX = wrapper.get(Type.INT, 0);
|
||||
int chunkZ = wrapper.get(Type.INT, 1);
|
||||
UserConnection userConnection = wrapper.user();
|
||||
// Convert ids
|
||||
for (BlockChangeRecord record : wrapper.get(Type.BLOCK_CHANGE_RECORD_ARRAY, 0)) {
|
||||
int newBlock = toNewId(record.getBlockId());
|
||||
@ -198,13 +211,52 @@ public class WorldPackets {
|
||||
(long) (record.getHorizontal() >> 4 & 15) + (chunkX * 16),
|
||||
(long) record.getY(),
|
||||
(long) (record.getHorizontal() & 15) + (chunkZ * 16));
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
ConnectionData.updateBlockStorage(userConnection, position, newBlock);
|
||||
}
|
||||
record.setBlockId(checkStorage(wrapper.user(), position, newBlock));
|
||||
}
|
||||
|
||||
for (BlockChangeRecord record : wrapper.get(Type.BLOCK_CHANGE_RECORD_ARRAY, 0)) {
|
||||
int blockState = record.getBlockId();
|
||||
|
||||
Position position = new Position(
|
||||
(long) (record.getHorizontal() >> 4 & 15) + (chunkX * 16),
|
||||
(long) record.getY(),
|
||||
(long) (record.getHorizontal() & 15) + (chunkZ * 16));
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
if (ConnectionData.connects(blockState)) {
|
||||
blockState = ConnectionData.connect(userConnection, position, blockState);
|
||||
record.setBlockId(blockState);
|
||||
}
|
||||
|
||||
ConnectionData.update(userConnection, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Unload Chunk
|
||||
protocol.registerOutgoing(State.PLAY, 0x1D, 0x1F, new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
if(Via.getConfig().isServersideBlockConnections()){
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
int x = wrapper.passthrough(Type.INT);
|
||||
int z = wrapper.passthrough(Type.INT);
|
||||
ConnectionData.getProvider().unloadChunk(wrapper.user(), x, z);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Named Sound Effect TODO String -> Identifier? Check if identifier is present?
|
||||
protocol.registerOutgoing(State.PLAY, 0x19, 0x1A, new PacketRemapper() {
|
||||
@Override
|
||||
@ -245,7 +297,7 @@ public class WorldPackets {
|
||||
for (int p = 0; p < section.getPaletteSize(); p++) {
|
||||
int old = section.getPaletteEntry(p);
|
||||
int newId = toNewId(old);
|
||||
if (storage.isWelcome(newId)) {
|
||||
if (storage.isWelcome(newId) || (Via.getConfig().isServersideBlockConnections() && ConnectionData.needStoreBlocks() && ConnectionData.isWelcome(newId))) {
|
||||
willStoreAnyBlock = true;
|
||||
}
|
||||
section.setPaletteEntry(p, newId);
|
||||
@ -263,12 +315,22 @@ public class WorldPackets {
|
||||
(long) (z + (chunk.getZ() << 4))
|
||||
), block);
|
||||
}
|
||||
if (Via.getConfig().isServersideBlockConnections() && ConnectionData.isWelcome(block)) {
|
||||
ConnectionData.getProvider().storeBlock(wrapper.user(), (long) (x + (chunk.getX() << 4)),
|
||||
(long) (y + (i << 4)),
|
||||
(long) (z + (chunk.getZ() << 4)),
|
||||
block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Via.getConfig().isServersideBlockConnections()) {
|
||||
ConnectionData.connectBlocks(wrapper.user(), chunk);
|
||||
}
|
||||
|
||||
// Rewrite biome id 255 to plains
|
||||
if (chunk.isBiomeData()) {
|
||||
int latestBiomeWarn = Integer.MIN_VALUE;
|
||||
|
@ -0,0 +1,75 @@
|
||||
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.data.StoredObject;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BlockConnectionStorage extends StoredObject {
|
||||
private Map<Pair<Integer, Integer>, Map<BlockPositon, Integer>> blockStorage = new HashMap<>();
|
||||
|
||||
public BlockConnectionStorage(UserConnection user) {
|
||||
super(user);
|
||||
}
|
||||
|
||||
public void store(Position position, int blockState) {
|
||||
Pair pair = getPair(position);
|
||||
Map<BlockPositon, Integer> map = getChunkMap(pair);
|
||||
map.put(new BlockPositon(position), blockState);
|
||||
}
|
||||
|
||||
public int get(Position position) {
|
||||
Pair pair = getPair(position);
|
||||
Map<BlockPositon, Integer> map = getChunkMap(pair);
|
||||
BlockPositon blockPositon = new BlockPositon(position);
|
||||
return map.containsKey(blockPositon) ? map.get(blockPositon) : 0;
|
||||
}
|
||||
|
||||
public void remove(Position position) {
|
||||
Pair pair = getPair(position);
|
||||
Map<BlockPositon, Integer> map = getChunkMap(pair);
|
||||
map.remove(new BlockPositon(position));
|
||||
if(map.isEmpty()){
|
||||
blockStorage.remove(pair);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
blockStorage.clear();
|
||||
}
|
||||
|
||||
public void unloadChunk(int x, int z){
|
||||
blockStorage.remove(new Pair<>(x, z));
|
||||
}
|
||||
|
||||
private Map<BlockPositon, Integer> getChunkMap(Pair pair){
|
||||
Map<BlockPositon, Integer> map = blockStorage.get(pair);
|
||||
if(map == null){
|
||||
map = new HashMap<>();
|
||||
blockStorage.put(pair, map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private Pair<Integer, Integer> getPair(Position position){
|
||||
int chunkX = (int) (position.getX() >> 4);
|
||||
int chunkZ = (int) (position.getZ() >> 4);
|
||||
return new Pair<>(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@EqualsAndHashCode
|
||||
@Data
|
||||
private class BlockPositon {
|
||||
int x,y,z;
|
||||
public BlockPositon(Position position){
|
||||
x = position.getX().intValue();
|
||||
y = position.getY().intValue();
|
||||
z = position.getZ().intValue();
|
||||
}
|
||||
}
|
||||
}
|
@ -151,4 +151,10 @@ replacement-piston-id: 0
|
||||
# Force the string -> json transform
|
||||
force-json-transform: false
|
||||
# Minimize the cooldown animation in 1.8 servers
|
||||
minimize-cooldown: true
|
||||
minimize-cooldown: true
|
||||
# Enable serverside block-connections for 1.13+ clients
|
||||
serverside-blockconnections: false
|
||||
# Sets the method for the block connections (world for world-level or packet for packet-level)
|
||||
blockconnection-method: world
|
||||
# When activated, only the most important blocks are stored in the blockstorage. (fences, glass panes etc. won't connect to solid blocks)
|
||||
reduce-blockstorage-memory: false
|
75782
common/src/main/resources/assets/viaversion/data/blockConnections.json
Normal file
75782
common/src/main/resources/assets/viaversion/data/blockConnections.json
Normal file
File diff suppressed because it is too large
Load Diff
1134
common/src/main/resources/assets/viaversion/data/blockData.json
Normal file
1134
common/src/main/resources/assets/viaversion/data/blockData.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -225,4 +225,19 @@ public class SpongeViaConfig extends Config implements ViaVersionConfig {
|
||||
public boolean isDisable1_13AutoComplete() {
|
||||
return getBoolean("disable-1_13-auto-complete", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServersideBlockConnections() {
|
||||
return getBoolean("serverside-blockconnections", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockConnectionMethod() {
|
||||
return getString("blockconnection-method", "world");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedueBlockStorageMemory() {
|
||||
return getBoolean("reduce-blockstorage-memory", false);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import us.myles.ViaVersion.api.minecraft.item.Item;
|
||||
import us.myles.ViaVersion.api.platform.TaskId;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.HandItemProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
@ -18,6 +19,7 @@ import us.myles.ViaVersion.sponge.listeners.protocol1_9to1_8.DeathListener;
|
||||
import us.myles.ViaVersion.sponge.listeners.protocol1_9to1_8.HandItemCache;
|
||||
import us.myles.ViaVersion.sponge.listeners.protocol1_9to1_8.sponge4.Sponge4ArmorListener;
|
||||
import us.myles.ViaVersion.sponge.listeners.protocol1_9to1_8.sponge5.Sponge5ArmorListener;
|
||||
import us.myles.ViaVersion.sponge.providers.SpongeBlockConnectionProvider;
|
||||
import us.myles.ViaVersion.sponge.providers.SpongeViaBulkChunkTranslator;
|
||||
import us.myles.ViaVersion.sponge.providers.SpongeViaMovementTransmitter;
|
||||
|
||||
@ -78,6 +80,9 @@ public class SpongeViaLoader implements ViaPlatformLoader {
|
||||
}
|
||||
}
|
||||
});
|
||||
if (Via.getConfig().getBlockConnectionMethod().equalsIgnoreCase("world")) {
|
||||
Via.getManager().getProviders().use(BlockConnectionProvider.class, new SpongeBlockConnectionProvider());
|
||||
}
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
|
@ -0,0 +1,57 @@
|
||||
package us.myles.ViaVersion.sponge.providers;
|
||||
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.block.BlockState;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.world.Chunk;
|
||||
import org.spongepowered.api.world.World;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SpongeBlockConnectionProvider extends BlockConnectionProvider {
|
||||
private static Class block;
|
||||
private static Map<Object, Integer> blockStateIds;
|
||||
|
||||
static {
|
||||
try {
|
||||
block = Class.forName("net.minecraft.block.Block");
|
||||
blockStateIds = ReflectionUtil.get(
|
||||
ReflectionUtil.getStatic(block, "field_176229_d", Object.class),
|
||||
"field_148749_a", Map.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Via.getPlatform().getLogger().warning("net.minecraft.block.Block not found! Are you using Lantern?");
|
||||
} catch (IllegalAccessException | NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWorldBlockData(UserConnection user, Position position) {
|
||||
if (blockStateIds != null) {
|
||||
UUID uuid = user.get(ProtocolInfo.class).getUuid();
|
||||
Optional<Player> player = Sponge.getServer().getPlayer(uuid);
|
||||
if (player.isPresent()) {
|
||||
World world = player.get().getWorld();
|
||||
Optional<Chunk> chunk = world.getChunkAtBlock(position.getX().intValue(), position.getY().intValue(), position.getZ().intValue());
|
||||
if (chunk.isPresent()) {
|
||||
BlockState b = chunk.get().getBlock(position.getX().intValue(), position.getY().intValue(), position.getZ().intValue());
|
||||
Integer id = blockStateIds.get(b);
|
||||
if (id == null) {
|
||||
System.out.println("id not found");
|
||||
} else {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -277,4 +277,19 @@ public class VelocityViaConfig extends Config implements ViaVersionConfig {
|
||||
public boolean isDisable1_13AutoComplete() {
|
||||
return getBoolean("disable-1_13-auto-complete", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServersideBlockConnections() {
|
||||
return getBoolean("serverside-blockconnections", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockConnectionMethod() {
|
||||
return "packet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedueBlockStorageMemory() {
|
||||
return getBoolean("reduce-blockstorage-memory", false);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user