func (l *pktHandler) handle() { var err, clientErr error defer func() { if err != nil { log.Print("Connection closed ", err.Error()) if clientErr == nil { clientErr = clientErrGeneral } proto.WriteDisconnect(l.conn, clientErr.Error()) l.conn.Close() } }() err = proto.ServerReadPacketExpect(l.conn, l, []byte{ proto.PacketIdHandshake, proto.PacketIdServerListPing, }) if err != nil { clientErr = clientErrLoginGeneral return } switch l.connType { case connTypeLogin: err, clientErr = l.handleLogin(l.conn) case connTypeServerQuery: err, clientErr = l.handleServerQuery(l.conn) default: err = loginErrorConnType } }
func (l *pktHandler) handleLogin(conn net.Conn) (err, clientErr error) { if !validPlayerUsername.MatchString(l.username) { err = clientErrUsername clientErr = err return } log.Print("Client ", conn.RemoteAddr(), " connected as ", l.username) // TODO Allow admins to connect. if l.gameInfo.maintenanceMsg != "" { err = loginErrorMaintenance clientErr = errors.New(l.gameInfo.maintenanceMsg) return } // Load player permissions. permissions := gamerules.Permissions.UserPermissions(l.username) if !permissions.Has("login") { err = fmt.Errorf("Player %q does not have login permission", l.username) clientErr = clientErrLoginDenied return } if err = proto.ServerWriteHandshake(conn, l.gameInfo.serverId); err != nil { clientErr = clientErrHandshake return } if l.gameInfo.serverId != "-" { var authenticated bool authenticated, err = l.gameInfo.authserver.Authenticate(l.gameInfo.serverId, l.username) if !authenticated || err != nil { var reason string if err != nil { reason = "Authentication check failed: " + err.Error() } else { reason = "Failed authentication" } err = fmt.Errorf("Client %v: %s", conn.RemoteAddr(), reason) clientErr = clientErrAuthFailed return } log.Print("Client ", conn.RemoteAddr(), " passed minecraft.net authentication") } err = proto.ServerReadPacketExpect(conn, l, []byte{ proto.PacketIdLogin, }) if err != nil { clientErr = clientErrLoginGeneral return } entityId := l.gameInfo.entityManager.NewEntity() var playerData *nbt.Compound if playerData, err = l.gameInfo.game.worldStore.PlayerData(l.username); err != nil { clientErr = clientErrUserData return } player := player.NewPlayer(entityId, l.gameInfo.shardManager, conn, l.username, l.gameInfo.worldStore.SpawnPosition, l.gameInfo.game.playerDisconnect, l.gameInfo.game) if playerData != nil { if err = player.UnmarshalNbt(playerData); err != nil { // Don't let the player log in, as they will only have default inventory // etc., which could lose items from them. Better for an administrator to // sort this out. err = fmt.Errorf("Error parsing player data for %q: %v", l.username, err) clientErr = clientErrUserData return } } l.gameInfo.game.playerConnect <- player player.Run() return }