/*
mc_schem is a rust library to generate, load, manipulate and save minecraft
schematic files. Copyright (C) 2024 joseph
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef MC_SCHEM_MC_SCHEM_HPP
#define MC_SCHEM_MC_SCHEM_HPP
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace mc_schem {
[[nodiscard]] std::string_view lib_version_string() noexcept {
return MC_SCHEM_version_string();
}
struct version {
uint16_t major;
uint16_t minor;
uint16_t patch;
};
[[nodiscard]] version lib_version() noexcept {
return version{MC_SCHEM_version_major(), MC_SCHEM_version_minor(),
MC_SCHEM_version_patch()};
}
enum class map_key_type : uint8_t {
string = 0,
pos_i32 = 1,
};
enum class map_value_type : uint8_t {
string = 0,
nbt = 1,
block_entity = 2,
pending_tick = 3,
};
namespace detail {
[[nodiscard]] std::string_view string_view_schem_to_std(
MC_SCHEM_string_view s) noexcept {
return std::string_view{s.begin, s.end};
}
[[nodiscard]] MC_SCHEM_string_view string_view_std_to_schem(
std::string_view s) noexcept {
return MC_SCHEM_string_view{s.data(), s.data() + s.size()};
}
[[nodiscard]] std::array array3_i32_schem_to_std(
MC_SCHEM_array3_i32 arr) noexcept {
std::array result{};
std::copy_n(arr.pos, 3, result.begin());
return result;
}
[[nodiscard]] MC_SCHEM_array3_i32 array3_i32_std_to_schem(
std::span arr) noexcept {
MC_SCHEM_array3_i32 result;
std::copy_n(arr.begin(), 3, result.pos);
return result;
}
void deep_swap(MC_SCHEM_string *a, MC_SCHEM_string *b) {
MC_SCHEM_swap_string(a, b);
}
void deep_swap(MC_SCHEM_nbt_value *a, MC_SCHEM_nbt_value *b) {
MC_SCHEM_swap_nbt(a, b);
}
void deep_swap(MC_SCHEM_block *a, MC_SCHEM_block *b) {
MC_SCHEM_swap_block(a, b);
}
void deep_swap(MC_SCHEM_entity *a, MC_SCHEM_entity *b) {
MC_SCHEM_swap_entity(a, b);
}
void deep_swap(MC_SCHEM_block_entity *a, MC_SCHEM_block_entity *b) {
MC_SCHEM_swap_block_entity(a, b);
}
void deep_swap(MC_SCHEM_pending_tick *a, MC_SCHEM_pending_tick *b) {
MC_SCHEM_swap_pending_tick(a, b);
}
void deep_swap(MC_SCHEM_error *a, MC_SCHEM_error *b) {
MC_SCHEM_swap_error(a, b);
}
void deep_swap(MC_SCHEM_region *a, MC_SCHEM_region *b) {
MC_SCHEM_swap_region(a, b);
}
void deep_swap(MC_SCHEM_schematic *a, MC_SCHEM_schematic *b) {
MC_SCHEM_swap_schem(a, b);
}
template
class wrapper {
protected:
handle_t handle{nullptr};
public:
using handle_type = handle_t;
wrapper() = delete;
explicit wrapper(handle_t p) : handle{p} {}
wrapper(const wrapper &) = delete;
wrapper(wrapper &&src) noexcept { std::swap(this->handle, src.handle); }
wrapper &operator=(const wrapper &) = delete;
wrapper &operator=(wrapper &&src) noexcept {
std::swap(this->handle, src.handle);
}
[[nodiscard]] handle_t unwrap_handle() noexcept { return this->handle; }
[[nodiscard]] const handle_t unwrap_handle() const noexcept {
return this->handle;
}
void swap_handle(wrapper &another) noexcept {
std::swap(this->handle, another.handle);
}
void deep_swap(wrapper &another) noexcept {
deep_swap(this->handle, another.handle);
}
void reset_handle(handle_t ptr) noexcept { this->handle = ptr; }
};
template
[[nodiscard]] std::vector c_view_to_vector(c_array_view view) noexcept {
using handle_t = std::decay_t;
std::vector result{};
result.reserve(view.end - view.begin);
for (auto ptr = view.begin; ptr < view.end; ptr++) {
result.emplace_back(ptr);
}
return result;
}
class deleter {
public:
static void operator()(MC_SCHEM_block *s) noexcept {
if (s == nullptr) return;
MC_SCHEM_block_box box{s};
MC_SCHEM_release_block(&box);
}
static void operator()(MC_SCHEM_nbt_value *v) noexcept {
if (v == nullptr) return;
MC_SCHEM_nbt_value_box box{v};
MC_SCHEM_release_nbt(&box);
}
static void operator()(MC_SCHEM_entity *v) noexcept {
if (v == nullptr) return;
MC_SCHEM_entity_box box{v};
MC_SCHEM_release_entity(&box);
}
static void operator()(MC_SCHEM_block_entity *v) noexcept {
if (v == nullptr) return;
MC_SCHEM_block_entity_box box{v};
MC_SCHEM_release_block_entity(&box);
}
static void operator()(MC_SCHEM_pending_tick *v) noexcept {
if (v == nullptr) return;
MC_SCHEM_pending_tick_box box{v};
MC_SCHEM_release_pending_tick(&box);
}
static void operator()(MC_SCHEM_error *v) noexcept {
if (v == nullptr) return;
MC_SCHEM_error_box box{v};
MC_SCHEM_release_error(&box);
}
static void operator()(MC_SCHEM_region *r) noexcept {
if (r == nullptr) return;
MC_SCHEM_region_box box{r};
MC_SCHEM_release_region(&box);
}
static void operator()(MC_SCHEM_schematic *s) noexcept {
if (s == nullptr) return;
MC_SCHEM_schematic_box box{s};
MC_SCHEM_release_schem(&box);
}
// void operator()(MC_SCHEM_map_ref *m) const noexcept {
// MC_SCHEM_map_box box{m};
// }
};
template
class box {
public:
using handle_t = typename content_t::handle_type;
static_assert(std::is_same_v);
protected:
content_t content{nullptr};
handle_t handle() noexcept { return this->content.unwrap_handle(); }
[[nodiscard]] const handle_t *handle() const noexcept {
return this->content.unwrap_handle();
}
public:
box() = default;
box(const box &) = delete;
box(box &&src) noexcept { this->content.swap_handle(src.content); }
explicit box(c_box_t &&src) : content{src.ptr} { src.ptr = nullptr; }
~box() {
if (this->handle() != nullptr) {
deleter{}(this->handle());
}
}
explicit operator bool() const noexcept {
return this->handle() != nullptr;
}
content_t *operator->() noexcept { return &this->content; }
const content_t *operator->() const noexcept { return &this->content; }
};
class error : public wrapper {
public:
error() = delete;
error(const error &) = delete;
explicit error(MC_SCHEM_error *handle)
: wrapper{handle} {}
void to_string(std::string &dest) const noexcept {
dest.resize(1024);
while (true) {
const auto cap = dest.size();
size_t len = 0;
MC_SCHEM_error_to_string(this->handle, dest.data(), cap, &len);
if (cap >= len) {
dest.resize(len);
break;
}
// size not enough
dest.resize(cap * 2);
}
if (dest.back() == '\0') {
dest.pop_back();
}
}
[[nodiscard]] std::string to_string() const noexcept {
std::string result;
this->to_string(result);
return result;
}
};
using error_box = box;
} // namespace detail
class error : public std::runtime_error {
protected:
detail::error_box content;
public:
error() = delete;
error(const error &) = delete;
error(error &&) = default;
explicit error(detail::error_box &&box)
: std::runtime_error{""}, content{std::move(box)} {
static_cast(*this) =
std::runtime_error{this->content->to_string()};
}
explicit error(MC_SCHEM_error_box &&box)
: error{detail::error_box{std::move(box)}} {
assert(this->content->unwrap_handle() != nullptr);
}
};
class rust_string : public detail::wrapper {
public:
rust_string() = delete;
explicit rust_string(MC_SCHEM_string *handle)
: detail::wrapper(handle) {}
explicit operator std::string_view() const noexcept {
auto schem_sv = MC_SCHEM_string_unwrap(this->handle);
return detail::string_view_schem_to_std(schem_sv);
}
explicit operator MC_SCHEM_string_view() const noexcept {
return MC_SCHEM_string_unwrap(this->handle);
}
void reset(std::string_view str) noexcept {
auto schem_sv = detail::string_view_std_to_schem(str);
MC_SCHEM_string_set(this->handle, schem_sv);
}
};
namespace detail {
template
class map_wrapper {
public:
using key_ref_type =
std::conditional_t>;
protected:
MC_SCHEM_map_ref map_ref{{0, 0}};
public:
map_wrapper() = delete;
explicit map_wrapper(MC_SCHEM_map_ref handel) : map_ref{handel} {
assert(MC_SCHEM_map_get_key_type(&handel) ==
static_cast(key_e));
assert(MC_SCHEM_map_get_value_type(&handel) ==
static_cast(value_e));
}
map_wrapper(const map_wrapper &) = delete;
map_wrapper(map_wrapper &&b) noexcept {
std::swap(this->map_ref, b.map_ref);
}
~map_wrapper() = default;
static MC_SCHEM_key_wrapper wrap_key(key_ref_type key) noexcept {
MC_SCHEM_key_wrapper kw;
if constexpr (key_e == map_key_type::string) {
kw.string = string_view_std_to_schem(key);
} else {
memcpy(reinterpret_cast(kw.pos), key.data(), key.size());
}
return kw;
}
static key_ref_type unwrap_key(MC_SCHEM_key_wrapper key) noexcept {
if constexpr (key_e == map_key_type::string) {
return string_view_schem_to_std(key.string);
} else {
return key.pos;
}
}
static MC_SCHEM_value_wrapper wrap_value(const value_t &value) noexcept {
MC_SCHEM_value_wrapper vw;
if constexpr (value_e == map_value_type::string) {
vw.string = value.unwrap_handle();
} else if constexpr (value_e == map_value_type::block_entity) {
vw.block_entity = value.unwrap_handle();
} else if constexpr (value_e == map_value_type::nbt) {
vw.nbt = value.unwrap_handle();
} else {
vw.pending_tick_list = value.unwrap_handle();
}
return vw;
}
static auto unwrap_value(MC_SCHEM_value_wrapper vw) noexcept {
if constexpr (value_e == map_value_type::string) {
return vw.string;
} else if constexpr (value_e == map_value_type::block_entity) {
return vw.block_entity;
} else if constexpr (value_e == map_value_type::nbt) {
return vw.nbt;
} else {
return vw.pending_tick_list;
}
}
[[nodiscard]] size_t size() const noexcept {
return MC_SCHEM_map_length(&this->map_ref);
}
void reserve(size_t new_cap) noexcept {
MC_SCHEM_map_reserve(&this->map_ref, new_cap);
}
[[nodiscard]] bool contains_key(key_ref_type key) noexcept {
auto k = wrap_key(key);
return MC_SCHEM_map_contains_key(
&this->map_ref, static_cast(key_e), &k);
}
// using foreach_fun_const = void (*)(size_t index, key_ref_type key,
// const value_t &value);
using foreach_fun_const_with_data = void (*)(size_t index,
key_ref_type key,
const value_t &value,
void *custom_data);
// using foreach_fun_mut = void (*)(size_t index, key_ref_type key,
// value_t &value);
using foreach_fun_mut_with_data = void (*)(size_t index, key_ref_type key,
value_t &value,
void *custom_data);
protected:
struct callback_data_mut {
foreach_fun_mut_with_data original_fun;
void *original_custom_data;
};
static void fun_wrap_mut(size_t index, MC_SCHEM_key_wrapper key,
MC_SCHEM_value_wrapper value,
void *callback_data_p) {
const callback_data_mut *data =
reinterpret_cast(callback_data_p);
auto k = unwrap_key(key);
auto v = unwrap_value(value);
data->original_fun(index, k, v, data->original_custom_data);
}
struct callback_data_const {
foreach_fun_const_with_data original_fun;
void *original_custom_data;
};
static void fun_wrap_const(size_t index, MC_SCHEM_key_wrapper key,
MC_SCHEM_value_wrapper value,
void *callback_data_p) {
const callback_data_const *data =
reinterpret_cast(callback_data_p);
auto k = unwrap_key(key);
auto v = unwrap_value(value);
data->original_fun(index, k, v, data->original_custom_data);
}
public:
void foreach (foreach_fun_mut_with_data fun, void *custom_data) {
callback_data_mut data{fun, custom_data};
MC_SCHEM_map_foreach(&this->map_ref, fun_wrap_mut, &data);
}
void foreach (const std::function &fun) {
using stdfun_t = std::decay_t;
this->foreach (
[](size_t idx, key_ref_type k, value_t &v, void *std_fun_p) {
const stdfun_t &fun_p = *reinterpret_cast(std_fun_p);
fun_p(idx, k, v);
},
&fun);
}
void foreach (foreach_fun_const_with_data fun, void *custom_data) const {
callback_data_const data{fun, custom_data};
MC_SCHEM_map_foreach(&this->map_ref, fun_wrap_mut, &data);
}
void foreach (
const std::function &fun) const {
using stdfun_t = std::decay_t;
this->foreach (
[](size_t idx, key_ref_type k, const value_t &v, void *std_fun_p) {
const stdfun_t &fun_p = *reinterpret_cast(std_fun_p);
fun_p(idx, k, v);
},
&fun);
}
protected:
[[nodiscard]] std::optional impl_get(
key_ref_type key) const noexcept {
bool ok = false;
auto k = wrap_key(key);
auto val_union =
MC_SCHEM_map_find(&this->map_ref, key_e, value_e, &k, &ok);
assert(ok);
auto val_ptr = unwrap_value(val_union);
if (val_ptr == nullptr) {
return std::nullopt;
}
return value_t{val_ptr};
}
public:
[[nodiscard]] std::optional get(key_ref_type key) noexcept {
return this->impl_get(key);
}
[[nodiscard]] std::optional get(
key_ref_type key) const noexcept {
auto result = this->impl_get(key);
if (result.has_value()) {
return std::move(result.value());
}
return std::nullopt;
}
void insert(key_ref_type key, const value_t &value) noexcept {
auto k = wrap_key(key);
auto v = wrap_value(value);
MC_SCHEM_map_insert(&this->map_ref, k, v);
}
// returns true if an element is remove, false if key doesn't exist
bool remove(key_ref_type key) noexcept {
auto k = wrap_key(key);
bool ret = false;
MC_SCHEM_map_remove(&this->map_ref, k, &ret);
return ret;
}
public:
template
class iterator_impl {
protected:
MC_SCHEM_map_iterator it;
// std::optional > deref;
explicit iterator_impl(MC_SCHEM_map_iterator it) : it{it} {}
friend class map_wrapper;
public:
iterator_impl() = delete;
[[nodiscard]] key_ref_type key() const noexcept {
MC_SCHEM_iterator_deref_result deref =
MC_SCHEM_map_iterator_deref(&this->it);
assert(deref.has_value);
if (!deref.has_value) {
abort();
}
return unwrap_key(deref.key);
}
[[nodiscard]] std::conditional_t
value() const noexcept {
MC_SCHEM_iterator_deref_result deref =
MC_SCHEM_map_iterator_deref(&this->it);
assert(deref.has_value);
if (!deref.has_value) {
abort();
}
auto value = unwrap_value(deref.value);
return value_t{value};
// if constexpr (value_e == map_value_type::string) {
// auto str = MC_SCHEM_string_unwrap(value);
// return string_view_schem_to_std(str);
// } else {
// }
}
iterator_impl &operator++() noexcept {
MC_SCHEM_map_iterator_add(&this->it);
return *this;
}
const iterator_impl operator++(int) noexcept {
iterator_impl copy{*this};
(*this)++;
return copy;
}
[[nodiscard]] bool operator==(const iterator_impl &b) const noexcept {
return MC_SCHEM_map_iterator_equal(&this->it, &b.it);
}
};
using iterator = iterator_impl;
using const_iterator = iterator_impl;
protected:
[[nodiscard]] MC_SCHEM_map_iterator impl_begin() const noexcept {
bool ok = false;
auto it = MC_SCHEM_map_iterator_first(
&this->map_ref, static_cast(key_e),
static_cast(value_e), &ok);
assert(ok);
return it;
}
[[nodiscard]] MC_SCHEM_map_iterator impl_end() const noexcept {
bool ok = false;
auto it = MC_SCHEM_map_iterator_end(
&this->map_ref, static_cast(key_e),
static_cast(value_e), &ok);
assert(ok);
return it;
}
public:
[[nodiscard]] iterator begin() noexcept {
return iterator{this->impl_begin()};
}
[[nodiscard]] iterator end() noexcept {
return iterator{this->impl_end()};
}
[[nodiscard]] const_iterator begin() const noexcept {
return this->cbegin();
}
[[nodiscard]] const_iterator end() const noexcept { return this->cend(); }
[[nodiscard]] const_iterator cbegin() const noexcept {
return const_iterator{this->impl_begin()};
}
[[nodiscard]] const_iterator cend() const noexcept {
return const_iterator{this->impl_end()};
}
};
} // namespace detail
class block : public detail::wrapper {
public:
enum class id_parse_error : uint8_t {
too_many_colons = 0,
too_many_left_brackets = 1,
too_many_right_brackets = 2,
missing_block_id = 3,
brackets_not_in_pairs = 4,
bracket_in_wrong_position = 5,
colons_in_wrong_position = 6,
missing_equal_in_attributes = 7,
too_many_equals_in_attributes = 8,
missing_attribute_name = 9,
missing_attribute_value = 10,
extra_string_after_right_bracket = 11,
invalid_character = 12,
};
public:
block() = delete;
explicit block(MC_SCHEM_block *handle)
: detail::wrapper{handle} {}
[[nodiscard]] std::string_view get_namespace() const noexcept {
return detail::string_view_schem_to_std(
MC_SCHEM_block_get_namespace(this->handle));
}
void set_namespace(std::string_view ns) noexcept {
MC_SCHEM_block_set_namespace(this->handle,
detail::string_view_std_to_schem(ns));
}
[[nodiscard]] std::string_view id() const noexcept {
return detail::string_view_schem_to_std(
MC_SCHEM_block_get_id(this->handle));
}
void set_id(std::string_view new_id) noexcept {
MC_SCHEM_block_set_id(this->handle,
detail::string_view_std_to_schem(new_id));
}
using attribute_map_t =
detail::map_wrapper;
protected:
[[nodiscard]] attribute_map_t impl_attributes() const noexcept {
auto handle = MC_SCHEM_block_get_attributes(this->handle);
return attribute_map_t{handle};
}
public:
[[nodiscard]] attribute_map_t attributes() noexcept {
return this->impl_attributes();
}
[[nodiscard]] const attribute_map_t attributes() const noexcept {
return this->impl_attributes();
}
void full_id(std::string &dest) const noexcept {
dest.resize(256);
while (true) {
size_t length = 0;
MC_SCHEM_block_to_full_id(this->unwrap_handle(), dest.data(),
dest.size(), &length);
if (length != 0) {
dest.resize(length);
break;
}
dest.resize(dest.size() * 2);
}
while (dest.back() == '\0') {
dest.pop_back();
}
}
[[nodiscard]] std::string full_id() const noexcept {
std::string result;
this->full_id(result);
return result;
}
using block_box_t = detail::box;
static block_box_t create() noexcept {
return block_box_t{MC_SCHEM_create_block()};
}
static std::expected parse_block(
std::string_view full_id) noexcept {
auto result = create();
MC_SCHEM_block_id_parse_error error;
const bool ok =
MC_SCHEM_parse_block(detail::string_view_std_to_schem(full_id),
result->unwrap_handle(), &error);
if (ok) {
return std::move(result);
}
return std::unexpected(static_cast(error));
}
};
class nbt : public detail::wrapper {
public:
enum class tag_type : uint8_t {
tag_byte = 1,
tag_short = 2,
tag_int = 3,
tag_long = 4,
tag_float = 5,
tag_double = 6,
tag_byte_array = 7,
tag_string = 8,
tag_list = 9,
tag_compound = 10,
tag_int_array = 11,
tag_long_array = 12,
};
static std::string_view tag_type_to_string(tag_type t) noexcept {
switch (t) {
case tag_type::tag_byte:
return "byte";
case tag_type::tag_short:
return "short";
case tag_type::tag_int:
return "int";
case tag_type::tag_long:
return "long";
case tag_type::tag_float:
return "float";
case tag_type::tag_double:
return "double";
case tag_type::tag_byte_array:
return "byte_array";
case tag_type::tag_string:
return "string";
case tag_type::tag_list:
return "list";
case tag_type::tag_compound:
return "compound";
case tag_type::tag_int_array:
return "int_array";
case tag_type::tag_long_array:
return "long_array";
}
}
public:
nbt() = delete;
explicit nbt(MC_SCHEM_nbt_value *handle)
: detail::wrapper{handle} {}
[[nodiscard]] tag_type type() const noexcept {
return static_cast(MC_SCHEM_nbt_get_type(this->handle));
}
using compound_map_type =
detail::map_wrapper;
using variant_rep_const =
std::variant, std::string_view,
std::span, const compound_map_type,
std::span, std::span>;
using variant_rep_mut =
std::variant, std::span, std::span,
compound_map_type, std::span, std::span>;
class nbt_unwrap_exception : public std::exception {
protected:
tag_type actual_type;
tag_type expected_type;
std::string what_str;
public:
nbt_unwrap_exception(tag_type actual, tag_type expected)
: actual_type{actual}, expected_type{expected} {
this->what_str =
std::format("Trying to unwrap a {} nbt tag as {}",
tag_type_to_string(actual), tag_type_to_string(expected));
}
[[nodiscard]] const char *what() const noexcept override {
return this->what_str.c_str();
}
};
// template
// [[nodiscard]] auto get() const {
// constexpr int index = static_cast(t) - 1;
// return std::get(this->to_variant());
// }
[[nodiscard]] int8_t as_byte() const {
bool ok = false;
auto ret = MC_SCHEM_nbt_get_byte(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_byte};
}
return ret;
}
[[nodiscard]] int16_t as_short() const {
bool ok = false;
auto ret = MC_SCHEM_nbt_get_short(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_short};
}
return ret;
}
[[nodiscard]] int32_t as_int() const {
bool ok = false;
auto ret = MC_SCHEM_nbt_get_int(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_int};
}
return ret;
}
[[nodiscard]] int64_t as_long() const {
bool ok = false;
auto ret = MC_SCHEM_nbt_get_long(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_long};
}
return ret;
}
[[nodiscard]] float as_float() const {
bool ok = false;
auto ret = MC_SCHEM_nbt_get_float(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_float};
}
return ret;
}
[[nodiscard]] double as_double() const {
bool ok = false;
auto ret = MC_SCHEM_nbt_get_double(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_double};
}
return ret;
}
[[nodiscard]] std::string_view as_string() const {
bool ok = false;
auto schem_str = MC_SCHEM_nbt_get_string(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_string};
}
auto schem_sv = MC_SCHEM_string_unwrap(schem_str);
return detail::string_view_schem_to_std(schem_sv);
}
protected:
[[nodiscard]] std::span impl_as_byte_array() const {
bool ok = false;
auto arr_view = MC_SCHEM_nbt_get_byte_array(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_byte_array};
}
return std::span{arr_view.begin, arr_view.end};
}
[[nodiscard]] std::vector impl_as_list() const {
bool ok = false;
auto arr_view = MC_SCHEM_nbt_get_list(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_list};
}
std::vector result;
result.reserve(arr_view.end - arr_view.begin);
for (auto p = arr_view.begin; p < arr_view.end; p++) {
result.emplace_back(p);
}
return result;
}
[[nodiscard]] compound_map_type impl_as_compound() const {
bool ok = false;
auto handle = MC_SCHEM_nbt_get_compound(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_compound};
}
return compound_map_type{handle};
}
[[nodiscard]] std::span impl_as_int_array() const {
bool ok = false;
auto arr_view = MC_SCHEM_nbt_get_int_array(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_int_array};
}
return std::span{arr_view.begin, arr_view.end};
}
[[nodiscard]] std::span impl_as_long_array() const {
bool ok = false;
auto arr_view = MC_SCHEM_nbt_get_long_array(this->handle, &ok);
if (!ok) {
throw nbt_unwrap_exception{this->type(), tag_type::tag_long_array};
}
return std::span{arr_view.begin, arr_view.end};
}
public:
[[nodiscard]] std::span as_byte_array() const {
return this->impl_as_byte_array();
}
[[nodiscard]] std::span as_byte_array() {
return this->impl_as_byte_array();
}
[[nodiscard]] std::span as_int_array() const {
return this->impl_as_int_array();
}
[[nodiscard]] std::span as_int_array() {
return this->impl_as_int_array();
}
[[nodiscard]] std::span as_long_array() const {
return this->impl_as_long_array();
}
[[nodiscard]] std::span as_long_array() {
return this->impl_as_long_array();
}
[[nodiscard]] const std::vector as_list() const {
return this->impl_as_list();
}
[[nodiscard]] std::vector as_list() { return this->impl_as_list(); }
[[nodiscard]] const compound_map_type as_compound() const {
return this->impl_as_compound();
}
[[nodiscard]] compound_map_type as_compound() {
return this->impl_as_compound();
}
public:
void set(int8_t v) noexcept { MC_SCHEM_nbt_set_byte(this->handle, v); }
void set(int16_t v) noexcept { MC_SCHEM_nbt_set_short(this->handle, v); }
void set(int32_t v) noexcept { MC_SCHEM_nbt_set_int(this->handle, v); }
void set(int64_t v) noexcept { MC_SCHEM_nbt_set_long(this->handle, v); }
void set(float v) noexcept { MC_SCHEM_nbt_set_float(this->handle, v); }
void set(double v) noexcept { MC_SCHEM_nbt_set_double(this->handle, v); }
void set(std::span v) noexcept {
auto *data = const_cast(v.data());
MC_SCHEM_nbt_set_byte_array(
this->handle, MC_SCHEM_nbt_byte_array_view{data, data + v.size()});
}
void set(std::span v) noexcept {
auto *data = const_cast(v.data());
MC_SCHEM_nbt_set_int_array(
this->handle, MC_SCHEM_nbt_int_array_view{data, data + v.size()});
}
void set(std::span v) noexcept {
auto *data = const_cast(v.data());
MC_SCHEM_nbt_set_long_array(
this->handle, MC_SCHEM_nbt_long_array_view{data, data + v.size()});
}
void set(std::span v) noexcept {
auto *data = const_cast(v.data());
MC_SCHEM_nbt_set_list(
this->handle,
MC_SCHEM_nbt_list_view{
reinterpret_cast(data),
reinterpret_cast(data + v.size())});
}
void set(std::string_view v) noexcept {
auto schem_sv = detail::string_view_std_to_schem(v);
MC_SCHEM_nbt_set_string(this->handle, schem_sv);
}
template
nbt &operator=(T src) noexcept {
this->set(src);
return *this;
}
static detail::box create() noexcept {
MC_SCHEM_nbt_value_box box = MC_SCHEM_create_nbt();
return detail::box{std::move(box)};
}
};
class entity : public detail::wrapper {
public:
entity() = delete;
entity(MC_SCHEM_entity *handle)
: detail::wrapper{handle} {}
[[nodiscard]] std::array block_pos() const noexcept {
MC_SCHEM_array3_i32 pos = MC_SCHEM_entity_get_block_pos(this->handle);
std::array ret{};
for (size_t i = 0; i < 3; i++) {
ret[i] = pos.pos[i];
}
return ret;
}
[[nodiscard]] std::array pos() const noexcept {
MC_SCHEM_array3_f64 pos = MC_SCHEM_entity_get_pos(this->handle);
std::array ret{};
for (size_t i = 0; i < 3; i++) {
ret[i] = pos.pos[i];
}
return ret;
}
void set_block_pos(std::span pos) noexcept {
MC_SCHEM_array3_i32 p;
for (size_t i = 0; i < 3; i++) {
p.pos[i] = pos[i];
}
MC_SCHEM_entity_set_block_pos(this->handle, p);
}
void set_pos(std::span pos) noexcept {
MC_SCHEM_array3_f64 p;
for (size_t i = 0; i < 3; i++) {
p.pos[i] = pos[i];
}
MC_SCHEM_entity_set_pos(this->handle, p);
}
using tag_nbt_map_t =
detail::map_wrapper;
protected:
[[nodiscard]] tag_nbt_map_t impl_tags() const noexcept {
return tag_nbt_map_t{MC_SCHEM_entity_get_tags(this->handle)};
}
public:
[[nodiscard]] const tag_nbt_map_t tags() const noexcept {
return this->impl_tags();
}
[[nodiscard]] tag_nbt_map_t tags() noexcept { return this->impl_tags(); }
[[nodiscard]] static detail::box
create() noexcept {
return detail::box{MC_SCHEM_create_entity()};
}
};
class block_entity : public detail::wrapper {
public:
block_entity() = delete;
block_entity(MC_SCHEM_block_entity *handle)
: detail::wrapper{handle} {}
using tag_nbt_map_t =
detail::map_wrapper;
protected:
[[nodiscard]] tag_nbt_map_t impl_tags() const noexcept {
return tag_nbt_map_t{MC_SCHEM_block_entity_get_tags(this->handle)};
}
public:
[[nodiscard]] const tag_nbt_map_t tags() const noexcept {
return this->impl_tags();
}
[[nodiscard]] tag_nbt_map_t tags() noexcept { return this->impl_tags(); }
[[nodiscard]] static detail::box
create() noexcept {
return detail::box{
MC_SCHEM_create_block_entity()};
}
};
class pending_tick : public detail::wrapper {
public:
pending_tick() = delete;
pending_tick(MC_SCHEM_pending_tick *handle)
: detail::wrapper{handle} {}
enum class pending_tick_type : uint8_t {
fluid = 0,
block = 1,
};
[[nodiscard]] int32_t priority() const noexcept {
return MC_SCHEM_pending_tick_get_priority(this->handle);
}
void set_priority(int32_t priority) noexcept {
MC_SCHEM_pending_tick_set_priority(this->handle, priority);
}
[[nodiscard]] int64_t sub_tick() const noexcept {
return MC_SCHEM_pending_tick_get_sub_tick(this->handle);
}
void set_sub_tick(int64_t sub_tick) noexcept {
MC_SCHEM_pending_tick_set_sub_tick(this->handle, sub_tick);
}
[[nodiscard]] int32_t time() const noexcept {
return MC_SCHEM_pending_tick_get_time(this->handle);
}
void set_time(int32_t time) noexcept {
MC_SCHEM_pending_tick_set_time(this->handle, time);
}
[[nodiscard]] std::string_view id() const noexcept {
return detail::string_view_schem_to_std(
MC_SCHEM_pending_tick_get_id(this->handle));
}
[[nodiscard]] pending_tick_type type() const noexcept {
return static_cast(
MC_SCHEM_pending_tick_get_type(this->handle));
}
void set_info(pending_tick_type type, std::string_view id) noexcept {
const auto t = static_cast(type);
MC_SCHEM_pending_tick_set_info(this->handle, t,
detail::string_view_std_to_schem(id));
}
static detail::box
create() noexcept {
return detail::box{
MC_SCHEM_create_pending_tick()};
}
};
class region : public detail::wrapper {
public:
region() = delete;
region(const region &) = delete;
region(region &&) = default;
explicit region(MC_SCHEM_region *handle)
: detail::wrapper{handle} {}
static detail::box create() noexcept {
return detail::box{MC_SCHEM_create_region()};
}
[[nodiscard]] std::string_view name() const noexcept {
return detail::string_view_schem_to_std(
MC_SCHEM_region_get_name(this->handle));
}
void set_name(std::string_view name) noexcept {
MC_SCHEM_region_set_name(this->handle,
detail::string_view_std_to_schem(name));
}
[[nodiscard]] std::array offset() const noexcept {
auto offset = MC_SCHEM_region_get_offset(this->handle);
return detail::array3_i32_schem_to_std(offset);
}
void set_offset(std::span offset) noexcept {
MC_SCHEM_region_set_offset(this->handle,
detail::array3_i32_std_to_schem(offset));
}
[[nodiscard]] const std::vector palette() const noexcept {
size_t len = 0;
auto pal = MC_SCHEM_region_get_palette(this->handle, &len);
std::vector result;
result.reserve(len);
for (size_t i = 0; i < len; i++) {
result.push_back(block{pal + i});
}
return result;
}
void set_palette(std::span pal) noexcept {
MC_SCHEM_region_set_palette(this->handle, pal.data(), pal.size());
}
void set_palette(std::span pal) noexcept {
std::vector p;
p.reserve(pal.size());
for (auto &blk : pal) {
p.push_back(blk.unwrap_handle());
}
this->set_palette(p);
}
using block_entity_map =
detail::map_wrapper,
map_value_type::block_entity, block_entity>;
using pending_tick_map =
detail::map_wrapper,
map_value_type::pending_tick, std::vector>;
protected:
[[nodiscard]] block_entity_map impl_block_entities() const noexcept {
return block_entity_map{MC_SCHEM_region_get_block_entities(this->handle)};
}
[[nodiscard]] pending_tick_map impl_pending_ticks() const noexcept {
return pending_tick_map{MC_SCHEM_region_get_pending_ticks(this->handle)};
}
[[nodiscard]] std::span impl_block_index_array() const noexcept {
auto ptr = MC_SCHEM_region_get_block_index_array(this->handle);
return {ptr, this->volume()};
}
public:
[[nodiscard]] block_entity_map block_entities() noexcept {
return this->impl_block_entities();
}
[[nodiscard]] const block_entity_map block_entities() const noexcept {
return this->impl_block_entities();
}
[[nodiscard]] pending_tick_map pending_ticks() noexcept {
return this->impl_pending_ticks();
}
[[nodiscard]] const pending_tick_map pending_ticks() const noexcept {
return this->impl_pending_ticks();
}
[[nodiscard]] uint64_t volume() const noexcept {
return MC_SCHEM_region_get_volume(this->handle);
}
[[nodiscard]] uint64_t total_blocks(bool include_air) const noexcept {
return MC_SCHEM_region_get_total_blocks(this->handle, include_air);
}
[[nodiscard]] std::array shape() const noexcept {
return detail::array3_i32_schem_to_std(
MC_SCHEM_region_get_shape(this->handle));
}
void reshape(std::span shape) noexcept {
MC_SCHEM_region_reshape(this->handle,
detail::array3_i32_std_to_schem(shape));
}
[[nodiscard]] const block block_at(
std::span r_pos) const noexcept {
auto ptr = MC_SCHEM_region_get_block(
this->handle, detail::array3_i32_std_to_schem(r_pos));
return block{const_cast(ptr)};
}
[[nodiscard]] bool set_block_at(std::span r_pos,
const block &blk) noexcept {
return MC_SCHEM_region_set_block(this->handle,
detail::array3_i32_std_to_schem(r_pos),
blk.unwrap_handle());
}
[[nodiscard]] uint16_t block_index_at(
std::span r_pos) const noexcept {
return MC_SCHEM_region_get_block_index(
this->handle, detail::array3_i32_std_to_schem(r_pos));
}
[[nodiscard]] bool set_block_index_at(std::span r_pos,
uint16_t block_index) noexcept {
return MC_SCHEM_region_set_block_index(
this->handle, detail::array3_i32_std_to_schem(r_pos), block_index);
}
[[nodiscard]] std::optional block_index_of_air() const noexcept {
bool ok = false;
auto result = MC_SCHEM_region_get_block_index_of_air(this->handle, &ok);
if (ok) {
return result;
}
return std::nullopt;
}
[[nodiscard]] std::optional block_index_of_structure_void()
const noexcept {
bool ok = false;
auto result =
MC_SCHEM_region_get_block_index_of_structure_void(this->handle, &ok);
if (ok) {
return result;
}
return std::nullopt;
}
[[nodiscard]] bool contains_coordinate(
std::span r_pos) const noexcept {
return MC_SCHEM_region_contains_coordinate(
this->handle, detail::array3_i32_std_to_schem(r_pos));
}
struct block_info {
uint16_t block_index;
const ::mc_schem::block block;
block_entity block_entity;
std::vector pending_ticks;
};
protected:
[[nodiscard]] block_info impl_block_info_at(
std::span r_pos) const noexcept {
auto result = MC_SCHEM_region_get_block_info(
this->handle, detail::array3_i32_std_to_schem(r_pos));
return block_info{
result.block_index,
block{const_cast(result.block)},
block_entity{const_cast(result.block_entity)},
detail::c_view_to_vector(result.pending_ticks)
};
}
public:
[[nodiscard]] const block_info block_info_at(
std::span r_pos) const noexcept {
return this->impl_block_info_at(r_pos);
}
[[nodiscard]] block_info block_info_at(
std::span r_pos) noexcept {
return this->impl_block_info_at(r_pos);
}
void shrink_palette() {
auto box = MC_SCHEM_region_shrink_palette(this->handle);
if (box.ptr != nullptr) {
throw error{std::move(box)};
}
}
};
enum class common_block : uint16_t {
air = 0,
structure_void = 1,
};
struct litematica_load_option {
using c_type = MC_SCHEM_load_option_litematica;
static_assert(sizeof(c_type) == 512);
litematica_load_option()
: litematica_load_option{MC_SCHEM_load_option_litematica_default()} {}
explicit litematica_load_option(const c_type &) {}
[[nodiscard]] c_type to_c_type() const noexcept {
c_type result{};
return result;
}
};
struct litematica_save_option {
using c_type = MC_SCHEM_save_option_litematica;
static_assert(sizeof(c_type) == 512);
uint32_t compress_level;
bool rename_duplicated_regions;
explicit litematica_save_option(const c_type &src)
: compress_level{src.compress_level},
rename_duplicated_regions{src.rename_duplicated_regions} {}
litematica_save_option()
: litematica_save_option{MC_SCHEM_save_option_litematica_default()} {}
[[nodiscard]] c_type to_c_type() const noexcept {
return c_type{
this->compress_level,
this->rename_duplicated_regions,
};
}
};
struct vanilla_structure_load_option {
using c_type = MC_SCHEM_load_option_vanilla_structure;
static_assert(sizeof(c_type) == 512);
common_block background_block;
explicit vanilla_structure_load_option(const c_type &src)
: background_block{src.background_block} {}
vanilla_structure_load_option()
: vanilla_structure_load_option{
MC_SCHEM_load_option_vanilla_structure_default()} {}
[[nodiscard]] c_type to_c_type() const noexcept {
c_type result{static_cast(this->background_block)};
return result;
}
};
struct vanilla_structure_save_option {
using c_type = MC_SCHEM_save_option_vanilla_structure;
static_assert(sizeof(c_type) == 512);
uint32_t compress_level;
bool keep_air;
explicit vanilla_structure_save_option(const c_type &src)
: compress_level{src.compress_level}, keep_air{src.keep_air} {}
vanilla_structure_save_option()
: vanilla_structure_save_option{
MC_SCHEM_save_option_vanilla_structure_default()} {}
[[nodiscard]] c_type to_c_type() const noexcept {
return c_type{
this->compress_level,
this->keep_air,
};
}
};
struct world_edit_13_load_option {
using c_type = MC_SCHEM_load_option_world_edit_13;
static_assert(sizeof(c_type) == 512);
explicit world_edit_13_load_option(const c_type &) {}
world_edit_13_load_option()
: world_edit_13_load_option{
MC_SCHEM_load_option_world_edit_13_default()} {}
[[nodiscard]] c_type to_c_type() const noexcept {
c_type result{};
return result;
}
};
struct world_edit_13_save_option {
using c_type = MC_SCHEM_save_option_world_edit_13;
static_assert(sizeof(c_type) == 512);
uint32_t compress_level;
common_block background_block;
explicit world_edit_13_save_option(const c_type &src)
: compress_level{src.compress_level},
background_block{static_cast(src.background_block)} {}
world_edit_13_save_option()
: world_edit_13_save_option{
MC_SCHEM_save_option_world_edit_13_default()} {}
[[nodiscard]] c_type to_c_type() const noexcept {
return c_type{
this->compress_level,
static_cast(this->background_block),
};
}
};
struct world_edit_12_load_option {
int32_t data_version;
// bool fix_string_id_with_block_entity_data;
// bool discard_number_id_array;
using c_type = MC_SCHEM_load_option_world_edit_12;
explicit world_edit_12_load_option(const c_type &src)
: data_version{src.data_version} {}
world_edit_12_load_option()
: world_edit_12_load_option{
MC_SCHEM_load_option_world_edit_12_default()} {}
[[nodiscard]] c_type to_c_type() const noexcept {
c_type result{this->data_version};
return result;
}
};
namespace detail {
template
[[nodiscard]] std::optional parse_c_option(
const c_option_t &src) noexcept {
if (src.has_value) {
return T{src.value};
}
return std::nullopt;
}
template
[[nodiscard]] std::optional parse_c_option(
const c_option_t &src) noexcept {
if (src.has_value) {
return {src.value};
}
return std::nullopt;
}
[[nodiscard]] std::optional parse_c_option(
const MC_SCHEM_optional_string_view &src) noexcept {
if (src.has_value) {
return std::string{string_view_schem_to_std(src.value)};
}
return std::nullopt;
}
[[nodiscard]] std::optional> parse_c_option(
const MC_SCHEM_optional_i32_array3 &src) noexcept {
if (src.has_value) {
return {array3_i32_schem_to_std(src.value)};
}
return std::nullopt;
}
[[nodiscard]] MC_SCHEM_optional_i32 make_c_option(
const std::optional &src) noexcept {
return {src.value_or(0), src.has_value()};
}
[[nodiscard]] MC_SCHEM_optional_i64 make_c_option(
const std::optional &src) noexcept {
return {src.value_or(0), src.has_value()};
}
[[nodiscard]] MC_SCHEM_optional_string_view make_c_option(
const std::optional &src) noexcept {
if (src.has_value()) {
return {string_view_std_to_schem(src.value()), true};
}
return {MC_SCHEM_string_view{nullptr, nullptr}, false};
}
[[nodiscard]] MC_SCHEM_optional_i32_array3 make_c_option(
const std::optional> &src) noexcept {
if (src.has_value()) {
return {array3_i32_std_to_schem(src.value()), true};
}
return {MC_SCHEM_array3_i32{{0, 0, 0}}, false};
}
} // namespace detail
struct metadata {
using c_type = MC_SCHEM_schem_metadata_c_rep;
static_assert(sizeof(c_type) == 1024);
int32_t mc_data_version;
int64_t time_created;
int64_t time_modified;
std::string author;
std::string name;
std::string description;
// litematica-related
int32_t litematica_version;
std::optional litematica_subversion;
// world edit 12&13 (.schem/.schematic) related
int32_t schem_version; // world edit schem
std::array schem_offset;
std::optional> schem_we_offset;
// std::optional date;
// world edit 12 related
std::optional schem_world_edit_version;
std::optional schem_editing_platform;
std::optional> schem_origin;
std::string schem_material; // Classic or Alpha
explicit metadata(const c_type &src)
: mc_data_version{src.mc_data_version},
time_created{src.time_created},
time_modified{src.time_modified},
author{detail::string_view_schem_to_std(src.author)},
name{detail::string_view_schem_to_std(src.name)},
description{detail::string_view_schem_to_std(src.author)},
litematica_version{src.litematica_version},
litematica_subversion{
detail::parse_c_option(src.litematica_subversion)},
schem_version{src.schem_version},
schem_offset{src.schem_offset[0], src.schem_offset[1],
src.schem_offset[2]},
schem_we_offset{detail::parse_c_option(src.schem_we_offset)},
// date{detail::parse_c_option(src.date)},
schem_world_edit_version{
detail::parse_c_option(src.schem_world_edit_version)},
schem_editing_platform{
detail::parse_c_option(src.schem_editing_platform)},
schem_origin{detail::parse_c_option(src.schem_origin)},
schem_material{detail::string_view_schem_to_std(src.schem_material)} {}
[[nodiscard]] c_type to_c_type() const noexcept {
return c_type{
this->mc_data_version,
this->time_created,
this->time_modified,
detail::string_view_std_to_schem(this->author),
detail::string_view_std_to_schem(this->name),
detail::string_view_std_to_schem(this->description),
this->litematica_version,
detail::make_c_option(this->litematica_subversion),
this->schem_version,
{this->schem_offset[0], this->schem_offset[1], this->schem_offset[2]},
detail::make_c_option(this->schem_we_offset),
// detail::make_c_option(this->date),
detail::make_c_option(this->schem_world_edit_version),
detail::make_c_option(this->schem_editing_platform),
detail::make_c_option(this->schem_origin),
detail::string_view_std_to_schem(this->schem_material)};
}
};
class schematic : public detail::wrapper {
public:
schematic() = delete;
explicit schematic(MC_SCHEM_schematic *handle)
: detail::wrapper{handle} {}
using schem_box = detail::box;
[[nodiscard]] static schem_box create() noexcept {
return schem_box{MC_SCHEM_create_schem()};
}
using load_result = std::expected;
[[nodiscard]] static load_result c_result_to_load_result(
MC_SCHEM_schem_load_result &&src) noexcept {
if (src.error.ptr != nullptr) {
return std::unexpected(error{std::move(src.error)});
}
return schem_box{std::move(src.schematic)};
}
using save_result = std::expected;
[[nodiscard]] static save_result c_error_box_to_save_result(
MC_SCHEM_error_box &&ret) noexcept {
if (ret.ptr != nullptr) {
return std::unexpected(error{std::move(ret)});
}
return {};
}
[[nodiscard]] static MC_SCHEM_reader wrap_istream(
std::istream &src) noexcept {
MC_SCHEM_reader result;
result.handle = reinterpret_cast(&src);
result.read_fun = [](void *handle, uint8_t *buffer, size_t buffer_size,
bool *ok, char *error,
size_t error_capacity) noexcept -> size_t {
auto *is = reinterpret_cast(handle);
size_t bytes = 0;
try {
bytes = is->readsome(reinterpret_cast(buffer),
static_cast(buffer_size));
} catch (std::exception &e) {
*ok = false;
snprintf(error, error_capacity, "%s", e.what());
return bytes;
}
*ok = true;
return bytes;
};
return result;
}
[[nodiscard]] static MC_SCHEM_writer wrap_ostream(
std::ostream &dst) noexcept {
MC_SCHEM_writer result;
result.handle = &dst;
result.write_fun = [](void *handle, const uint8_t *buffer,
size_t buffer_size, bool *ok, char *error,
size_t error_capacity) noexcept -> size_t {
auto *os = reinterpret_cast(handle);
try {
os->write(reinterpret_cast(buffer), buffer_size);
} catch (std::exception &e) {
*ok = false;
snprintf(error, error_capacity, "%s", e.what());
return 0;
}
*ok = true;
return buffer_size;
};
result.flush_fun = [](void *handle, bool *ok, char *error,
size_t error_capacity) noexcept {
auto *os = reinterpret_cast(handle);
try {
os->flush();
} catch (std::exception &e) {
*ok = false;
snprintf(error, error_capacity, "%s", e.what());
return;
}
*ok = true;
};
return result;
}
// load litematica
[[nodiscard]] static load_result load_litematica(
std::string_view filename,
const litematica_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto file_name = detail::string_view_std_to_schem(filename);
auto result = MC_SCHEM_schem_load_litematica_file(file_name, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_litematica(
std::span bytes,
const litematica_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto result = MC_SCHEM_schem_load_litematica_bytes(
bytes.data(), bytes.size_bytes(), &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_litematica(
MC_SCHEM_reader &reader, const litematica_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto result = MC_SCHEM_schem_load_litematica(reader, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_litematica(
std::istream &src, const litematica_load_option &option) noexcept {
auto reader = wrap_istream(src);
return load_litematica(reader, option);
}
// load vanilla_structure
[[nodiscard]] static load_result load_vanilla_structure(
std::string_view filename,
const vanilla_structure_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto file_name = detail::string_view_std_to_schem(filename);
auto result =
MC_SCHEM_schem_load_vanilla_structure_file(file_name, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_vanilla_structure(
std::span bytes,
const vanilla_structure_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto result = MC_SCHEM_schem_load_vanilla_structure_bytes(
bytes.data(), bytes.size_bytes(), &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_vanilla_structure(
MC_SCHEM_reader &reader,
const vanilla_structure_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto result = MC_SCHEM_schem_load_vanilla_structure(reader, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_vanilla_structure(
std::istream &src, const vanilla_structure_load_option &option) noexcept {
auto reader = wrap_istream(src);
return load_vanilla_structure(reader, option);
}
// load world_edit_13
[[nodiscard]] static load_result load_world_edit_13(
std::string_view filename,
const world_edit_13_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto file_name = detail::string_view_std_to_schem(filename);
auto result =
MC_SCHEM_schem_load_world_edit_13_file(file_name, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_world_edit_13(
std::span bytes,
const world_edit_13_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto result = MC_SCHEM_schem_load_world_edit_13_bytes(
bytes.data(), bytes.size_bytes(), &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_world_edit_13(
MC_SCHEM_reader &reader,
const world_edit_13_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto result = MC_SCHEM_schem_load_world_edit_13(reader, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_world_edit_13(
std::istream &src, const world_edit_13_load_option &option) noexcept {
auto reader = wrap_istream(src);
return load_world_edit_13(reader, option);
}
// load world_edit_12
[[nodiscard]] static load_result load_world_edit_12(
std::string_view filename,
const world_edit_12_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto file_name = detail::string_view_std_to_schem(filename);
auto result =
MC_SCHEM_schem_load_world_edit_12_file(file_name, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_world_edit_12(
std::span bytes,
const world_edit_12_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto result = MC_SCHEM_schem_load_world_edit_12_bytes(
bytes.data(), bytes.size_bytes(), &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_world_edit_12(
MC_SCHEM_reader &reader,
const world_edit_12_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto result = MC_SCHEM_schem_load_world_edit_12(reader, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] static load_result load_world_edit_12(
std::istream &src, const world_edit_12_load_option &option) noexcept {
auto c_option = option.to_c_type();
auto reader = wrap_istream(src);
auto result = MC_SCHEM_schem_load_world_edit_12(reader, &c_option);
return c_result_to_load_result(std::move(result));
}
[[nodiscard]] save_result save_litematica(
std::string_view filename,
const litematica_save_option &option) const noexcept {
auto c_option = option.to_c_type();
auto file = detail::string_view_std_to_schem(filename);
auto error =
MC_SCHEM_schem_save_litematica_file(this->handle, file, &c_option);
return c_error_box_to_save_result(std::move(error));
}
[[nodiscard]] save_result save_litematica(
MC_SCHEM_writer &writer,
const litematica_save_option &option) const noexcept {
auto c_option = option.to_c_type();
auto error =
MC_SCHEM_schem_save_litematica(this->handle, writer, &c_option);
return c_error_box_to_save_result(std::move(error));
}
[[nodiscard]] save_result save_litematica(
std::ostream &dest, const litematica_save_option &option) const noexcept {
auto writer = wrap_ostream(dest);
return this->save_litematica(writer, option);
}
[[nodiscard]] save_result save_vanilla_structure(
std::string_view filename,
const vanilla_structure_save_option &option) const noexcept {
auto c_option = option.to_c_type();
auto file = detail::string_view_std_to_schem(filename);
auto error = MC_SCHEM_schem_save_vanilla_structure_file(this->handle,
file, &c_option);
return c_error_box_to_save_result(std::move(error));
}
[[nodiscard]] save_result save_vanilla_structure(
MC_SCHEM_writer &writer,
const vanilla_structure_save_option &option) const noexcept {
auto c_option = option.to_c_type();
auto error =
MC_SCHEM_schem_save_vanilla_structure(this->handle, writer, &c_option);
return c_error_box_to_save_result(std::move(error));
}
[[nodiscard]] save_result save_vanilla_structure(
std::ostream &dest,
const vanilla_structure_save_option &option) const noexcept {
auto writer = wrap_ostream(dest);
return this->save_vanilla_structure(writer, option);
}
[[nodiscard]] save_result save_world_edit_13(
std::string_view filename,
const world_edit_13_save_option &option) const noexcept {
auto c_option = option.to_c_type();
auto file = detail::string_view_std_to_schem(filename);
auto error =
MC_SCHEM_schem_save_world_edit_13_file(this->handle, file, &c_option);
return c_error_box_to_save_result(std::move(error));
}
[[nodiscard]] save_result save_world_edit_13(
MC_SCHEM_writer &writer,
const world_edit_13_save_option &option) const noexcept {
auto c_option = option.to_c_type();
auto error =
MC_SCHEM_schem_save_world_edit_13(this->handle, writer, &c_option);
return c_error_box_to_save_result(std::move(error));
}
[[nodiscard]] save_result save_world_edit_13(
std::ostream &dest,
const world_edit_13_save_option &option) const noexcept {
auto writer = wrap_ostream(dest);
return this->save_world_edit_13(writer, option);
}
[[nodiscard]] ::mc_schem::metadata metadata() const noexcept {
return ::mc_schem::metadata{MC_SCHEM_schem_get_metadata(this->handle)};
}
void set_metadata(const MC_SCHEM_schem_metadata_c_rep *c_md) noexcept {
MC_SCHEM_schem_set_metadata(this->handle, c_md);
}
void set_metadata(const ::mc_schem::metadata &src) noexcept {
auto c_md = src.to_c_type();
this->set_metadata(&c_md);
}
[[nodiscard]] size_t num_regions() const noexcept {
return MC_SCHEM_schem_get_region_num(this->handle);
}
protected:
[[nodiscard]] std::vector impl_regions() const noexcept {
std::vector result;
const size_t num_regions = MC_SCHEM_schem_get_region_num(this->handle);
result.reserve(num_regions);
for (size_t i = 0; i < num_regions; i++) {
auto reg_ptr = MC_SCHEM_schem_get_region(this->handle, i);
result.emplace_back(reg_ptr);
}
return result;
}
public:
[[nodiscard]] std::vector regions() noexcept {
return this->impl_regions();
}
[[nodiscard]] const std::vector regions() const noexcept {
return this->impl_regions();
}
using region_box = detail::box;
[[nodiscard]] region_box take_region(size_t index) noexcept {
return region_box{MC_SCHEM_schem_take_region(this->handle, index)};
}
void insert_region(const region ®, size_t index) noexcept {
MC_SCHEM_schem_insert_region_copy(this->handle, reg.unwrap_handle(),
index);
}
void insert_region(region_box &&box, size_t index) noexcept {
MC_SCHEM_region_box b{box->unwrap_handle()};
MC_SCHEM_schem_insert_region_move(this->handle, &b, index);
}
void block_indices_at(std::span pos,
std::vector &dest) const noexcept {
size_t size = 0;
dest.resize(this->num_regions());
MC_SCHEM_schem_get_block_indices_at(this->handle,
detail::array3_i32_std_to_schem(pos),
&size, dest.data(), dest.size());
assert(size <= dest.size());
dest.resize(size);
}
[[nodiscard]] std::vector block_indices_at(
std::span pos) const noexcept {
std::vector result;
this->block_indices_at(pos, result);
return result;
}
void blocks_at(std::span pos,
std::vector &dest) const noexcept {
size_t size = 0;
dest.resize(this->num_regions());
MC_SCHEM_schem_get_blocks_at(this->handle,
detail::array3_i32_std_to_schem(pos), &size,
dest.data(), dest.size());
assert(size <= dest.size());
dest.resize(size);
}
[[nodiscard]] const std::vector blocks_at(
std::span pos) const noexcept {
std::vector temp;
this->blocks_at(pos, temp);
std::vector result;
result.reserve(temp.size());
for (auto handle : temp) {
result.emplace_back(const_cast(handle));
}
return result;
}
[[nodiscard]] std::optional first_block_index_at(
std::span pos) const noexcept {
return detail::parse_c_option(MC_SCHEM_schem_get_first_block_index_at(
this->handle, detail::array3_i32_std_to_schem(pos)));
}
[[nodiscard]] std::optional first_block_at(
std::span pos) const noexcept {
auto blkp = MC_SCHEM_schem_get_first_block_at(
this->handle, detail::array3_i32_std_to_schem(pos));
if (blkp != nullptr) {
return block{const_cast(blkp)};
}
return std::nullopt;
}
[[nodiscard]] std::array shape() const noexcept {
return detail::array3_i32_schem_to_std(
MC_SCHEM_schem_get_shape(this->handle));
}
[[nodiscard]] uint64_t volume() const noexcept {
return MC_SCHEM_schem_get_volume(this->handle);
}
[[nodiscard]] uint64_t total_blocks(bool include_air) const noexcept {
return MC_SCHEM_schem_get_total_blocks(this->handle, include_air);
}
};
} // namespace mc_schem
#endif // MC_SCHEM_MC_SCHEM_HPP