func (cc *GameConnection) HandleNewConnection() { defer func() { delete(cc.Server.PlayerConnections, cc.Player.Uuid) cc.EntityServer = nil }() cc.Server.PlayerConnections[cc.Player.Uuid] = make(chan *protocol.Packet, 256) cc.Player.EntityId = int64(len(cc.Server.PlayerConnections)+1) + cc.Server.Offset cc.Player.HeadY = 105 cc.Player.FeetY = 105 - 1.62 cc.Player.OnGround = true var err error cc.EntityServer, err = cc.Server.FindEntityServer(cc.Player) if err != nil { log.Printf("Failed to connect to entity server: %s", err) protocol.WriteNewPacket(cc.ConnEncrypted, protocol.PreAuthKickID, protocol.CreateJsonMessage("Failed to connect to entity server!", "")) return } cc.EntityServer.SendMessage(&protobuf.PlayerAction{ Player: cc.Player, Action: protobuf.PlayerAction_JOIN, }) var x, z int64 for x = -8; x < 8; x++ { for z = -8; z < 8; z++ { conn, err := cc.Server.Cluster.ChunkConnection(x, z, cc.Server) if err != nil { log.Printf("Failed to connect to chunk server (%d, %d): %s", x, z, err) protocol.WriteNewPacket(cc.ConnEncrypted, protocol.PreAuthKickID, protocol.CreateJsonMessage("Failed to connect to chunk server!", "")) return } conn.SendMessage(&protobuf.ChunkRequest{ X: x, Z: z, Uuid: cc.Player.Uuid, }) } } protocol.WriteNewPacket(cc.ConnEncrypted, protocol.LoginSuccessID, cc.Player.Uuid, cc.Player.Username) protocol.WriteNewPacket(cc.ConnEncrypted, protocol.JoinGameID, int32(cc.Player.EntityId), uint8(1), byte(0), uint8(1), uint8(cc.Server.Size), "default") protocol.WriteNewPacket(cc.ConnEncrypted, protocol.SpawnPositionID, int32(0), int32(128), int32(0)) protocol.WriteNewPacket(cc.ConnEncrypted, protocol.PlayerAbilitiesID, byte(1), float32(0.05), float32(0.1)) protocol.WriteNewPacket(cc.ConnEncrypted, protocol.PlayerPositionAndLookID, cc.Player.X, cc.Player.HeadY, cc.Player.Z, cc.Player.Yaw, cc.Player.Pitch, cc.Player.OnGround) go cc.Server.DrainPlayerConnections(cc) cc.HandleEncryptedConnection() }
func (cc *GameConnection) HandleAuth() { defer func() { delete(cc.Server.Clients, cc) cc.Conn.Close() }() remoteAddr := cc.Conn.RemoteAddr().String() state := 0 verifyToken := make([]byte, 0) for { cc.Conn.SetReadDeadline(time.Now().Add(time.Second * 10)) id, buf, err := protocol.ReadPacket(cc.Conn) if err != nil { err2, ok := err.(net.Error) if ok && err2.Timeout() { log.Printf("Timeout handling connection (%s): %s", remoteAddr, err2.Error()) } return } else { switch id { case 0x00: // Handshake, Status Request, Login start if state == 1 { log.Printf("Server pinged from: %s", remoteAddr) protocol.WriteNewPacket(cc.Conn, protocol.StatusResponseID, cc.Server.GetMinecraftStatus()) } else if state == 2 { cc.Player.Username, _ = protocol.ReadString(buf, 0) log.Printf("Got connection from %s", cc.Player.Username) defer log.Printf("Connection closed for %s", cc.Player.Username) pubKey := cc.Server.keyPair.Serialize() verifyToken = protocol.GenerateKey(16) protocol.WriteNewPacket(cc.Conn, protocol.EncryptionRequestID, "", int16(len(pubKey)), pubKey, int16(len(verifyToken)), verifyToken) } else { _, n := protocol.ReadVarint(buf, 0) // version _, n = protocol.ReadString(buf, n) // address _, n = protocol.ReadShort(buf, n) // port nextstate, n := protocol.ReadVarint(buf, n) state = int(nextstate) } case 0x01: // Encryption Response, Ping Request if state == 2 { secretLen, n := protocol.ReadShort(buf, 0) secretEncrypted, n := protocol.ReadBytes(buf, n, secretLen) tokenLen, n := protocol.ReadShort(buf, n) tokenEncrypted, n := protocol.ReadBytes(buf, n, tokenLen) verifyToken2, err := protocol.DecryptRSABytes(tokenEncrypted, cc.Server.keyPair) if err != nil { log.Printf("Error decrypting RSA token: %s", err.Error()) return } else if !bytes.Equal(verifyToken, verifyToken2) { log.Printf("Error: verification token did not match!") return } sharedSecret, err := protocol.DecryptRSABytes(secretEncrypted, cc.Server.keyPair) if err != nil { log.Printf("Error decrypting RSA secret: %s", err.Error()) return } cc.ConnEncrypted, err = protocol.NewAESConn(cc.Conn, sharedSecret) if err != nil { log.Printf("Error creating AES connection: %s", err.Error()) } cc.Player.Uuid, err = protocol.CheckAuth(cc.Player.Username, "", cc.Server.keyPair, sharedSecret) if err != nil { log.Printf("Failed to verify username %s: %s", cc.Player.Username, err) protocol.WriteNewPacket(cc.ConnEncrypted, protocol.PreAuthKickID, protocol.CreateJsonMessage("Failed to verify username!", "")) return } // protocol.WriteNewPacket(cc.ConnEncrypted, protocol.PreAuthKickID, protocol.CreateJsonMessage("Server will bbl", "blue")) cc.HandleNewConnection() return } else { time, _ := protocol.ReadLong(buf, 0) //fmt.Printf("Ping: %d\n", time) protocol.WriteNewPacket(cc.Conn, protocol.PingResponseID, time) return } default: log.Printf("Unknown Packet (state:%d): 0x%X : %s", state, id, hex.Dump(buf)) return } } } }
func (s *Server) HandleMessage(message interface{}, conn *network.InternalConnection) { switch req := message.(type) { case *protobuf.ChatMessage: player := s.Players[req.Uuid] message := protocol.CreateJsonMessage("<"+player.Username+"> "+req.Message, "") log.Printf("Chat: %s", message.Message) for uuid, p := range s.Players { p.Conn.SendMessage(&protobuf.ChatMessage{ Message: message.String(), Uuid: uuid, }) } case *protobuf.BlockUpdate: for uuid, p := range s.Players { p.Conn.SendMessage(&protobuf.BlockUpdate{ X: req.X, Y: req.Y, Z: req.Z, BlockId: req.BlockId, BlockMetadata: req.BlockMetadata, Uuid: uuid, }) } case *protobuf.PlayerAction: player, action := req.GetPlayer(), req.GetAction() switch action { case protobuf.PlayerAction_JOIN: s.Players[player.Uuid] = &PlayerEntity{ Player: protobuf.Player{ Uuid: player.Uuid, Username: player.Username, EntityId: player.EntityId, X: 0, HeadY: 105, FeetY: 105 - 1.62, Z: 0, }, LastX: 0, LastY: 105 - 1.62, LastZ: 0, Conn: conn, } log.Printf("Player joined (%d): %s", player.EntityId, player.Username) cx, cz := world.ChunkCoordsToNode(0, 0) for ix := cx; ix >= cx-world.ChunkWidthPerNode; ix -= world.ChunkWidthPerNode { for iz := cz; iz >= cz-world.ChunkWidthPerNode; iz -= world.ChunkWidthPerNode { conn, err := s.Cluster.ChunkConnection(ix, iz, s) if err != nil { log.Printf("Chunk subscription error (%d, %d): %s", ix, iz, err) continue } conn.SendMessage(&protobuf.Subscription{ Subscribe: true, }) } } for uuid, p := range s.Players { p.Conn.SendMessage(&protobuf.PlayerAction{ Player: &s.Players[player.Uuid].Player, Action: protobuf.PlayerAction_JOIN, Uuid: uuid, }) if uuid != player.Uuid { conn.SendMessage(&protobuf.PlayerAction{ Player: &p.Player, Action: protobuf.PlayerAction_JOIN, Uuid: player.Uuid, }) } } case protobuf.PlayerAction_MOVE_ABSOLUTE: responseType := protobuf.PlayerAction_MOVE_RELATIVE tmp := s.Players[player.Uuid] if req.Flags&1 == 1 { if math.Abs(player.X-tmp.LastX) > 3 || math.Abs(player.FeetY-tmp.LastY) > 3 || math.Abs(player.Z-tmp.LastZ) > 3 { responseType = protobuf.PlayerAction_MOVE_ABSOLUTE tmp.LastX = player.X tmp.LastY = player.FeetY tmp.LastZ = player.Z } } for uuid, p := range s.Players { if uuid != player.Uuid { sendPlayer := protobuf.Player{ Uuid: player.Uuid, EntityId: tmp.EntityId, } if responseType == protobuf.PlayerAction_MOVE_ABSOLUTE { sendPlayer.X = player.X sendPlayer.HeadY = player.HeadY sendPlayer.FeetY = player.FeetY sendPlayer.Z = player.Z } else if req.Flags&1 == 1 { sendPlayer.X = player.X - tmp.X sendPlayer.FeetY = player.FeetY - tmp.FeetY sendPlayer.Z = player.Z - tmp.Z } if req.Flags&2 == 2 { sendPlayer.Pitch = player.Pitch sendPlayer.Yaw = player.Yaw } p.Conn.SendMessage(&protobuf.PlayerAction{ Player: &sendPlayer, Action: responseType, Uuid: uuid, Flags: req.Flags, }) } } if req.Flags&1 == 1 { tmp.X = player.X tmp.HeadY = player.HeadY tmp.FeetY = player.FeetY tmp.Z = player.Z } if req.Flags&2 == 2 { tmp.Pitch = player.Pitch tmp.Yaw = player.Yaw } case protobuf.PlayerAction_LEAVE: tmp := s.Players[player.Uuid] delete(s.Players, player.Uuid) log.Printf("Player left: %s", tmp.Username) for uuid, p := range s.Players { sendPlayer := protobuf.Player{ Uuid: player.Uuid, Username: tmp.Username, EntityId: tmp.EntityId, } p.Conn.SendMessage(&protobuf.PlayerAction{ Player: &sendPlayer, Action: protobuf.PlayerAction_LEAVE, Uuid: uuid, }) } } } }
func (s *Server) HandleMessage(message interface{}, conn *network.InternalConnection) { switch msg := message.(type) { case *protobuf.ChunkResponse: s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.MapChunkBulkID, int16(1), int32(len(msg.Data)), true, msg.Data, int32(msg.X), int32(msg.Z), uint16(0xFFFF), uint16(0)) case *protobuf.ChatMessage: s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.ChatMessageID, msg.Message) case *protobuf.BlockUpdate: log.Printf("Sending block update to: %s", msg.Uuid) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.BlockChangeID, int32(msg.X), uint8(msg.Y), int32(msg.Z), protocol.Varint{uint64(msg.BlockId)}, uint8(msg.BlockMetadata)) case *protobuf.PlayerAction: switch msg.Action { case protobuf.PlayerAction_JOIN: s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.PlayerListItemID, msg.Player.Username, true, int16(0)) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.ChatMessageID, protocol.CreateJsonMessage(msg.Player.Username+" joined the game", "yellow")) if msg.Uuid != msg.Player.Uuid { meta := protocol.NewMetadata( protocol.AbsorptionHeartsID, float32(0), protocol.OnFireID, false, protocol.UnknownBitFieldID, byte(0), protocol.AirID, uint16(0x012c), protocol.ScoreID, uint32(0), protocol.HealthID, float32(20), protocol.PotionColorID, int32(0), protocol.AmbientPotionID, byte(0), protocol.ArrowCountID, byte(0), ) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.SpawnPlayerID, protocol.Varint{uint64(msg.Player.EntityId)}, msg.Player.Uuid, msg.Player.Username, protocol.Varint{0}, int32(msg.Player.X*32), int32(msg.Player.FeetY*32), int32(msg.Player.Z*32), byte(msg.Player.Yaw*256/2/math.Pi), byte(msg.Player.Pitch*256/2/math.Pi), int16(0), meta, ) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityMetadataID, int32(msg.Player.EntityId), meta, ) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityPropertiesID, int32(msg.Player.EntityId), int32(2), "generic.maxHealth", float64(20), int16(0), "generic.movementSpeed", float64(0.1), int16(0), ) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityTeleportID, int32(msg.Player.EntityId), int32(msg.Player.X*32), int32(msg.Player.FeetY*32), int32(msg.Player.Z*32), byte(msg.Player.Yaw*256/360), byte(msg.Player.Pitch*256/360), ) } case protobuf.PlayerAction_MOVE_RELATIVE: if msg.Flags == 1 { s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityRelativeMoveID, int32(msg.Player.EntityId), byte(msg.Player.X*32), byte(msg.Player.FeetY*32), byte(msg.Player.Z*32), ) } else if msg.Flags == 2 { s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityLookID, int32(msg.Player.EntityId), byte(msg.Player.Yaw*256/360), byte(msg.Player.Pitch*256/360), ) } else if msg.Flags == 3 { s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityLookAndMoveID, int32(msg.Player.EntityId), byte(msg.Player.X*32), byte(msg.Player.FeetY*32), byte(msg.Player.Z*32), byte(msg.Player.Yaw*256/360), byte(msg.Player.Pitch*256/360), ) } if msg.Flags&2 == 2 { s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityHeadLookID, int32(msg.Player.EntityId), byte(msg.Player.Yaw*256/360)) } case protobuf.PlayerAction_MOVE_ABSOLUTE: s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityTeleportID, int32(msg.Player.EntityId), int32(msg.Player.X*32), int32(msg.Player.FeetY*32), int32(msg.Player.Z*32), byte(msg.Player.Yaw*256/360), byte(msg.Player.Pitch*256/360), ) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.EntityHeadLookID, int32(msg.Player.EntityId), byte(msg.Player.Yaw*256/360)) case protobuf.PlayerAction_LEAVE: s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.DestroyEntitiesID, byte(1), int32(msg.Player.EntityId)) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.PlayerListItemID, msg.Player.Username, false, int16(0)) s.PlayerConnections[msg.Uuid] <- protocol.CreatePacket(protocol.ChatMessageID, protocol.CreateJsonMessage(msg.Player.Username+" left the game", "yellow")) } } }