commit
3f0c710a47
5
res/content/base/block_materials/glass.json
Normal file
5
res/content/base/block_materials/glass.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"steps-sound": "steps/wood",
|
||||
"place-sound": "blocks/wood_place",
|
||||
"break-sound": "blocks/glass_break"
|
||||
}
|
||||
5
res/content/base/block_materials/grass.json
Normal file
5
res/content/base/block_materials/grass.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"steps-sound": "steps/grass",
|
||||
"place-sound": "steps/grass",
|
||||
"break-sound": "steps/grass"
|
||||
}
|
||||
5
res/content/base/block_materials/grass_block.json
Normal file
5
res/content/base/block_materials/grass_block.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"steps-sound": "steps/grass",
|
||||
"place-sound": "blocks/ground_place",
|
||||
"break-sound": "blocks/ground_break"
|
||||
}
|
||||
5
res/content/base/block_materials/ground.json
Normal file
5
res/content/base/block_materials/ground.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"steps-sound": "steps/ground",
|
||||
"place-sound": "blocks/ground_place",
|
||||
"break-sound": "blocks/ground_break"
|
||||
}
|
||||
5
res/content/base/block_materials/sand.json
Normal file
5
res/content/base/block_materials/sand.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"steps-sound": "steps/sand",
|
||||
"steps-sound": "blocks/ground_place",
|
||||
"break-sound": "blocks/ground_break"
|
||||
}
|
||||
5
res/content/base/block_materials/stone.json
Normal file
5
res/content/base/block_materials/stone.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"steps-sound": "steps/stone",
|
||||
"place-sound": "blocks/stone_place",
|
||||
"break-sound": "blocks/stone_break"
|
||||
}
|
||||
5
res/content/base/block_materials/wood.json
Normal file
5
res/content/base/block_materials/wood.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"steps-sound": "steps/wood",
|
||||
"place-sound": "blocks/wood_place",
|
||||
"break-sound": "blocks/wood_break"
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
{
|
||||
"texture": "dirt"
|
||||
"texture": "dirt",
|
||||
"material": "base:ground"
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"texture": "flower",
|
||||
"material": "base:grass",
|
||||
"draw-group": 1,
|
||||
"light-passing": true,
|
||||
"obstacle": false,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"texture": "glass",
|
||||
"material": "base:glass",
|
||||
"draw-group": 2,
|
||||
"light-passing": true,
|
||||
"sky-light-passing": true
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"texture": "grass",
|
||||
"material": "base:grass",
|
||||
"draw-group": 1,
|
||||
"light-passing": true,
|
||||
"obstacle": false,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"material": "base:grass_block",
|
||||
"texture-faces": [
|
||||
"grass_side",
|
||||
"grass_side",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
{
|
||||
"texture": "leaves"
|
||||
"texture": "leaves",
|
||||
"material": "base:grass"
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
"pane",
|
||||
"pane"
|
||||
],
|
||||
"material": "base:wood",
|
||||
"model": "aabb",
|
||||
"hitbox": [0.0, 0.0, 0.0, 1.0, 1.0, 0.2],
|
||||
"light-passing": true,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
{
|
||||
"texture": "planks"
|
||||
"texture": "planks",
|
||||
"material": "base:wood"
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
{
|
||||
"texture": "sand"
|
||||
"texture": "sand",
|
||||
"material": "base:sand"
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"material": "base:wood",
|
||||
"texture-faces": [
|
||||
"wood",
|
||||
"wood",
|
||||
|
||||
BIN
res/content/base/sounds/blocks/glass_break.ogg
Normal file
BIN
res/content/base/sounds/blocks/glass_break.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/blocks/ground_break.ogg
Normal file
BIN
res/content/base/sounds/blocks/ground_break.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/blocks/ground_place.ogg
Normal file
BIN
res/content/base/sounds/blocks/ground_place.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/blocks/stone_break.ogg
Normal file
BIN
res/content/base/sounds/blocks/stone_break.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/blocks/stone_place.ogg
Normal file
BIN
res/content/base/sounds/blocks/stone_place.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/blocks/wood_break.ogg
Normal file
BIN
res/content/base/sounds/blocks/wood_break.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/blocks/wood_place.ogg
Normal file
BIN
res/content/base/sounds/blocks/wood_place.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/grass_0.ogg
Normal file
BIN
res/content/base/sounds/steps/grass_0.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/grass_1.ogg
Normal file
BIN
res/content/base/sounds/steps/grass_1.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/grass_2.ogg
Normal file
BIN
res/content/base/sounds/steps/grass_2.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/grass_3.ogg
Normal file
BIN
res/content/base/sounds/steps/grass_3.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/ground_0.ogg
Normal file
BIN
res/content/base/sounds/steps/ground_0.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/ground_1.ogg
Normal file
BIN
res/content/base/sounds/steps/ground_1.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/ground_2.ogg
Normal file
BIN
res/content/base/sounds/steps/ground_2.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/ground_3.ogg
Normal file
BIN
res/content/base/sounds/steps/ground_3.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/sand_0.ogg
Normal file
BIN
res/content/base/sounds/steps/sand_0.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/sand_1.ogg
Normal file
BIN
res/content/base/sounds/steps/sand_1.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/sand_2.ogg
Normal file
BIN
res/content/base/sounds/steps/sand_2.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/sand_3.ogg
Normal file
BIN
res/content/base/sounds/steps/sand_3.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/snow_0.ogg
Normal file
BIN
res/content/base/sounds/steps/snow_0.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/snow_1.ogg
Normal file
BIN
res/content/base/sounds/steps/snow_1.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/snow_2.ogg
Normal file
BIN
res/content/base/sounds/steps/snow_2.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/snow_3.ogg
Normal file
BIN
res/content/base/sounds/steps/snow_3.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/snow_4.ogg
Normal file
BIN
res/content/base/sounds/steps/snow_4.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/stone_0.ogg
Normal file
BIN
res/content/base/sounds/steps/stone_0.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/stone_1.ogg
Normal file
BIN
res/content/base/sounds/steps/stone_1.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/stone_2.ogg
Normal file
BIN
res/content/base/sounds/steps/stone_2.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/stone_3.ogg
Normal file
BIN
res/content/base/sounds/steps/stone_3.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/wood_0.ogg
Normal file
BIN
res/content/base/sounds/steps/wood_0.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/wood_1.ogg
Normal file
BIN
res/content/base/sounds/steps/wood_1.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/wood_2.ogg
Normal file
BIN
res/content/base/sounds/steps/wood_2.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/steps/wood_3.ogg
Normal file
BIN
res/content/base/sounds/steps/wood_3.ogg
Normal file
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 |
@ -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) {
|
||||
loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal");
|
||||
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"/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);
|
||||
for (auto& entry : content->getPacks()) {
|
||||
auto pack = entry.second.get();
|
||||
|
||||
@ -49,6 +49,8 @@ class AssetsLoader {
|
||||
std::map<int, aloader_func> loaders;
|
||||
std::queue<aloader_entry> entries;
|
||||
const ResPaths* paths;
|
||||
|
||||
void tryAddSound(std::string name);
|
||||
public:
|
||||
AssetsLoader(Assets* assets, const ResPaths* paths);
|
||||
void addLoader(int tag, aloader_func func);
|
||||
|
||||
@ -38,6 +38,11 @@ ALStream::ALStream(ALAudio* al, std::shared_ptr<PCMStream> source, bool keepSour
|
||||
ALStream::~ALStream() {
|
||||
bindSpeaker(0);
|
||||
source = nullptr;
|
||||
|
||||
while (!unusedBuffers.empty()) {
|
||||
al->freeBuffer(unusedBuffers.front());
|
||||
unusedBuffers.pop();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<PCMStream> ALStream::getSource() const {
|
||||
@ -135,6 +140,11 @@ void ALStream::update(double delta) {
|
||||
return;
|
||||
}
|
||||
ALSpeaker* alspeaker = dynamic_cast<ALSpeaker*>(speaker);
|
||||
if (alspeaker->stopped) {
|
||||
speaker = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
uint alsource = alspeaker->source;
|
||||
|
||||
unqueueBuffers(alsource);
|
||||
@ -194,6 +204,8 @@ ALSpeaker::~ALSpeaker() {
|
||||
}
|
||||
|
||||
void ALSpeaker::update(const Channel* channel, float masterVolume) {
|
||||
if (source == 0)
|
||||
return;
|
||||
float gain = this->volume * channel->getVolume()*masterVolume;
|
||||
AL_CHECK(alSourcef(source, AL_GAIN, gain));
|
||||
|
||||
@ -265,7 +277,9 @@ void ALSpeaker::stop() {
|
||||
AL_CHECK(alSourceUnqueueBuffers(source, 1, &buffer));
|
||||
al->freeBuffer(buffer);
|
||||
}
|
||||
AL_CHECK(alSourcei(source, AL_BUFFER, 0));
|
||||
al->freeSource(source);
|
||||
source = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,8 +409,9 @@ uint ALAudio::getFreeSource(){
|
||||
}
|
||||
ALuint id;
|
||||
alGenSources(1, &id);
|
||||
if (!AL_GET_ERROR())
|
||||
if (!AL_GET_ERROR()) {
|
||||
return 0;
|
||||
}
|
||||
allsources.push_back(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -17,7 +17,8 @@
|
||||
#define AL_CHECK(STATEMENT) STATEMENT; 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);
|
||||
|
||||
/// @brief alGetSourcef wrapper
|
||||
@ -27,6 +28,8 @@ namespace AL {
|
||||
/// @return field value or default
|
||||
inline float getSourcef(uint source, ALenum field, float def=0.0f) {
|
||||
float value = def;
|
||||
if (source == 0)
|
||||
return def;
|
||||
AL_CHECK(alGetSourcef(source, field, &value));
|
||||
return value;
|
||||
}
|
||||
@ -38,6 +41,8 @@ namespace AL {
|
||||
/// @return field value or default
|
||||
inline glm::vec3 getSource3f(uint source, ALenum field, glm::vec3 def={}) {
|
||||
glm::vec3 value = def;
|
||||
if (source == 0)
|
||||
return def;
|
||||
AL_CHECK(alGetSource3f(source, field, &value.x, &value.y, &value.z));
|
||||
return value;
|
||||
}
|
||||
@ -49,6 +54,8 @@ namespace AL {
|
||||
/// @return field value or default
|
||||
inline float getSourcei(uint source, ALenum field, int def=0) {
|
||||
int value = def;
|
||||
if (source == 0)
|
||||
return def;
|
||||
AL_CHECK(alGetSourcei(source, field, &value));
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -249,6 +249,15 @@ speakerid_t audio::play(
|
||||
int priority,
|
||||
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);
|
||||
if (speaker == nullptr) {
|
||||
remove_lower_priority_speaker(priority);
|
||||
@ -359,6 +368,10 @@ size_t audio::count_speakers() {
|
||||
return speakers.size();
|
||||
}
|
||||
|
||||
size_t audio::count_streams() {
|
||||
return streams.size();
|
||||
}
|
||||
|
||||
void audio::update(double delta) {
|
||||
backend->update(delta);
|
||||
|
||||
|
||||
@ -484,6 +484,9 @@ namespace audio {
|
||||
/// @brief Get alive speakers number (including paused)
|
||||
extern size_t count_speakers();
|
||||
|
||||
/// @brief Get playing streams number (including paused)
|
||||
extern size_t count_streams();
|
||||
|
||||
/// @brief Update audio streams and sound instanced
|
||||
/// @param delta time elapsed since the last update (seconds)
|
||||
extern void update(double delta);
|
||||
|
||||
@ -10,8 +10,7 @@
|
||||
#include "ContentPack.h"
|
||||
#include "../logic/scripting/scripting.h"
|
||||
|
||||
ContentBuilder::~ContentBuilder() {
|
||||
}
|
||||
ContentBuilder::~ContentBuilder() {}
|
||||
|
||||
void ContentBuilder::add(Block* def) {
|
||||
checkIdentifier(def->name);
|
||||
@ -29,6 +28,10 @@ void ContentBuilder::add(ContentPackRuntime* pack) {
|
||||
packs.emplace(pack->getId(), pack);
|
||||
}
|
||||
|
||||
void ContentBuilder::add(BlockMaterial material) {
|
||||
blockMaterials.emplace(material.name, material);
|
||||
}
|
||||
|
||||
Block& ContentBuilder::createBlock(std::string id) {
|
||||
auto found = blockDefs.find(id);
|
||||
if (found != blockDefs.end()) {
|
||||
@ -110,7 +113,12 @@ Content* ContentBuilder::build() {
|
||||
auto indices = new ContentIndices(blockDefsIndices, itemDefsIndices);
|
||||
|
||||
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
|
||||
@ -127,25 +135,27 @@ Content* ContentBuilder::build() {
|
||||
|
||||
ContentIndices::ContentIndices(
|
||||
std::vector<Block*> blockDefs,
|
||||
std::vector<ItemDef*> itemDefs)
|
||||
: blockDefs(blockDefs),
|
||||
itemDefs(itemDefs) {
|
||||
}
|
||||
std::vector<ItemDef*> itemDefs
|
||||
) : blockDefs(blockDefs),
|
||||
itemDefs(itemDefs)
|
||||
{}
|
||||
|
||||
Content::Content(ContentIndices* indices,
|
||||
std::unique_ptr<DrawGroups> drawGroups,
|
||||
std::unordered_map<std::string, Block*> blockDefs,
|
||||
std::unordered_map<std::string, ItemDef*> itemDefs,
|
||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs)
|
||||
: blockDefs(blockDefs),
|
||||
itemDefs(itemDefs),
|
||||
indices(indices),
|
||||
packs(std::move(packs)),
|
||||
drawGroups(std::move(drawGroups)) {
|
||||
}
|
||||
Content::Content(
|
||||
ContentIndices* indices,
|
||||
std::unique_ptr<DrawGroups> drawGroups,
|
||||
std::unordered_map<std::string, Block*> blockDefs,
|
||||
std::unordered_map<std::string, ItemDef*> itemDefs,
|
||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs,
|
||||
std::unordered_map<std::string, BlockMaterial> blockMaterials
|
||||
) : blockDefs(blockDefs),
|
||||
itemDefs(itemDefs),
|
||||
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 {
|
||||
auto found = blockDefs.find(id);
|
||||
@ -179,6 +189,14 @@ ItemDef& Content::requireItem(std::string id) const {
|
||||
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 {
|
||||
auto found = packs.find(id);
|
||||
if (found == packs.end()) {
|
||||
@ -187,6 +205,10 @@ const ContentPackRuntime* Content::getPackRuntime(std::string id) const {
|
||||
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 {
|
||||
return packs;
|
||||
}
|
||||
|
||||
@ -8,10 +8,10 @@
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include "../typedefs.h"
|
||||
#include "../voxels/Block.h"
|
||||
|
||||
using DrawGroups = std::set<ubyte>;
|
||||
|
||||
class Block;
|
||||
class ItemDef;
|
||||
class Content;
|
||||
class ContentPackRuntime;
|
||||
@ -48,6 +48,8 @@ class ContentBuilder {
|
||||
std::unordered_map<std::string, ItemDef*> itemDefs;
|
||||
std::vector<std::string> itemIds;
|
||||
|
||||
std::unordered_map<std::string, BlockMaterial> blockMaterials;
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs;
|
||||
public:
|
||||
~ContentBuilder();
|
||||
@ -55,6 +57,7 @@ public:
|
||||
void add(Block* def);
|
||||
void add(ItemDef* def);
|
||||
void add(ContentPackRuntime* pack);
|
||||
void add(BlockMaterial material);
|
||||
|
||||
Block& createBlock(std::string id);
|
||||
ItemDef& createItem(std::string id);
|
||||
@ -65,13 +68,15 @@ public:
|
||||
Content* build();
|
||||
};
|
||||
|
||||
/* Runtime defs cache: indices */
|
||||
/// @brief Runtime defs cache: indices
|
||||
class ContentIndices {
|
||||
std::vector<Block*> blockDefs;
|
||||
std::vector<ItemDef*> itemDefs;
|
||||
public:
|
||||
ContentIndices(std::vector<Block*> blockDefs,
|
||||
std::vector<ItemDef*> itemDefs);
|
||||
ContentIndices(
|
||||
std::vector<Block*> blockDefs,
|
||||
std::vector<ItemDef*> itemDefs
|
||||
);
|
||||
|
||||
inline Block* getBlockDef(blockid_t id) const {
|
||||
if (id >= blockDefs.size())
|
||||
@ -109,14 +114,18 @@ class Content {
|
||||
std::unordered_map<std::string, ItemDef*> itemDefs;
|
||||
std::unique_ptr<ContentIndices> indices;
|
||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs;
|
||||
std::unordered_map<std::string, BlockMaterial> blockMaterials;
|
||||
public:
|
||||
std::unique_ptr<DrawGroups> const drawGroups;
|
||||
|
||||
Content(ContentIndices* indices,
|
||||
std::unique_ptr<DrawGroups> drawGroups,
|
||||
std::unordered_map<std::string, Block*> blockDefs,
|
||||
std::unordered_map<std::string, ItemDef*> itemDefs,
|
||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs);
|
||||
Content(
|
||||
ContentIndices* indices,
|
||||
std::unique_ptr<DrawGroups> drawGroups,
|
||||
std::unordered_map<std::string, Block*> blockDefs,
|
||||
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();
|
||||
|
||||
inline ContentIndices* getIndices() const {
|
||||
@ -129,8 +138,11 @@ public:
|
||||
ItemDef* findItem(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 std::unordered_map<std::string, BlockMaterial>& getBlockMaterials() const;
|
||||
const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& getPacks() const;
|
||||
};
|
||||
|
||||
|
||||
@ -19,9 +19,9 @@ struct contententry {
|
||||
|
||||
// TODO: make it unified for all types of content
|
||||
|
||||
/* Content indices lookup table or report
|
||||
used to convert world with different indices
|
||||
Building with indices.json */
|
||||
/// @brief Content indices lookup table or report
|
||||
/// used to convert world with different indices
|
||||
/// Building with indices.json
|
||||
class ContentLUT {
|
||||
std::vector<blockid_t> blocks;
|
||||
std::vector<std::string> blockNames;
|
||||
|
||||
@ -144,6 +144,8 @@ void ContentLoader::loadBlock(Block& def, std::string name, fs::path file) {
|
||||
def.model = BlockModel::none;
|
||||
}
|
||||
|
||||
root->str("material", def.material);
|
||||
|
||||
// rotation profile
|
||||
std::string profile = "none";
|
||||
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) {
|
||||
std::cout << "-- loading pack [" << pack->id << "]" << std::endl;
|
||||
|
||||
@ -361,4 +372,13 @@ void ContentLoader::load(ContentBuilder& builder) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
#ifndef CONTENT_CONTENT_LOADER_H_
|
||||
#define CONTENT_CONTENT_LOADER_H_
|
||||
|
||||
#include "../voxels/Block.h"
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class Block;
|
||||
class ItemDef;
|
||||
struct ContentPack;
|
||||
class ContentBuilder;
|
||||
@ -22,12 +23,15 @@ class ContentLoader {
|
||||
void loadBlock(Block& def, std::string full, std::string name);
|
||||
void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
|
||||
void loadItem(ItemDef& def, std::string full, std::string name);
|
||||
BlockMaterial loadBlockMaterial(fs::path file, std::string full);
|
||||
public:
|
||||
ContentLoader(ContentPack* pack);
|
||||
|
||||
bool fixPackIndices(std::filesystem::path folder,
|
||||
dynamic::Map* indicesRoot,
|
||||
std::string contentSection);
|
||||
bool fixPackIndices(
|
||||
fs::path folder,
|
||||
dynamic::Map* indicesRoot,
|
||||
std::string contentSection
|
||||
);
|
||||
void fixPackIndices();
|
||||
void loadBlock(Block& def, std::string name, fs::path file);
|
||||
void loadItem(ItemDef& def, std::string name, fs::path file);
|
||||
|
||||
@ -1,16 +1,70 @@
|
||||
#include "LevelFrontend.h"
|
||||
|
||||
#include "../world/Level.h"
|
||||
#include "../assets/Assets.h"
|
||||
#include "../graphics/Atlas.h"
|
||||
#include "BlocksPreview.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)
|
||||
: level(level),
|
||||
assets(assets),
|
||||
contentCache(std::make_unique<ContentGfxCache>(level->content, assets)),
|
||||
blocksAtlas(BlocksPreview::build(contentCache.get(), assets, level->content)) {
|
||||
: level(level),
|
||||
assets(assets),
|
||||
contentCache(std::make_unique<ContentGfxCache>(level->content, assets)),
|
||||
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() {
|
||||
|
||||
@ -8,6 +8,7 @@ class Level;
|
||||
class Assets;
|
||||
class BlocksPreview;
|
||||
class ContentGfxCache;
|
||||
class LevelController;
|
||||
|
||||
class LevelFrontend {
|
||||
Level* level;
|
||||
@ -18,6 +19,8 @@ public:
|
||||
LevelFrontend(Level* level, Assets* assets);
|
||||
~LevelFrontend();
|
||||
|
||||
void observe(LevelController* controller);
|
||||
|
||||
Level* getLevel() const;
|
||||
Assets* getAssets() const;
|
||||
ContentGfxCache* getContentGfxCache() const;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "gui/controls.h"
|
||||
#include "../audio/audio.h"
|
||||
#include "../graphics/Mesh.h"
|
||||
#include "../objects/Player.h"
|
||||
#include "../physics/Hitbox.h"
|
||||
@ -52,6 +53,10 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
panel->add(create_label([](){
|
||||
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([=](){
|
||||
auto& settings = engine->getSettings();
|
||||
bool culling = settings.graphics.frustumCulling;
|
||||
|
||||
@ -100,6 +100,8 @@ LevelScreen::LevelScreen(Engine* engine, Level* level) : Screen(engine) {
|
||||
worldRenderer = std::make_unique<WorldRenderer>(engine, frontend.get(), controller->getPlayer());
|
||||
hud = std::make_unique<Hud>(engine, frontend.get(), controller->getPlayer());
|
||||
|
||||
frontend->observe(controller.get());
|
||||
|
||||
backlight = settings.graphics.backlight;
|
||||
|
||||
animator = std::make_unique<TextureAnimator>();
|
||||
@ -156,9 +158,9 @@ void LevelScreen::update(float delta) {
|
||||
auto player = controller->getPlayer();
|
||||
auto camera = player->camera;
|
||||
audio::set_listener(
|
||||
camera->position,
|
||||
camera->position-camera->dir,
|
||||
player->hitbox->velocity,
|
||||
camera->position+camera->dir,
|
||||
camera->dir,
|
||||
camera->up
|
||||
);
|
||||
|
||||
|
||||
@ -57,3 +57,7 @@ Level* LevelController::getLevel() {
|
||||
Player* LevelController::getPlayer() {
|
||||
return player->getPlayer();
|
||||
}
|
||||
|
||||
PlayerController* LevelController::getPlayerController() {
|
||||
return player.get();
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
class Level;
|
||||
class Player;
|
||||
|
||||
/* LevelController manages other controllers */
|
||||
/// @brief LevelController manages other controllers
|
||||
class LevelController {
|
||||
EngineSettings& settings;
|
||||
std::unique_ptr<Level> level;
|
||||
@ -22,20 +22,22 @@ class LevelController {
|
||||
public:
|
||||
LevelController(EngineSettings& settings, Level* level);
|
||||
|
||||
/*
|
||||
@param delta time elapsed since the last update
|
||||
@param input is user input allowed to be handled
|
||||
@param pause is world and player simulation paused
|
||||
*/
|
||||
void update(float delta,
|
||||
bool input,
|
||||
bool pause);
|
||||
/// @param delta time elapsed since the last update
|
||||
/// @param input is user input allowed to be handled
|
||||
/// @param pause is world and player simulation paused
|
||||
void update(
|
||||
float delta,
|
||||
bool input,
|
||||
bool pause
|
||||
);
|
||||
|
||||
void onWorldSave();
|
||||
void onWorldQuit();
|
||||
|
||||
Level* getLevel();
|
||||
Player* getPlayer();
|
||||
|
||||
PlayerController* getPlayerController();
|
||||
};
|
||||
|
||||
#endif // LOGIC_LEVEL_CONTROLLER_H_
|
||||
|
||||
@ -20,10 +20,14 @@
|
||||
|
||||
#include "../core_defs.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
|
||||
const float CAM_SHAKE_OFFSET = 0.025f;
|
||||
const float CAM_SHAKE_OFFSET_Y = 0.031f;
|
||||
const float CAM_SHAKE_SPEED = 1.75f;
|
||||
const float CAM_SHAKE_DELTA_K = 10.0f;
|
||||
const float STEPS_SPEED = 1.75f;
|
||||
const float ZOOM_SPEED = 16.0f;
|
||||
const float CROUCH_ZOOM = 0.9f;
|
||||
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)
|
||||
: player(player),
|
||||
camera(player->camera),
|
||||
currentViewCamera(player->currentCamera),
|
||||
settings(settings),
|
||||
offset(0.0f, 0.7f, 0.0f) {
|
||||
: player(player),
|
||||
camera(player->camera),
|
||||
settings(settings),
|
||||
offset(0.0f, 0.7f, 0.0f) {
|
||||
}
|
||||
|
||||
void CameraControl::refresh() {
|
||||
@ -46,7 +49,10 @@ void CameraControl::refresh() {
|
||||
void CameraControl::updateMouse(PlayerInput& input) {
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) {
|
||||
Hitbox* hitbox = player->hitbox.get();
|
||||
glm::vec3 CameraControl::updateCameraShaking(float delta) {
|
||||
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);
|
||||
|
||||
if (settings.shaking && !input.cheat) {
|
||||
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);
|
||||
offset += updateCameraShaking(delta);
|
||||
}
|
||||
|
||||
if (settings.fovEvents){
|
||||
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);
|
||||
updateFovEffects(input, delta);
|
||||
}
|
||||
if (input.cameraMode) {
|
||||
switchCamera();
|
||||
}
|
||||
|
||||
auto spCamera = player->spCamera;
|
||||
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) {
|
||||
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->front = -camera->front;
|
||||
}
|
||||
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->front = camera->front;
|
||||
}
|
||||
@ -140,11 +173,62 @@ int PlayerController::selectedBlockStates = 0;
|
||||
PlayerController::PlayerController(
|
||||
Level* level,
|
||||
const EngineSettings& settings,
|
||||
BlocksController* blocksController)
|
||||
: level(level),
|
||||
player(level->getObject<Player>(0)),
|
||||
camControl(player, settings.camera),
|
||||
blocksController(blocksController) {
|
||||
BlocksController* blocksController
|
||||
) : level(level),
|
||||
player(level->getObject<Player>(0)),
|
||||
camControl(player, settings.camera),
|
||||
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) {
|
||||
@ -154,6 +238,7 @@ void PlayerController::update(float delta, bool input, bool pause) {
|
||||
} else {
|
||||
resetKeyboard();
|
||||
}
|
||||
updateFootsteps(delta);
|
||||
updateCamera(delta, input);
|
||||
updateControls(delta);
|
||||
|
||||
@ -289,12 +374,17 @@ void PlayerController::updateInteraction(){
|
||||
uint8_t states = determine_rotation(def, norm, camera->dir);
|
||||
|
||||
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))
|
||||
return;
|
||||
}
|
||||
|
||||
Block* target = indices->getBlockDef(vox->id);
|
||||
if (lclick && target->breakable){
|
||||
onBlockInteraction(
|
||||
glm::ivec3(x, y, z), target,
|
||||
BlockInteraction::destruction
|
||||
);
|
||||
blocksController->breakBlock(player.get(), target, x, y, z);
|
||||
}
|
||||
if (rclick && !input.shift) {
|
||||
@ -331,9 +421,14 @@ void PlayerController::updateInteraction(){
|
||||
chosenBlock = 0;
|
||||
}
|
||||
if (chosenBlock != vox->id && chosenBlock) {
|
||||
onBlockInteraction(
|
||||
glm::ivec3(x, y, z), def,
|
||||
BlockInteraction::placing
|
||||
);
|
||||
chunks->set(x, y, z, chosenBlock, states);
|
||||
lighting->onBlockSet(x,y,z, chosenBlock);
|
||||
if (def->rt.funcsset.onplaced) {
|
||||
// TODO: move scripting to interaction callbacks
|
||||
scripting::on_block_placed(player.get(), def, x, y, z);
|
||||
}
|
||||
blocksController->updateSides(x, y, z);
|
||||
@ -358,3 +453,7 @@ void PlayerController::updateInteraction(){
|
||||
Player* PlayerController::getPlayer() {
|
||||
return player.get();
|
||||
}
|
||||
|
||||
void PlayerController::listenBlockInteraction(on_block_interaction callback) {
|
||||
blockInteractionCallbacks.push_back(callback);
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#define PLAYER_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "../settings.h"
|
||||
@ -9,48 +11,87 @@
|
||||
|
||||
class Camera;
|
||||
class Level;
|
||||
class Block;
|
||||
class BlocksController;
|
||||
|
||||
class CameraControl {
|
||||
std::shared_ptr<Player> player;
|
||||
std::shared_ptr<Camera> camera, currentViewCamera;
|
||||
const CameraSettings& settings;
|
||||
glm::vec3 offset;
|
||||
float shake = 0.0f;
|
||||
float shakeTimer = 0.0f;
|
||||
glm::vec3 interpVel {0.0f};
|
||||
std::shared_ptr<Player> player;
|
||||
std::shared_ptr<Camera> camera;
|
||||
const CameraSettings& settings;
|
||||
glm::vec3 offset;
|
||||
float shake = 0.0f;
|
||||
float shakeTimer = 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:
|
||||
CameraControl(std::shared_ptr<Player> player, const CameraSettings& settings);
|
||||
void updateMouse(PlayerInput& input);
|
||||
void update(PlayerInput& input, float delta, Chunks* chunks);
|
||||
void refresh();
|
||||
CameraControl(std::shared_ptr<Player> player, const CameraSettings& settings);
|
||||
void updateMouse(PlayerInput& input);
|
||||
void update(PlayerInput& input, float delta, Chunks* chunks);
|
||||
void refresh();
|
||||
};
|
||||
|
||||
enum class BlockInteraction {
|
||||
step,
|
||||
destruction,
|
||||
placing
|
||||
};
|
||||
|
||||
using on_block_interaction = std::function<void(
|
||||
Player*, glm::ivec3, const Block*, BlockInteraction type
|
||||
)>;
|
||||
|
||||
class PlayerController {
|
||||
Level* level;
|
||||
std::shared_ptr<Player> player;
|
||||
PlayerInput input;
|
||||
CameraControl camControl;
|
||||
Level* level;
|
||||
std::shared_ptr<Player> player;
|
||||
PlayerInput input;
|
||||
CameraControl camControl;
|
||||
BlocksController* blocksController;
|
||||
|
||||
void updateKeyboard();
|
||||
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;
|
||||
std::vector<on_block_interaction> blockInteractionCallbacks;
|
||||
|
||||
PlayerController(Level* level,
|
||||
const EngineSettings& settings,
|
||||
BlocksController* blocksController);
|
||||
void update(float delta, bool input, bool pause);
|
||||
void updateKeyboard();
|
||||
void updateCamera(float delta, bool movement);
|
||||
void resetKeyboard();
|
||||
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();
|
||||
|
||||
void listenBlockInteraction(on_block_interaction callback);
|
||||
};
|
||||
|
||||
#endif /* PLAYER_CONTROL_H_ */
|
||||
|
||||
@ -19,14 +19,14 @@ const float CHEAT_SPEED_MUL = 5.0f;
|
||||
const float JUMP_FORCE = 8.0f;
|
||||
|
||||
Player::Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv) :
|
||||
speed(speed),
|
||||
chosenSlot(0),
|
||||
inventory(inv),
|
||||
camera(new Camera(position, glm::radians(90.0f))),
|
||||
spCamera(new Camera(position, glm::radians(90.0f))),
|
||||
tpCamera(new Camera(position, glm::radians(90.0f))),
|
||||
currentCamera(camera),
|
||||
hitbox(new Hitbox(position, glm::vec3(0.3f,0.9f,0.3f)))
|
||||
speed(speed),
|
||||
chosenSlot(0),
|
||||
inventory(inv),
|
||||
camera(std::make_shared<Camera>(position, glm::radians(90.0f))),
|
||||
spCamera(std::make_shared<Camera>(position, glm::radians(90.0f))),
|
||||
tpCamera(std::make_shared<Camera>(position, glm::radians(90.0f))),
|
||||
currentCamera(camera),
|
||||
hitbox(std::make_unique<Hitbox>(position, glm::vec3(0.3f,0.9f,0.3f)))
|
||||
{
|
||||
}
|
||||
|
||||
@ -34,116 +34,123 @@ Player::~Player() {
|
||||
}
|
||||
|
||||
void Player::updateInput(
|
||||
Level* level,
|
||||
PlayerInput& input,
|
||||
float delta) {
|
||||
bool crouch = input.shift && hitbox->grounded && !input.sprint;
|
||||
float speed = this->speed;
|
||||
if (flight){
|
||||
speed *= FLIGHT_SPEED_MUL;
|
||||
}
|
||||
if (input.cheat){
|
||||
speed *= CHEAT_SPEED_MUL;
|
||||
}
|
||||
Level* level,
|
||||
PlayerInput& input,
|
||||
float delta) {
|
||||
bool crouch = input.shift && hitbox->grounded && !input.sprint;
|
||||
float speed = this->speed;
|
||||
if (flight){
|
||||
speed *= FLIGHT_SPEED_MUL;
|
||||
}
|
||||
if (input.cheat){
|
||||
speed *= CHEAT_SPEED_MUL;
|
||||
}
|
||||
|
||||
if (crouch) {
|
||||
speed *= CROUCH_SPEED_MUL;
|
||||
} else if (input.sprint) {
|
||||
speed *= RUN_SPEED_MUL;
|
||||
}
|
||||
if (crouch) {
|
||||
speed *= CROUCH_SPEED_MUL;
|
||||
} else if (input.sprint) {
|
||||
speed *= RUN_SPEED_MUL;
|
||||
}
|
||||
|
||||
glm::vec3 dir(0,0,0);
|
||||
if (input.moveForward){
|
||||
dir.x += camera->dir.x;
|
||||
dir.z += camera->dir.z;
|
||||
}
|
||||
if (input.moveBack){
|
||||
dir.x -= camera->dir.x;
|
||||
dir.z -= camera->dir.z;
|
||||
}
|
||||
if (input.moveRight){
|
||||
dir.x += camera->right.x;
|
||||
dir.z += camera->right.z;
|
||||
}
|
||||
if (input.moveLeft){
|
||||
dir.x -= camera->right.x;
|
||||
dir.z -= camera->right.z;
|
||||
}
|
||||
if (glm::length(dir) > 0.0f){
|
||||
dir = glm::normalize(dir);
|
||||
hitbox->velocity.x += dir.x * speed * delta * 9;
|
||||
hitbox->velocity.z += dir.z * speed * delta * 9;
|
||||
}
|
||||
glm::vec3 dir(0,0,0);
|
||||
if (input.moveForward){
|
||||
dir.x += camera->dir.x;
|
||||
dir.z += camera->dir.z;
|
||||
}
|
||||
if (input.moveBack){
|
||||
dir.x -= camera->dir.x;
|
||||
dir.z -= camera->dir.z;
|
||||
}
|
||||
if (input.moveRight){
|
||||
dir.x += camera->right.x;
|
||||
dir.z += camera->right.z;
|
||||
}
|
||||
if (input.moveLeft){
|
||||
dir.x -= camera->right.x;
|
||||
dir.z -= camera->right.z;
|
||||
}
|
||||
if (glm::length(dir) > 0.0f){
|
||||
dir = glm::normalize(dir);
|
||||
hitbox->velocity.x += dir.x * speed * delta * 9;
|
||||
hitbox->velocity.z += dir.z * speed * delta * 9;
|
||||
}
|
||||
|
||||
float vel = std::max(glm::length(hitbox->velocity * 0.25f), 1.0f);
|
||||
int substeps = int(delta * vel * 1000);
|
||||
substeps = std::min(100, std::max(1, substeps));
|
||||
level->physics->step(level->chunks.get(), hitbox.get(),
|
||||
delta, substeps,
|
||||
crouch, flight ? 0.0f : 1.0f,
|
||||
!noclip);
|
||||
int substeps = int(delta * vel * 1000);
|
||||
substeps = std::min(100, std::max(1, substeps));
|
||||
level->physics->step(
|
||||
level->chunks.get(),
|
||||
hitbox.get(),
|
||||
delta,
|
||||
substeps,
|
||||
crouch,
|
||||
flight ? 0.0f : 1.0f,
|
||||
!noclip
|
||||
);
|
||||
|
||||
if (flight && hitbox->grounded) {
|
||||
flight = false;
|
||||
}
|
||||
if (flight && hitbox->grounded) {
|
||||
flight = false;
|
||||
}
|
||||
|
||||
if (input.jump && hitbox->grounded){
|
||||
hitbox->velocity.y = JUMP_FORCE;
|
||||
}
|
||||
if (input.jump && hitbox->grounded){
|
||||
hitbox->velocity.y = JUMP_FORCE;
|
||||
}
|
||||
|
||||
if ((input.flight && !noclip) ||
|
||||
(input.noclip && flight == noclip)){
|
||||
flight = !flight;
|
||||
if (flight){
|
||||
hitbox->grounded = false;
|
||||
}
|
||||
}
|
||||
if (input.noclip) {
|
||||
noclip = !noclip;
|
||||
}
|
||||
if ((input.flight && !noclip) ||
|
||||
(input.noclip && flight == noclip)){
|
||||
flight = !flight;
|
||||
if (flight){
|
||||
hitbox->grounded = false;
|
||||
}
|
||||
}
|
||||
if (input.noclip) {
|
||||
noclip = !noclip;
|
||||
}
|
||||
|
||||
hitbox->linear_damping = PLAYER_GROUND_DAMPING;
|
||||
if (flight){
|
||||
hitbox->linear_damping = PLAYER_AIR_DAMPING;
|
||||
hitbox->velocity.y *= 1.0f - delta * 9;
|
||||
if (input.jump){
|
||||
hitbox->velocity.y += speed * delta * 9;
|
||||
}
|
||||
if (input.shift){
|
||||
hitbox->velocity.y -= speed * delta * 9;
|
||||
}
|
||||
}
|
||||
if (!hitbox->grounded) {
|
||||
hitbox->linear_damping = PLAYER_AIR_DAMPING;
|
||||
}
|
||||
hitbox->linear_damping = PLAYER_GROUND_DAMPING;
|
||||
if (flight){
|
||||
hitbox->linear_damping = PLAYER_AIR_DAMPING;
|
||||
hitbox->velocity.y *= 1.0f - delta * 9;
|
||||
if (input.jump){
|
||||
hitbox->velocity.y += speed * delta * 9;
|
||||
}
|
||||
if (input.shift){
|
||||
hitbox->velocity.y -= speed * delta * 9;
|
||||
}
|
||||
}
|
||||
if (!hitbox->grounded) {
|
||||
hitbox->linear_damping = PLAYER_AIR_DAMPING;
|
||||
}
|
||||
|
||||
input.noclip = false;
|
||||
input.flight = false;
|
||||
input.noclip = false;
|
||||
input.flight = false;
|
||||
|
||||
if (spawnpoint.y <= 0.1) {
|
||||
attemptToFindSpawnpoint(level);
|
||||
}
|
||||
if (spawnpoint.y <= 0.1) {
|
||||
attemptToFindSpawnpoint(level);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::teleport(glm::vec3 position) {
|
||||
hitbox->position = position;
|
||||
hitbox->position = position;
|
||||
}
|
||||
|
||||
void Player::attemptToFindSpawnpoint(Level* level) {
|
||||
glm::vec3 ppos = hitbox->position;
|
||||
glm::vec3 newpos {ppos.x + (rand() % 200 - 100),
|
||||
rand() % 80 + 100,
|
||||
ppos.z + (rand() % 200 - 100)};
|
||||
while (newpos.y > 0 && !level->chunks->isObstacleBlock(newpos.x, newpos.y-2, newpos.z)) {
|
||||
newpos.y--;
|
||||
}
|
||||
glm::vec3 ppos = hitbox->position;
|
||||
glm::vec3 newpos (
|
||||
ppos.x + (rand() % 200 - 100),
|
||||
rand() % 80 + 100,
|
||||
ppos.z + (rand() % 200 - 100)
|
||||
);
|
||||
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);
|
||||
if (level->chunks->isObstacleBlock(newpos.x, newpos.y, newpos.z) ||
|
||||
headvox == nullptr || headvox->id != 0)
|
||||
return;
|
||||
spawnpoint = newpos + glm::vec3(0.5f, 0.0f, 0.5f);
|
||||
teleport(spawnpoint);
|
||||
voxel* headvox = level->chunks->get(newpos.x, newpos.y+1, newpos.z);
|
||||
if (level->chunks->isObstacleBlock(newpos.x, newpos.y, newpos.z) ||
|
||||
headvox == nullptr || headvox->id != 0)
|
||||
return;
|
||||
spawnpoint = newpos + glm::vec3(0.5f, 0.0f, 0.5f);
|
||||
teleport(spawnpoint);
|
||||
}
|
||||
|
||||
void Player::setChosenSlot(int index) {
|
||||
@ -155,7 +162,7 @@ int Player::getChosenSlot() const {
|
||||
}
|
||||
|
||||
float Player::getSpeed() const {
|
||||
return speed;
|
||||
return speed;
|
||||
}
|
||||
|
||||
std::shared_ptr<Inventory> Player::getInventory() const {
|
||||
@ -163,62 +170,62 @@ std::shared_ptr<Inventory> Player::getInventory() const {
|
||||
}
|
||||
|
||||
void Player::setSpawnPoint(glm::vec3 spawnpoint) {
|
||||
this->spawnpoint = spawnpoint;
|
||||
this->spawnpoint = spawnpoint;
|
||||
}
|
||||
|
||||
glm::vec3 Player::getSpawnPoint() const {
|
||||
return spawnpoint;
|
||||
return spawnpoint;
|
||||
}
|
||||
|
||||
std::unique_ptr<dynamic::Map> Player::serialize() const {
|
||||
glm::vec3 position = hitbox->position;
|
||||
auto root = std::make_unique<dynamic::Map>();
|
||||
auto& posarr = root->putList("position");
|
||||
posarr.put(position.x);
|
||||
posarr.put(position.y);
|
||||
posarr.put(position.z);
|
||||
glm::vec3 position = hitbox->position;
|
||||
auto root = std::make_unique<dynamic::Map>();
|
||||
auto& posarr = root->putList("position");
|
||||
posarr.put(position.x);
|
||||
posarr.put(position.y);
|
||||
posarr.put(position.z);
|
||||
|
||||
auto& rotarr = root->putList("rotation");
|
||||
rotarr.put(cam.x);
|
||||
rotarr.put(cam.y);
|
||||
auto& rotarr = root->putList("rotation");
|
||||
rotarr.put(cam.x);
|
||||
rotarr.put(cam.y);
|
||||
|
||||
auto& sparr = root->putList("spawnpoint");
|
||||
sparr.put(spawnpoint.x);
|
||||
sparr.put(spawnpoint.y);
|
||||
sparr.put(spawnpoint.z);
|
||||
auto& sparr = root->putList("spawnpoint");
|
||||
sparr.put(spawnpoint.x);
|
||||
sparr.put(spawnpoint.y);
|
||||
sparr.put(spawnpoint.z);
|
||||
|
||||
root->put("flight", flight);
|
||||
root->put("noclip", noclip);
|
||||
root->put("flight", flight);
|
||||
root->put("noclip", noclip);
|
||||
root->put("chosen-slot", chosenSlot);
|
||||
root->put("inventory", inventory->serialize().release());
|
||||
return root;
|
||||
}
|
||||
|
||||
void Player::deserialize(dynamic::Map *src) {
|
||||
auto posarr = src->list("position");
|
||||
glm::vec3& position = hitbox->position;
|
||||
position.x = posarr->num(0);
|
||||
position.y = posarr->num(1);
|
||||
position.z = posarr->num(2);
|
||||
camera->position = position;
|
||||
auto posarr = src->list("position");
|
||||
glm::vec3& position = hitbox->position;
|
||||
position.x = posarr->num(0);
|
||||
position.y = posarr->num(1);
|
||||
position.z = posarr->num(2);
|
||||
camera->position = position;
|
||||
|
||||
auto rotarr = src->list("rotation");
|
||||
cam.x = rotarr->num(0);
|
||||
cam.y = rotarr->num(1);
|
||||
auto rotarr = src->list("rotation");
|
||||
cam.x = rotarr->num(0);
|
||||
cam.y = rotarr->num(1);
|
||||
|
||||
if (src->has("spawnpoint")) {
|
||||
auto sparr = src->list("spawnpoint");
|
||||
setSpawnPoint(glm::vec3(
|
||||
sparr->num(0),
|
||||
sparr->num(1),
|
||||
sparr->num(2)
|
||||
));
|
||||
} else {
|
||||
setSpawnPoint(position);
|
||||
}
|
||||
if (src->has("spawnpoint")) {
|
||||
auto sparr = src->list("spawnpoint");
|
||||
setSpawnPoint(glm::vec3(
|
||||
sparr->num(0),
|
||||
sparr->num(1),
|
||||
sparr->num(2)
|
||||
));
|
||||
} else {
|
||||
setSpawnPoint(position);
|
||||
}
|
||||
|
||||
src->flag("flight", flight);
|
||||
src->flag("noclip", noclip);
|
||||
src->flag("flight", flight);
|
||||
src->flag("noclip", noclip);
|
||||
setChosenSlot(src->getInt("chosen-slot", getChosenSlot()));
|
||||
|
||||
auto invmap = src->map("inventory");
|
||||
|
||||
@ -2,10 +2,8 @@
|
||||
|
||||
#include "../core_defs.h"
|
||||
|
||||
using glm::vec3;
|
||||
|
||||
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);
|
||||
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 {
|
||||
vec3 X(axisX);
|
||||
vec3 Y(axisY);
|
||||
vec3 Z(axisZ);
|
||||
glm::vec3 X(axisX);
|
||||
glm::vec3 Y(axisY);
|
||||
glm::vec3 Z(axisZ);
|
||||
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.a += fix;
|
||||
|
||||
@ -18,8 +18,12 @@ inline constexpr uint FACE_PY = 3;
|
||||
inline constexpr uint FACE_MZ = 4;
|
||||
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 std::string DEFAULT_MATERIAL = "base:stone";
|
||||
|
||||
struct block_funcs_set {
|
||||
bool init: 1;
|
||||
bool update: 1;
|
||||
@ -35,7 +39,7 @@ struct CoordSystem {
|
||||
glm::ivec3 axisY;
|
||||
glm::ivec3 axisZ;
|
||||
|
||||
// Grid 3d position fix offset (for negative vectors)
|
||||
/// @brief Grid 3d position fix offset (for negative vectors)
|
||||
glm::ivec3 fix;
|
||||
|
||||
CoordSystem() = default;
|
||||
@ -43,11 +47,8 @@ struct CoordSystem {
|
||||
|
||||
void transform(AABB& aabb) const;
|
||||
|
||||
static bool isVectorHasNegatives(glm::ivec3 vec) {
|
||||
if (vec.x < 0 || vec.y < 0 || vec.z < 0) {
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
inline bool isVectorHasNegatives(glm::ivec3 vec) {
|
||||
return (vec.x < 0 || vec.y < 0 || vec.z < 0);
|
||||
}
|
||||
};
|
||||
|
||||
@ -56,56 +57,127 @@ struct BlockRotProfile {
|
||||
std::string name;
|
||||
CoordSystem variants[MAX_COUNT];
|
||||
|
||||
/* Wood logs, pillars, pipes */
|
||||
/// @brief Wood logs, pillars, pipes
|
||||
static const BlockRotProfile PIPE;
|
||||
/* Doors, signs and other panes */
|
||||
|
||||
/// @brief Doors, signs and other panes
|
||||
static const BlockRotProfile PANE;
|
||||
};
|
||||
|
||||
enum class BlockModel {
|
||||
none, // invisible
|
||||
block, // default shape
|
||||
xsprite, // X-shape (grass)
|
||||
aabb, // box shaped as block hitbox
|
||||
/// @brief invisible
|
||||
none,
|
||||
/// @brief default cube shape
|
||||
block,
|
||||
/// @brief X-shape (grass)
|
||||
xsprite,
|
||||
/// @brief box shape sized as block hitbox
|
||||
aabb,
|
||||
/// @brief custom model defined in json
|
||||
custom
|
||||
};
|
||||
|
||||
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 {
|
||||
public:
|
||||
/// @brief Block string id (with prefix included)
|
||||
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::vector<std::string> modelTextures = {};
|
||||
std::vector<BoxModel> modelBoxes = {};
|
||||
std::vector<glm::vec3> modelExtraPoints = {}; //initially made for tetragons
|
||||
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};
|
||||
|
||||
/// @brief Influences visible block sides for transparent blocks
|
||||
uint8_t drawGroup = 0;
|
||||
|
||||
/// @brief Block model type
|
||||
BlockModel model = BlockModel::block;
|
||||
|
||||
/// @brief Does the block passing lights into itself
|
||||
bool lightPassing = false;
|
||||
|
||||
/// @brief Does the block passing top-down sky lights into itself
|
||||
bool skyLightPassing = false;
|
||||
|
||||
/// @brief Is the block a physical obstacle
|
||||
bool obstacle = true;
|
||||
|
||||
/// @brief Can the block be selected
|
||||
bool selectable = true;
|
||||
|
||||
/// @brief Can the block be replaced with other.
|
||||
/// Examples of replaceable blocks: air, flower, water
|
||||
bool replaceable = false;
|
||||
|
||||
/// @brief Can player destroy the block
|
||||
bool breakable = true;
|
||||
|
||||
/// @brief Can the block be oriented different ways
|
||||
bool rotatable = false;
|
||||
|
||||
/// @brief Can the block exist without physical support be a solid block below
|
||||
bool grounded = false;
|
||||
|
||||
/// @brief Turns off block item generation
|
||||
bool hidden = false;
|
||||
|
||||
/// @brief Set of block physical hitboxes
|
||||
std::vector<AABB> hitboxes;
|
||||
|
||||
/// @brief Set of available block rotations (coord-systems)
|
||||
BlockRotProfile rotations;
|
||||
|
||||
/// @brief Item will be picked on MMB click on the block
|
||||
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;
|
||||
|
||||
/// @brief Block inventory size. 0 - no inventory
|
||||
uint inventorySize = 0;
|
||||
|
||||
/// @brief Runtime indices (content indexing results)
|
||||
struct {
|
||||
/// @brief block runtime integer id
|
||||
blockid_t id;
|
||||
|
||||
/// @brief is the block completely opaque for render and raycast
|
||||
bool solid = true;
|
||||
|
||||
/// @brief does the block emit any lights
|
||||
bool emissive = false;
|
||||
|
||||
/// @brief set of hitboxes sets with all coord-systems precalculated
|
||||
std::vector<AABB> hitboxes[BlockRotProfile::MAX_COUNT];
|
||||
|
||||
/// @brief set of block callbacks flags
|
||||
block_funcs_set funcsset {};
|
||||
|
||||
/// @brief picking item integer id
|
||||
itemid_t pickingItem = 0;
|
||||
} rt;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user