@@ -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"
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
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 |
@@ -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;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define AL_GET_ERROR() AL::check_errors(__FILE__, __LINE__)
|
||||
|
||||
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);
|
||||
|
||||
+36
-14
@@ -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,
|
||||
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),
|
||||
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)),
|
||||
drawGroups(std::move(drawGroups)) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
+18
-6
@@ -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,
|
||||
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, 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,
|
||||
bool fixPackIndices(
|
||||
fs::path folder,
|
||||
dynamic::Map* indicesRoot,
|
||||
std::string contentSection);
|
||||
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)) {
|
||||
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,
|
||||
/// @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);
|
||||
bool pause
|
||||
);
|
||||
|
||||
void onWorldSave();
|
||||
void onWorldQuit();
|
||||
|
||||
Level* getLevel();
|
||||
Player* getPlayer();
|
||||
|
||||
PlayerController* getPlayerController();
|
||||
};
|
||||
|
||||
#endif // LOGIC_LEVEL_CONTROLLER_H_
|
||||
|
||||
+121
-22
@@ -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;
|
||||
@@ -34,7 +38,6 @@ 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) {
|
||||
}
|
||||
@@ -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,12 +72,9 @@ 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();
|
||||
|
||||
offset = glm::vec3(0.0f, 0.7f, 0.0f);
|
||||
|
||||
if (settings.shaking && !input.cheat) {
|
||||
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;
|
||||
@@ -90,9 +93,11 @@ void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (settings.fovEvents){
|
||||
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);
|
||||
@@ -108,24 +113,52 @@ void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) {
|
||||
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) {
|
||||
offset += updateCameraShaking(delta);
|
||||
}
|
||||
if (settings.fovEvents){
|
||||
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),
|
||||
BlocksController* blocksController
|
||||
) : level(level),
|
||||
player(level->getObject<Player>(0)),
|
||||
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) {
|
||||
@@ -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,16 +11,30 @@
|
||||
|
||||
class Camera;
|
||||
class Level;
|
||||
class Block;
|
||||
class BlocksController;
|
||||
|
||||
class CameraControl {
|
||||
std::shared_ptr<Player> player;
|
||||
std::shared_ptr<Camera> camera, currentViewCamera;
|
||||
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);
|
||||
@@ -26,6 +42,16 @@ public:
|
||||
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;
|
||||
@@ -33,11 +59,22 @@ class PlayerController {
|
||||
CameraControl camControl;
|
||||
BlocksController* blocksController;
|
||||
|
||||
std::vector<on_block_interaction> blockInteractionCallbacks;
|
||||
|
||||
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;
|
||||
@@ -45,12 +82,16 @@ public:
|
||||
static int selectedBlockId;
|
||||
static int selectedBlockStates;
|
||||
|
||||
PlayerController(Level* level,
|
||||
PlayerController(
|
||||
Level* level,
|
||||
const EngineSettings& settings,
|
||||
BlocksController* blocksController);
|
||||
BlocksController* blocksController
|
||||
);
|
||||
void update(float delta, bool input, bool pause);
|
||||
|
||||
Player* getPlayer();
|
||||
|
||||
void listenBlockInteraction(on_block_interaction callback);
|
||||
};
|
||||
|
||||
#endif /* PLAYER_CONTROL_H_ */
|
||||
|
||||
+17
-10
@@ -22,11 +22,11 @@ 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))),
|
||||
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(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)))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -78,10 +78,15 @@ void Player::updateInput(
|
||||
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);
|
||||
level->physics->step(
|
||||
level->chunks.get(),
|
||||
hitbox.get(),
|
||||
delta,
|
||||
substeps,
|
||||
crouch,
|
||||
flight ? 0.0f : 1.0f,
|
||||
!noclip
|
||||
);
|
||||
|
||||
if (flight && hitbox->grounded) {
|
||||
flight = false;
|
||||
@@ -131,9 +136,11 @@ void Player::teleport(glm::vec3 position) {
|
||||
|
||||
void Player::attemptToFindSpawnpoint(Level* level) {
|
||||
glm::vec3 ppos = hitbox->position;
|
||||
glm::vec3 newpos {ppos.x + (rand() % 200 - 100),
|
||||
glm::vec3 newpos (
|
||||
ppos.x + (rand() % 200 - 100),
|
||||
rand() % 80 + 100,
|
||||
ppos.z + (rand() % 200 - 100)};
|
||||
ppos.z + (rand() % 200 - 100)
|
||||
);
|
||||
while (newpos.y > 0 && !level->chunks->isObstacleBlock(newpos.x, newpos.y-2, newpos.z)) {
|
||||
newpos.y--;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include "../core_defs.h"
|
||||
|
||||
using glm::vec3;
|
||||
|
||||
CoordSystem::CoordSystem(glm::ivec3 axisX, glm::ivec3 axisY, glm::ivec3 axisZ)
|
||||
: axisX(axisX), axisY(axisY), axisZ(axisZ)
|
||||
{
|
||||
@@ -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;
|
||||
|
||||
+85
-13
@@ -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;
|
||||
|
||||
/// @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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user