示例#1
0
    private void SendJoinGame(IMinecraftUser user)
    {
        using var joinPacket = new JoinGamePacket();

        joinPacket.WriteInt32(user.Player.EntityId);                  // EntityID
        joinPacket.WriteBoolean(_gameConfiguration.Value.IsHardcore); // Is hardcore
        joinPacket.WriteByte((byte)_gameConfiguration.Value.Mode);    // GameMode
        joinPacket.WriteSByte((sbyte)ServerGameModeType.Survival);    // Previous game mode

        var worldList = new[] { "minecraft:world" };

        joinPacket.WriteVarInt32(worldList.Length); // World count
        foreach (string world in worldList)
        {
            joinPacket.WriteString(world);
        }

        WriteDimensionsAndBiomes(_registry.Dimensions, _registry.Biomes, joinPacket);

        Dimension currentDimension = _registry.Dimensions.First();

        WriteDimension(currentDimension, joinPacket);
        joinPacket.WriteString(currentDimension.Name);                                                                                                                    // World name identifier

        joinPacket.WriteInt64(_gameConfiguration.Value.Seed);                                                                                                             // Seed
        joinPacket.WriteVarInt32((int)_serverConfiguration.Value.MaxPlayers);                                                                                             // Max players
        joinPacket.WriteVarInt32(Math.Clamp(_gameConfiguration.Value.RenderingDistance, RedstoneContants.MinimumRenderDistance, RedstoneContants.MaximumRenderDistance)); // Render distance (2-32 chunks)
        joinPacket.WriteBoolean(_serverConfiguration.Value.ReducedDebugInfo);                                                                                             // Reduced debug info
        joinPacket.WriteBoolean(_gameConfiguration.Value.DisplayRespawnScreen);                                                                                           // Respawn screen
        joinPacket.WriteBoolean(_serverConfiguration.Value.Debug);                                                                                                        // Is debug
        joinPacket.WriteBoolean(_serverConfiguration.Value.FlatTerrain);                                                                                                  // is flat terrain

        user.Send(joinPacket);
    }
示例#2
0
    public void OnPlayerDigging(IMinecraftUser user, IMinecraftPacket packet)
    {
        var status   = (DiggingType)packet.ReadVarInt32();
        var position = packet.ReadPosition();
        var face     = (BlockFaceType)packet.ReadByte();

        _logger.LogTrace($"Status={status};Position={position};Face={face}");

        if (user.Player.GameMode is ServerGameModeType.Creative)
        {
            IBlock previousBlock = user.Player.Map.GetBlock(position);

            if (previousBlock.IsAir)
            {
                throw new InvalidOperationException($"Cannot dig air blocks ({position})");
            }

            using var playerDiggingAck = new AcknowledgePlayerDiggingPacket(position, previousBlock, DiggingType.Started);
            user.Player.SendPacketToVisibleEntities(playerDiggingAck);

            using var blockChange = new BlockChangePacket(BlockType.Air, position);
            user.Player.SendPacketToVisibleEntities(blockChange);

            IBlock block = user.Player.Map.SetBlock(BlockType.Air, position);

            using var chunkPacket = new ChunkDataPacket(block.Chunk);
            user.Player.SendPacketToVisibleEntities(chunkPacket, includeEntity: true);
        }
        else
        {
            // TODO: other modes
        }
    }
示例#3
0
    public void OnPlayerPosition(IMinecraftUser user, IMinecraftPacket packet)
    {
        Position destinationPosition = packet.ReadAbsolutePosition();
        bool     isOnGround          = packet.ReadBoolean();

        user.Player.Move(destinationPosition, isOnGround);
    }
示例#4
0
    public void OnPing(IMinecraftUser user, IMinecraftPacket packet)
    {
        var pingPacket = new StatusPingPacket(packet);

        using var pongPacket = new StatusPongPacket(pingPacket.Payload);
        user.Send(pongPacket);
    }
示例#5
0
    private void SendUpdateViewPosition(IMinecraftUser user)
    {
        // TODO: get chunk position according to current user's position.
        using var packet = new UpdateViewPositionPacket(0, 0);

        user.Send(packet);
    }
    public void OnPlayerRotation(IMinecraftUser user, IMinecraftPacket packet)
    {
        float yawAngle   = packet.ReadSingle();
        float pitchAngle = packet.ReadSingle();
        bool  isOnGround = packet.ReadBoolean();

        user.Player.Rotate(yawAngle, pitchAngle);
    }
示例#7
0
    private void SendServerBrand(IMinecraftUser user)
    {
        using var serverBrandPacket = new PluginMessagePacket("minecraft:brand");

        serverBrandPacket.WriteString(_serverConfiguration.Value.Name);

        user.Send(serverBrandPacket);
    }
