2019-07-10 06:34:10 +00:00
/ *
2019-07-11 21:30:35 +00:00
* Copyright ( c ) 2019 GeyserMC . http : //geysermc.org
2019-07-10 06:34:10 +00:00
*
2019-07-11 21:30:35 +00:00
* 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 :
2019-07-10 06:34:10 +00:00
*
2019-07-11 21:30:35 +00:00
* 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 .
2019-07-10 06:34:10 +00:00
*
* @author GeyserMC
* @link https : //github.com/GeyserMC/Geyser
* /
package org.geysermc.connector.network.session ;
2019-07-24 06:29:54 +00:00
import com.flowpowered.math.vector.Vector2f ;
2019-09-13 10:49:18 +00:00
import com.flowpowered.math.vector.Vector2i ;
2019-07-24 06:29:54 +00:00
import com.flowpowered.math.vector.Vector3f ;
import com.flowpowered.math.vector.Vector3i ;
2019-09-16 22:28:29 +00:00
import com.github.steveice10.mc.auth.data.GameProfile ;
2019-07-24 06:29:54 +00:00
import com.github.steveice10.mc.auth.exception.request.RequestException ;
2019-07-10 06:34:10 +00:00
import com.github.steveice10.mc.protocol.MinecraftProtocol ;
2019-09-30 22:17:36 +00:00
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace ;
2019-07-10 06:34:10 +00:00
import com.github.steveice10.packetlib.Client ;
import com.github.steveice10.packetlib.event.session.ConnectedEvent ;
import com.github.steveice10.packetlib.event.session.DisconnectedEvent ;
import com.github.steveice10.packetlib.event.session.PacketReceivedEvent ;
import com.github.steveice10.packetlib.event.session.SessionAdapter ;
2019-08-06 02:09:45 +00:00
import com.github.steveice10.packetlib.packet.Packet ;
2019-07-10 06:34:10 +00:00
import com.github.steveice10.packetlib.tcp.TcpSessionFactory ;
import com.nukkitx.protocol.bedrock.BedrockServerSession ;
2019-07-24 06:29:54 +00:00
import com.nukkitx.protocol.bedrock.data.GamePublishSetting ;
import com.nukkitx.protocol.bedrock.data.GameRule ;
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket ;
import com.nukkitx.protocol.bedrock.packet.StartGamePacket ;
2019-07-22 00:52:20 +00:00
import com.nukkitx.protocol.bedrock.packet.TextPacket ;
2019-07-10 06:34:10 +00:00
import lombok.Getter ;
2019-08-06 02:09:45 +00:00
import lombok.Setter ;
2019-07-23 23:16:25 +00:00
import org.geysermc.api.Player ;
import org.geysermc.api.RemoteServer ;
import org.geysermc.api.session.AuthData ;
import org.geysermc.api.window.FormWindow ;
2019-07-10 06:34:10 +00:00
import org.geysermc.connector.GeyserConnector ;
2019-08-06 02:09:45 +00:00
import org.geysermc.connector.entity.PlayerEntity ;
import org.geysermc.connector.inventory.PlayerInventory ;
2019-09-13 10:49:18 +00:00
import org.geysermc.connector.network.session.cache.* ;
2019-07-11 22:39:28 +00:00
import org.geysermc.connector.network.translators.Registry ;
2019-07-24 06:29:54 +00:00
import org.geysermc.connector.utils.Toolbox ;
2019-07-10 06:34:10 +00:00
2019-09-13 13:37:31 +00:00
import java.net.InetSocketAddress ;
2019-08-06 02:09:45 +00:00
import java.util.UUID ;
@Getter
2019-09-13 14:45:55 +00:00
public class GeyserSession implements Player {
2019-09-30 16:44:25 +00:00
2019-09-13 13:37:31 +00:00
private final GeyserConnector connector ;
2019-10-02 20:45:29 +00:00
private final UpstreamSession upstream ;
2019-07-23 23:16:25 +00:00
private RemoteServer remoteServer ;
2019-07-10 06:34:10 +00:00
private Client downstream ;
2019-07-23 23:16:25 +00:00
private AuthData authenticationData ;
2019-08-06 02:09:45 +00:00
private PlayerEntity playerEntity ;
private PlayerInventory inventory ;
2019-07-29 22:20:48 +00:00
2019-09-15 23:34:14 +00:00
private ChunkCache chunkCache ;
2019-08-06 02:09:45 +00:00
private EntityCache entityCache ;
private InventoryCache inventoryCache ;
2019-07-30 02:57:43 +00:00
private ScoreboardCache scoreboardCache ;
2019-09-15 23:34:14 +00:00
private WindowCache windowCache ;
2019-07-30 02:57:43 +00:00
2019-08-06 02:09:45 +00:00
private DataCache < Packet > javaPacketCache ;
2019-09-13 10:49:18 +00:00
@Setter
private Vector2i lastChunkPosition = null ;
2019-09-21 07:42:44 +00:00
@Setter
private int renderDistance ;
2019-09-13 10:49:18 +00:00
2019-07-24 06:29:54 +00:00
private boolean loggedIn ;
2019-09-21 07:42:44 +00:00
private boolean loggingIn ;
2019-07-24 06:29:54 +00:00
2019-08-06 02:09:45 +00:00
@Setter
private boolean spawned ;
2019-07-10 06:34:10 +00:00
private boolean closed ;
2019-09-30 16:44:25 +00:00
@Setter
2019-09-30 22:17:36 +00:00
private Vector3i blockDiggingPos = Vector3i . ZERO ;
@Setter
private BlockFace blockDiggingFace = BlockFace . DOWN ;
2019-09-30 16:44:25 +00:00
2019-07-10 06:34:10 +00:00
public GeyserSession ( GeyserConnector connector , BedrockServerSession bedrockServerSession ) {
this . connector = connector ;
2019-10-02 20:45:29 +00:00
this . upstream = new UpstreamSession ( bedrockServerSession ) ;
2019-07-23 23:16:25 +00:00
2019-09-15 23:34:14 +00:00
this . chunkCache = new ChunkCache ( this ) ;
2019-08-06 02:09:45 +00:00
this . entityCache = new EntityCache ( this ) ;
2019-07-29 22:20:48 +00:00
this . inventoryCache = new InventoryCache ( this ) ;
2019-07-30 02:57:43 +00:00
this . scoreboardCache = new ScoreboardCache ( this ) ;
2019-09-15 23:34:14 +00:00
this . windowCache = new WindowCache ( this ) ;
2019-07-30 02:57:43 +00:00
2019-09-25 21:52:28 +00:00
this . playerEntity = new PlayerEntity ( new GameProfile ( UUID . randomUUID ( ) , " unknown " ) , 1 , 1 , Vector3f . ZERO , Vector3f . ZERO , Vector3f . ZERO ) ;
2019-08-06 02:09:45 +00:00
this . inventory = new PlayerInventory ( ) ;
2019-09-21 07:42:44 +00:00
this . javaPacketCache = new DataCache < > ( ) ;
2019-08-06 02:09:45 +00:00
this . spawned = false ;
2019-07-24 06:29:54 +00:00
this . loggedIn = false ;
2019-08-06 02:09:45 +00:00
this . inventoryCache . getInventories ( ) . put ( 0 , inventory ) ;
2019-07-10 06:34:10 +00:00
}
2019-07-23 23:16:25 +00:00
public void connect ( RemoteServer remoteServer ) {
2019-07-24 06:29:54 +00:00
// This has to be sent first so the player actually joins
startGame ( ) ;
2019-07-10 06:34:10 +00:00
2019-07-24 06:29:54 +00:00
this . remoteServer = remoteServer ;
2019-09-11 20:28:48 +00:00
if ( ! ( connector . getConfig ( ) . getRemote ( ) . getAuthType ( ) . hashCode ( ) = = " online " . hashCode ( ) ) ) {
2019-07-24 06:29:54 +00:00
connector . getLogger ( ) . info ( " Attempting to login using offline mode... authentication is disabled. " ) ;
authenticate ( authenticationData . getName ( ) ) ;
}
}
2019-07-10 06:34:10 +00:00
2019-07-24 06:29:54 +00:00
public void authenticate ( String username ) {
authenticate ( username , " " ) ;
2019-08-09 01:42:55 +00:00
connector . addPlayer ( this ) ;
2019-07-24 06:29:54 +00:00
}
public void authenticate ( String username , String password ) {
if ( loggedIn ) {
connector . getLogger ( ) . severe ( username + " is already logged in! " ) ;
return ;
}
2019-07-10 06:34:10 +00:00
2019-09-21 07:42:44 +00:00
loggedIn = true ;
// new thread so clients don't timeout
new Thread ( ( ) - > {
try {
MinecraftProtocol protocol ;
if ( password ! = null & & ! password . isEmpty ( ) ) {
protocol = new MinecraftProtocol ( username , password ) ;
} else {
protocol = new MinecraftProtocol ( username ) ;
2019-07-24 06:29:54 +00:00
}
2019-09-21 07:42:44 +00:00
downstream = new Client ( remoteServer . getAddress ( ) , remoteServer . getPort ( ) , protocol , new TcpSessionFactory ( ) ) ;
downstream . getSession ( ) . addListener ( new SessionAdapter ( ) {
@Override
public void connected ( ConnectedEvent event ) {
loggingIn = false ;
loggedIn = true ;
connector . getLogger ( ) . info ( authenticationData . getName ( ) + " (logged in as: " + protocol . getProfile ( ) . getName ( ) + " ) " + " has connected to remote java server on address " + remoteServer . getAddress ( ) ) ;
playerEntity . setUuid ( protocol . getProfile ( ) . getId ( ) ) ;
playerEntity . setUsername ( protocol . getProfile ( ) . getName ( ) ) ;
}
@Override
public void disconnected ( DisconnectedEvent event ) {
loggingIn = false ;
loggedIn = false ;
connector . getLogger ( ) . info ( authenticationData . getName ( ) + " has disconnected from remote java server on address " + remoteServer . getAddress ( ) + " because of " + event . getReason ( ) ) ;
upstream . disconnect ( event . getReason ( ) ) ;
}
@Override
public void packetReceived ( PacketReceivedEvent event ) {
2019-10-02 20:45:29 +00:00
if ( ! closed ) {
2019-09-21 07:42:44 +00:00
Registry . JAVA . translate ( event . getPacket ( ) . getClass ( ) , event . getPacket ( ) , GeyserSession . this ) ;
2019-10-02 20:45:29 +00:00
}
2019-09-21 07:42:44 +00:00
}
} ) ;
downstream . getSession ( ) . connect ( ) ;
} catch ( RequestException ex ) {
ex . printStackTrace ( ) ;
}
} ) . start ( ) ;
2019-07-10 06:34:10 +00:00
}
public void disconnect ( String reason ) {
if ( ! closed ) {
2019-07-24 06:29:54 +00:00
loggedIn = false ;
2019-08-02 20:54:40 +00:00
if ( downstream ! = null & & downstream . getSession ( ) ! = null ) {
downstream . getSession ( ) . disconnect ( reason ) ;
}
2019-09-13 13:37:31 +00:00
if ( upstream ! = null & & ! upstream . isClosed ( ) ) {
2019-08-02 20:54:40 +00:00
upstream . disconnect ( reason ) ;
}
2019-07-10 06:34:10 +00:00
}
2019-08-06 02:09:45 +00:00
closed = true ;
2019-07-10 06:34:10 +00:00
}
public boolean isClosed ( ) {
return closed ;
}
public void close ( ) {
disconnect ( " Server closed. " ) ;
}
2019-07-23 23:16:25 +00:00
public void setAuthenticationData ( AuthData authData ) {
authenticationData = authData ;
2019-07-10 06:34:10 +00:00
}
2019-07-22 00:52:20 +00:00
@Override
public String getName ( ) {
return authenticationData . getName ( ) ;
}
@Override
public void sendMessage ( String message ) {
TextPacket textPacket = new TextPacket ( ) ;
textPacket . setPlatformChatId ( " " ) ;
textPacket . setSourceName ( " " ) ;
textPacket . setXuid ( " " ) ;
textPacket . setType ( TextPacket . Type . CHAT ) ;
textPacket . setNeedsTranslation ( false ) ;
textPacket . setMessage ( message ) ;
upstream . sendPacket ( textPacket ) ;
}
@Override
public void sendMessage ( String [ ] messages ) {
for ( String message : messages ) {
sendMessage ( message ) ;
}
}
2019-07-23 23:16:25 +00:00
public void sendForm ( FormWindow window , int id ) {
windowCache . showWindow ( window , id ) ;
}
2019-07-10 06:34:10 +00:00
2019-09-13 13:37:31 +00:00
@Override
public InetSocketAddress getSocketAddress ( ) {
return this . upstream . getAddress ( ) ;
}
2019-07-23 23:16:25 +00:00
public void sendForm ( FormWindow window ) {
windowCache . showWindow ( window ) ;
2019-07-10 06:34:10 +00:00
}
2019-07-24 06:29:54 +00:00
private void startGame ( ) {
StartGamePacket startGamePacket = new StartGamePacket ( ) ;
2019-08-06 02:09:45 +00:00
startGamePacket . setUniqueEntityId ( playerEntity . getGeyserId ( ) ) ;
startGamePacket . setRuntimeEntityId ( playerEntity . getGeyserId ( ) ) ;
2019-07-24 06:29:54 +00:00
startGamePacket . setPlayerGamemode ( 0 ) ;
2019-08-06 02:09:45 +00:00
startGamePacket . setPlayerPosition ( new Vector3f ( 0 , 69 , 0 ) ) ;
2019-07-24 06:29:54 +00:00
startGamePacket . setRotation ( new Vector2f ( 1 , 1 ) ) ;
2019-08-06 02:09:45 +00:00
startGamePacket . setSeed ( 0 ) ;
startGamePacket . setDimensionId ( playerEntity . getDimension ( ) ) ;
startGamePacket . setGeneratorId ( 1 ) ;
2019-07-24 06:29:54 +00:00
startGamePacket . setLevelGamemode ( 0 ) ;
startGamePacket . setDifficulty ( 1 ) ;
startGamePacket . setDefaultSpawn ( new Vector3i ( 0 , 0 , 0 ) ) ;
startGamePacket . setAcheivementsDisabled ( true ) ;
startGamePacket . setTime ( 0 ) ;
startGamePacket . setEduLevel ( false ) ;
startGamePacket . setEduFeaturesEnabled ( false ) ;
startGamePacket . setRainLevel ( 0 ) ;
startGamePacket . setLightningLevel ( 0 ) ;
startGamePacket . setMultiplayerGame ( true ) ;
startGamePacket . setBroadcastingToLan ( true ) ;
startGamePacket . getGamerules ( ) . add ( new GameRule < > ( " showcoordinates " , true ) ) ;
startGamePacket . setPlatformBroadcastMode ( GamePublishSetting . PUBLIC ) ;
startGamePacket . setXblBroadcastMode ( GamePublishSetting . PUBLIC ) ;
startGamePacket . setCommandsEnabled ( true ) ;
startGamePacket . setTexturePacksRequired ( false ) ;
startGamePacket . setBonusChestEnabled ( false ) ;
startGamePacket . setStartingWithMap ( false ) ;
startGamePacket . setTrustingPlayers ( true ) ;
startGamePacket . setDefaultPlayerPermission ( 1 ) ;
startGamePacket . setServerChunkTickRange ( 4 ) ;
startGamePacket . setBehaviorPackLocked ( false ) ;
startGamePacket . setResourcePackLocked ( false ) ;
startGamePacket . setFromLockedWorldTemplate ( false ) ;
startGamePacket . setUsingMsaGamertagsOnly ( false ) ;
startGamePacket . setFromWorldTemplate ( false ) ;
startGamePacket . setWorldTemplateOptionLocked ( false ) ;
2019-08-06 02:09:45 +00:00
startGamePacket . setLevelId ( " world " ) ;
2019-07-24 06:29:54 +00:00
startGamePacket . setWorldName ( " world " ) ;
startGamePacket . setPremiumWorldTemplateId ( " 00000000-0000-0000-0000-000000000000 " ) ;
startGamePacket . setCurrentTick ( 0 ) ;
startGamePacket . setEnchantmentSeed ( 0 ) ;
startGamePacket . setMultiplayerCorrelationId ( " " ) ;
2019-10-04 17:25:08 +00:00
startGamePacket . setCachedPalette ( Toolbox . CACHED_PALLETE . retainedDuplicate ( ) ) ;
2019-07-24 06:29:54 +00:00
startGamePacket . setItemEntries ( Toolbox . ITEMS ) ;
upstream . sendPacket ( startGamePacket ) ;
PlayStatusPacket playStatusPacket = new PlayStatusPacket ( ) ;
playStatusPacket . setStatus ( PlayStatusPacket . Status . PLAYER_SPAWN ) ;
upstream . sendPacket ( playStatusPacket ) ;
2019-10-02 20:45:29 +00:00
upstream . setFrozen ( true ) ; // will freeze until the client decides it is ready
2019-07-24 06:29:54 +00:00
}
2019-08-24 03:49:48 +00:00
}