mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-13 15:01:49 +00:00
Merge branch 'main' into physics-upgrade
This commit is contained in:
commit
6676db3525
21 changed files with 249 additions and 53 deletions
|
|
@ -241,6 +241,15 @@ Number of block inventory slots. Default - 0 (no inventory).
|
||||||
|
|
||||||
Array of three integers. Default value is `[1, 1, 1]`.
|
Array of three integers. Default value is `[1, 1, 1]`.
|
||||||
|
|
||||||
|
### *grounding-behaviour*
|
||||||
|
|
||||||
|
Defines the behavior of the extended grounded block. Available behavior options:
|
||||||
|
|
||||||
|
- "partial" - at least one segment must be grounded (default)
|
||||||
|
- "complete" - all segments must be grounded
|
||||||
|
- "origin" - origin segment must be grounded
|
||||||
|
|
||||||
|
|
||||||
## Block fields
|
## Block fields
|
||||||
|
|
||||||
Block fields allow you to write more data unique to a specified voxel than the user bits allow.
|
Block fields allow you to write more data unique to a specified voxel than the user bits allow.
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ block.get_picking_item(id: int) -> int
|
||||||
block.get_variant(x: int, y: int, z: int) -> int
|
block.get_variant(x: int, y: int, z: int) -> int
|
||||||
|
|
||||||
-- Sets the block variant by index
|
-- Sets the block variant by index
|
||||||
block.set_variant(x: int, y: int, z: int, index: int) -> int
|
block.set_variant(x: int, y: int, z: int, index: int)
|
||||||
|
|
||||||
-- Checks if an block has specified tag
|
-- Checks if an block has specified tag
|
||||||
block.has_tag(id: int, tag: str) -> bool
|
block.has_tag(id: int, tag: str) -> bool
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,14 @@
|
||||||
|
|
||||||
Массив из трех целых чисел. Значение по-умолчанию - `[1, 1, 1]`.
|
Массив из трех целых чисел. Значение по-умолчанию - `[1, 1, 1]`.
|
||||||
|
|
||||||
|
### Поведение приземленности - *grounding-behaviour*
|
||||||
|
|
||||||
|
Определяет поведение расширенного приземленного блока. Доступные варианты поведения:
|
||||||
|
|
||||||
|
- "partial" - как минимум один сегмент блока должен быть приземленным (по-умолчанию)
|
||||||
|
- "complete" - все сегменты блока должны быть приземленными
|
||||||
|
- "origin" - главный сегмент должен быть приземленным
|
||||||
|
|
||||||
## Поля блока
|
## Поля блока
|
||||||
|
|
||||||
Поля блоков позволяет записывать больше уникальных для конкретного блока данных, чем это позволяют пользовательские биты.
|
Поля блоков позволяет записывать больше уникальных для конкретного блока данных, чем это позволяют пользовательские биты.
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ block.destruct(x: int, y: int, z: int, playerid: int)
|
||||||
block.get_variant(x: int, y: int, z: int) -> int
|
block.get_variant(x: int, y: int, z: int) -> int
|
||||||
|
|
||||||
-- Устанавливает вариант блока по индексу
|
-- Устанавливает вариант блока по индексу
|
||||||
block.set_variant(x: int, y: int, z: int, index: int) -> int
|
block.set_variant(x: int, y: int, z: int, index: int)
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,19 @@
|
||||||
#include "Assets.hpp"
|
#include "Assets.hpp"
|
||||||
|
|
||||||
Assets::~Assets() = default;
|
Assets::Assets(util::ObjectsKeeper* vault) : vault(vault) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Assets::~Assets() {
|
||||||
|
if (vault == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto& [_, map] : assets) {
|
||||||
|
for (auto& [__, asset] : map) {
|
||||||
|
vault->keepAlive(std::move(asset));
|
||||||
|
}
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<TextureAnimation>& Assets::getAnimations() {
|
const std::vector<TextureAnimation>& Assets::getAnimations() {
|
||||||
return animations;
|
return animations;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
#include "util/ObjectsKeeper.hpp"
|
||||||
#include "graphics/core/TextureAnimation.hpp"
|
#include "graphics/core/TextureAnimation.hpp"
|
||||||
|
|
||||||
class Assets;
|
class Assets;
|
||||||
|
|
@ -64,13 +65,14 @@ namespace assetload {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Assets {
|
class Assets {
|
||||||
|
util::ObjectsKeeper* vault;
|
||||||
std::vector<TextureAnimation> animations;
|
std::vector<TextureAnimation> animations;
|
||||||
|
|
||||||
using assets_map = std::unordered_map<std::string, std::shared_ptr<void>>;
|
using assets_map = std::unordered_map<std::string, std::shared_ptr<void>>;
|
||||||
std::unordered_map<std::type_index, assets_map> assets;
|
std::unordered_map<std::type_index, assets_map> assets;
|
||||||
std::vector<assetload::setupfunc> setupFuncs;
|
std::vector<assetload::setupfunc> setupFuncs;
|
||||||
public:
|
public:
|
||||||
Assets() = default;
|
Assets(util::ObjectsKeeper* vault);
|
||||||
Assets(const Assets&) = delete;
|
Assets(const Assets&) = delete;
|
||||||
~Assets();
|
~Assets();
|
||||||
|
|
||||||
|
|
@ -79,12 +81,20 @@ public:
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void store(std::unique_ptr<T> asset, const std::string& name) {
|
void store(std::unique_ptr<T> asset, const std::string& name) {
|
||||||
assets[typeid(T)][name].reset(asset.release());
|
auto& dst = assets[typeid(T)][name];
|
||||||
|
if (vault != nullptr && dst != nullptr) {
|
||||||
|
vault->keepAlive(std::move(dst));
|
||||||
|
}
|
||||||
|
dst.reset(asset.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void store(std::shared_ptr<T> asset, const std::string& name) {
|
void store(std::shared_ptr<T> asset, const std::string& name) {
|
||||||
assets[typeid(T)][name] = std::move(asset);
|
auto& dst = assets[typeid(T)][name];
|
||||||
|
if (vault != nullptr && dst != nullptr) {
|
||||||
|
vault->keepAlive(std::move(dst));
|
||||||
|
}
|
||||||
|
dst = std::move(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ inline constexpr int CHUNK_W = 16;
|
||||||
inline constexpr int CHUNK_H = 256;
|
inline constexpr int CHUNK_H = 256;
|
||||||
inline constexpr int CHUNK_D = 16;
|
inline constexpr int CHUNK_D = 16;
|
||||||
|
|
||||||
|
inline constexpr int EXTENDED_BLOCK_LIMIT = CHUNK_W; // must not be greater than chunk width and depth
|
||||||
|
|
||||||
inline constexpr uint VOXEL_USER_BITS = 8;
|
inline constexpr uint VOXEL_USER_BITS = 8;
|
||||||
inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS;
|
inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include "presets/ParticlesPreset.hpp"
|
#include "presets/ParticlesPreset.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
|
#include "constants.hpp"
|
||||||
|
|
||||||
using namespace data;
|
using namespace data;
|
||||||
|
|
||||||
|
|
@ -120,8 +121,8 @@ template<> void ContentUnitLoader<Block>::loadUnit(
|
||||||
}
|
}
|
||||||
|
|
||||||
def.variants = std::make_unique<Variants>();
|
def.variants = std::make_unique<Variants>();
|
||||||
def.variants->offset = 0;
|
def.variants->offset = offset;
|
||||||
def.variants->mask = 0xF;
|
def.variants->mask = (1ULL << bitsCount) - 1;
|
||||||
def.variants->variants.push_back(def.defaults);
|
def.variants->variants.push_back(def.defaults);
|
||||||
for (int i = 0; i < variants.size(); i++) {
|
for (int i = 0; i < variants.size(); i++) {
|
||||||
Variant variant = def.defaults;
|
Variant variant = def.defaults;
|
||||||
|
|
@ -184,7 +185,11 @@ template<> void ContentUnitLoader<Block>::loadUnit(
|
||||||
if (auto found = root.at("emission")) {
|
if (auto found = root.at("emission")) {
|
||||||
const auto& emissionarr = *found;
|
const auto& emissionarr = *found;
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (size_t i = 0; i < 3; i++) {
|
||||||
def.emission[i] = glm::clamp(emissionarr[i].asInteger(), static_cast<integer_t>(0), static_cast<integer_t>(15));
|
def.emission[i] = glm::clamp(
|
||||||
|
emissionarr[i].asInteger(),
|
||||||
|
static_cast<integer_t>(0),
|
||||||
|
static_cast<integer_t>(15)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,13 +204,31 @@ template<> void ContentUnitLoader<Block>::loadUnit(
|
||||||
"block " + util::quote(def.name) + ": invalid block size"
|
"block " + util::quote(def.name) + ": invalid block size"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (def.size.x > EXTENDED_BLOCK_LIMIT ||
|
||||||
|
def.size.y > EXTENDED_BLOCK_LIMIT ||
|
||||||
|
def.size.z > EXTENDED_BLOCK_LIMIT) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"extended block " + util::quote(def.name) + " size limit " +
|
||||||
|
std::to_string(EXTENDED_BLOCK_LIMIT) + " exceeded"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// should variant modify hitbox?
|
// should variant modify hitbox?
|
||||||
if (def.defaults.model.type == BlockModelType::BLOCK &&
|
if (def.defaults.model.type == BlockModelType::BLOCK &&
|
||||||
(def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) {
|
(def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) {
|
||||||
def.defaults.model.type = BlockModelType::AABB;
|
def.defaults.model.type = BlockModelType::AABB;
|
||||||
def.hitboxes = {AABB(def.size)};
|
def.hitboxes = {AABB(def.size)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// grounding behaviour
|
||||||
|
if (root.has("grounding-behaviour")) {
|
||||||
|
std::string groundingBehaviourName = GroundingBehaviourMeta.getNameString(def.groundingBehaviour);
|
||||||
|
root.at("grounding-behaviour").get(groundingBehaviourName);
|
||||||
|
if (!GroundingBehaviourMeta.getItem(groundingBehaviourName, def.groundingBehaviour)) {
|
||||||
|
logger.error() << "unknown grounding behaviour: " << groundingBehaviourName;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// primitive properties
|
// primitive properties
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,9 @@ void AssetsManagement::loadAssets(Content* content) {
|
||||||
logger.info() << "loading assets";
|
logger.info() << "loading assets";
|
||||||
Shader::preprocessor->setPaths(&paths.resPaths);
|
Shader::preprocessor->setPaths(&paths.resPaths);
|
||||||
|
|
||||||
auto new_assets = std::make_unique<Assets>();
|
auto new_assets = std::make_unique<Assets>(
|
||||||
|
settings.system.preserveAssetsDuringFrame.get() ? &assetsVault : nullptr
|
||||||
|
);
|
||||||
AssetsLoader loader(engine, *new_assets, paths.resPaths);
|
AssetsLoader loader(engine, *new_assets, paths.resPaths);
|
||||||
AssetsLoader::addDefaults(loader, content);
|
AssetsLoader::addDefaults(loader, content);
|
||||||
|
|
||||||
|
|
@ -78,6 +80,7 @@ void AssetsManagement::loadAssets(Content* content) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManagement::update() {
|
void AssetsManagement::update() {
|
||||||
|
assetsVault.clearKeepedObjects();
|
||||||
if (backgroundLoaderTask) {
|
if (backgroundLoaderTask) {
|
||||||
backgroundLoaderTask->update();
|
backgroundLoaderTask->update();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "assets/Assets.hpp"
|
#include "assets/Assets.hpp"
|
||||||
|
#include "util/ObjectsKeeper.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -30,4 +31,5 @@ private:
|
||||||
std::unique_ptr<Assets> assets;
|
std::unique_ptr<Assets> assets;
|
||||||
std::unique_ptr<AssetsLoader> backgroundLoader;
|
std::unique_ptr<AssetsLoader> backgroundLoader;
|
||||||
std::shared_ptr<Task> backgroundLoaderTask;
|
std::shared_ptr<Task> backgroundLoaderTask;
|
||||||
|
util::ObjectsKeeper assetsVault;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ void ContentGfxCache::refresh(const Block& def, const Atlas& atlas) {
|
||||||
refreshVariant(def, def.defaults, 0, atlas);
|
refreshVariant(def, def.defaults, 0, atlas);
|
||||||
if (def.variants) {
|
if (def.variants) {
|
||||||
const auto& variants = def.variants->variants;
|
const auto& variants = def.variants->variants;
|
||||||
for (int i = 1; i < variants.size() - 1; i++) {
|
for (int i = 1; i < variants.size(); i++) {
|
||||||
refreshVariant(def, variants[i], i, atlas);
|
refreshVariant(def, variants[i], i, atlas);
|
||||||
}
|
}
|
||||||
def.variants->variants.at(0) = def.defaults;
|
def.variants->variants.at(0) = def.defaults;
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ LevelScreen::~LevelScreen() {
|
||||||
}
|
}
|
||||||
scripting::on_frontend_close();
|
scripting::on_frontend_close();
|
||||||
input.getBindings().enableAll();
|
input.getBindings().enableAll();
|
||||||
playerController->getPlayer()->chunks->saveAndClear();
|
playerController->getPlayer().chunks->saveAndClear();
|
||||||
controller->onWorldQuit();
|
controller->onWorldQuit();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -168,12 +168,12 @@ void LevelScreen::saveDecorations() {
|
||||||
void LevelScreen::saveWorldPreview() {
|
void LevelScreen::saveWorldPreview() {
|
||||||
try {
|
try {
|
||||||
logger.info() << "saving world preview";
|
logger.info() << "saving world preview";
|
||||||
auto player = playerController->getPlayer();
|
const Player& player = playerController->getPlayer();
|
||||||
auto& settings = engine.getSettings();
|
const auto& settings = engine.getSettings();
|
||||||
int previewSize = settings.ui.worldPreviewSize.get();
|
int previewSize = settings.ui.worldPreviewSize.get();
|
||||||
|
|
||||||
// camera special copy for world preview
|
// camera special copy for world preview
|
||||||
Camera camera = *player->fpCamera;
|
Camera& camera = *player.fpCamera;
|
||||||
camera.setFov(glm::radians(70.0f));
|
camera.setFov(glm::radians(70.0f));
|
||||||
|
|
||||||
DrawContext pctx(nullptr, engine.getWindow(), batch.get());
|
DrawContext pctx(nullptr, engine.getWindow(), batch.get());
|
||||||
|
|
@ -215,18 +215,18 @@ void LevelScreen::updateHotkeys() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelScreen::updateAudio() {
|
void LevelScreen::updateAudio() {
|
||||||
auto player = playerController->getPlayer();
|
Player& player = playerController->getPlayer();
|
||||||
auto camera = player->currentCamera;
|
Camera& camera = *player.currentCamera;
|
||||||
bool paused = hud->isPause();
|
bool paused = hud->isPause();
|
||||||
|
|
||||||
audio::get_channel("regular")->setPaused(paused);
|
audio::get_channel("regular")->setPaused(paused);
|
||||||
audio::get_channel("ambient")->setPaused(paused);
|
audio::get_channel("ambient")->setPaused(paused);
|
||||||
glm::vec3 velocity {};
|
glm::vec3 velocity {};
|
||||||
if (auto hitbox = player->getHitbox()) {
|
if (auto hitbox = player.getHitbox()) {
|
||||||
velocity = hitbox->velocity;
|
velocity = hitbox->velocity;
|
||||||
}
|
}
|
||||||
audio::set_listener(
|
audio::set_listener(
|
||||||
camera->position, velocity, camera->dir, glm::vec3(0, 1, 0)
|
camera.position, velocity, camera.dir, glm::vec3(0, 1, 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,22 +257,22 @@ void LevelScreen::update(float delta) {
|
||||||
|
|
||||||
hud->update(hudVisible);
|
hud->update(hudVisible);
|
||||||
|
|
||||||
const auto& weather = renderer->getWeather();
|
const Weather& weather = renderer->getWeather();
|
||||||
const auto& player = *playerController->getPlayer();
|
const Player& player = playerController->getPlayer();
|
||||||
const auto& camera = *player.currentCamera;
|
const Camera& camera = *player.currentCamera;
|
||||||
decorator->update(paused ? 0.0f : delta, camera, weather);
|
decorator->update(paused ? 0.0f : delta, camera, weather);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelScreen::draw(float delta) {
|
void LevelScreen::draw(float delta) {
|
||||||
auto camera = playerController->getPlayer()->currentCamera;
|
Camera& camera = *playerController->getPlayer().currentCamera;
|
||||||
|
|
||||||
DrawContext ctx(nullptr, engine.getWindow(), batch.get());
|
const DrawContext ctx(nullptr, engine.getWindow(), batch.get());
|
||||||
|
|
||||||
if (!hud->isPause()) {
|
if (!hud->isPause()) {
|
||||||
scripting::on_entities_render(engine.getTime().getDelta());
|
scripting::on_entities_render(engine.getTime().getDelta());
|
||||||
}
|
}
|
||||||
renderer->update(*camera, delta * !hud->isPause());
|
renderer->update(camera, delta * !hud->isPause());
|
||||||
renderer->renderFrame(ctx, *camera, hudVisible, *postProcessing);
|
renderer->renderFrame(ctx, camera, hudVisible, *postProcessing);
|
||||||
if (!hud->isPause()) {
|
if (!hud->isPause()) {
|
||||||
scripting::on_frontend_render();
|
scripting::on_frontend_render();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,12 @@ void ModelsGenerator::prepareModel(
|
||||||
void ModelsGenerator::prepare(Content& content, Assets& assets) {
|
void ModelsGenerator::prepare(Content& content, Assets& assets) {
|
||||||
for (auto& [name, def] : content.blocks.getDefs()) {
|
for (auto& [name, def] : content.blocks.getDefs()) {
|
||||||
prepareModel(assets, *def, def->defaults, 0);
|
prepareModel(assets, *def, def->defaults, 0);
|
||||||
|
if (def->variants) {
|
||||||
|
auto& variants = def->variants->variants;
|
||||||
|
for (int i = 1; i < variants.size(); i++) {
|
||||||
|
prepareModel(assets, *def, variants[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (auto& [name, def] : content.items.getDefs()) {
|
for (auto& [name, def] : content.items.getDefs()) {
|
||||||
assets.store(
|
assets.store(
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
||||||
|
|
||||||
builder.addSection("system");
|
builder.addSection("system");
|
||||||
builder.add("max-bg-asset-loaders", &settings.system.maxBgAssetLoaders);
|
builder.add("max-bg-asset-loaders", &settings.system.maxBgAssetLoaders);
|
||||||
|
builder.add("preserve-assets-during-frame", &settings.system.preserveAssetsDuringFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
dv::value SettingsHandler::getValue(const std::string& name) const {
|
dv::value SettingsHandler::getValue(const std::string& name) const {
|
||||||
|
|
|
||||||
|
|
@ -111,10 +111,17 @@ void BlocksController::updateBlock(int x, int y, int z) {
|
||||||
if (vox == nullptr) return;
|
if (vox == nullptr) return;
|
||||||
const auto& def = level.content.getIndices()->blocks.require(vox->id);
|
const auto& def = level.content.getIndices()->blocks.require(vox->id);
|
||||||
if (def.grounded) {
|
if (def.grounded) {
|
||||||
const auto& vec = get_ground_direction(def, vox->state.rotation);
|
if (def.rt.extended) {
|
||||||
if (!blocks_agent::is_solid_at(chunks, x + vec.x, y + vec.y, z + vec.z)) {
|
auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state);
|
||||||
breakBlock(nullptr, def, x, y, z);
|
if (!blocks_agent::check_grounding(chunks, def, vox->state.rotation, origin)) {
|
||||||
return;
|
breakBlock(nullptr, def, origin.x, origin.y, origin.z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!blocks_agent::check_grounding(chunks, def, vox->state.rotation, {x, y, z})) {
|
||||||
|
breakBlock(nullptr, def, x, y, z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (def.rt.funcsset.update) {
|
if (def.rt.funcsset.update) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include "scripting/scripting.hpp"
|
#include "scripting/scripting.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
|
#include "voxels/blocks_agent.hpp"
|
||||||
#include "voxels/Chunks.hpp"
|
#include "voxels/Chunks.hpp"
|
||||||
#include "voxels/voxel.hpp"
|
#include "voxels/voxel.hpp"
|
||||||
#include "window/Camera.hpp"
|
#include "window/Camera.hpp"
|
||||||
|
|
@ -252,18 +253,18 @@ void PlayerController::onFootstep(const Hitbox& hitbox) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::updateFootsteps(float delta) {
|
void PlayerController::updateFootsteps(float delta) {
|
||||||
const float pi = glm::pi<float>();
|
constexpr float GLM_PI = glm::pi<float>();
|
||||||
auto hitbox = player.getHitbox();
|
auto hitbox = player.getHitbox();
|
||||||
if (hitbox && hitbox->grounded) {
|
if (hitbox && hitbox->grounded) {
|
||||||
const glm::vec3& vel = hitbox->velocity;
|
const glm::vec3& vel = hitbox->velocity;
|
||||||
float f = glm::length(glm::vec2(vel.x, vel.z));
|
float f = glm::length(glm::vec2(vel.x, vel.z));
|
||||||
stepsTimer += delta * f * STEPS_SPEED;
|
stepsTimer += delta * f * STEPS_SPEED;
|
||||||
if (stepsTimer >= pi) {
|
if (stepsTimer >= GLM_PI) {
|
||||||
stepsTimer = fmod(stepsTimer, pi);
|
stepsTimer = fmod(stepsTimer, GLM_PI);
|
||||||
onFootstep(*hitbox);
|
onFootstep(*hitbox);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stepsTimer = pi;
|
stepsTimer = GLM_PI;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -448,10 +449,7 @@ void PlayerController::processRightClick(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (def.grounded) {
|
if (def.grounded) {
|
||||||
const auto& vec = get_ground_direction(def, state.rotation);
|
if (!blocks_agent::check_grounding(chunks, def, state.rotation, coord)) {
|
||||||
if (!chunks.isSolidBlock(
|
|
||||||
coord.x + vec.x, coord.y + vec.y, coord.z + vec.z
|
|
||||||
)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -556,6 +554,6 @@ void PlayerController::updateInteraction(const Input& inputEvents, float delta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* PlayerController::getPlayer() {
|
Player& PlayerController::getPlayer() {
|
||||||
return &player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,5 +89,5 @@ public:
|
||||||
void postUpdate(
|
void postUpdate(
|
||||||
float delta, int windowHeight, const Input* inputEvents, bool pause
|
float delta, int windowHeight, const Input* inputEvents, bool pause
|
||||||
);
|
);
|
||||||
Player* getPlayer();
|
Player& getPlayer();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -246,11 +246,12 @@ static int l_get_user_bits(lua::State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_get_variant(lua::State* L) {
|
static int l_get_variant(lua::State* L) {
|
||||||
|
auto& chunks = *level->chunks;
|
||||||
auto x = lua::tointeger(L, 1);
|
auto x = lua::tointeger(L, 1);
|
||||||
auto y = lua::tointeger(L, 2);
|
auto y = lua::tointeger(L, 2);
|
||||||
auto z = lua::tointeger(L, 3);
|
auto z = lua::tointeger(L, 3);
|
||||||
|
|
||||||
auto vox = blocks_agent::get(*level->chunks, x, y, z);
|
auto vox = blocks_agent::get(chunks, x, y, z);
|
||||||
if (vox == nullptr) {
|
if (vox == nullptr) {
|
||||||
return lua::pushinteger(L, 0);
|
return lua::pushinteger(L, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -258,6 +259,13 @@ static int l_get_variant(lua::State* L) {
|
||||||
if (def.variants == nullptr) {
|
if (def.variants == nullptr) {
|
||||||
return lua::pushinteger(L, 0);
|
return lua::pushinteger(L, 0);
|
||||||
}
|
}
|
||||||
|
if (def.rt.extended) {
|
||||||
|
auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state);
|
||||||
|
vox = blocks_agent::get(chunks, origin.x, origin.y, origin.z);
|
||||||
|
if (vox == nullptr) {
|
||||||
|
return lua::pushinteger(L, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
return lua::pushinteger(
|
return lua::pushinteger(
|
||||||
L, (vox->state.userbits >> def.variants->offset) & def.variants->mask
|
L, (vox->state.userbits >> def.variants->offset) & def.variants->mask
|
||||||
);
|
);
|
||||||
|
|
@ -290,6 +298,14 @@ static int l_set_user_bits(lua::State* L) {
|
||||||
if (vox == nullptr) {
|
if (vox == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int ocx = floordiv<CHUNK_W>(origin.x);
|
||||||
|
int ocz = floordiv<CHUNK_D>(origin.z);
|
||||||
|
if (cx != ocx || cz != ocz) {
|
||||||
|
chunk = blocks_agent::get_chunk(chunks, ocx, ocz);
|
||||||
|
if (chunk == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vox->state.userbits = (vox->state.userbits & (~mask)) | value;
|
vox->state.userbits = (vox->state.userbits & (~mask)) | value;
|
||||||
chunk->setModifiedAndUnsaved();
|
chunk->setModifiedAndUnsaved();
|
||||||
|
|
@ -318,8 +334,8 @@ static int l_set_variant(lua::State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto offset = def.variants->offset;
|
auto offset = def.variants->offset;
|
||||||
auto mask = def.variants->mask;
|
auto mask = def.variants->mask << offset;
|
||||||
auto value = (lua::tointeger(L, 4) << offset) & mask;
|
auto value = (lua::tointeger(L, 4) << offset);
|
||||||
|
|
||||||
if (def.rt.extended) {
|
if (def.rt.extended) {
|
||||||
auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state);
|
auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state);
|
||||||
|
|
@ -327,6 +343,14 @@ static int l_set_variant(lua::State* L) {
|
||||||
if (vox == nullptr) {
|
if (vox == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int ocx = floordiv<CHUNK_W>(origin.x);
|
||||||
|
int ocz = floordiv<CHUNK_D>(origin.z);
|
||||||
|
if (cx != ocx || cz != ocz) {
|
||||||
|
chunk = blocks_agent::get_chunk(chunks, ocx, ocz);
|
||||||
|
if (chunk == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vox->state.userbits = (vox->state.userbits & (~mask)) | value;
|
vox->state.userbits = (vox->state.userbits & (~mask)) | value;
|
||||||
chunk->setModifiedAndUnsaved();
|
chunk->setModifiedAndUnsaved();
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,10 @@ struct NetworkSettings {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SystemSettings {
|
struct SystemSettings {
|
||||||
|
/// @brief Max background assets loaders
|
||||||
IntegerSetting maxBgAssetLoaders {3, -4, 16};
|
IntegerSetting maxBgAssetLoaders {3, -4, 16};
|
||||||
|
/// @brief Preserve assets during current frame from being destroyed
|
||||||
|
FlagSetting preserveAssetsDuringFrame {true};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EngineSettings {
|
struct EngineSettings {
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,22 @@ VC_ENUM_METADATA(CullingMode)
|
||||||
{"disabled", CullingMode::DISABLED},
|
{"disabled", CullingMode::DISABLED},
|
||||||
VC_ENUM_END
|
VC_ENUM_END
|
||||||
|
|
||||||
|
/// @brief Grounding behaviour for extended blocks
|
||||||
|
enum class GroundingBehaviour : uint8_t {
|
||||||
|
/// @brief at least one segment must be grounded
|
||||||
|
PARTIAL,
|
||||||
|
/// @brief all segments must be grounded
|
||||||
|
COMPLETE,
|
||||||
|
/// @brief origin segment must be grounded
|
||||||
|
ORIGIN
|
||||||
|
};
|
||||||
|
|
||||||
|
VC_ENUM_METADATA(GroundingBehaviour)
|
||||||
|
{"partial", GroundingBehaviour::PARTIAL},
|
||||||
|
{"complete", GroundingBehaviour::COMPLETE},
|
||||||
|
{"origin", GroundingBehaviour::ORIGIN},
|
||||||
|
VC_ENUM_END
|
||||||
|
|
||||||
/// @brief Common kit of block properties applied to groups of blocks
|
/// @brief Common kit of block properties applied to groups of blocks
|
||||||
struct BlockMaterial : Serializable {
|
struct BlockMaterial : Serializable {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
@ -239,6 +255,9 @@ public:
|
||||||
/// @brief Explicitly overriding 'solid' property if true assigned
|
/// @brief Explicitly overriding 'solid' property if true assigned
|
||||||
bool explictlySolid = false;
|
bool explictlySolid = false;
|
||||||
|
|
||||||
|
/// @brief Grounding behaviour
|
||||||
|
GroundingBehaviour groundingBehaviour = GroundingBehaviour::PARTIAL;
|
||||||
|
|
||||||
/// @brief Set of block physical hitboxes
|
/// @brief Set of block physical hitboxes
|
||||||
std::vector<AABB> hitboxes {AABB()};
|
std::vector<AABB> hitboxes {AABB()};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,6 @@ inline const Block& get_block_def(const Storage& chunks, blockid_t id) {
|
||||||
return chunks.getContentIndices().blocks.require(id);
|
return chunks.getContentIndices().blocks.require(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @brief Check if block at specified position is solid.
|
/// @brief Check if block at specified position is solid.
|
||||||
/// @tparam Storage chunks storage class
|
/// @tparam Storage chunks storage class
|
||||||
/// @param chunks chunks storage
|
/// @param chunks chunks storage
|
||||||
|
|
@ -103,8 +102,10 @@ inline const Block& get_block_def(const Storage& chunks, blockid_t id) {
|
||||||
/// @param y position Y
|
/// @param y position Y
|
||||||
/// @param z position Z
|
/// @param z position Z
|
||||||
/// @return true if block exists and solid
|
/// @return true if block exists and solid
|
||||||
template<class Storage>
|
template <class Storage>
|
||||||
inline bool is_solid_at(const Storage& chunks, int32_t x, int32_t y, int32_t z) {
|
inline bool is_solid_at(
|
||||||
|
const Storage& chunks, int32_t x, int32_t y, int32_t z
|
||||||
|
) {
|
||||||
if (auto vox = get(chunks, x, y, z)) {
|
if (auto vox = get(chunks, x, y, z)) {
|
||||||
return get_block_def(chunks, vox->id).rt.solid;
|
return get_block_def(chunks, vox->id).rt.solid;
|
||||||
}
|
}
|
||||||
|
|
@ -118,8 +119,10 @@ inline bool is_solid_at(const Storage& chunks, int32_t x, int32_t y, int32_t z)
|
||||||
/// @param y position Y
|
/// @param y position Y
|
||||||
/// @param z position Z
|
/// @param z position Z
|
||||||
/// @return true if block exists and replaceable
|
/// @return true if block exists and replaceable
|
||||||
template<class Storage>
|
template <class Storage>
|
||||||
inline bool is_replaceable_at(const Storage& chunks, int32_t x, int32_t y, int32_t z) {
|
inline bool is_replaceable_at(
|
||||||
|
const Storage& chunks, int32_t x, int32_t y, int32_t z
|
||||||
|
) {
|
||||||
if (auto vox = get(chunks, x, y, z)) {
|
if (auto vox = get(chunks, x, y, z)) {
|
||||||
return get_block_def(chunks, vox->id).replaceable;
|
return get_block_def(chunks, vox->id).replaceable;
|
||||||
}
|
}
|
||||||
|
|
@ -455,12 +458,18 @@ voxel* raycast(
|
||||||
bool includeNonSelectable
|
bool includeNonSelectable
|
||||||
);
|
);
|
||||||
|
|
||||||
void get_voxels(const Chunks& chunks, VoxelsVolume* volume, bool backlight=false);
|
void get_voxels(
|
||||||
|
const Chunks& chunks, VoxelsVolume* volume, bool backlight = false
|
||||||
|
);
|
||||||
|
|
||||||
void get_voxels(const GlobalChunks& chunks, VoxelsVolume* volume, bool backlight=false);
|
void get_voxels(
|
||||||
|
const GlobalChunks& chunks, VoxelsVolume* volume, bool backlight = false
|
||||||
|
);
|
||||||
|
|
||||||
template <class Storage>
|
template <class Storage>
|
||||||
inline std::optional<AABB> is_obstacle_at(const Storage& chunks, float x, float y, float z, const AABB& aabb) {
|
inline std::optional<AABB> is_obstacle_at(
|
||||||
|
const Storage& chunks, float x, float y, float z, const AABB& aabb
|
||||||
|
) {
|
||||||
int ix = std::floor(x);
|
int ix = std::floor(x);
|
||||||
int iy = std::floor(y);
|
int iy = std::floor(y);
|
||||||
int iz = std::floor(z);
|
int iz = std::floor(z);
|
||||||
|
|
@ -497,4 +506,63 @@ inline std::optional<AABB> is_obstacle_at(const Storage& chunks, float x, float
|
||||||
return is_obstacle_at(chunks, x, y, z, AABB({x, y, z}, {x + 1, y + 1, z + 1}));
|
return is_obstacle_at(chunks, x, y, z, AABB({x, y, z}, {x + 1, y + 1, z + 1}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Check block grounding
|
||||||
|
/// @tparam Storage chunks storage class
|
||||||
|
/// @param chunks chunks storage
|
||||||
|
/// @param def block definition
|
||||||
|
/// @param rotationIndex target block rotation index
|
||||||
|
/// @param origin target block origin
|
||||||
|
/// @return true if grounded
|
||||||
|
template <class Storage>
|
||||||
|
inline bool check_grounding(
|
||||||
|
const Storage& chunks,
|
||||||
|
const Block& def,
|
||||||
|
uint8_t rotationIndex,
|
||||||
|
const glm::ivec3& origin
|
||||||
|
) {
|
||||||
|
const auto& vec = get_ground_direction(def, rotationIndex);
|
||||||
|
|
||||||
|
if (!def.rt.extended) {
|
||||||
|
return blocks_agent::is_solid_at(
|
||||||
|
chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& rotation = def.rotations.variants[rotationIndex];
|
||||||
|
|
||||||
|
if (def.groundingBehaviour == GroundingBehaviour::PARTIAL) {
|
||||||
|
for (int sz = 0; sz < def.size.z; sz++) {
|
||||||
|
for (int sx = 0; sx < def.size.x; sx++) {
|
||||||
|
auto pos = origin;
|
||||||
|
pos += rotation.axes[0] * sx;
|
||||||
|
pos += rotation.axes[2] * sz;
|
||||||
|
if (blocks_agent::is_solid_at(
|
||||||
|
chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z
|
||||||
|
)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (def.groundingBehaviour == GroundingBehaviour::COMPLETE) {
|
||||||
|
for (int sz = 0; sz < def.size.z; sz++) {
|
||||||
|
for (int sx = 0; sx < def.size.x; sx++) {
|
||||||
|
auto pos = origin;
|
||||||
|
pos += rotation.axes[0] * sx;
|
||||||
|
pos += rotation.axes[2] * sz;
|
||||||
|
if (!blocks_agent::is_solid_at(
|
||||||
|
chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z
|
||||||
|
)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return blocks_agent::is_solid_at(
|
||||||
|
chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // blocks_agent
|
} // blocks_agent
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue