Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions example/pyramid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ int main() {
int min_height = *std::min_element(heights.begin(), heights.end());

// Build rings, diminishing up to pyramid height
mcpp::Coordinate base_pt = heights.base_pt();
base_pt.y = min_height;
mcpp::Coordinate base_pt = heights.base_pt().with_height(min_height);
int side_len = pyramid_base_len;
for (int i = 0; i < PYRAMID_HEIGHT; i++) {
make_ring(base_pt + mcpp::Coordinate(i, i, i), side_len - (i * 2));
Expand Down
105 changes: 105 additions & 0 deletions include/mcpp/coordinate.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
*
*/
namespace mcpp {

struct Coordinate2D;

/**
* Represented using integers since sub-unit coordinates are not of particular
* relevance. Allows for operations such as addition between coordinates.
Expand Down Expand Up @@ -49,6 +52,8 @@ struct Coordinate {
*/
Coordinate operator+(const Coordinate& obj) const;

Coordinate operator+(const Coordinate2D& obj) const;

/**
* @brief Checks if two Coordinate objects are equal.
*
Expand Down Expand Up @@ -93,6 +98,106 @@ struct Coordinate {
friend std::ostream& operator<<(std::ostream& out, const Coordinate& coord);
};

/**
* @brief Height-agnostic coordinate class.
*
* Represented using integers since sub-unit coordinates are not of particular
* relevance. Allows for operations such as addition between flat coordinates.
*/
struct Coordinate2D {
/**
* @brief Constructs a Coordinate2D object with integer values.
*
* @param x The x-coordinate.
* @param z The z-coordinate.
*/
constexpr Coordinate2D(int x, int z) : x(x), z(z) {}

/**
* @brief Constructs a Coordinate2D object with zero values.
*/
constexpr Coordinate2D() : x(0), z(0) {}

/**
* @brief Constructs a Coordinate2D object with double values.
*
* @param x The x-coordinate as a double.
* @param z The z-coordinate as a double.
*/
constexpr Coordinate2D(double x, double z) : x(static_cast<int>(x)), z(static_cast<int>(z)) {}

/**
* @brief Constructs a Coordinate2D object from a Coordinate object.
*
* @param coord The Coordinate object.
*/
constexpr Coordinate2D(const Coordinate& coord) : x(coord.x), z(coord.z) {}

/**
* @brief Constructs a Coordinate object from a Coordinate2D object and a
* y value.
*
* @param coord The Coordinate2D object.
* @param y The y value.
*/
Coordinate with_height(int y) const;

/**
* @brief Adds two Coordinate2D objects.
*
* @param obj The Coordinate2D object to add.
* @return A new Coordinate2D object representing the sum of the two
* coordinates.
*/
Coordinate2D operator+(const Coordinate2D& obj) const;

/**
* @brief Checks if two Coordinate2D objects are equal.
*
* @param obj The Coordinate2D object to compare with.
* @return True if the flat coordinates are equal, false otherwise.
*/
bool operator==(const Coordinate2D& obj) const;

/**
* @brief Checks if two Coordinate2D objects are not equal.
*
* @param obj The Coordinate2D object to compare with.
* @return True if the flat coordinates are not equal, false otherwise.
*/
bool operator!=(const Coordinate2D& obj) const;

/**
* @brief Subtracts one Coordinate2D object from another.
*
* @param obj The Coordinate2D object to subtract.
* @return A new Coordinate2D object representing the difference between
* the two coordinates.
*/
Coordinate2D operator-(const Coordinate2D& obj) const;

/**
* @brief Implements hash algorithm for Coordinate2D object using non-negative
* mapping and weighted coordinate values.
*
* @param obj The Coordinate2D object to hash.
* @return Hash of Coordinate2D object.
*/
std::size_t operator()(const Coordinate2D& obj) const;

/**
* @brief Outputs the Coordinate2D object to an ostream.
*
* @param out The output stream.
* @param coord The Coordinate2D object to output.
* @return The output stream with the Coordinate object's values.
*/
friend std::ostream& operator<<(std::ostream& out, const Coordinate2D& coord);

int x;
int z;
};

/**
* @brief Convert coordinate to string representation.
*
Expand Down
11 changes: 6 additions & 5 deletions include/mcpp/heightmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ namespace mcpp {
*/
struct HeightMap {
private:
Coordinate _base_pt;
Coordinate2D _base_pt;
uint16_t _x_len;
uint16_t _z_len;
std::unique_ptr<int16_t[]> _raw_heights;

public:
// Constructors and assignment
HeightMap(const Coordinate& loc1, const Coordinate& loc2, const std::vector<int16_t>& heights);
HeightMap(const Coordinate2D& loc1, const Coordinate2D& loc2,
const std::vector<int16_t>& heights);
~HeightMap() = default;

HeightMap(const HeightMap& other)
Expand All @@ -45,10 +46,10 @@ struct HeightMap {

/**
* Get the height at a Minecraft coordinate if saved inside the height map
* @param loc: Coordinate in Minecraft world to access in the map
* @param loc: Coordinate2D in Minecraft world to access in the map
* @return: height at specified coordinate
*/
int16_t get_worldspace(const Coordinate& loc) const;
int16_t get_worldspace(const Coordinate2D& loc) const;

/**
* Fill a coordinate inplace with the highest y coordinate at the `loc`'s x
Expand All @@ -73,7 +74,7 @@ struct HeightMap {
* Gets the minimum coordinate in the HeightMap.
* @return the minimum coordinate in the HeightMap.
*/
Coordinate base_pt() const;
Coordinate2D base_pt() const;

/**
* @brief An iterator for the HeightMap structure.
Expand Down
30 changes: 22 additions & 8 deletions include/mcpp/mcpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,31 +134,45 @@ class MinecraftConnection {
[[nodiscard]] Chunk getBlocks(const Coordinate& loc1, const Coordinate& loc2) const;

/**
* @brief Returns the height of the specific provided x and z coordinate
* @brief Returns the height of the specific provided 2D coordinate
*
* ***IMPORTANT:***
* DO NOT USE FOR LARGE AREAS, IT WILL BE VERY SLOW
* USE getHeights() INSTEAD
*
* Gets the y-value of the highest non-air block at the specified (x, z)
* Gets the y-value of the highest non-air block at the specified 2D
* coordinate.
* @param x
* @param z
* @param loc 2D coordinate
* @return Returns the integer y-height at the requested coordinate.
*/
[[nodiscard]] int32_t getHeight(int x, int z) const;
[[nodiscard]] int32_t getHeight(Coordinate2D loc) const;

/**
* @brief Returns the coordinate with the x, z, and in-world height of the
* specific provided 2D coordinate
*
* ***IMPORTANT:***
* DO NOT USE FOR LARGE AREAS, IT WILL BE VERY SLOW
* USE getHeights() INSTEAD
*
* Gets the y-value of the highest non-air block at the specified 2D
* coordinate, and creates a new 3D coordinate.
* @param loc 2D coordinate
* @return Returns the coordinate with the filled-in height.
*/
Coordinate fillHeight(Coordinate2D loc) const;

/**
* @brief Provides a scaled option of the getHeight call to allow for
* considerable performance gains.
*
* \par USE THIS instead of getHeight in a for loop.
*
* @param loc1
* @param loc2
* @param loc1 1st corner of rectangle
* @param loc2 2nd corner of rectangle
* @return Returns a vector of integers representing the 2D area of heights.
*/
[[nodiscard]] HeightMap getHeights(const Coordinate& loc1, const Coordinate& loc2) const;
[[nodiscard]] HeightMap getHeights(const Coordinate2D& loc1, const Coordinate2D& loc2) const;

// NOLINTEND(readability-identifier-naming)
};
Expand Down
50 changes: 50 additions & 0 deletions src/coordinate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ Coordinate Coordinate::operator+(const Coordinate& obj) const {
return result;
}

Coordinate Coordinate::operator+(const Coordinate2D& obj) const {
Coordinate result;
result.x = this->x + obj.x;
result.y = this->y;
result.z = this->z + obj.z;
return result;
}

bool Coordinate::operator==(const Coordinate& obj) const {
return (this->x == obj.x) && (this->y == obj.y) && (this->z == obj.z);
}
Expand Down Expand Up @@ -44,4 +52,46 @@ std::ostream& operator<<(std::ostream& out, const Coordinate& coord) {
out << to_string(coord);
return out;
}

Coordinate Coordinate2D::with_height(int y) const { return Coordinate(this->x, y, this->z); }

Coordinate2D Coordinate2D::operator+(const Coordinate2D& obj) const {
Coordinate2D result;
result.x = this->x + obj.x;
result.z = this->z + obj.z;
return result;
}

bool Coordinate2D::operator==(const Coordinate2D& obj) const {
return (this->x == obj.x) && (this->z == obj.z);
}

bool Coordinate2D::operator!=(const Coordinate2D& obj) const { return !(*this == obj); }

Coordinate2D Coordinate2D::operator-(const Coordinate2D& obj) const {
Coordinate2D result;
result.x = this->x - obj.x;
result.z = this->z - obj.z;
return result;
}

std::size_t Coordinate2D::operator()(const mcpp::Coordinate2D& obj) const {
int lower = -3e7, upper = 3e7;
size_t base = upper - lower + 1;

size_t nx = obj.x - lower;
size_t nz = obj.z - lower;

return nx * base + nz;
}

std::string to_string(const Coordinate2D& coord) {
using std::to_string;
return "(" + to_string(coord.x) + "," + to_string(coord.z) + ")";
}

std::ostream& operator<<(std::ostream& out, const Coordinate2D& coord) {
out << to_string(coord);
return out;
}
} // namespace mcpp
6 changes: 3 additions & 3 deletions src/heightmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <cstdint>

namespace mcpp {
HeightMap::HeightMap(const Coordinate& loc1, const Coordinate& loc2,
HeightMap::HeightMap(const Coordinate2D& loc1, const Coordinate2D& loc2,
const std::vector<int16_t>& heights) {
_base_pt = Coordinate{
std::min(loc1.x, loc2.x),
Expand Down Expand Up @@ -37,7 +37,7 @@ int16_t HeightMap::get(int x, int z) const {
return _raw_heights[(x * _z_len) + z];
}

int16_t HeightMap::get_worldspace(const Coordinate& loc) const {
int16_t HeightMap::get_worldspace(const Coordinate2D& loc) const {
return get(loc.x - _base_pt.x, loc.z - _base_pt.z);
}

Expand All @@ -47,5 +47,5 @@ uint16_t HeightMap::x_len() const { return _x_len; }

uint16_t HeightMap::z_len() const { return _z_len; }

Coordinate HeightMap::base_pt() const { return _base_pt; }
Coordinate2D HeightMap::base_pt() const { return _base_pt; }
} // namespace mcpp
14 changes: 10 additions & 4 deletions src/mcpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,20 +103,26 @@ Chunk MinecraftConnection::getBlocks(const Coordinate& loc1, const Coordinate& l
return Chunk{loc1, loc2, result};
}

int MinecraftConnection::getHeight(int x, int z) const {
std::string response = _conn->send_receive_command("world.getHeight", x, z);
int MinecraftConnection::getHeight(Coordinate2D loc) const {
std::string response = _conn->send_receive_command("world.getHeight", loc.x, loc.z);
return stoi(response);
}

HeightMap MinecraftConnection::getHeights(const Coordinate& loc1, const Coordinate& loc2) const {
Coordinate MinecraftConnection::fillHeight(Coordinate2D loc) const {
int y = this->getHeight(loc);
return Coordinate(loc.x, y, loc.z);
}

HeightMap MinecraftConnection::getHeights(const Coordinate2D& loc1,
const Coordinate2D& loc2) const {
std::string response =
_conn->send_receive_command("world.getHeights", loc1.x, loc1.z, loc2.x, loc2.z);

// Returned in format "1,2,3,4,5"
std::vector<int16_t> parsed;
split_response(response, parsed);

return {loc1, loc2, parsed};
return HeightMap{loc1, loc2, parsed};
}

} // namespace mcpp
8 changes: 4 additions & 4 deletions test/minecraft_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ TEST_CASE("Test the main mcpp class") {
SUBCASE("getHeight") {
Coordinate heightTestLoc(300, 200, 300);
mc.setBlock(heightTestLoc, Blocks::DIRT);
auto height = mc.getHeight(heightTestLoc.x, heightTestLoc.z);
auto height = mc.getHeight(heightTestLoc);
CHECK_EQ(height, heightTestLoc.y);

// Clean up
Expand Down Expand Up @@ -384,14 +384,14 @@ TEST_CASE("HeightMap functionality") {
// Copy assignment
mc.setBlocks({10, 310, 10}, {20, 320, 20}, Blocks::AIR);
mc.setBlocks({10, 310, 10}, {20, 310, 20}, Blocks::STONE);
auto map = mc.getHeights({10, 10, 10}, {20, 20, 20});
auto map = mc.getHeights({10, 10}, {20, 20});
HeightMap map_copy = map; // Contains 310
CHECK_EQ(map.get(0, 0), map_copy.get(0, 0));
CHECK_EQ(map.get(0, 0), 310);

// Reassignment
mc.setBlock({10, 311, 10}, Blocks::STONE);
map = mc.getHeights({10, 10, 10}, {20, 20, 20}); // Now contains 311
map = mc.getHeights({10, 10}, {20, 20}); // Now contains 311
CHECK_NE(map.get(0, 0), map_copy.get(0, 0));
CHECK_EQ(map.get(0, 0), 311);

Expand All @@ -402,7 +402,7 @@ TEST_CASE("HeightMap functionality") {
// Copy constructor
auto map_copy2 = HeightMap(map); // Contains 310
mc.setBlock({10, 312, 10}, Blocks::STONE);
map = mc.getHeights({10, 10, 10}, {20, 20, 20}); // Now contains 312
map = mc.getHeights({10, 10}, {20, 20}); // Now contains 312
CHECK_NE(map_copy2.get(0, 0), 312);
CHECK_EQ(map.get(0, 0), 312);

Expand Down