forked from GeyserMC/Geyser
Merge pull request #29 from GeyserMC/chunks
Merge branch 'chunks' into master
This commit is contained in:
commit
ed79f59d28
37 changed files with 11189 additions and 9719 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -223,3 +223,4 @@ nbdist/
|
|||
|
||||
### Geyser ###
|
||||
config.yml
|
||||
logs/
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -121,7 +121,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ public class JavaItem {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id & identifier.hashCode();
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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
|
||||
|
|
42
plugin/src/main/java/org/geysermc/plugin/GeyserPlugin.java
Normal file
42
plugin/src/main/java/org/geysermc/plugin/GeyserPlugin.java
Normal 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);
|
||||
}*/
|
||||
}
|
Loading…
Reference in a new issue