示例#8
0
    private void SendLoginSucess(IMinecraftUser user)
    {
        using var p = new MinecraftPacket(ClientLoginPacketType.LoginSuccess);

        p.WriteUUID(user.Id);
        p.WriteString(user.Username);

        user.Send(p);
    }
    public void OnPlayerPositionAndRotation(IMinecraftUser user, IMinecraftPacket packet)
    {
        Position destinationPosition = packet.ReadAbsolutePosition();
        float    yawAngle            = packet.ReadSingle();
        float    pitchAngle          = packet.ReadSingle();
        bool     isOnGround          = packet.ReadBoolean();

        user.Player.MoveAndRotate(destinationPosition, yawAngle, pitchAngle, isOnGround);
    }
示例#10
0
 public Player(IMinecraftUser user, Guid id, string name, IServiceProvider serviceProvider)
     : base(serviceProvider)
 {
     _user             = user;
     Id                = id;
     Name              = name;
     _keepAliveIdQueue = new Queue <long>();
     _gameOptions      = serviceProvider.GetRequiredService <IOptions <GameOptions> >();
     Inventory         = new Inventory(this);
     HotBar            = new HotBar(this);
 }
示例#11
0
    private void SendChunkData(IMinecraftUser user)
    {
        IChunk chunk = _worldManager.Overworld.GetRegion(0, 0).GetChunk(0, 0);

        chunk.GenerateHeightMap();

        // Temporary
        _worldManager.Overworld.AddPlayer(user.Player);

        using var packet = new ChunkDataPacket(chunk, serializeFullChunk: true);
        user.Send(packet);
    }
示例#12
0
    private void SendPlayerPositionAndLook(IMinecraftUser user, Position position)
    {
        using var packet = new PlayerPositionAndLookPacket();

        packet.WriteDouble(position.X); // x
        packet.WriteDouble(position.Y); // y
        packet.WriteDouble(position.Z); // z
        packet.WriteSingle(0);          // yaw
        packet.WriteSingle(0);          // pitch
        packet.WriteByte(0);
        //packet.WriteByte(0x01 | 0x02 | 0x04); // position flags (x|y|z)
        packet.WriteVarInt32(0); // teleport id

        user.Send(packet);
    }
示例#13
0
    public void OnHeldItemChange(IMinecraftUser user, IMinecraftPacket packet)
    {
        short slot = packet.ReadInt16();

        if (slot < 0 || slot > 8)
        {
            throw new IndexOutOfRangeException($"Slot was out of bounds: {slot}");
        }

        _logger.LogDebug($"Current slot: {slot}");

        user.Player.HotBar.SetSlotIndex(slot);

        _logger.LogDebug($"Selected Item: ItemId = {user.Player.HotBar.SelectedSlot.ItemId}");
    }
示例#14
0
    public void OnPlayerBlockPlacement(IMinecraftUser user, IMinecraftPacket packet)
    {
        var      handType      = (HandType)packet.ReadVarInt32();
        Position blockPosition = packet.ReadPosition();
        var      blockFace     = (BlockFaceType)packet.ReadVarInt32();
        float    cursorX       = packet.ReadSingle();
        float    cursorY       = packet.ReadSingle();
        float    cursorZ       = packet.ReadSingle();
        bool     isInsideBlock = packet.ReadBoolean();

        // TODO: check if the current player is interacting with an interactable object.
        // Like: Chest, anvil, crafting table.

        IItemSlot currentHeldItem = user.Player.HotBar.SelectedSlot;

        if (currentHeldItem.HasItem)
        {
            BlockData block        = _registry.Blocks.FirstOrDefault(x => x.ItemId == currentHeldItem.ItemId);
            BlockType blockToPlace = block.Type;

            if (blockToPlace is not BlockType.Air)
            {
                Position realBlockPosition = blockFace switch
                {
                    BlockFaceType.Bottom => new Position(blockPosition.X, blockPosition.Y - 1, blockPosition.Z),
                    BlockFaceType.Top => new Position(blockPosition.X, blockPosition.Y + 1, blockPosition.Z),
                    BlockFaceType.North => new Position(blockPosition.X, blockPosition.Y, blockPosition.Z - 1),
                    BlockFaceType.South => new Position(blockPosition.X, blockPosition.Y, blockPosition.Z + 1),
                    BlockFaceType.West => new Position(blockPosition.X - 1, blockPosition.Y, blockPosition.Z),
                    BlockFaceType.East => new Position(blockPosition.X + 1, blockPosition.Y, blockPosition.Z),
                    _ => throw new InvalidOperationException("Invalid block face type.")
                };

                _logger.LogDebug($"Placing block '{blockToPlace}' at position {realBlockPosition}");

                user.Player.Map.SetBlock(blockToPlace, (int)realBlockPosition.X, (int)realBlockPosition.Y, (int)realBlockPosition.Z);

                using var blockChangePacket = new BlockChangePacket(blockToPlace, blockPosition);
                user.Player.SendPacketToVisibleEntities(blockChangePacket);

                using var chunkDataPacket = new ChunkDataPacket(user.Player.Chunk);
                user.Player.SendPacketToVisibleEntities(chunkDataPacket);
            }
        }
    }
}
示例#15
0
    public void OnChatMessage(IMinecraftUser user, IMinecraftPacket packet)
    {
        string message = packet.ReadString();

        if (message.Length > 256)
        {
            user.Disconnect("Chat message exceeds 256 characters.");
        }

        if (message.StartsWith(RedstoneContants.CommandPrefix))
        {
            // TODO: interpret commands
        }
        else
        {
            user.Player.Speak(message);
        }
    }
