예제 #1
0
        public bool JoinWorld( World newWorld, bool useHandshakePacket )
        {
            if( newWorld.classAccess.rank > player.info.playerClass.rank ) {
                return false;
            }

            if( !newWorld.FirePlayerTriedToJoinEvent( player ) ) {
                return false;
            }

            isBetweenWorlds = true;
            if( player.world != null ) {
                player.world.ReleasePlayer( player );
            }
            ClearQueues();

            client.NoDelay = false;

            World oldWorld = player.world;
            newWorld.AcceptPlayer( player );
            player.world = newWorld;

            // Start sending over the level copy
            if( useHandshakePacket ) {
                writer.Write( PacketWriter.MakeHandshake( player, Config.GetString( ConfigKey.ServerName ), "Loading world \"" + player.world.name + "\"" ) );
            }
            writer.WriteLevelBegin();
            byte[] buffer = new byte[1024];
            int bytesSent = 0;

            // Fetch compressed map copy
            byte[] blockData;
            using( MemoryStream stream = new MemoryStream() ) {
                player.world.map.GetCompressedCopy( stream, true );
                blockData = stream.ToArray();
            }
            Logger.Log( "Session.LoginSequence: Sending compressed level copy ({0} bytes) to {1}.", LogType.Debug,
                           blockData.Length, player.name );

            while ( bytesSent < blockData.Length ) {
                int chunkSize = blockData.Length - bytesSent;
                if ( chunkSize > 1024 ) {
                    chunkSize = 1024;
                }
                Array.Copy( blockData, bytesSent, buffer, 0, chunkSize );
                byte progress = (byte)( 100 * bytesSent / blockData.Length );

                // write in chunks of 1024 bytes or less
                writer.WriteLevelChunk( buffer, chunkSize, progress );
                bytesSent += chunkSize;
            }

            writer.Write( PacketWriter.MakeHandshake( player, Config.GetString( ConfigKey.ServerName ), "Almost there..." ) );

            // Done sending over level copy
            writer.Write( PacketWriter.MakeLevelEnd( player.world.map ) );

            // Send new spawn
            player.pos = player.world.map.spawn;
            Thread.Sleep( 100 );
            writer.WriteAddEntity( 255, player, player.pos );
            writer.WriteTeleport( 255, player.pos );

            isBetweenWorlds = false;

            // Send player list
            player.world.SendPlayerList( player );

            if( Config.GetBool( ConfigKey.LowLatencyMode ) ) {
                client.NoDelay = true;
            }

            Server.FireWorldChangedEvent( player, oldWorld, newWorld );

            // Done.
            GC.Collect( GC.MaxGeneration, GCCollectionMode.Optimized );

            return true;
        }
예제 #2
0
파일: Session.cs 프로젝트: fragmer/fCraft
        internal bool JoinWorldNow( World newWorld, bool firstTime, bool doUseWorldSpawn ) {
            if( newWorld == null ) throw new ArgumentNullException( "newWorld" );

            if( !Player.CanJoin( newWorld ) ) {
                Logger.Log( "Session.JoinWorldNow: Access limits prevented {0} from joining {1}.", LogType.Error,
                            Player.Name, newWorld.Name );
                return false;
            }

            if( !newWorld.FirePlayerTriedToJoinEvent( Player ) ) {
                Logger.Log( "Session.JoinWorldNow: FirePlayerTriedToJoinEvent prevented {0} from joining {1}", LogType.Warning,
                            Player.Name, newWorld.Name );
                return false;
            }

            World oldWorld = Player.World;

            // remove player from the old world
            if( oldWorld != null && oldWorld != newWorld ) {
                if( !oldWorld.ReleasePlayer( Player ) ) {
                    Logger.Log( "Session.JoinWorldNow: Player asked to be released from its world, " +
                                "but the world did not contain the player.", LogType.Error );
                }
            }

            ResetVisibleEntities();

            ClearBlockUpdateQueue();

            Map map;

            // try to join the new world
            if( oldWorld != newWorld ) {
                bool announce = !firstTime && (oldWorld.Name != newWorld.Name);
                map = newWorld.AcceptPlayer( Player, announce );
                if( map == null ) {
                    return false;
                }
            } else {
                map = oldWorld.EnsureMapLoaded();
            }
            Player.World = newWorld;

            // Set spawn point
            Position spawn;
            if( doUseWorldSpawn ) {
                spawn = map.Spawn;
            }else{
                spawn = postJoinPosition;
            }
            Player.Position = spawn;

            // Start sending over the level copy
            if( !firstTime ) {
                SendNow( PacketWriter.MakeHandshake( Player,
                                                     ConfigKey.ServerName.GetString(),
                                                     "Loading world " + newWorld.GetClassyName() ) );
            }

            writer.WriteLevelBegin();
            bytesSent++;

            // enable Nagle's algorithm (in case it was turned off by LowLatencyMode)
            // to avoid wasting bandwidth for map transfer
            client.NoDelay = false;

            // Fetch compressed map copy
            byte[] buffer = new byte[1024];
            int mapBytesSent = 0;
            byte[] blockData;
            using( MemoryStream stream = new MemoryStream() ) {
                map.GetCompressedCopy( stream, true );
                blockData = stream.ToArray();
            }
            Logger.Log( "Session.JoinWorldNow: Sending compressed level copy ({0} bytes) to {1}.", LogType.Debug,
                        blockData.Length, Player.Name );

            // Transfer the map copy
            while( mapBytesSent < blockData.Length ) {
                int chunkSize = blockData.Length - mapBytesSent;
                if( chunkSize > 1024 ) {
                    chunkSize = 1024;
                } else {
                    // CRC fix for ManicDigger
                    for( int i = 0; i < buffer.Length; i++ ) {
                        buffer[i] = 0;
                    }
                }
                Array.Copy( blockData, mapBytesSent, buffer, 0, chunkSize );
                byte progress = (byte)(100 * mapBytesSent / blockData.Length);

                // write in chunks of 1024 bytes or less
                writer.WriteLevelChunk( buffer, chunkSize, progress );
                bytesSent += 1028; 
                mapBytesSent += chunkSize;
            }

            // Done sending over level copy
            writer.WriteLevelEnd( map );
            bytesSent += 7;

            // Send spawn point
            writer.WriteAddEntity( 255, Player, map.Spawn );
            bytesSent += 74;
            writer.WriteTeleport( 255, spawn );
            bytesSent += 10;

            Player.Message( "Joined world {0}", newWorld.GetClassyName() );

            // Turn off Nagel's algorithm again for LowLatencyMode
            if( ConfigKey.LowLatencyMode.GetBool() ) {
                client.NoDelay = true;
            }

            Server.FireWorldChangedEvent( Player, oldWorld, newWorld );

            // Done.
            if( MonoCompat.IsMono ) {
                Server.RequestGC();
            }

            return true;
        }