Merge pull request #174 from MihailRis/block_materials

Block materials
This commit is contained in:
MihailRis
2024-03-10 10:10:07 +03:00
committed by GitHub
73 changed files with 750 additions and 305 deletions
@@ -0,0 +1,5 @@
{
"steps-sound": "steps/wood",
"place-sound": "blocks/wood_place",
"break-sound": "blocks/glass_break"
}
@@ -0,0 +1,5 @@
{
"steps-sound": "steps/grass",
"place-sound": "steps/grass",
"break-sound": "steps/grass"
}
@@ -0,0 +1,5 @@
{
"steps-sound": "steps/grass",
"place-sound": "blocks/ground_place",
"break-sound": "blocks/ground_break"
}
@@ -0,0 +1,5 @@
{
"steps-sound": "steps/ground",
"place-sound": "blocks/ground_place",
"break-sound": "blocks/ground_break"
}
@@ -0,0 +1,5 @@
{
"steps-sound": "steps/sand",
"steps-sound": "blocks/ground_place",
"break-sound": "blocks/ground_break"
}
@@ -0,0 +1,5 @@
{
"steps-sound": "steps/stone",
"place-sound": "blocks/stone_place",
"break-sound": "blocks/stone_break"
}
@@ -0,0 +1,5 @@
{
"steps-sound": "steps/wood",
"place-sound": "blocks/wood_place",
"break-sound": "blocks/wood_break"
}
+2 -1
View File
@@ -1,3 +1,4 @@
{ {
"texture": "dirt" "texture": "dirt",
"material": "base:ground"
} }
+1
View File
@@ -1,5 +1,6 @@
{ {
"texture": "flower", "texture": "flower",
"material": "base:grass",
"draw-group": 1, "draw-group": 1,
"light-passing": true, "light-passing": true,
"obstacle": false, "obstacle": false,
+1
View File
@@ -1,5 +1,6 @@
{ {
"texture": "glass", "texture": "glass",
"material": "base:glass",
"draw-group": 2, "draw-group": 2,
"light-passing": true, "light-passing": true,
"sky-light-passing": true "sky-light-passing": true
+1
View File
@@ -1,5 +1,6 @@
{ {
"texture": "grass", "texture": "grass",
"material": "base:grass",
"draw-group": 1, "draw-group": 1,
"light-passing": true, "light-passing": true,
"obstacle": false, "obstacle": false,
+1
View File
@@ -1,4 +1,5 @@
{ {
"material": "base:grass_block",
"texture-faces": [ "texture-faces": [
"grass_side", "grass_side",
"grass_side", "grass_side",
+2 -1
View File
@@ -1,3 +1,4 @@
{ {
"texture": "leaves" "texture": "leaves",
"material": "base:grass"
} }
+1
View File
@@ -7,6 +7,7 @@
"pane", "pane",
"pane" "pane"
], ],
"material": "base:wood",
"model": "aabb", "model": "aabb",
"hitbox": [0.0, 0.0, 0.0, 1.0, 1.0, 0.2], "hitbox": [0.0, 0.0, 0.0, 1.0, 1.0, 0.2],
"light-passing": true, "light-passing": true,
+2 -1
View File
@@ -1,3 +1,4 @@
{ {
"texture": "planks" "texture": "planks",
"material": "base:wood"
} }
+2 -1
View File
@@ -1,3 +1,4 @@
{ {
"texture": "sand" "texture": "sand",
"material": "base:sand"
} }
+1
View File
@@ -1,4 +1,5 @@
{ {
"material": "base:wood",
"texture-faces": [ "texture-faces": [
"wood", "wood",
"wood", "wood",
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

+15
View File
@@ -61,6 +61,14 @@ void addLayouts(int env, const std::string& prefix, const fs::path& folder, Asse
} }
} }
void AssetsLoader::tryAddSound(std::string name) {
if (name.empty()) {
return;
}
fs::path file = SOUNDS_FOLDER"/"+name+".ogg";
add(ASSET_SOUND, file, name);
}
void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) { void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal"); loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui");
@@ -81,6 +89,13 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/sun.png", "misc/sun"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/sun.png", "misc/sun");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/crosshair.png", "gui/crosshair"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/crosshair.png", "gui/crosshair");
for (auto& entry : content->getBlockMaterials()) {
auto& material = entry.second;
loader.tryAddSound(material.stepsSound);
loader.tryAddSound(material.placeSound);
loader.tryAddSound(material.breakSound);
}
addLayouts(0, "core", loader.getPaths()->getMainRoot()/fs::path("layouts"), loader); addLayouts(0, "core", loader.getPaths()->getMainRoot()/fs::path("layouts"), loader);
for (auto& entry : content->getPacks()) { for (auto& entry : content->getPacks()) {
auto pack = entry.second.get(); auto pack = entry.second.get();
+2
View File
@@ -49,6 +49,8 @@ class AssetsLoader {
std::map<int, aloader_func> loaders; std::map<int, aloader_func> loaders;
std::queue<aloader_entry> entries; std::queue<aloader_entry> entries;
const ResPaths* paths; const ResPaths* paths;
void tryAddSound(std::string name);
public: public:
AssetsLoader(Assets* assets, const ResPaths* paths); AssetsLoader(Assets* assets, const ResPaths* paths);
void addLoader(int tag, aloader_func func); void addLoader(int tag, aloader_func func);
+16 -1
View File
@@ -38,6 +38,11 @@ ALStream::ALStream(ALAudio* al, std::shared_ptr<PCMStream> source, bool keepSour
ALStream::~ALStream() { ALStream::~ALStream() {
bindSpeaker(0); bindSpeaker(0);
source = nullptr; source = nullptr;
while (!unusedBuffers.empty()) {
al->freeBuffer(unusedBuffers.front());
unusedBuffers.pop();
}
} }
std::shared_ptr<PCMStream> ALStream::getSource() const { std::shared_ptr<PCMStream> ALStream::getSource() const {
@@ -135,6 +140,11 @@ void ALStream::update(double delta) {
return; return;
} }
ALSpeaker* alspeaker = dynamic_cast<ALSpeaker*>(speaker); ALSpeaker* alspeaker = dynamic_cast<ALSpeaker*>(speaker);
if (alspeaker->stopped) {
speaker = 0;
return;
}
uint alsource = alspeaker->source; uint alsource = alspeaker->source;
unqueueBuffers(alsource); unqueueBuffers(alsource);
@@ -194,6 +204,8 @@ ALSpeaker::~ALSpeaker() {
} }
void ALSpeaker::update(const Channel* channel, float masterVolume) { void ALSpeaker::update(const Channel* channel, float masterVolume) {
if (source == 0)
return;
float gain = this->volume * channel->getVolume()*masterVolume; float gain = this->volume * channel->getVolume()*masterVolume;
AL_CHECK(alSourcef(source, AL_GAIN, gain)); AL_CHECK(alSourcef(source, AL_GAIN, gain));
@@ -265,7 +277,9 @@ void ALSpeaker::stop() {
AL_CHECK(alSourceUnqueueBuffers(source, 1, &buffer)); AL_CHECK(alSourceUnqueueBuffers(source, 1, &buffer));
al->freeBuffer(buffer); al->freeBuffer(buffer);
} }
AL_CHECK(alSourcei(source, AL_BUFFER, 0));
al->freeSource(source); al->freeSource(source);
source = 0;
} }
} }
@@ -395,8 +409,9 @@ uint ALAudio::getFreeSource(){
} }
ALuint id; ALuint id;
alGenSources(1, &id); alGenSources(1, &id);
if (!AL_GET_ERROR()) if (!AL_GET_ERROR()) {
return 0; return 0;
}
allsources.push_back(id); allsources.push_back(id);
return id; return id;
} }
+8 -1
View File
@@ -17,7 +17,8 @@
#define AL_CHECK(STATEMENT) STATEMENT; AL::check_errors(__FILE__, __LINE__) #define AL_CHECK(STATEMENT) STATEMENT; AL::check_errors(__FILE__, __LINE__)
#define AL_GET_ERROR() AL::check_errors(__FILE__, __LINE__) #define AL_GET_ERROR() AL::check_errors(__FILE__, __LINE__)
namespace AL { namespace AL {
/// @return true if no errors
bool check_errors(const std::string& filename, const std::uint_fast32_t line); bool check_errors(const std::string& filename, const std::uint_fast32_t line);
/// @brief alGetSourcef wrapper /// @brief alGetSourcef wrapper
@@ -27,6 +28,8 @@ namespace AL {
/// @return field value or default /// @return field value or default
inline float getSourcef(uint source, ALenum field, float def=0.0f) { inline float getSourcef(uint source, ALenum field, float def=0.0f) {
float value = def; float value = def;
if (source == 0)
return def;
AL_CHECK(alGetSourcef(source, field, &value)); AL_CHECK(alGetSourcef(source, field, &value));
return value; return value;
} }
@@ -38,6 +41,8 @@ namespace AL {
/// @return field value or default /// @return field value or default
inline glm::vec3 getSource3f(uint source, ALenum field, glm::vec3 def={}) { inline glm::vec3 getSource3f(uint source, ALenum field, glm::vec3 def={}) {
glm::vec3 value = def; glm::vec3 value = def;
if (source == 0)
return def;
AL_CHECK(alGetSource3f(source, field, &value.x, &value.y, &value.z)); AL_CHECK(alGetSource3f(source, field, &value.x, &value.y, &value.z));
return value; return value;
} }
@@ -49,6 +54,8 @@ namespace AL {
/// @return field value or default /// @return field value or default
inline float getSourcei(uint source, ALenum field, int def=0) { inline float getSourcei(uint source, ALenum field, int def=0) {
int value = def; int value = def;
if (source == 0)
return def;
AL_CHECK(alGetSourcei(source, field, &value)); AL_CHECK(alGetSourcei(source, field, &value));
return value; return value;
} }
+13
View File
@@ -249,6 +249,15 @@ speakerid_t audio::play(
int priority, int priority,
int channel int channel
) { ) {
if (sound == nullptr) {
return 0;
}
if (!sound->variants.empty()) {
size_t index = rand() % (sound->variants.size() + 1);
if (index < sound->variants.size()) {
sound = sound->variants.at(index).get();
}
}
Speaker* speaker = sound->newInstance(priority, channel); Speaker* speaker = sound->newInstance(priority, channel);
if (speaker == nullptr) { if (speaker == nullptr) {
remove_lower_priority_speaker(priority); remove_lower_priority_speaker(priority);
@@ -359,6 +368,10 @@ size_t audio::count_speakers() {
return speakers.size(); return speakers.size();
} }
size_t audio::count_streams() {
return streams.size();
}
void audio::update(double delta) { void audio::update(double delta) {
backend->update(delta); backend->update(delta);
+3
View File
@@ -484,6 +484,9 @@ namespace audio {
/// @brief Get alive speakers number (including paused) /// @brief Get alive speakers number (including paused)
extern size_t count_speakers(); extern size_t count_speakers();
/// @brief Get playing streams number (including paused)
extern size_t count_streams();
/// @brief Update audio streams and sound instanced /// @brief Update audio streams and sound instanced
/// @param delta time elapsed since the last update (seconds) /// @param delta time elapsed since the last update (seconds)
extern void update(double delta); extern void update(double delta);
+42 -20
View File
@@ -10,8 +10,7 @@
#include "ContentPack.h" #include "ContentPack.h"
#include "../logic/scripting/scripting.h" #include "../logic/scripting/scripting.h"
ContentBuilder::~ContentBuilder() { ContentBuilder::~ContentBuilder() {}
}
void ContentBuilder::add(Block* def) { void ContentBuilder::add(Block* def) {
checkIdentifier(def->name); checkIdentifier(def->name);
@@ -29,6 +28,10 @@ void ContentBuilder::add(ContentPackRuntime* pack) {
packs.emplace(pack->getId(), pack); packs.emplace(pack->getId(), pack);
} }
void ContentBuilder::add(BlockMaterial material) {
blockMaterials.emplace(material.name, material);
}
Block& ContentBuilder::createBlock(std::string id) { Block& ContentBuilder::createBlock(std::string id) {
auto found = blockDefs.find(id); auto found = blockDefs.find(id);
if (found != blockDefs.end()) { if (found != blockDefs.end()) {
@@ -110,7 +113,12 @@ Content* ContentBuilder::build() {
auto indices = new ContentIndices(blockDefsIndices, itemDefsIndices); auto indices = new ContentIndices(blockDefsIndices, itemDefsIndices);
auto content = std::make_unique<Content>( auto content = std::make_unique<Content>(
indices, std::move(groups), blockDefs, itemDefs, std::move(packs) indices,
std::move(groups),
blockDefs,
itemDefs,
std::move(packs),
std::move(blockMaterials)
); );
// Now, it's time to resolve foreign keys // Now, it's time to resolve foreign keys
@@ -127,25 +135,27 @@ Content* ContentBuilder::build() {
ContentIndices::ContentIndices( ContentIndices::ContentIndices(
std::vector<Block*> blockDefs, std::vector<Block*> blockDefs,
std::vector<ItemDef*> itemDefs) std::vector<ItemDef*> itemDefs
: blockDefs(blockDefs), ) : blockDefs(blockDefs),
itemDefs(itemDefs) { itemDefs(itemDefs)
} {}
Content::Content(ContentIndices* indices, Content::Content(
std::unique_ptr<DrawGroups> drawGroups, ContentIndices* indices,
std::unordered_map<std::string, Block*> blockDefs, std::unique_ptr<DrawGroups> drawGroups,
std::unordered_map<std::string, ItemDef*> itemDefs, std::unordered_map<std::string, Block*> blockDefs,
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs) std::unordered_map<std::string, ItemDef*> itemDefs,
: blockDefs(blockDefs), std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs,
itemDefs(itemDefs), std::unordered_map<std::string, BlockMaterial> blockMaterials
indices(indices), ) : blockDefs(blockDefs),
packs(std::move(packs)), itemDefs(itemDefs),
drawGroups(std::move(drawGroups)) { indices(indices),
} packs(std::move(packs)),
blockMaterials(std::move(blockMaterials)),
drawGroups(std::move(drawGroups))
{}
Content::~Content() { Content::~Content() {}
}
Block* Content::findBlock(std::string id) const { Block* Content::findBlock(std::string id) const {
auto found = blockDefs.find(id); auto found = blockDefs.find(id);
@@ -179,6 +189,14 @@ ItemDef& Content::requireItem(std::string id) const {
return *found->second; return *found->second;
} }
const BlockMaterial* Content::findBlockMaterial(std::string id) const {
auto found = blockMaterials.find(id);
if (found == blockMaterials.end()) {
return nullptr;
}
return &found->second;
}
const ContentPackRuntime* Content::getPackRuntime(std::string id) const { const ContentPackRuntime* Content::getPackRuntime(std::string id) const {
auto found = packs.find(id); auto found = packs.find(id);
if (found == packs.end()) { if (found == packs.end()) {
@@ -187,6 +205,10 @@ const ContentPackRuntime* Content::getPackRuntime(std::string id) const {
return found->second.get(); return found->second.get();
} }
const std::unordered_map<std::string, BlockMaterial>& Content::getBlockMaterials() const {
return blockMaterials;
}
const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& Content::getPacks() const { const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& Content::getPacks() const {
return packs; return packs;
} }
+21 -9
View File
@@ -8,10 +8,10 @@
#include <unordered_map> #include <unordered_map>
#include <set> #include <set>
#include "../typedefs.h" #include "../typedefs.h"
#include "../voxels/Block.h"
using DrawGroups = std::set<ubyte>; using DrawGroups = std::set<ubyte>;
class Block;
class ItemDef; class ItemDef;
class Content; class Content;
class ContentPackRuntime; class ContentPackRuntime;
@@ -48,6 +48,8 @@ class ContentBuilder {
std::unordered_map<std::string, ItemDef*> itemDefs; std::unordered_map<std::string, ItemDef*> itemDefs;
std::vector<std::string> itemIds; std::vector<std::string> itemIds;
std::unordered_map<std::string, BlockMaterial> blockMaterials;
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs; std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs;
public: public:
~ContentBuilder(); ~ContentBuilder();
@@ -55,6 +57,7 @@ public:
void add(Block* def); void add(Block* def);
void add(ItemDef* def); void add(ItemDef* def);
void add(ContentPackRuntime* pack); void add(ContentPackRuntime* pack);
void add(BlockMaterial material);
Block& createBlock(std::string id); Block& createBlock(std::string id);
ItemDef& createItem(std::string id); ItemDef& createItem(std::string id);
@@ -65,13 +68,15 @@ public:
Content* build(); Content* build();
}; };
/* Runtime defs cache: indices */ /// @brief Runtime defs cache: indices
class ContentIndices { class ContentIndices {
std::vector<Block*> blockDefs; std::vector<Block*> blockDefs;
std::vector<ItemDef*> itemDefs; std::vector<ItemDef*> itemDefs;
public: public:
ContentIndices(std::vector<Block*> blockDefs, ContentIndices(
std::vector<ItemDef*> itemDefs); std::vector<Block*> blockDefs,
std::vector<ItemDef*> itemDefs
);
inline Block* getBlockDef(blockid_t id) const { inline Block* getBlockDef(blockid_t id) const {
if (id >= blockDefs.size()) if (id >= blockDefs.size())
@@ -109,14 +114,18 @@ class Content {
std::unordered_map<std::string, ItemDef*> itemDefs; std::unordered_map<std::string, ItemDef*> itemDefs;
std::unique_ptr<ContentIndices> indices; std::unique_ptr<ContentIndices> indices;
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs; std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs;
std::unordered_map<std::string, BlockMaterial> blockMaterials;
public: public:
std::unique_ptr<DrawGroups> const drawGroups; std::unique_ptr<DrawGroups> const drawGroups;
Content(ContentIndices* indices, Content(
std::unique_ptr<DrawGroups> drawGroups, ContentIndices* indices,
std::unordered_map<std::string, Block*> blockDefs, std::unique_ptr<DrawGroups> drawGroups,
std::unordered_map<std::string, ItemDef*> itemDefs, std::unordered_map<std::string, Block*> blockDefs,
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs); std::unordered_map<std::string, ItemDef*> itemDefs,
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs,
std::unordered_map<std::string, BlockMaterial> blockMaterials
);
~Content(); ~Content();
inline ContentIndices* getIndices() const { inline ContentIndices* getIndices() const {
@@ -129,8 +138,11 @@ public:
ItemDef* findItem(std::string id) const; ItemDef* findItem(std::string id) const;
ItemDef& requireItem(std::string id) const; ItemDef& requireItem(std::string id) const;
const BlockMaterial* findBlockMaterial(std::string id) const;
const ContentPackRuntime* getPackRuntime(std::string id) const; const ContentPackRuntime* getPackRuntime(std::string id) const;
const std::unordered_map<std::string, BlockMaterial>& getBlockMaterials() const;
const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& getPacks() const; const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& getPacks() const;
}; };
+3 -3
View File
@@ -19,9 +19,9 @@ struct contententry {
// TODO: make it unified for all types of content // TODO: make it unified for all types of content
/* Content indices lookup table or report /// @brief Content indices lookup table or report
used to convert world with different indices /// used to convert world with different indices
Building with indices.json */ /// Building with indices.json
class ContentLUT { class ContentLUT {
std::vector<blockid_t> blocks; std::vector<blockid_t> blocks;
std::vector<std::string> blockNames; std::vector<std::string> blockNames;
+20
View File
@@ -144,6 +144,8 @@ void ContentLoader::loadBlock(Block& def, std::string name, fs::path file) {
def.model = BlockModel::none; def.model = BlockModel::none;
} }
root->str("material", def.material);
// rotation profile // rotation profile
std::string profile = "none"; std::string profile = "none";
root->str("rotation", profile); root->str("rotation", profile);
@@ -301,6 +303,15 @@ void ContentLoader::loadItem(ItemDef& def, std::string full, std::string name) {
} }
} }
BlockMaterial ContentLoader::loadBlockMaterial(fs::path file, std::string full) {
auto root = files::read_json(file);
BlockMaterial material {full};
root->str("steps-sound", material.stepsSound);
root->str("place-sound", material.placeSound);
root->str("break-sound", material.breakSound);
return material;
}
void ContentLoader::load(ContentBuilder& builder) { void ContentLoader::load(ContentBuilder& builder) {
std::cout << "-- loading pack [" << pack->id << "]" << std::endl; std::cout << "-- loading pack [" << pack->id << "]" << std::endl;
@@ -361,4 +372,13 @@ void ContentLoader::load(ContentBuilder& builder) {
stats.totalItems++; stats.totalItems++;
} }
} }
fs::path materialsDir = folder / fs::u8path("block_materials");
if (fs::is_directory(materialsDir)) {
for (auto entry : fs::directory_iterator(materialsDir)) {
fs::path file = entry.path();
std::string name = pack->id+":"+file.stem().u8string();
builder.add(loadBlockMaterial(file, name));
}
}
} }
+8 -4
View File
@@ -1,12 +1,13 @@
#ifndef CONTENT_CONTENT_LOADER_H_ #ifndef CONTENT_CONTENT_LOADER_H_
#define CONTENT_CONTENT_LOADER_H_ #define CONTENT_CONTENT_LOADER_H_
#include "../voxels/Block.h"
#include <string> #include <string>
#include <filesystem> #include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
class Block;
class ItemDef; class ItemDef;
struct ContentPack; struct ContentPack;
class ContentBuilder; class ContentBuilder;
@@ -22,12 +23,15 @@ class ContentLoader {
void loadBlock(Block& def, std::string full, std::string name); void loadBlock(Block& def, std::string full, std::string name);
void loadCustomBlockModel(Block& def, dynamic::Map* primitives); void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
void loadItem(ItemDef& def, std::string full, std::string name); void loadItem(ItemDef& def, std::string full, std::string name);
BlockMaterial loadBlockMaterial(fs::path file, std::string full);
public: public:
ContentLoader(ContentPack* pack); ContentLoader(ContentPack* pack);
bool fixPackIndices(std::filesystem::path folder, bool fixPackIndices(
dynamic::Map* indicesRoot, fs::path folder,
std::string contentSection); dynamic::Map* indicesRoot,
std::string contentSection
);
void fixPackIndices(); void fixPackIndices();
void loadBlock(Block& def, std::string name, fs::path file); void loadBlock(Block& def, std::string name, fs::path file);
void loadItem(ItemDef& def, std::string name, fs::path file); void loadItem(ItemDef& def, std::string name, fs::path file);
+61 -7
View File
@@ -1,16 +1,70 @@
#include "LevelFrontend.h" #include "LevelFrontend.h"
#include "../world/Level.h"
#include "../assets/Assets.h"
#include "../graphics/Atlas.h"
#include "BlocksPreview.h" #include "BlocksPreview.h"
#include "ContentGfxCache.h" #include "ContentGfxCache.h"
#include "../audio/audio.h"
#include "../world/Level.h"
#include "../voxels/Block.h"
#include "../assets/Assets.h"
#include "../graphics/Atlas.h"
#include "../content/Content.h"
#include "../logic/LevelController.h"
#include "../logic/PlayerController.h"
LevelFrontend::LevelFrontend(Level* level, Assets* assets) LevelFrontend::LevelFrontend(Level* level, Assets* assets)
: level(level), : level(level),
assets(assets), assets(assets),
contentCache(std::make_unique<ContentGfxCache>(level->content, assets)), contentCache(std::make_unique<ContentGfxCache>(level->content, assets)),
blocksAtlas(BlocksPreview::build(contentCache.get(), assets, level->content)) { blocksAtlas(BlocksPreview::build(contentCache.get(), assets, level->content))
{}
void LevelFrontend::observe(LevelController* controller) {
controller->getPlayerController()->listenBlockInteraction(
[=](Player*, glm::ivec3 pos, const Block* def, BlockInteraction type) {
auto material = level->content->findBlockMaterial(def->material);
if (material == nullptr) {
return;
}
if (type == BlockInteraction::step) {
auto sound = assets->getSound(material->stepsSound);
audio::play(
sound,
glm::vec3(),
true,
0.333f,
1.0f + (rand() % 6 - 3) * 0.05f,
false,
audio::PRIORITY_LOW,
audio::get_channel_index("regular")
);
} else {
audio::Sound* sound = nullptr;
switch (type) {
case BlockInteraction::placing:
sound = assets->getSound(material->placeSound);
break;
case BlockInteraction::destruction:
sound = assets->getSound(material->breakSound);
break;
case BlockInteraction::step:
break;
}
audio::play(
sound,
glm::vec3(pos.x, pos.y, pos.z) + 0.5f,
false,
1.0f,
1.0f + (rand() % 6 - 3) * 0.05f,
false,
audio::PRIORITY_NORMAL,
audio::get_channel_index("regular")
);
}
}
);
} }
LevelFrontend::~LevelFrontend() { LevelFrontend::~LevelFrontend() {
+3
View File
@@ -8,6 +8,7 @@ class Level;
class Assets; class Assets;
class BlocksPreview; class BlocksPreview;
class ContentGfxCache; class ContentGfxCache;
class LevelController;
class LevelFrontend { class LevelFrontend {
Level* level; Level* level;
@@ -18,6 +19,8 @@ public:
LevelFrontend(Level* level, Assets* assets); LevelFrontend(Level* level, Assets* assets);
~LevelFrontend(); ~LevelFrontend();
void observe(LevelController* controller);
Level* getLevel() const; Level* getLevel() const;
Assets* getAssets() const; Assets* getAssets() const;
ContentGfxCache* getContentGfxCache() const; ContentGfxCache* getContentGfxCache() const;
+5
View File
@@ -2,6 +2,7 @@
#include <memory> #include <memory>
#include "gui/controls.h" #include "gui/controls.h"
#include "../audio/audio.h"
#include "../graphics/Mesh.h" #include "../graphics/Mesh.h"
#include "../objects/Player.h" #include "../objects/Player.h"
#include "../physics/Hitbox.h" #include "../physics/Hitbox.h"
@@ -52,6 +53,10 @@ std::shared_ptr<UINode> create_debug_panel(
panel->add(create_label([](){ panel->add(create_label([](){
return L"meshes: " + std::to_wstring(Mesh::meshesCount); return L"meshes: " + std::to_wstring(Mesh::meshesCount);
})); }));
panel->add(create_label([](){
return L"speakers: " + std::to_wstring(audio::count_speakers())+
L" streams: " + std::to_wstring(audio::count_streams());
}));
panel->add(create_label([=](){ panel->add(create_label([=](){
auto& settings = engine->getSettings(); auto& settings = engine->getSettings();
bool culling = settings.graphics.frustumCulling; bool culling = settings.graphics.frustumCulling;
+4 -2
View File
@@ -100,6 +100,8 @@ LevelScreen::LevelScreen(Engine* engine, Level* level) : Screen(engine) {
worldRenderer = std::make_unique<WorldRenderer>(engine, frontend.get(), controller->getPlayer()); worldRenderer = std::make_unique<WorldRenderer>(engine, frontend.get(), controller->getPlayer());
hud = std::make_unique<Hud>(engine, frontend.get(), controller->getPlayer()); hud = std::make_unique<Hud>(engine, frontend.get(), controller->getPlayer());
frontend->observe(controller.get());
backlight = settings.graphics.backlight; backlight = settings.graphics.backlight;
animator = std::make_unique<TextureAnimator>(); animator = std::make_unique<TextureAnimator>();
@@ -156,9 +158,9 @@ void LevelScreen::update(float delta) {
auto player = controller->getPlayer(); auto player = controller->getPlayer();
auto camera = player->camera; auto camera = player->camera;
audio::set_listener( audio::set_listener(
camera->position, camera->position-camera->dir,
player->hitbox->velocity, player->hitbox->velocity,
camera->position+camera->dir, camera->dir,
camera->up camera->up
); );
+4
View File
@@ -57,3 +57,7 @@ Level* LevelController::getLevel() {
Player* LevelController::getPlayer() { Player* LevelController::getPlayer() {
return player->getPlayer(); return player->getPlayer();
} }
PlayerController* LevelController::getPlayerController() {
return player.get();
}
+11 -9
View File
@@ -11,7 +11,7 @@
class Level; class Level;
class Player; class Player;
/* LevelController manages other controllers */ /// @brief LevelController manages other controllers
class LevelController { class LevelController {
EngineSettings& settings; EngineSettings& settings;
std::unique_ptr<Level> level; std::unique_ptr<Level> level;
@@ -22,20 +22,22 @@ class LevelController {
public: public:
LevelController(EngineSettings& settings, Level* level); LevelController(EngineSettings& settings, Level* level);
/* /// @param delta time elapsed since the last update
@param delta time elapsed since the last update /// @param input is user input allowed to be handled
@param input is user input allowed to be handled /// @param pause is world and player simulation paused
@param pause is world and player simulation paused void update(
*/ float delta,
void update(float delta, bool input,
bool input, bool pause
bool pause); );
void onWorldSave(); void onWorldSave();
void onWorldQuit(); void onWorldQuit();
Level* getLevel(); Level* getLevel();
Player* getPlayer(); Player* getPlayer();
PlayerController* getPlayerController();
}; };
#endif // LOGIC_LEVEL_CONTROLLER_H_ #endif // LOGIC_LEVEL_CONTROLLER_H_
+154 -55
View File
@@ -20,10 +20,14 @@
#include "../core_defs.h" #include "../core_defs.h"
#define _USE_MATH_DEFINES
#include <cmath>
const float CAM_SHAKE_OFFSET = 0.025f; const float CAM_SHAKE_OFFSET = 0.025f;
const float CAM_SHAKE_OFFSET_Y = 0.031f; const float CAM_SHAKE_OFFSET_Y = 0.031f;
const float CAM_SHAKE_SPEED = 1.75f; const float CAM_SHAKE_SPEED = 1.75f;
const float CAM_SHAKE_DELTA_K = 10.0f; const float CAM_SHAKE_DELTA_K = 10.0f;
const float STEPS_SPEED = 1.75f;
const float ZOOM_SPEED = 16.0f; const float ZOOM_SPEED = 16.0f;
const float CROUCH_ZOOM = 0.9f; const float CROUCH_ZOOM = 0.9f;
const float RUN_ZOOM = 1.1f; const float RUN_ZOOM = 1.1f;
@@ -32,11 +36,10 @@ const float CROUCH_SHIFT_Y = -0.2f;
CameraControl::CameraControl(std::shared_ptr<Player> player, const CameraSettings& settings) CameraControl::CameraControl(std::shared_ptr<Player> player, const CameraSettings& settings)
: player(player), : player(player),
camera(player->camera), camera(player->camera),
currentViewCamera(player->currentCamera), settings(settings),
settings(settings), offset(0.0f, 0.7f, 0.0f) {
offset(0.0f, 0.7f, 0.0f) {
} }
void CameraControl::refresh() { void CameraControl::refresh() {
@@ -46,7 +49,10 @@ void CameraControl::refresh() {
void CameraControl::updateMouse(PlayerInput& input) { void CameraControl::updateMouse(PlayerInput& input) {
glm::vec2& cam = player->cam; glm::vec2& cam = player->cam;
float sensitivity = (input.zoom ? settings.sensitivity / 4.f : settings.sensitivity); float sensitivity = (input.zoom
? settings.sensitivity / 4.f
: settings.sensitivity);
cam -= glm::degrees(Events::delta / (float)Window::height * sensitivity); cam -= glm::degrees(Events::delta / (float)Window::height * sensitivity);
if (cam.y < -89.9f) { if (cam.y < -89.9f) {
@@ -66,66 +72,93 @@ void CameraControl::updateMouse(PlayerInput& input) {
camera->rotate(glm::radians(cam.y), glm::radians(cam.x), 0); camera->rotate(glm::radians(cam.y), glm::radians(cam.x), 0);
} }
void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) { glm::vec3 CameraControl::updateCameraShaking(float delta) {
Hitbox* hitbox = player->hitbox.get(); glm::vec3 offset {};
auto hitbox = player->hitbox.get();
const float k = CAM_SHAKE_DELTA_K;
const float oh = CAM_SHAKE_OFFSET;
const float ov = CAM_SHAKE_OFFSET_Y;
const glm::vec3& vel = hitbox->velocity;
interpVel = interpVel * (1.0f - delta * 5) + vel * delta * 0.1f;
if (hitbox->grounded && interpVel.y < 0.0f){
interpVel.y *= -30.0f;
}
shake = shake * (1.0f - delta * k);
if (hitbox->grounded) {
float f = glm::length(glm::vec2(vel.x, vel.z));
shakeTimer += delta * f * CAM_SHAKE_SPEED;
shake += f * delta * k;
}
offset += camera->right * glm::sin(shakeTimer) * oh * shake;
offset += camera->up * glm::abs(glm::cos(shakeTimer)) * ov * shake;
offset -= glm::min(interpVel * 0.05f, 1.0f);
return offset;
}
void CameraControl::updateFovEffects(const PlayerInput& input, float delta) {
auto hitbox = player->hitbox.get();
bool crouch = input.shift && hitbox->grounded && !input.sprint;
float dt = fmin(1.0f, delta * ZOOM_SPEED);
float zoomValue = 1.0f;
if (crouch){
offset += glm::vec3(0.f, CROUCH_SHIFT_Y, 0.f);
zoomValue = CROUCH_ZOOM;
} else if (input.sprint){
zoomValue = RUN_ZOOM;
}
if (input.zoom)
zoomValue *= C_ZOOM;
camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt);
}
// temporary solution
// more extensible but uglier
void CameraControl::switchCamera() {
const std::vector<std::shared_ptr<Camera>> playerCameras {
camera, player->tpCamera, player->spCamera
};
auto index = std::distance(
playerCameras.begin(),
std::find_if(
playerCameras.begin(),
playerCameras.end(),
[=](auto ptr) {
return ptr.get() == player->currentCamera.get();
}
)
);
if (static_cast<size_t>(index) != playerCameras.size()) {
index = (index + 1) % playerCameras.size();
player->currentCamera = playerCameras.at(index);
}
}
void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) {
offset = glm::vec3(0.0f, 0.7f, 0.0f); offset = glm::vec3(0.0f, 0.7f, 0.0f);
if (settings.shaking && !input.cheat) { if (settings.shaking && !input.cheat) {
const float k = CAM_SHAKE_DELTA_K; offset += updateCameraShaking(delta);
const float oh = CAM_SHAKE_OFFSET;
const float ov = CAM_SHAKE_OFFSET_Y;
const glm::vec3& vel = hitbox->velocity;
interpVel = interpVel * (1.0f - delta * 5) + vel * delta * 0.1f;
if (hitbox->grounded && interpVel.y < 0.0f){
interpVel.y *= -30.0f;
}
shake = shake * (1.0f - delta * k);
if (hitbox->grounded) {
float f = glm::length(glm::vec2(vel.x, vel.z));
shakeTimer += delta * f * CAM_SHAKE_SPEED;
shake += f * delta * k;
}
offset += camera->right * glm::sin(shakeTimer) * oh * shake;
offset += camera->up * glm::abs(glm::cos(shakeTimer)) * ov * shake;
offset -= glm::min(interpVel * 0.05f, 1.0f);
} }
if (settings.fovEvents){ if (settings.fovEvents){
bool crouch = input.shift && hitbox->grounded && !input.sprint; updateFovEffects(input, delta);
}
float dt = fmin(1.0f, delta * ZOOM_SPEED); if (input.cameraMode) {
float zoomValue = 1.0f; switchCamera();
if (crouch){
offset += glm::vec3(0.f, CROUCH_SHIFT_Y, 0.f);
zoomValue = CROUCH_ZOOM;
} else if (input.sprint){
zoomValue = RUN_ZOOM;
}
if (input.zoom)
zoomValue *= C_ZOOM;
camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt);
} }
auto spCamera = player->spCamera; auto spCamera = player->spCamera;
auto tpCamera = player->tpCamera; auto tpCamera = player->tpCamera;
if (input.cameraMode) { //ugly but effective
if (player->currentCamera == camera)
player->currentCamera = tpCamera;
else if (player->currentCamera == spCamera)
player->currentCamera = camera;
else if (player->currentCamera == tpCamera)
player->currentCamera = spCamera;
}
if (player->currentCamera == spCamera) { if (player->currentCamera == spCamera) {
spCamera->position = chunks->rayCastToObstacle(camera->position, camera->front, 3.0f) - 0.2f*(camera->front); spCamera->position = chunks->rayCastToObstacle(camera->position, camera->front, 3.0f) - 0.2f * camera->front;
spCamera->dir = -camera->dir; spCamera->dir = -camera->dir;
spCamera->front = -camera->front; spCamera->front = -camera->front;
} }
else if (player->currentCamera == tpCamera) { else if (player->currentCamera == tpCamera) {
tpCamera->position = chunks->rayCastToObstacle(camera->position, -camera->front, 3.0f) + 0.2f * (camera->front); tpCamera->position = chunks->rayCastToObstacle(camera->position, -camera->front, 3.0f) + 0.2f * camera->front;
tpCamera->dir = camera->dir; tpCamera->dir = camera->dir;
tpCamera->front = camera->front; tpCamera->front = camera->front;
} }
@@ -140,11 +173,62 @@ int PlayerController::selectedBlockStates = 0;
PlayerController::PlayerController( PlayerController::PlayerController(
Level* level, Level* level,
const EngineSettings& settings, const EngineSettings& settings,
BlocksController* blocksController) BlocksController* blocksController
: level(level), ) : level(level),
player(level->getObject<Player>(0)), player(level->getObject<Player>(0)),
camControl(player, settings.camera), camControl(player, settings.camera),
blocksController(blocksController) { blocksController(blocksController)
{}
void PlayerController::onBlockInteraction(
glm::ivec3 pos,
const Block* def,
BlockInteraction type
) {
for (auto callback : blockInteractionCallbacks) {
callback(player.get(), pos, def, type);
}
}
void PlayerController::onFootstep() {
auto hitbox = player->hitbox.get();
glm::vec3 pos = hitbox->position;
glm::vec3 half = hitbox->halfsize;
for (int offsetZ = -1; offsetZ <= 1; offsetZ++) {
for (int offsetX = -1; offsetX <= 1; offsetX++) {
int x = std::floor(pos.x+half.x*offsetX);
int y = std::floor(pos.y-half.y*1.1f);
int z = std::floor(pos.z+half.z*offsetZ);
auto vox = level->chunks->get(x, y, z);
if (vox) {
auto def = level->content->getIndices()->getBlockDef(vox->id);
if (!def->obstacle)
continue;
onBlockInteraction(
glm::ivec3(x, y, z), def,
BlockInteraction::step
);
return;
}
}
}
}
void PlayerController::updateFootsteps(float delta) {
auto hitbox = player->hitbox.get();
if (hitbox->grounded) {
const glm::vec3& vel = hitbox->velocity;
float f = glm::length(glm::vec2(vel.x, vel.z));
stepsTimer += delta * f * STEPS_SPEED;
if (stepsTimer >= M_PI) {
stepsTimer = fmod(stepsTimer, M_PI);
onFootstep();
}
} else {
stepsTimer = M_PI;
}
} }
void PlayerController::update(float delta, bool input, bool pause) { void PlayerController::update(float delta, bool input, bool pause) {
@@ -154,6 +238,7 @@ void PlayerController::update(float delta, bool input, bool pause) {
} else { } else {
resetKeyboard(); resetKeyboard();
} }
updateFootsteps(delta);
updateCamera(delta, input); updateCamera(delta, input);
updateControls(delta); updateControls(delta);
@@ -289,12 +374,17 @@ void PlayerController::updateInteraction(){
uint8_t states = determine_rotation(def, norm, camera->dir); uint8_t states = determine_rotation(def, norm, camera->dir);
if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) { if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) {
// TODO: move scripting to interaction callbacks
if (scripting::on_item_break_block(player.get(), item, x, y, z)) if (scripting::on_item_break_block(player.get(), item, x, y, z))
return; return;
} }
Block* target = indices->getBlockDef(vox->id); Block* target = indices->getBlockDef(vox->id);
if (lclick && target->breakable){ if (lclick && target->breakable){
onBlockInteraction(
glm::ivec3(x, y, z), target,
BlockInteraction::destruction
);
blocksController->breakBlock(player.get(), target, x, y, z); blocksController->breakBlock(player.get(), target, x, y, z);
} }
if (rclick && !input.shift) { if (rclick && !input.shift) {
@@ -331,9 +421,14 @@ void PlayerController::updateInteraction(){
chosenBlock = 0; chosenBlock = 0;
} }
if (chosenBlock != vox->id && chosenBlock) { if (chosenBlock != vox->id && chosenBlock) {
onBlockInteraction(
glm::ivec3(x, y, z), def,
BlockInteraction::placing
);
chunks->set(x, y, z, chosenBlock, states); chunks->set(x, y, z, chosenBlock, states);
lighting->onBlockSet(x,y,z, chosenBlock); lighting->onBlockSet(x,y,z, chosenBlock);
if (def->rt.funcsset.onplaced) { if (def->rt.funcsset.onplaced) {
// TODO: move scripting to interaction callbacks
scripting::on_block_placed(player.get(), def, x, y, z); scripting::on_block_placed(player.get(), def, x, y, z);
} }
blocksController->updateSides(x, y, z); blocksController->updateSides(x, y, z);
@@ -358,3 +453,7 @@ void PlayerController::updateInteraction(){
Player* PlayerController::getPlayer() { Player* PlayerController::getPlayer() {
return player.get(); return player.get();
} }
void PlayerController::listenBlockInteraction(on_block_interaction callback) {
blockInteractionCallbacks.push_back(callback);
}
+71 -30
View File
@@ -2,6 +2,8 @@
#define PLAYER_CONTROL_H_ #define PLAYER_CONTROL_H_
#include <memory> #include <memory>
#include <vector>
#include <functional>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "../settings.h" #include "../settings.h"
@@ -9,48 +11,87 @@
class Camera; class Camera;
class Level; class Level;
class Block;
class BlocksController; class BlocksController;
class CameraControl { class CameraControl {
std::shared_ptr<Player> player; std::shared_ptr<Player> player;
std::shared_ptr<Camera> camera, currentViewCamera; std::shared_ptr<Camera> camera;
const CameraSettings& settings; const CameraSettings& settings;
glm::vec3 offset; glm::vec3 offset;
float shake = 0.0f; float shake = 0.0f;
float shakeTimer = 0.0f; float shakeTimer = 0.0f;
glm::vec3 interpVel {0.0f}; glm::vec3 interpVel {0.0f};
/// @brief Update shaking timer and calculate camera offset
/// @param delta delta time
/// @return camera offset
glm::vec3 updateCameraShaking(float delta);
/// @brief Update field-of-view effects
/// @param input player inputs
/// @param delta delta time
void updateFovEffects(const PlayerInput& input, float delta);
/// @brief Switch active player camera
void switchCamera();
public: public:
CameraControl(std::shared_ptr<Player> player, const CameraSettings& settings); CameraControl(std::shared_ptr<Player> player, const CameraSettings& settings);
void updateMouse(PlayerInput& input); void updateMouse(PlayerInput& input);
void update(PlayerInput& input, float delta, Chunks* chunks); void update(PlayerInput& input, float delta, Chunks* chunks);
void refresh(); void refresh();
}; };
enum class BlockInteraction {
step,
destruction,
placing
};
using on_block_interaction = std::function<void(
Player*, glm::ivec3, const Block*, BlockInteraction type
)>;
class PlayerController { class PlayerController {
Level* level; Level* level;
std::shared_ptr<Player> player; std::shared_ptr<Player> player;
PlayerInput input; PlayerInput input;
CameraControl camControl; CameraControl camControl;
BlocksController* blocksController; BlocksController* blocksController;
void updateKeyboard(); std::vector<on_block_interaction> blockInteractionCallbacks;
void updateCamera(float delta, bool movement);
void resetKeyboard();
void updateControls(float delta);
void updateInteraction();
public:
static glm::vec3 selectedBlockPosition;
static glm::ivec3 selectedBlockNormal;
static glm::vec3 selectedPointPosition;
static int selectedBlockId;
static int selectedBlockStates;
PlayerController(Level* level, void updateKeyboard();
const EngineSettings& settings, void updateCamera(float delta, bool movement);
BlocksController* blocksController); void resetKeyboard();
void update(float delta, bool input, bool pause); void updateControls(float delta);
void updateInteraction();
void onBlockInteraction(
glm::ivec3 pos,
const Block* def,
BlockInteraction type
);
float stepsTimer = 0.0f;
void onFootstep();
void updateFootsteps(float delta);
public:
static glm::vec3 selectedBlockPosition;
static glm::ivec3 selectedBlockNormal;
static glm::vec3 selectedPointPosition;
static int selectedBlockId;
static int selectedBlockStates;
PlayerController(
Level* level,
const EngineSettings& settings,
BlocksController* blocksController
);
void update(float delta, bool input, bool pause);
Player* getPlayer(); Player* getPlayer();
void listenBlockInteraction(on_block_interaction callback);
}; };
#endif /* PLAYER_CONTROL_H_ */ #endif /* PLAYER_CONTROL_H_ */
+147 -140
View File
@@ -19,14 +19,14 @@ const float CHEAT_SPEED_MUL = 5.0f;
const float JUMP_FORCE = 8.0f; const float JUMP_FORCE = 8.0f;
Player::Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv) : Player::Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv) :
speed(speed), speed(speed),
chosenSlot(0), chosenSlot(0),
inventory(inv), inventory(inv),
camera(new Camera(position, glm::radians(90.0f))), camera(std::make_shared<Camera>(position, glm::radians(90.0f))),
spCamera(new Camera(position, glm::radians(90.0f))), spCamera(std::make_shared<Camera>(position, glm::radians(90.0f))),
tpCamera(new Camera(position, glm::radians(90.0f))), tpCamera(std::make_shared<Camera>(position, glm::radians(90.0f))),
currentCamera(camera), currentCamera(camera),
hitbox(new Hitbox(position, glm::vec3(0.3f,0.9f,0.3f))) hitbox(std::make_unique<Hitbox>(position, glm::vec3(0.3f,0.9f,0.3f)))
{ {
} }
@@ -34,116 +34,123 @@ Player::~Player() {
} }
void Player::updateInput( void Player::updateInput(
Level* level, Level* level,
PlayerInput& input, PlayerInput& input,
float delta) { float delta) {
bool crouch = input.shift && hitbox->grounded && !input.sprint; bool crouch = input.shift && hitbox->grounded && !input.sprint;
float speed = this->speed; float speed = this->speed;
if (flight){ if (flight){
speed *= FLIGHT_SPEED_MUL; speed *= FLIGHT_SPEED_MUL;
} }
if (input.cheat){ if (input.cheat){
speed *= CHEAT_SPEED_MUL; speed *= CHEAT_SPEED_MUL;
} }
if (crouch) { if (crouch) {
speed *= CROUCH_SPEED_MUL; speed *= CROUCH_SPEED_MUL;
} else if (input.sprint) { } else if (input.sprint) {
speed *= RUN_SPEED_MUL; speed *= RUN_SPEED_MUL;
} }
glm::vec3 dir(0,0,0); glm::vec3 dir(0,0,0);
if (input.moveForward){ if (input.moveForward){
dir.x += camera->dir.x; dir.x += camera->dir.x;
dir.z += camera->dir.z; dir.z += camera->dir.z;
} }
if (input.moveBack){ if (input.moveBack){
dir.x -= camera->dir.x; dir.x -= camera->dir.x;
dir.z -= camera->dir.z; dir.z -= camera->dir.z;
} }
if (input.moveRight){ if (input.moveRight){
dir.x += camera->right.x; dir.x += camera->right.x;
dir.z += camera->right.z; dir.z += camera->right.z;
} }
if (input.moveLeft){ if (input.moveLeft){
dir.x -= camera->right.x; dir.x -= camera->right.x;
dir.z -= camera->right.z; dir.z -= camera->right.z;
} }
if (glm::length(dir) > 0.0f){ if (glm::length(dir) > 0.0f){
dir = glm::normalize(dir); dir = glm::normalize(dir);
hitbox->velocity.x += dir.x * speed * delta * 9; hitbox->velocity.x += dir.x * speed * delta * 9;
hitbox->velocity.z += dir.z * speed * delta * 9; hitbox->velocity.z += dir.z * speed * delta * 9;
} }
float vel = std::max(glm::length(hitbox->velocity * 0.25f), 1.0f); float vel = std::max(glm::length(hitbox->velocity * 0.25f), 1.0f);
int substeps = int(delta * vel * 1000); int substeps = int(delta * vel * 1000);
substeps = std::min(100, std::max(1, substeps)); substeps = std::min(100, std::max(1, substeps));
level->physics->step(level->chunks.get(), hitbox.get(), level->physics->step(
delta, substeps, level->chunks.get(),
crouch, flight ? 0.0f : 1.0f, hitbox.get(),
!noclip); delta,
substeps,
crouch,
flight ? 0.0f : 1.0f,
!noclip
);
if (flight && hitbox->grounded) { if (flight && hitbox->grounded) {
flight = false; flight = false;
} }
if (input.jump && hitbox->grounded){ if (input.jump && hitbox->grounded){
hitbox->velocity.y = JUMP_FORCE; hitbox->velocity.y = JUMP_FORCE;
} }
if ((input.flight && !noclip) || if ((input.flight && !noclip) ||
(input.noclip && flight == noclip)){ (input.noclip && flight == noclip)){
flight = !flight; flight = !flight;
if (flight){ if (flight){
hitbox->grounded = false; hitbox->grounded = false;
} }
} }
if (input.noclip) { if (input.noclip) {
noclip = !noclip; noclip = !noclip;
} }
hitbox->linear_damping = PLAYER_GROUND_DAMPING; hitbox->linear_damping = PLAYER_GROUND_DAMPING;
if (flight){ if (flight){
hitbox->linear_damping = PLAYER_AIR_DAMPING; hitbox->linear_damping = PLAYER_AIR_DAMPING;
hitbox->velocity.y *= 1.0f - delta * 9; hitbox->velocity.y *= 1.0f - delta * 9;
if (input.jump){ if (input.jump){
hitbox->velocity.y += speed * delta * 9; hitbox->velocity.y += speed * delta * 9;
} }
if (input.shift){ if (input.shift){
hitbox->velocity.y -= speed * delta * 9; hitbox->velocity.y -= speed * delta * 9;
} }
} }
if (!hitbox->grounded) { if (!hitbox->grounded) {
hitbox->linear_damping = PLAYER_AIR_DAMPING; hitbox->linear_damping = PLAYER_AIR_DAMPING;
} }
input.noclip = false; input.noclip = false;
input.flight = false; input.flight = false;
if (spawnpoint.y <= 0.1) { if (spawnpoint.y <= 0.1) {
attemptToFindSpawnpoint(level); attemptToFindSpawnpoint(level);
} }
} }
void Player::teleport(glm::vec3 position) { void Player::teleport(glm::vec3 position) {
hitbox->position = position; hitbox->position = position;
} }
void Player::attemptToFindSpawnpoint(Level* level) { void Player::attemptToFindSpawnpoint(Level* level) {
glm::vec3 ppos = hitbox->position; glm::vec3 ppos = hitbox->position;
glm::vec3 newpos {ppos.x + (rand() % 200 - 100), glm::vec3 newpos (
rand() % 80 + 100, ppos.x + (rand() % 200 - 100),
ppos.z + (rand() % 200 - 100)}; rand() % 80 + 100,
while (newpos.y > 0 && !level->chunks->isObstacleBlock(newpos.x, newpos.y-2, newpos.z)) { ppos.z + (rand() % 200 - 100)
newpos.y--; );
} while (newpos.y > 0 && !level->chunks->isObstacleBlock(newpos.x, newpos.y-2, newpos.z)) {
newpos.y--;
}
voxel* headvox = level->chunks->get(newpos.x, newpos.y+1, newpos.z); voxel* headvox = level->chunks->get(newpos.x, newpos.y+1, newpos.z);
if (level->chunks->isObstacleBlock(newpos.x, newpos.y, newpos.z) || if (level->chunks->isObstacleBlock(newpos.x, newpos.y, newpos.z) ||
headvox == nullptr || headvox->id != 0) headvox == nullptr || headvox->id != 0)
return; return;
spawnpoint = newpos + glm::vec3(0.5f, 0.0f, 0.5f); spawnpoint = newpos + glm::vec3(0.5f, 0.0f, 0.5f);
teleport(spawnpoint); teleport(spawnpoint);
} }
void Player::setChosenSlot(int index) { void Player::setChosenSlot(int index) {
@@ -155,7 +162,7 @@ int Player::getChosenSlot() const {
} }
float Player::getSpeed() const { float Player::getSpeed() const {
return speed; return speed;
} }
std::shared_ptr<Inventory> Player::getInventory() const { std::shared_ptr<Inventory> Player::getInventory() const {
@@ -163,62 +170,62 @@ std::shared_ptr<Inventory> Player::getInventory() const {
} }
void Player::setSpawnPoint(glm::vec3 spawnpoint) { void Player::setSpawnPoint(glm::vec3 spawnpoint) {
this->spawnpoint = spawnpoint; this->spawnpoint = spawnpoint;
} }
glm::vec3 Player::getSpawnPoint() const { glm::vec3 Player::getSpawnPoint() const {
return spawnpoint; return spawnpoint;
} }
std::unique_ptr<dynamic::Map> Player::serialize() const { std::unique_ptr<dynamic::Map> Player::serialize() const {
glm::vec3 position = hitbox->position; glm::vec3 position = hitbox->position;
auto root = std::make_unique<dynamic::Map>(); auto root = std::make_unique<dynamic::Map>();
auto& posarr = root->putList("position"); auto& posarr = root->putList("position");
posarr.put(position.x); posarr.put(position.x);
posarr.put(position.y); posarr.put(position.y);
posarr.put(position.z); posarr.put(position.z);
auto& rotarr = root->putList("rotation"); auto& rotarr = root->putList("rotation");
rotarr.put(cam.x); rotarr.put(cam.x);
rotarr.put(cam.y); rotarr.put(cam.y);
auto& sparr = root->putList("spawnpoint"); auto& sparr = root->putList("spawnpoint");
sparr.put(spawnpoint.x); sparr.put(spawnpoint.x);
sparr.put(spawnpoint.y); sparr.put(spawnpoint.y);
sparr.put(spawnpoint.z); sparr.put(spawnpoint.z);
root->put("flight", flight); root->put("flight", flight);
root->put("noclip", noclip); root->put("noclip", noclip);
root->put("chosen-slot", chosenSlot); root->put("chosen-slot", chosenSlot);
root->put("inventory", inventory->serialize().release()); root->put("inventory", inventory->serialize().release());
return root; return root;
} }
void Player::deserialize(dynamic::Map *src) { void Player::deserialize(dynamic::Map *src) {
auto posarr = src->list("position"); auto posarr = src->list("position");
glm::vec3& position = hitbox->position; glm::vec3& position = hitbox->position;
position.x = posarr->num(0); position.x = posarr->num(0);
position.y = posarr->num(1); position.y = posarr->num(1);
position.z = posarr->num(2); position.z = posarr->num(2);
camera->position = position; camera->position = position;
auto rotarr = src->list("rotation"); auto rotarr = src->list("rotation");
cam.x = rotarr->num(0); cam.x = rotarr->num(0);
cam.y = rotarr->num(1); cam.y = rotarr->num(1);
if (src->has("spawnpoint")) { if (src->has("spawnpoint")) {
auto sparr = src->list("spawnpoint"); auto sparr = src->list("spawnpoint");
setSpawnPoint(glm::vec3( setSpawnPoint(glm::vec3(
sparr->num(0), sparr->num(0),
sparr->num(1), sparr->num(1),
sparr->num(2) sparr->num(2)
)); ));
} else { } else {
setSpawnPoint(position); setSpawnPoint(position);
} }
src->flag("flight", flight); src->flag("flight", flight);
src->flag("noclip", noclip); src->flag("noclip", noclip);
setChosenSlot(src->getInt("chosen-slot", getChosenSlot())); setChosenSlot(src->getInt("chosen-slot", getChosenSlot()));
auto invmap = src->map("inventory"); auto invmap = src->map("inventory");
+4 -6
View File
@@ -2,10 +2,8 @@
#include "../core_defs.h" #include "../core_defs.h"
using glm::vec3;
CoordSystem::CoordSystem(glm::ivec3 axisX, glm::ivec3 axisY, glm::ivec3 axisZ) CoordSystem::CoordSystem(glm::ivec3 axisX, glm::ivec3 axisY, glm::ivec3 axisZ)
: axisX(axisX), axisY(axisY), axisZ(axisZ) : axisX(axisX), axisY(axisY), axisZ(axisZ)
{ {
fix = glm::ivec3(0); fix = glm::ivec3(0);
if (isVectorHasNegatives(axisX)) fix -= axisX; if (isVectorHasNegatives(axisX)) fix -= axisX;
@@ -14,9 +12,9 @@ CoordSystem::CoordSystem(glm::ivec3 axisX, glm::ivec3 axisY, glm::ivec3 axisZ)
} }
void CoordSystem::transform(AABB& aabb) const { void CoordSystem::transform(AABB& aabb) const {
vec3 X(axisX); glm::vec3 X(axisX);
vec3 Y(axisY); glm::vec3 Y(axisY);
vec3 Z(axisZ); glm::vec3 Z(axisZ);
aabb.a = X * aabb.a.x + Y * aabb.a.y + Z * aabb.a.z; aabb.a = X * aabb.a.x + Y * aabb.a.y + Z * aabb.a.z;
aabb.b = X * aabb.b.x + Y * aabb.b.y + Z * aabb.b.z; aabb.b = X * aabb.b.x + Y * aabb.b.y + Z * aabb.b.z;
aabb.a += fix; aabb.a += fix;
+86 -14
View File
@@ -18,8 +18,12 @@ inline constexpr uint FACE_PY = 3;
inline constexpr uint FACE_MZ = 4; inline constexpr uint FACE_MZ = 4;
inline constexpr uint FACE_PZ = 5; inline constexpr uint FACE_PZ = 5;
/// @brief Grid size used for physics solver collision checking with
/// complex hitboxes
inline constexpr uint BLOCK_AABB_GRID = 16; inline constexpr uint BLOCK_AABB_GRID = 16;
inline std::string DEFAULT_MATERIAL = "base:stone";
struct block_funcs_set { struct block_funcs_set {
bool init: 1; bool init: 1;
bool update: 1; bool update: 1;
@@ -35,7 +39,7 @@ struct CoordSystem {
glm::ivec3 axisY; glm::ivec3 axisY;
glm::ivec3 axisZ; glm::ivec3 axisZ;
// Grid 3d position fix offset (for negative vectors) /// @brief Grid 3d position fix offset (for negative vectors)
glm::ivec3 fix; glm::ivec3 fix;
CoordSystem() = default; CoordSystem() = default;
@@ -43,11 +47,8 @@ struct CoordSystem {
void transform(AABB& aabb) const; void transform(AABB& aabb) const;
static bool isVectorHasNegatives(glm::ivec3 vec) { inline bool isVectorHasNegatives(glm::ivec3 vec) {
if (vec.x < 0 || vec.y < 0 || vec.z < 0) { return (vec.x < 0 || vec.y < 0 || vec.z < 0);
return true;
}
else return false;
} }
}; };
@@ -56,56 +57,127 @@ struct BlockRotProfile {
std::string name; std::string name;
CoordSystem variants[MAX_COUNT]; CoordSystem variants[MAX_COUNT];
/* Wood logs, pillars, pipes */ /// @brief Wood logs, pillars, pipes
static const BlockRotProfile PIPE; static const BlockRotProfile PIPE;
/* Doors, signs and other panes */
/// @brief Doors, signs and other panes
static const BlockRotProfile PANE; static const BlockRotProfile PANE;
}; };
enum class BlockModel { enum class BlockModel {
none, // invisible /// @brief invisible
block, // default shape none,
xsprite, // X-shape (grass) /// @brief default cube shape
aabb, // box shaped as block hitbox block,
/// @brief X-shape (grass)
xsprite,
/// @brief box shape sized as block hitbox
aabb,
/// @brief custom model defined in json
custom custom
}; };
using BoxModel = AABB; using BoxModel = AABB;
/// @brief Common kit of block properties applied to groups of blocks
struct BlockMaterial {
std::string name;
std::string stepsSound {""};
std::string placeSound {""};
std::string breakSound {""};
};
/// @brief Block properties definition
class Block { class Block {
public: public:
/// @brief Block string id (with prefix included)
std::string const name; std::string const name;
// 0 1 2 3 4 5
/// @brief Textures set applied to block sides
std::string textureFaces[6]; // -x,x, -y,y, -z,z std::string textureFaces[6]; // -x,x, -y,y, -z,z
std::vector<std::string> modelTextures = {}; std::vector<std::string> modelTextures = {};
std::vector<BoxModel> modelBoxes = {}; std::vector<BoxModel> modelBoxes = {};
std::vector<glm::vec3> modelExtraPoints = {}; //initially made for tetragons std::vector<glm::vec3> modelExtraPoints = {}; //initially made for tetragons
std::vector<UVRegion> modelUVs = {}; // boxes' tex-UVs also there std::vector<UVRegion> modelUVs = {}; // boxes' tex-UVs also there
/// @brief id of used BlockMaterial, may specify non-existing material
std::string material = DEFAULT_MATERIAL;
/// @brief Light emission R, G, B, S (sky lights: sun, moon, radioactive clouds)
uint8_t emission[4] {0, 0, 0, 0}; uint8_t emission[4] {0, 0, 0, 0};
/// @brief Influences visible block sides for transparent blocks
uint8_t drawGroup = 0; uint8_t drawGroup = 0;
/// @brief Block model type
BlockModel model = BlockModel::block; BlockModel model = BlockModel::block;
/// @brief Does the block passing lights into itself
bool lightPassing = false; bool lightPassing = false;
/// @brief Does the block passing top-down sky lights into itself
bool skyLightPassing = false; bool skyLightPassing = false;
/// @brief Is the block a physical obstacle
bool obstacle = true; bool obstacle = true;
/// @brief Can the block be selected
bool selectable = true; bool selectable = true;
/// @brief Can the block be replaced with other.
/// Examples of replaceable blocks: air, flower, water
bool replaceable = false; bool replaceable = false;
/// @brief Can player destroy the block
bool breakable = true; bool breakable = true;
/// @brief Can the block be oriented different ways
bool rotatable = false; bool rotatable = false;
/// @brief Can the block exist without physical support be a solid block below
bool grounded = false; bool grounded = false;
/// @brief Turns off block item generation
bool hidden = false; bool hidden = false;
/// @brief Set of block physical hitboxes
std::vector<AABB> hitboxes; std::vector<AABB> hitboxes;
/// @brief Set of available block rotations (coord-systems)
BlockRotProfile rotations; BlockRotProfile rotations;
/// @brief Item will be picked on MMB click on the block
std::string pickingItem = name+BLOCK_ITEM_SUFFIX; std::string pickingItem = name+BLOCK_ITEM_SUFFIX;
std::string scriptName = name.substr(name.find(':')+1);
/// @brief Block script name in blocks/ without extension
std::string scriptName = name.substr(name.find(':')+1);
/// @brief Default block layout will be used by hud.open_block(...)
std::string uiLayout = name; std::string uiLayout = name;
/// @brief Block inventory size. 0 - no inventory
uint inventorySize = 0; uint inventorySize = 0;
/// @brief Runtime indices (content indexing results)
struct { struct {
/// @brief block runtime integer id
blockid_t id; blockid_t id;
/// @brief is the block completely opaque for render and raycast
bool solid = true; bool solid = true;
/// @brief does the block emit any lights
bool emissive = false; bool emissive = false;
/// @brief set of hitboxes sets with all coord-systems precalculated
std::vector<AABB> hitboxes[BlockRotProfile::MAX_COUNT]; std::vector<AABB> hitboxes[BlockRotProfile::MAX_COUNT];
/// @brief set of block callbacks flags
block_funcs_set funcsset {}; block_funcs_set funcsset {};
/// @brief picking item integer id
itemid_t pickingItem = 0; itemid_t pickingItem = 0;
} rt; } rt;