Merge pull request #29 from GeyserMC/chunks

Merge branch 'chunks' into master
This commit is contained in:
Redned 2019-09-13 20:22:30 -05:00 committed by GitHub
commit ed79f59d28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 11189 additions and 9719 deletions

3
.gitignore vendored
View file

@ -222,4 +222,5 @@ nbdist/
# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all
### Geyser ###
config.yml
config.yml
logs/

View file

@ -4,7 +4,7 @@
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Build Status](https://ci.nukkitx.com/job/Geyser/job/master/badge/icon)](https://ci.nukkitx.com/job/Geyser/job/master/)
[![Discord](https://img.shields.io/discord/597838753859633172.svg?color=%237289da&label=discord)](https://discord.gg/7ZDSKa5)
[![Discord](https://img.shields.io/discord/597838753859633172.svg?color=%237289da&label=discord)](https://discord.gg/GPMF8E2)
[![HitCount](http://hits.dwyl.io/Geyser/GeyserMC.svg)](http://hits.dwyl.io/Geyser/GeyserMC)
A bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition, closing the gap from those wanting to play together.

View file

@ -29,6 +29,8 @@ import org.geysermc.api.command.CommandSender;
import org.geysermc.api.session.AuthData;
import org.geysermc.api.window.FormWindow;
import java.net.InetSocketAddress;
public interface Player extends CommandSender {
/**
@ -68,4 +70,11 @@ public interface Player extends CommandSender {
* @param id the id of the window
*/
void sendForm(FormWindow window, int id);
/**
* Returns the current hostname and port the player is connected with.
*
* @return player's socket address.
*/
InetSocketAddress getSocketAddress();
}

View file

@ -72,15 +72,9 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.protocol</groupId>
<artifactId>bedrock-v354</artifactId>
<version>2.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.protocol</groupId>
<artifactId>bedrock-v340</artifactId>
<version>2.1.2</version>
<groupId>com.nukkitx</groupId>
<artifactId>fastutil-lite</artifactId>
<version>8.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>

View file

@ -43,7 +43,6 @@ import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.metrics.Metrics;
import org.geysermc.connector.network.ConnectorServerEventHandler;
import org.geysermc.connector.network.remote.RemoteJavaServer;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.TranslatorsInit;
import org.geysermc.connector.plugin.GeyserPluginLoader;
import org.geysermc.connector.plugin.GeyserPluginManager;
@ -92,6 +91,7 @@ public class GeyserConnector implements Connector {
}
private GeyserConnector() {
System.out.println(UUID.randomUUID().toString());
//Metric
if(!(System.console() == null) && System.getProperty("os.name", "Windows 10").toLowerCase().contains("windows")) {
AnsiConsole.systemInstall();
@ -173,10 +173,12 @@ public class GeyserConnector implements Connector {
public void addPlayer(Player player) {
players.put(player.getAuthenticationData().getName(), player);
players.put(player.getAuthenticationData().getUUID(), player);
players.put(player.getSocketAddress(), player);
}
public void removePlayer(Player player) {
players.remove(player.getAuthenticationData().getName());
players.remove(player.getAuthenticationData().getUUID());
players.remove(player.getSocketAddress());
}
}

View file

@ -37,6 +37,6 @@ public class RemoteConfiguration {
private String motd1;
private String motd2;
@JsonProperty("online-mode")
private boolean onlineMode;
@JsonProperty("auth-type")
private String authType;
}

View file

@ -29,6 +29,8 @@ import com.flowpowered.math.vector.Vector3f;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPropertiesPacket;
import com.nukkitx.protocol.bedrock.data.EntityData;
import com.nukkitx.protocol.bedrock.data.EntityDataDictionary;
import com.nukkitx.protocol.bedrock.data.EntityFlag;
import com.nukkitx.protocol.bedrock.data.EntityFlags;
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
@ -41,12 +43,7 @@ import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.AttributeUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
@Getter
@Setter
@ -139,6 +136,9 @@ public class Entity {
public EntityDataDictionary getMetadata() {
EntityFlags flags = new EntityFlags();
flags.setFlag(EntityFlag.HAS_GRAVITY, true);
EntityDataDictionary dictionary = new EntityDataDictionary();
dictionary.put(EntityData.NAMETAG, "");
dictionary.put(EntityData.ENTITY_AGE, 0);
@ -147,6 +147,7 @@ public class Entity {
dictionary.put(EntityData.AIR, (short) 0);
dictionary.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
dictionary.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth());
dictionary.putFlags(flags);
return dictionary;
}

View file

@ -27,8 +27,10 @@ package org.geysermc.connector.entity.attribute;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class Attribute {

View file

@ -35,7 +35,7 @@ public enum AttributeType {
// Universal Attributes
FOLLOW_RANGE("generic.followRange", "minecraft:follow_range", 0f, 2048f, 32f),
KNOCKBACK_RESISTANCE("generic.knockbackResistance", "minecraft:knockback_resistance", 0f, 1f, 0f),
MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.699999988079071f),
MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f),
FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f),

View file

@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo;
import com.nukkitx.protocol.bedrock.BedrockPong;
import com.nukkitx.protocol.bedrock.BedrockServerEventHandler;
import com.nukkitx.protocol.bedrock.BedrockServerSession;
import org.geysermc.api.Player;
import org.geysermc.api.events.PingEvent;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.configuration.GeyserConfiguration;
@ -102,7 +103,15 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
public void onSessionCreation(BedrockServerSession bedrockServerSession) {
bedrockServerSession.setLogging(true);
bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserSession(connector, bedrockServerSession)));
bedrockServerSession.addDisconnectHandler((x) -> GeyserLogger.DEFAULT.warning("Bedrock user with ip: " + bedrockServerSession.getAddress().getAddress() + " has disconnected for reason " + x));
bedrockServerSession.addDisconnectHandler(disconnectReason -> {
GeyserLogger.DEFAULT.info("Bedrock user with ip: " + bedrockServerSession.getAddress().getAddress() + " has disconnected for reason " + disconnectReason);
Player player = connector.getPlayers().get(bedrockServerSession.getAddress());
if (player != null) {
player.disconnect(disconnectReason.name());
connector.removePlayer(player);
}
});
bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC);
}
}

View file

@ -121,7 +121,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
return true;
}
return false;
return translateAndDefault(packet);
}
@Override

View file

@ -26,6 +26,7 @@
package org.geysermc.connector.network.session;
import com.flowpowered.math.vector.Vector2f;
import com.flowpowered.math.vector.Vector2i;
import com.flowpowered.math.vector.Vector3f;
import com.flowpowered.math.vector.Vector3i;
import com.github.steveice10.mc.auth.exception.request.RequestException;
@ -37,8 +38,6 @@ import com.github.steveice10.packetlib.event.session.PacketReceivedEvent;
import com.github.steveice10.packetlib.event.session.SessionAdapter;
import com.github.steveice10.packetlib.packet.Packet;
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
import com.nukkitx.network.util.DisconnectReason;
import com.nukkitx.protocol.PlayerSession;
import com.nukkitx.protocol.bedrock.BedrockServerSession;
import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
import com.nukkitx.protocol.bedrock.data.GameRule;
@ -47,7 +46,6 @@ import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
import com.nukkitx.protocol.bedrock.packet.TextPacket;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.api.Geyser;
import org.geysermc.api.Player;
import org.geysermc.api.RemoteServer;
import org.geysermc.api.session.AuthData;
@ -56,22 +54,19 @@ import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.entity.PlayerEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.session.cache.DataCache;
import org.geysermc.connector.network.session.cache.EntityCache;
import org.geysermc.connector.network.session.cache.InventoryCache;
import org.geysermc.connector.network.session.cache.ScoreboardCache;
import org.geysermc.connector.network.session.cache.WindowCache;
import org.geysermc.connector.network.session.cache.*;
import org.geysermc.connector.network.translators.Registry;
import org.geysermc.connector.utils.Toolbox;
import java.net.InetSocketAddress;
import java.util.UUID;
@Getter
public class GeyserSession implements PlayerSession, Player {
public class GeyserSession implements Player {
private GeyserConnector connector;
private final GeyserConnector connector;
private final BedrockServerSession upstream;
private RemoteServer remoteServer;
private BedrockServerSession upstream;
private Client downstream;
@ -87,6 +82,9 @@ public class GeyserSession implements PlayerSession, Player {
private DataCache<Packet> javaPacketCache;
@Setter
private Vector2i lastChunkPosition = null;
private boolean loggedIn;
@Setter
@ -119,7 +117,7 @@ public class GeyserSession implements PlayerSession, Player {
startGame();
this.remoteServer = remoteServer;
if (!connector.getConfig().getRemote().isOnlineMode()) {
if (!(connector.getConfig().getRemote().getAuthType().hashCode() == "online".hashCode())) {
connector.getLogger().info("Attempting to login using offline mode... authentication is disabled.");
authenticate(authenticationData.getName());
}
@ -180,7 +178,7 @@ public class GeyserSession implements PlayerSession, Player {
if (downstream != null && downstream.getSession() != null) {
downstream.getSession().disconnect(reason);
}
if (upstream != null) {
if (upstream != null && !upstream.isClosed()) {
upstream.disconnect(reason);
}
}
@ -188,27 +186,14 @@ public class GeyserSession implements PlayerSession, Player {
closed = true;
}
@Override
public boolean isClosed() {
return closed;
}
@Override
public void close() {
disconnect("Server closed.");
}
@Override
public void onDisconnect(DisconnectReason disconnectReason) {
downstream.getSession().disconnect("Disconnected from server. Reason: " + disconnectReason);
}
@Override
public void onDisconnect(String reason) {
downstream.getSession().disconnect("Disconnected from server. Reason: " + reason);
connector.removePlayer(this);
}
public void setAuthenticationData(AuthData authData) {
authenticationData = authData;
}
@ -242,6 +227,11 @@ public class GeyserSession implements PlayerSession, Player {
windowCache.showWindow(window, id);
}
@Override
public InetSocketAddress getSocketAddress() {
return this.upstream.getAddress();
}
public void sendForm(FormWindow window) {
windowCache.showWindow(window);
}

View file

@ -65,6 +65,7 @@ import com.nukkitx.nbt.tag.CompoundTag;
import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket;
import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket;
import com.nukkitx.protocol.bedrock.packet.TextPacket;
import lombok.Getter;
@ -72,6 +73,7 @@ import org.geysermc.connector.network.translators.bedrock.BedrockActionTranslato
import org.geysermc.connector.network.translators.bedrock.BedrockAnimateTranslator;
import org.geysermc.connector.network.translators.bedrock.BedrockCommandRequestTranslator;
import org.geysermc.connector.network.translators.bedrock.BedrockMobEquipmentTranslator;
import org.geysermc.connector.network.translators.bedrock.BedrockMovePlayerTranslator;
import org.geysermc.connector.network.translators.bedrock.BedrockTextTranslator;
import org.geysermc.connector.network.translators.inventory.GenericInventoryTranslator;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
@ -100,7 +102,7 @@ import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnPla
import org.geysermc.connector.network.translators.java.scoreboard.JavaDisplayScoreboardTranslator;
import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator;
import org.geysermc.connector.network.translators.java.scoreboard.JavaUpdateScoreTranslator;
import org.geysermc.connector.network.translators.java.world.JavaChunkDataPacket;
import org.geysermc.connector.network.translators.java.world.JavaChunkDataTranslator;
import org.geysermc.connector.network.translators.java.world.JavaNotifyClientTranslator;
import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator;
import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator;
@ -168,7 +170,7 @@ public class TranslatorsInit {
Registry.registerJava(ServerPlayerHealthPacket.class, new JavaPlayerHealthTranslator());
Registry.registerJava(ServerNotifyClientPacket.class, new JavaNotifyClientTranslator());
Registry.registerJava(ServerChunkDataPacket.class, new JavaChunkDataPacket());
Registry.registerJava(ServerChunkDataPacket.class, new JavaChunkDataTranslator());
Registry.registerJava(ServerEntityDestroyPacket.class, new JavaEntityDestroyTranslator());
Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator());
Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator());
@ -182,6 +184,7 @@ public class TranslatorsInit {
Registry.registerBedrock(TextPacket.class, new BedrockTextTranslator());
Registry.registerBedrock(MobEquipmentPacket.class, new BedrockMobEquipmentTranslator());
Registry.registerBedrock(PlayerActionPacket.class, new BedrockActionTranslator());
Registry.registerBedrock(MovePlayerPacket.class, new BedrockMovePlayerTranslator());
itemTranslator = new ItemTranslator();

View file

@ -25,7 +25,14 @@
package org.geysermc.connector.network.translators.bedrock;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
@ -33,11 +40,45 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
@Override
public void translate(PlayerActionPacket packet, GeyserSession session) {
Entity entity = session.getPlayerEntity();
if (entity == null)
return;
switch (packet.getAction()) {
case RESPAWN:
// Don't put anything here as respawn is already handled
// in JavaPlayerSetHealthTranslator
break;
case START_GLIDE:
case STOP_GLIDE:
ClientPlayerStatePacket glidePacket = new ClientPlayerStatePacket((int) session.getPlayerEntity().getGeyserId(), PlayerState.START_ELYTRA_FLYING);
session.getDownstream().getSession().send(glidePacket);
break;
case START_SNEAK:
ClientPlayerStatePacket startSneakPacket = new ClientPlayerStatePacket((int) session.getPlayerEntity().getGeyserId(), PlayerState.START_SNEAKING);
session.getDownstream().getSession().send(startSneakPacket);
break;
case STOP_SNEAK:
ClientPlayerStatePacket stopSneakPacket = new ClientPlayerStatePacket((int) session.getPlayerEntity().getGeyserId(), PlayerState.STOP_SNEAKING);
session.getDownstream().getSession().send(stopSneakPacket);
break;
case START_SPRINT:
ClientPlayerStatePacket startSprintPacket = new ClientPlayerStatePacket((int) session.getPlayerEntity().getGeyserId(), PlayerState.START_SPRINTING);
session.getDownstream().getSession().send(startSprintPacket);
break;
case STOP_SPRINT:
ClientPlayerStatePacket stopSprintPacket = new ClientPlayerStatePacket((int) session.getPlayerEntity().getGeyserId(), PlayerState.STOP_SPRINTING);
session.getDownstream().getSession().send(stopSprintPacket);
break;
case DROP_ITEM:
ClientPlayerActionPacket dropItemPacket = new ClientPlayerActionPacket(PlayerAction.DROP_ITEM, new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(),
packet.getBlockPosition().getZ()), BlockFace.values()[packet.getFace()]);
session.getDownstream().getSession().send(dropItemPacket);
break;
case STOP_SLEEP:
ClientPlayerStatePacket stopSleepingPacket = new ClientPlayerStatePacket((int) session.getPlayerEntity().getGeyserId(), PlayerState.LEAVE_BED);
session.getDownstream().getSession().send(stopSleepingPacket);
break;
}
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators.bedrock;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPacket> {
@Override
public void translate(MovePlayerPacket packet, GeyserSession session) {
Entity entity = session.getPlayerEntity();
if (entity == null)
return;
// TODO: Implement collision support
ClientPlayerPositionRotationPacket playerPositionRotationPacket = new ClientPlayerPositionRotationPacket(
packet.isOnGround(), packet.getPosition().getX(), Math.ceil((packet.getPosition().getY() - EntityType.PLAYER.getOffset()) * 2) / 2,
packet.getPosition().getZ(), packet.getRotation().getY(), packet.getRotation().getX());
entity.moveAbsolute(packet.getPosition(), packet.getRotation());
session.getDownstream().getSession().send(playerPositionRotationPacket);
}
}

View file

@ -37,4 +37,14 @@ public class BedrockItem {
private String identifier;
private int id;
private int data;
@Override
public int hashCode() {
return id << 4 | data;
}
@Override
public boolean equals(Object obj) {
return obj == this || (obj instanceof BedrockItem && ((BedrockItem) obj).id == this.id && ((BedrockItem) obj).identifier.equals(this.identifier) && ((BedrockItem) obj).data == this.data);
}
}

View file

@ -97,9 +97,9 @@ public class ItemTranslator {
}
public BedrockItem getBedrockBlock(BlockState state) {
BedrockItem bedrockItem = Remapper.BLOCK_REMAPPER.convertToBedrock(new ItemStack(state.getId()));
BedrockItem bedrockItem = Remapper.BLOCK_REMAPPER.convertToBedrockB(new ItemStack(state.getId()));
if (bedrockItem == null) {
//GeyserLogger.DEFAULT.debug("Missing mapping for java item " + state.getId());
// GeyserLogger.DEFAULT.debug("Missing mapping for java block " + state.getId());
return BedrockItem.AIR;
}

View file

@ -39,7 +39,7 @@ public class JavaItem {
@Override
public int hashCode() {
return id & identifier.hashCode();
return id;
}
@Override

View file

@ -35,6 +35,7 @@ import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
@ -56,7 +57,7 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
session.getUpstream().sendPacketImmediately(playStatus);
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getPitch(), packet.getYaw());
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getPitch(), packet.getYaw());
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(javaJoinPacket.getGameMode().ordinal());
@ -71,7 +72,7 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
movePlayerPacket.setPosition(new Vector3f(packet.getX(), packet.getY(), packet.getZ()));
movePlayerPacket.setPosition(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()));
movePlayerPacket.setRotation(new Vector3f(packet.getPitch(), packet.getYaw(), 0));
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
movePlayerPacket.setOnGround(true);
@ -83,11 +84,11 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
GeyserLogger.DEFAULT.info("Spawned player at " + packet.getX() + " " + packet.getY() + " " + packet.getZ());
}
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY(), packet.getZ()), packet.getPitch(), packet.getYaw());
entity.moveAbsolute(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ()), packet.getPitch(), packet.getYaw());
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
movePlayerPacket.setPosition(new Vector3f(packet.getX(), packet.getY(), packet.getZ()));
movePlayerPacket.setPosition(new Vector3f(packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.01f, packet.getZ()));
movePlayerPacket.setRotation(new Vector3f(packet.getPitch(), packet.getYaw(), 0));
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
movePlayerPacket.setOnGround(true);

View file

@ -1,25 +0,0 @@
package org.geysermc.connector.network.translators.java.world;
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket;
import com.github.steveice10.packetlib.packet.Packet;
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.utils.Chunks;
public class JavaChunkDataPacket extends PacketTranslator<ServerChunkDataPacket> {
@Override
public void translate(ServerChunkDataPacket packet, GeyserSession session) {
LevelChunkPacket levelChunkPacket = new LevelChunkPacket();
Chunks.ChunkData data = Chunks.getData(packet.getColumn());
levelChunkPacket.setSubChunksLength(data.count);
levelChunkPacket.setData(data.bytes);
levelChunkPacket.setChunkX(packet.getColumn().getX());
levelChunkPacket.setChunkZ(packet.getColumn().getZ());
GeyserLogger.DEFAULT.info("Sent chunk packet!");
session.getUpstream().sendPacket(levelChunkPacket);
}
}

View file

@ -0,0 +1,72 @@
package org.geysermc.connector.network.translators.java.world;
import com.flowpowered.math.vector.Vector2i;
import com.flowpowered.math.vector.Vector3f;
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket;
import com.nukkitx.network.VarInts;
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.geysermc.api.Geyser;
import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.utils.ChunkUtils;
import org.geysermc.connector.world.chunk.ChunkSection;
public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPacket> {
@Override
public void translate(ServerChunkDataPacket packet, GeyserSession session) {
// Not sure if this is safe or not, however without this the client usually times out
Geyser.getConnector().getGeneralThreadPool().execute(() -> {
Vector2i chunkPos = session.getLastChunkPosition();
Vector3f position = session.getPlayerEntity().getPosition();
Vector2i newChunkPos = Vector2i.from(position.getFloorX() >> 4, position.getFloorZ() >> 4);
if (chunkPos == null || !chunkPos.equals(newChunkPos)) {
NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket();
chunkPublisherUpdatePacket.setPosition(position.toInt());
chunkPublisherUpdatePacket.setRadius(8 << 4);
session.getUpstream().sendPacket(chunkPublisherUpdatePacket);
session.setLastChunkPosition(newChunkPos);
}
try {
ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn());
ByteBuf byteBuf = Unpooled.buffer(32);
ChunkSection[] sections = chunkData.sections;
int sectionCount = sections.length - 1;
while (sectionCount >= 0 && sections[sectionCount].isEmpty()) {
sectionCount--;
}
sectionCount++;
for (int i = 0; i < sectionCount; i++) {
ChunkSection section = chunkData.sections[i];
section.writeToNetwork(byteBuf);
}
byteBuf.writeBytes(chunkData.biomes); // Biomes - 256 bytes
byteBuf.writeByte(0); // Border blocks - Edu edition only
VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now
byte[] payload = new byte[byteBuf.writerIndex()];
byteBuf.readBytes(payload);
LevelChunkPacket levelChunkPacket = new LevelChunkPacket();
levelChunkPacket.setSubChunksLength(sectionCount);
levelChunkPacket.setCachingEnabled(false);
levelChunkPacket.setChunkX(packet.getColumn().getX());
levelChunkPacket.setChunkZ(packet.getColumn().getZ());
levelChunkPacket.setData(payload);
session.getUpstream().sendPacket(levelChunkPacket);
} catch (Exception ex) {
ex.printStackTrace();
}
});
}
}

View file

@ -0,0 +1,54 @@
package org.geysermc.connector.utils;
import com.github.steveice10.mc.protocol.data.game.chunk.BlockStorage;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import org.geysermc.connector.network.translators.TranslatorsInit;
import org.geysermc.connector.network.translators.item.BedrockItem;
import org.geysermc.connector.world.chunk.ChunkSection;
import org.geysermc.connector.world.chunk.bitarray.BitArrayVersion;
public class ChunkUtils {
public static ChunkData translateToBedrock(Column column) {
ChunkData chunkData = new ChunkData();
Chunk[] chunks = column.getChunks();
int chunkSectionCount = chunks.length;
chunkData.sections = new ChunkSection[chunkSectionCount];
for (int i = 0; i < chunkSectionCount; i++) {
chunkData.sections[i] = new ChunkSection();
}
for (int chunkY = 0; chunkY < chunkSectionCount; chunkY++) {
Chunk chunk = chunks[chunkY];
if (chunk == null || chunk.isEmpty())
continue;
BlockStorage storage = chunk.getBlocks();
ChunkSection section = chunkData.sections[chunkY];
for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
BlockState block = storage.get(x, y, z);
BedrockItem bedrockBlock = TranslatorsInit.getItemTranslator().getBedrockBlock(block);
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z),
bedrockBlock.getId() << 4 | bedrockBlock.getData());
}
}
}
}
return chunkData;
}
public static final class ChunkData {
public ChunkSection[] sections;
public byte[] biomes = new byte[256];
public byte[] blockEntities = new byte[0];
}
}

View file

@ -1,80 +0,0 @@
package org.geysermc.connector.utils;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
import gnu.trove.list.TByteList;
import gnu.trove.list.array.TByteArrayList;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import org.geysermc.connector.network.translators.TranslatorsInit;
import java.util.Objects;
public class Chunks {
public static ChunkData getData(Column c) {
Objects.requireNonNull(c);
int count = 0;
for(Chunk chunk : c.getChunks()) {
if(chunk != null) {
count++;
}
}
int block = 0;
TByteList list = new TByteArrayList(4096 * 4);
for(int i = 0; i < 256; i++) {
list.add((byte) 0);
}
for(Chunk chunk : c.getChunks()) {
if (chunk != null) {
list.add((byte) 0);
for (int x = 0; x < 16; x++) {
for (int y = 0; x < 16; x++) {
for (int z = 0; x < 16; x++) {
try {
list.add((byte) TranslatorsInit.getItemTranslator().getBedrockBlock(chunk.getBlocks().get(x, y, z)).getId());
} catch (NullPointerException e) {
list.add((byte) 0);
}
block++;
}
}
}
for (int x = 0; x < 16; x++) {
for (int y = 0; x < 16; x++) {
for (int z = 0; x < 16; x++) {
try {
list.add((byte) TranslatorsInit.getItemTranslator().getBedrockBlock(chunk.getBlocks().get(x, y, z)).getData());
} catch (NullPointerException e) {
list.add((byte) 0);
}
block++;
}
}
}
}
}
list.add((byte) 0);
list.add((byte) 0);
return new ChunkData(count, list.toArray());
}
@AllArgsConstructor(access = AccessLevel.PACKAGE)
public static final class ChunkData {
public final int count;
public final byte[] bytes;
}
}

