Esempio n. 1
0
func (c *Cluster) ChunkConnection(x, z int64, h MessageHandler) (*InternalConnection, error) {
	x, z = world.ChunkCoordsToNode(x, z)

	zm := c.ChunkNodes[z]
	if zm == nil {
		return nil, ErrMissingChunk
	}

	node := zm[x]
	if node == nil {
		return nil, ErrMissingChunk
	}

	if node.Connection != nil {
		return node.Connection, nil
	}

	conn, err := ConnectInternal(node.Meta.Addr, h)
	if err != nil {
		return nil, err
	}

	node.Connection = conn
	return conn, nil
}
Esempio n. 2
0
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,
				})
			}
		}
	}
}