示例#16
0
    public void OnCreativeInventoryAction(IMinecraftUser user, IMinecraftPacket packet)
    {
        short slot = (short)(packet.ReadInt16() - RedstoneContants.PlayerInventoryHotbarOffset);
        // item slot structure
        bool present = packet.ReadBoolean();

        if (present)
        {
            int         itemId     = packet.ReadVarInt32();
            byte        itemCount  = packet.ReadByte();
            NbtCompound itemExtras = packet.ReadNbtCompound();

            _logger.LogInformation($"Item with id: {itemId} (x{itemCount}) set at slot {slot}");
            user.Player.HotBar.SetItem(slot, itemId, itemCount);
        }
        else
        {
            _logger.LogInformation($"Clearing item slot '{slot}'");
            user.Player.HotBar.ClearItem(slot);
        }
    }
示例#17
0
    public void OnHandshake(IMinecraftUser user, IMinecraftPacket packet)
    {
        var handshake = new HandshakePacket(packet);

        user.UpdateStatus(handshake.NextState);
    }
示例#18
0
    public void OnAnimation(IMinecraftUser user, IMinecraftPacket packet)
    {
        var hand = (HandType)packet.ReadVarInt32();

        user.Player.SwingHand(hand);
    }
示例#19
0
    public void OnLogin(IMinecraftUser user, IMinecraftPacket packet)
    {
        string username = packet.ReadString();

        _logger.LogInformation($"{user.Username} trying to log-in");

        if (_serverConfiguration.Value.Mode == ServerModeType.Offline)
        {
            if (_serverConfiguration.Value.AllowMultiplayerDebug)
            {
                int count = _server.ConnectedPlayers.Count(x => x.Username.StartsWith(username));

                if (count > 0 && _server.ConnectedPlayers.Any(x => x.Username.Equals(username)))
                {
                    username = $"{username} ({count})";
                }
            }
            else
            {
                if (_server.HasUser(username))
                {
                    user.Disconnect($"A player with the same name '{username}' is already connected.");
                    return;
                }
            }

            Guid playerId = GuidUtilities.GenerateGuidFromString($"OfflinePlayer:{username}");

            // TODO: initialize current player
            // TODO: Read player data from storage (DB or file-system)
            user.LoadPlayer(playerId, username);

            // DEBUG
            user.Player.Position.X = 8;
            user.Player.Position.Y = 2;
            user.Player.Position.Z = 8;

            SendLoginSucess(user);
            user.UpdateStatus(MinecraftUserStatus.Play);
            _server.Events.OnPlayerJoinGame(new PlayerJoinEventArgs(user.Player));

            SendJoinGame(user);
            SendServerBrand(user);
            // TODO: held item changed
            // TODO: declare recipes
            // TODO: Tags
            // TODO: Entity status
            // TODO: declare commands
            // TODO: Unlock recipes
            SendPlayerPositionAndLook(user, user.Player.Position);
            SendPlayerInfo(user, PlayerInfoActionType.Add);
            SendPlayerInfo(user, PlayerInfoActionType.UpdateLatency);
            SendUpdateViewPosition(user);
            // TODO: Update light
            SendChunkData(user);
            SendUpdateViewPosition(user);
            // TODO: World border
            SendSpawnPosition(user, Position.Zero);
            SendPlayerPositionAndLook(user, user.Player.Position);

            user.Player.IsSpawned = true;
        }
        else
        {
            // TODO: login to Mojang API
        }
    }
示例#20
0
    private void SendSpawnPosition(IMinecraftUser user, Position position)
    {
        using var packet = new SpawnPositionPacket(position);

        user.Send(packet);
    }
示例#21
0
    private void SendPlayerInfo(IMinecraftUser user, PlayerInfoActionType actionType)
    {
        using var packet = new PlayerInfoPacket(actionType, _server.ConnectedPlayers.Select(x => x.Player));

        user.Send(packet);
    }
示例#22
0
    public void OnStatusRequest(IMinecraftUser user, IMinecraftPacket _)
    {
        using var responsePacket = new StatusResponsePacket(_server.GetServerStatus());

        user.Send(responsePacket);
    }