View file

@ -0,0 +1,9 @@
package org.geysermc.connector.utils;
public class MathUtils {
public static int ceil(float floatNumber) {
int truncated = (int) floatNumber;
return floatNumber > truncated ? truncated + 1 : truncated;
}
}

View file

@ -34,6 +34,7 @@ public class Remapper {
BedrockItem bedrockItem = bedrockItemEntry.getValue();
String identifier = bedrockItem.getIdentifier();
// Colorable block remapping
for (ColoredBlock coloredBlock : ColoredBlock.values()) {
if (!getBedrockIdentifier(coloredBlock.name()).equalsIgnoreCase(bedrockItem.getIdentifier().replace(MINECRAFT, "")))
continue;
@ -48,6 +49,7 @@ public class Remapper {
}
}
// Wood remapping
for (WoodBlock woodBlock : WoodBlock.values()) {
if (!getBedrockIdentifier(woodBlock.name()).equalsIgnoreCase(bedrockItem.getIdentifier().replace(MINECRAFT, "")))
continue;
@ -66,6 +68,7 @@ public class Remapper {
}
}
// Stone remapping
if (bedrockItem.getIdentifier().replace(MINECRAFT, "").equalsIgnoreCase("stone") && !isTool(bedrockItem.getIdentifier())) {
for (StoneType stoneType : StoneType.values()) {
if (stoneType.getId() != bedrockItem.getData())
@ -76,6 +79,23 @@ public class Remapper {
}
}
// Grass remapping
if (bedrockItem.getIdentifier().replace(MINECRAFT, "").equalsIgnoreCase("grass")) {
identifier = MINECRAFT + "grass_block";
}
if (bedrockItem.getIdentifier().replace(MINECRAFT, "").equalsIgnoreCase("tallgrass")) {
identifier = MINECRAFT + "grass";
}
// Dirt remapping
if (bedrockItem.getIdentifier().replace(MINECRAFT, "").equalsIgnoreCase("dirt")) {
if (bedrockItem.getData() == 0)
identifier = MINECRAFT + "dirt";
else
identifier = MINECRAFT + "coarse_dirt";
}
for (Map.Entry<String, JavaItem> javaItemEntry : javaItems.entrySet()) {
if (identifier.equalsIgnoreCase(javaItemEntry.getKey())) {
bedrockToJava.put(bedrockItemEntry.getValue(), javaItemEntry.getValue());
@ -107,6 +127,19 @@ public class Remapper {
return null;
}
public BedrockItem convertToBedrockB(ItemStack block) {
for (Map.Entry<String, JavaItem> javaItem : Toolbox.JAVA_BLOCKS.entrySet()) {
if (javaItem.getValue().getId() != block.getId())
continue;
return javaToBedrock.get(javaItem.getValue());
}
return null;
}
private static String getBedrockIdentifier(String javaIdentifier) {
javaIdentifier = javaIdentifier.toLowerCase();
javaIdentifier = javaIdentifier.replace("terracotta", "stained_hardened_clay");

View file

@ -10,6 +10,7 @@ import io.netty.buffer.Unpooled;
import org.geysermc.connector.console.GeyserLogger;
import org.geysermc.connector.network.translators.item.BedrockItem;
import org.geysermc.connector.network.translators.item.JavaItem;
import org.geysermc.connector.world.GlobalBlockPalette;
import java.io.InputStream;
import java.util.*;
@ -30,15 +31,14 @@ public class Toolbox {
Map<String, BedrockItem> bedrockBlocks = new HashMap<>();
Map<String, BedrockItem> bedrockItems = new HashMap<>();
for (Map<String, Object> e : entries) {
BedrockItem bedrockItem = new BedrockItem((String) e.get("name"), (int) e.get("id"), (int) e.get("data"));
bedrockBlocks.put(bedrockItem.getIdentifier(), bedrockItem);
bedrockItems.put(bedrockItem.getIdentifier() + ":" + bedrockItem.getData(), bedrockItem);
}
ByteBuf b = Unpooled.buffer();
VarInts.writeUnsignedInt(b, entries.size());
for (Map<String, Object> e : entries) {
BedrockItem bedrockItem = new BedrockItem((String) e.get("name"), (int) e.get("id"), (int) e.get("data"));
bedrockItems.put(bedrockItem.getIdentifier() + ":" + bedrockItem.getData(), bedrockItem);
bedrockBlocks.put(bedrockItem.getIdentifier() + ":" + bedrockItem.getData(), bedrockItem);
GlobalBlockPalette.registerMapping((int) e.get("id") << 4 | (int) e.get("data"));
BedrockUtils.writeString(b, (String) e.get("name"));
b.writeShortLE((int) e.get("data"));
b.writeShortLE((int) e.get("id"));

View file

@ -0,0 +1,47 @@
package org.geysermc.connector.world;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Adapted from NukkitX: https://github.com/NukkitX/Nukkit
*/
public class GlobalBlockPalette {
private static final Int2IntMap legacyToRuntimeId = new Int2IntOpenHashMap();
private static final Int2IntMap runtimeIdToLegacy = new Int2IntOpenHashMap();
private static final AtomicInteger runtimeIdAllocator = new AtomicInteger(0);
static {
legacyToRuntimeId.defaultReturnValue(-1);
runtimeIdToLegacy.defaultReturnValue(-1);
}
public static int getOrCreateRuntimeId(int id, int meta) {
return getOrCreateRuntimeId((id << 4) | meta);
}
public static int getOrCreateRuntimeId(int legacyId) throws NoSuchElementException {
int runtimeId = legacyToRuntimeId.get(legacyId);
if (!legacyToRuntimeId.containsKey(legacyId) || runtimeId == -1) {
//runtimeId = registerMapping(runtimeIdAllocator.incrementAndGet(), legacyId);
// throw new NoSuchElementException("Unmapped block registered id:" + (legacyId >>> 4) + " meta:" + (legacyId & 0xf));
return 0;
}
return runtimeId;
}
public static int registerMapping(int legacyId) {
int runtimeId = runtimeIdAllocator.getAndIncrement();
runtimeIdToLegacy.put(runtimeId, legacyId);
legacyToRuntimeId.put(legacyId, runtimeId);
return runtimeId;
}
public static int getLegacyId(int runtimeId) {
return runtimeIdToLegacy.get(runtimeId);
}
}

View file

@ -0,0 +1,114 @@
package org.geysermc.connector.world.chunk;
import com.nukkitx.network.VarInts;
import gnu.trove.list.array.TIntArrayList;
import io.netty.buffer.ByteBuf;
import org.geysermc.connector.world.GlobalBlockPalette;
import org.geysermc.connector.world.chunk.bitarray.BitArray;
import org.geysermc.connector.world.chunk.bitarray.BitArrayVersion;
/**
* Adapted from NukkitX: https://github.com/NukkitX/Nukkit
*/
public class BlockStorage {
private static final int SIZE = 4096;
private final TIntArrayList palette;
private BitArray bitArray;
public BlockStorage() {
this(BitArrayVersion.V2);
}
public BlockStorage(BitArrayVersion version) {
this.bitArray = version.createPalette(SIZE);
this.palette = new TIntArrayList(16, -1);
this.palette.add(0); // Air is at the start of every palette.
}
private BlockStorage(BitArray bitArray, TIntArrayList palette) {
this.palette = palette;
this.bitArray = bitArray;
}
private static int getPaletteHeader(BitArrayVersion version, boolean runtime) {
return (version.getId() << 1) | (runtime ? 1 : 0);
}
private static BitArrayVersion getVersionFromHeader(byte header) {
return BitArrayVersion.get(header >> 1, true);
}
public synchronized int getFullBlock(int index) {
return this.legacyIdFor(this.bitArray.get(index));
}
public synchronized void setFullBlock(int index, int legacyId) {
int idx = this.idFor(legacyId);
this.bitArray.set(index, idx);
}
public synchronized void writeToNetwork(ByteBuf buffer) {
buffer.writeByte(getPaletteHeader(bitArray.getVersion(), true));
for (int word : bitArray.getWords()) {
buffer.writeIntLE(word);
}
VarInts.writeInt(buffer, palette.size());
palette.forEach(id -> {
VarInts.writeInt(buffer, id);
return true;
});
}
private void onResize(BitArrayVersion version) {
BitArray newBitArray = version.createPalette(SIZE);
for (int i = 0; i < SIZE; i++) {
newBitArray.set(i, this.bitArray.get(i));
}
this.bitArray = newBitArray;
}
private int idFor(int legacyId) {
int runtimeId = GlobalBlockPalette.getOrCreateRuntimeId(legacyId);
int index = this.palette.indexOf(runtimeId);
if (index != -1) {
return index;
}
index = this.palette.size();
this.palette.add(runtimeId);
BitArrayVersion version = this.bitArray.getVersion();
if (index > version.getMaxEntryValue()) {
BitArrayVersion next = version.next();
if (next != null) {
this.onResize(next);
}
}
return index;
}
private int legacyIdFor(int index) {
int runtimeId = this.palette.get(index);
return GlobalBlockPalette.getLegacyId(runtimeId);
}
public boolean isEmpty() {
if (this.palette.size() == 1) {
return true;
}
for (int word : this.bitArray.getWords()) {
if (Integer.toUnsignedLong(word) != 0L) {
return false;
}
}
return true;
}
public BlockStorage copy() {
return new BlockStorage(this.bitArray.copy(), new TIntArrayList(this.palette));
}
}

View file

@ -0,0 +1,128 @@
package org.geysermc.connector.world.chunk;
import com.nukkitx.network.util.Preconditions;
import io.netty.buffer.ByteBuf;
import lombok.Synchronized;
/**
* Adapted from NukkitX: https://github.com/NukkitX/Nukkit
*/
public class ChunkSection {
private static final int CHUNK_SECTION_VERSION = 8;
public static final int SIZE = 4096;
private final BlockStorage[] storage;
private final NibbleArray blockLight;
private final NibbleArray skyLight;
public ChunkSection() {
this(new BlockStorage[]{new BlockStorage(), new BlockStorage()}, new NibbleArray(SIZE),
new NibbleArray(SIZE));
}
public ChunkSection(BlockStorage[] blockStorage) {
this(blockStorage, new NibbleArray(SIZE), new NibbleArray(SIZE));
}
public ChunkSection(BlockStorage[] storage, byte[] blockLight, byte[] skyLight) {
Preconditions.checkNotNull(storage, "storage");
Preconditions.checkArgument(storage.length > 1, "Block storage length must be at least 2");
for (BlockStorage blockStorage : storage) {
Preconditions.checkNotNull(blockStorage, "storage");
}
this.storage = storage;
this.blockLight = new NibbleArray(blockLight);
this.skyLight = new NibbleArray(skyLight);
}
private ChunkSection(BlockStorage[] storage, NibbleArray blockLight, NibbleArray skyLight) {
this.storage = storage;
this.blockLight = blockLight;
this.skyLight = skyLight;
}
public int getFullBlock(int x, int y, int z, int layer) {
checkBounds(x, y, z);
Preconditions.checkElementIndex(layer, this.storage.length);
return this.storage[layer].getFullBlock(blockPosition(x, y, z));
}
public void setFullBlock(int x, int y, int z, int layer, int fullBlock) {
checkBounds(x, y, z);
Preconditions.checkElementIndex(layer, this.storage.length);
this.storage[layer].setFullBlock(blockPosition(x, y, z), fullBlock);
}
@Synchronized("skyLight")
public byte getSkyLight(int x, int y, int z) {
checkBounds(x, y, z);
return this.skyLight.get(blockPosition(x, y, z));
}
@Synchronized("skyLight")
public void setSkyLight(int x, int y, int z, byte val) {
checkBounds(x, y, z);
this.skyLight.set(blockPosition(x, y, z), val);
}
@Synchronized("blockLight")
public byte getBlockLight(int x, int y, int z) {
checkBounds(x, y, z);
return this.blockLight.get(blockPosition(x, y, z));
}
@Synchronized("blockLight")
public void setBlockLight(int x, int y, int z, byte val) {
checkBounds(x, y, z);
this.blockLight.set(blockPosition(x, y, z), val);
}
public void writeToNetwork(ByteBuf buffer) {
buffer.writeByte(CHUNK_SECTION_VERSION);
buffer.writeByte(this.storage.length);
for (BlockStorage blockStorage : this.storage) {
blockStorage.writeToNetwork(buffer);
}
}
public NibbleArray getSkyLightArray() {
return skyLight;
}
public NibbleArray getBlockLightArray() {
return blockLight;
}
public BlockStorage[] getBlockStorageArray() {
return storage;
}
public boolean isEmpty() {
for (BlockStorage blockStorage : this.storage) {
if (!blockStorage.isEmpty()) {
return false;
}
}
return true;
}
public ChunkSection copy() {
BlockStorage[] storage = new BlockStorage[this.storage.length];
for (int i = 0; i < storage.length; i++) {
storage[i] = this.storage[i].copy();
}
return new ChunkSection(storage, skyLight.copy(), blockLight.copy());
}
public static int blockPosition(int x, int y, int z) {
return (x << 8) | (z << 4) | y;
}
private static void checkBounds(int x, int y, int z) {
Preconditions.checkArgument(x >= 0 && x < 16, "x (%s) is not between 0 and 15", x);
Preconditions.checkArgument(y >= 0 && y < 16, "y (%s) is not between 0 and 15", y);
Preconditions.checkArgument(z >= 0 && z < 16, "z (%s) is not between 0 and 15", z);
}
}

View file

@ -0,0 +1,70 @@
package org.geysermc.connector.world.chunk;
import com.nukkitx.network.util.Preconditions;
/**
* Adapted from NukkitX: https://github.com/NukkitX/Nukkit
*/
public class NibbleArray implements Cloneable {
private final byte[] data;
public NibbleArray(int length) {
data = new byte[length / 2];
}
public NibbleArray(byte[] array) {
data = array;
}
public byte get(int index) {
Preconditions.checkElementIndex(index, data.length * 2);
byte val = data[index / 2];
if ((index & 1) == 0) {
return (byte) (val & 0x0f);
} else {
return (byte) ((val & 0xf0) >>> 4);
}
}
public void set(int index, byte value) {
Preconditions.checkArgument(value >= 0 && value < 16, "Nibbles must have a value between 0 and 15.");
Preconditions.checkElementIndex(index, data.length * 2);
value &= 0xf;
int half = index / 2;
byte previous = data[half];
if ((index & 1) == 0) {
data[half] = (byte) (previous & 0xf0 | value);
} else {
data[half] = (byte) (previous & 0x0f | value << 4);
}
}
public void fill(byte value) {
Preconditions.checkArgument(value >= 0 && value < 16, "Nibbles must have a value between 0 and 15.");
value &= 0xf;
for (int i = 0; i < data.length; i++) {
data[i] = (byte) ((value << 4) | value);
}
}
public void copyFrom(byte[] bytes) {
Preconditions.checkNotNull(bytes, "bytes");
Preconditions.checkArgument(bytes.length == data.length, "length of provided byte array is %s but expected %s", bytes.length,
data.length);
System.arraycopy(bytes, 0, data, 0, data.length);
}
public void copyFrom(NibbleArray array) {
Preconditions.checkNotNull(array, "array");
copyFrom(array.data);
}
public byte[] getData() {
return data;
}
public NibbleArray copy() {
return new NibbleArray(getData().clone());
}
}

View file

@ -0,0 +1,19 @@
package org.geysermc.connector.world.chunk.bitarray;
/**
* Adapted from NukkitX: https://github.com/NukkitX/Nukkit
*/
public interface BitArray {
void set(int index, int value);
int get(int index);
int size();
int[] getWords();
BitArrayVersion getVersion();
BitArray copy();
}

View file

@ -0,0 +1,67 @@
package org.geysermc.connector.world.chunk.bitarray;
import org.geysermc.connector.utils.MathUtils;
/**
* Adapted from NukkitX: https://github.com/NukkitX/Nukkit
*/
public enum BitArrayVersion {
V16(16, 2, null),
V8(8, 4, V16),
V6(6, 5, V8), // 2 bit padding
V5(5, 6, V6), // 2 bit padding
V4(4, 8, V5),
V3(3, 10, V4), // 2 bit padding
V2(2, 16, V3),
V1(1, 32, V2);
final byte bits;
final byte entriesPerWord;
final int maxEntryValue;
final BitArrayVersion next;
BitArrayVersion(int bits, int entriesPerWord, BitArrayVersion next) {
this.bits = (byte) bits;
this.entriesPerWord = (byte) entriesPerWord;
this.maxEntryValue = (1 << this.bits) - 1;
this.next = next;
}
public static BitArrayVersion get(int version, boolean read) {
for (BitArrayVersion ver : values()) {
if ((!read && ver.entriesPerWord <= version) || (read && ver.bits == version)) {
return ver;
}
}
throw new IllegalArgumentException("Invalid palette version: " + version);
}
public BitArray createPalette(int size) {
return this.createPalette(size, new int[MathUtils.ceil((float) size / entriesPerWord)]);
}
public byte getId() {
return bits;
}
public int getMaxEntryValue() {
return maxEntryValue;
}
public int getWordsForSize(int size) {
return MathUtils.ceil((float) size / entriesPerWord);
}
public BitArrayVersion next() {
return next;
}
public BitArray createPalette(int size, int[] words) {
if (this == V3 || this == V5 || this == V6) {
// Padded palettes aren't able to use bitwise operations due to their padding.
return new PaddedBitArray(this, size, words);
} else {
return new Pow2BitArray(this, size, words);
}
}
}

View file

@ -0,0 +1,77 @@
package org.geysermc.connector.world.chunk.bitarray;
import com.nukkitx.network.util.Preconditions;
import org.geysermc.connector.utils.MathUtils;
import java.util.Arrays;
/**
* Adapted from NukkitX: https://github.com/NukkitX/Nukkit
*/
public class PaddedBitArray implements BitArray {
/**
* Array used to store data
*/
private final int[] words;
/**
* Palette version information
*/
private final BitArrayVersion version;
/**
* Number of entries in this palette (<b>not</b> the length of the words array that internally backs this palette)
*/
private final int size;
PaddedBitArray(BitArrayVersion version, int size, int[] words) {
this.size = size;
this.version = version;
this.words = words;
int expectedWordsLength = MathUtils.ceil((float) size / version.entriesPerWord);
if (words.length != expectedWordsLength) {
throw new IllegalArgumentException("Invalid length given for storage, got: " + words.length +
" but expected: " + expectedWordsLength);
}
}
@Override
public void set(int index, int value) {
Preconditions.checkElementIndex(index, this.size);
Preconditions.checkArgument(value >= 0 && value <= this.version.maxEntryValue, "Invalid value");
int arrayIndex = index / this.version.entriesPerWord;
int offset = (index % this.version.entriesPerWord) * this.version.bits;
this.words[arrayIndex] = this.words[arrayIndex] & ~(this.version.maxEntryValue << offset) | (value & this.version.maxEntryValue) << offset;
}
@Override
public int get(int index) {
Preconditions.checkElementIndex(index, this.size);
int arrayIndex = index / this.version.entriesPerWord;
int offset = (index % this.version.entriesPerWord) * this.version.bits;
return (this.words[arrayIndex] >>> offset) & this.version.maxEntryValue;
}
@Override
public int size() {
return this.size;
}
@Override
public int[] getWords() {
return this.words;
}
@Override
public BitArrayVersion getVersion() {
return this.version;
}
@Override
public BitArray copy() {
return new PaddedBitArray(this.version, this.size, Arrays.copyOf(this.words, this.words.length));
}
}

View file

@ -0,0 +1,86 @@
package org.geysermc.connector.world.chunk.bitarray;
import com.nukkitx.network.util.Preconditions;
import org.geysermc.connector.utils.MathUtils;
import java.util.Arrays;
/**
* Adapted from NukkitX: https://github.com/NukkitX/Nukkit
*/
public class Pow2BitArray implements BitArray {
/**
* Array used to store data
*/
private final int[] words;
/**
* Palette version information
*/
private final BitArrayVersion version;
/**
* Number of entries in this palette (<b>not</b> the length of the words array that internally backs this palette)
*/
private final int size;
Pow2BitArray(BitArrayVersion version, int size, int[] words) {
this.size = size;
this.version = version;
this.words = words;
int expectedWordsLength = MathUtils.ceil((float) size / version.entriesPerWord);
if (words.length != expectedWordsLength) {
throw new IllegalArgumentException("Invalid length given for storage, got: " + words.length +
" but expected: " + expectedWordsLength);
}
}
/**
* Sets the entry at the given location to the given value
*/
public void set(int index, int value) {
Preconditions.checkElementIndex(index, this.size);
Preconditions.checkArgument(value >= 0 && value <= this.version.maxEntryValue, "Invalid value %s", value);
int bitIndex = index * this.version.bits;
int arrayIndex = bitIndex >> 5;
int offset = bitIndex & 31;
this.words[arrayIndex] = this.words[arrayIndex] & ~(this.version.maxEntryValue << offset) | (value & this.version.maxEntryValue) << offset;
}
/**
* Gets the entry at the given index
*/
public int get(int index) {
Preconditions.checkElementIndex(index, this.size);
int bitIndex = index * this.version.bits;
int arrayIndex = bitIndex >> 5;
int wordOffset = bitIndex & 31;
return this.words[arrayIndex] >>> wordOffset & this.version.maxEntryValue;
}
/**
* Gets the long array that is used to store the data in this BitArray. This is useful for sending packet data.
*/
public int size() {
return this.size;
}
/**
* {@inheritDoc}
* @return {@inheritDoc}
*/
@Override
public int[] getWords() {
return this.words;
}
public BitArrayVersion getVersion() {
return version;
}
@Override
public BitArray copy() {
return new Pow2BitArray(this.version, this.size, Arrays.copyOf(this.words, this.words.length));
}
}

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,9 @@ remote:
address: 127.0.0.1
# The port of the remote (Java Edition) server
port: 25565
online-mode: false
# Authentication type. Can be offline, online, or hybrid (see the wiki).
auth-type: offline
## the Xbox/MCPE username is the key for the Java server auth-info
## this allows automatic configuration/login to the remote Java server

View file

@ -0,0 +1,42 @@
package org.geysermc.plugin;
public class GeyserPlugin {
/*private List<ConnectedPlayer> players;
@SuppressWarnings("unchecked")
@Override
public void onEnable() {
try {
Class<? extends ProxyServer> clazz = getProxy().getClass();
Field field = clazz.getDeclaredField("connections");
field.setAccessible(true);
players = (List<ConnectedPlayer>) field.get(getProxy());
} catch (Exception e) {
throw new RuntimeException(e);
}
RakNetServer server = new RakNetServer(new InetSocketAddress("0.0.0.0", 65500), 1000000);
server.addListener(new RakNetServerListener() {
@Override
public void handleMessage(RakNetServer server, RakNetClientPeer peer, RakNetPacket packet, int channel) {
if(packet.getId() == 0) {
}
}
});
}
private UUID fromXUID(String XUID) {
String one = XUID.substring(0, XUID.length()/2);
String two = XUID.substring(XUID.length()/2, XUID.length());
long L1 = Long.parseLong(one);
long L2 = Long.parseLong(two);
return new UUID(L1, L2);
}*/
}