mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-07 03:51:50 +00:00
Merge branch 'main' into environments
This commit is contained in:
commit
a557068b90
54 changed files with 780 additions and 539 deletions
|
|
@ -711,7 +711,7 @@ std::unique_ptr<ALAudio> ALAudio::create(const AudioSettings& settings) {
|
|||
return nullptr;
|
||||
}
|
||||
bool effects = true;
|
||||
ALint attribs[4] {};
|
||||
[[maybe_unused]] ALint attribs[4] {};
|
||||
if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE) {
|
||||
logger.info() << "AL effects extension present";
|
||||
attribs[0] = ALC_MAX_AUXILIARY_SENDS;
|
||||
|
|
|
|||
|
|
@ -190,18 +190,34 @@ void audio::initialize(
|
|||
audio::get_channel(channel.name)->setVolume(value * value);
|
||||
}, true));
|
||||
}
|
||||
objects_keeper.keepAlive(settings.acousticEffects.observe([=](auto value) {
|
||||
objects_keeper.keepAlive(settings.acousticEffects.observe([=](bool value) {
|
||||
if (value) return;
|
||||
backend->setAcoustics(audio::Acoustics {});
|
||||
}, true));
|
||||
|
||||
if (inputEnabled) {
|
||||
::input_device = backend->openInputDevice("", 44100, 1, 16);
|
||||
::input_enabled = true;
|
||||
}
|
||||
if (::input_device) {
|
||||
::input_device->startCapture();
|
||||
}
|
||||
::input_enabled = inputEnabled;
|
||||
|
||||
objects_keeper.keepAlive(settings.recordingEnabled.observe([&settings](bool enabled) {
|
||||
if (!::input_enabled) {
|
||||
return;
|
||||
}
|
||||
if (!enabled && ::input_device == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (enabled) {
|
||||
logger.info() << "recording enabled; input device is "
|
||||
<< settings.inputDevice.get();
|
||||
::input_device = backend->openInputDevice(
|
||||
settings.inputDevice.get(), 44100, 1, 16
|
||||
);
|
||||
::input_device->startCapture();
|
||||
} else {
|
||||
if (::input_device) {
|
||||
::input_device->stopCapture();
|
||||
}
|
||||
::input_device = nullptr;
|
||||
}
|
||||
}, true));
|
||||
}
|
||||
|
||||
InputDevice* audio::get_input_device() {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ inline bool is_identifier_part(int c) {
|
|||
return is_identifier_start(c) || is_digit(c) || c == '-';
|
||||
}
|
||||
|
||||
inline bool is_minimal_identifier_part(int c) {
|
||||
return is_identifier_start(c) || is_digit(c);
|
||||
}
|
||||
|
||||
inline bool is_json_identifier_start(int c) {
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' ||
|
||||
c == '.';
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public:
|
|||
throw error("identifier expected");
|
||||
}
|
||||
int start = pos;
|
||||
while (hasNext() && is_identifier_part(source[pos])) {
|
||||
while (hasNext() && is_minimal_identifier_part(source[pos])) {
|
||||
pos++;
|
||||
}
|
||||
return std::wstring(source.substr(start, pos - start));
|
||||
|
|
|
|||
|
|
@ -55,12 +55,12 @@ model::Model VcmModel::squashed() const {
|
|||
}
|
||||
|
||||
static const std::unordered_map<std::string, int> side_indices {
|
||||
{"north", 0},
|
||||
{"south", 1},
|
||||
{"top", 2},
|
||||
{"bottom", 3},
|
||||
{"west", 4},
|
||||
{"east", 5},
|
||||
{"east", 0},
|
||||
{"west", 1},
|
||||
{"bottom", 2},
|
||||
{"top", 3},
|
||||
{"south", 4},
|
||||
{"north", 5},
|
||||
};
|
||||
|
||||
static bool to_boolean(const xml::Attribute& attr) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
|
||||
struct CoreParameters {
|
||||
bool headless = false;
|
||||
|
|
@ -13,4 +14,5 @@ struct CoreParameters {
|
|||
std::filesystem::path projectFolder;
|
||||
std::string debugServerString;
|
||||
int tps = 20;
|
||||
std::unordered_map<std::string, std::string> projectArgs;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ void Engine::initialize(CoreParameters coreParameters) {
|
|||
|
||||
keepAlive(settings.audio.inputDevice.observe([](auto name) {
|
||||
audio::set_input_device(name == "auto" ? "" : name);
|
||||
}, true));
|
||||
}));
|
||||
|
||||
project->loadProjectStartScript();
|
||||
if (!params.headless) {
|
||||
|
|
|
|||
|
|
@ -61,16 +61,19 @@ std::unique_ptr<UiDocument> UiDocument::read(
|
|||
const scriptenv& penv,
|
||||
const std::string& name,
|
||||
const io::path& file,
|
||||
const std::string& fileName
|
||||
const std::string& fileName,
|
||||
scriptenv&& env
|
||||
) {
|
||||
const std::string text = io::read_string(file);
|
||||
auto xmldoc = xml::parse(file.string(), text);
|
||||
|
||||
auto env = penv == nullptr
|
||||
? scripting::create_doc_environment(scripting::get_root_environment(), name)
|
||||
: scripting::create_doc_environment(penv, name);
|
||||
if (env == nullptr) {
|
||||
env = penv == nullptr
|
||||
? scripting::create_doc_environment(scripting::get_root_environment(), name)
|
||||
: scripting::create_doc_environment(penv, name);
|
||||
}
|
||||
|
||||
gui::UiXmlReader reader(gui, scriptenv(env));
|
||||
gui::UiXmlReader reader(gui, env);
|
||||
auto view = reader.readXML(file.string(), *xmldoc->getRoot());
|
||||
view->setId("root");
|
||||
UiDocScript script {};
|
||||
|
|
@ -82,9 +85,3 @@ std::unique_ptr<UiDocument> UiDocument::read(
|
|||
}
|
||||
return std::make_unique<UiDocument>(name, script, view, env);
|
||||
}
|
||||
|
||||
std::shared_ptr<gui::UINode> UiDocument::readElement(
|
||||
gui::GUI& gui, const io::path& file, const std::string& fileName
|
||||
) {
|
||||
return read(gui, nullptr, file.name(), file, fileName)->getRoot();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,9 +50,7 @@ public:
|
|||
const scriptenv& parent_env,
|
||||
const std::string& name,
|
||||
const io::path& file,
|
||||
const std::string& fileName
|
||||
);
|
||||
static std::shared_ptr<gui::UINode> readElement(
|
||||
gui::GUI&, const io::path& file, const std::string& fileName
|
||||
const std::string& fileName,
|
||||
scriptenv&& env = nullptr
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ void LevelScreen::update(float delta) {
|
|||
const Player& player = playerController->getPlayer();
|
||||
const Camera& camera = *player.currentCamera;
|
||||
decorator->update(paused ? 0.0f : delta, camera, weather);
|
||||
renderer->update(camera, delta * !hud->isPause());
|
||||
}
|
||||
|
||||
void LevelScreen::draw(float delta) {
|
||||
|
|
@ -271,7 +272,6 @@ void LevelScreen::draw(float delta) {
|
|||
if (!hud->isPause()) {
|
||||
scripting::on_entities_render(engine.getTime().getDelta());
|
||||
}
|
||||
renderer->update(camera, delta * !hud->isPause());
|
||||
renderer->renderFrame(ctx, camera, hudVisible, *postProcessing);
|
||||
if (!hud->isPause()) {
|
||||
scripting::on_frontend_render();
|
||||
|
|
|
|||
|
|
@ -136,18 +136,18 @@ void Mesh::addBox(
|
|||
const bool enabledSides[6],
|
||||
const glm::mat4& transform
|
||||
) {
|
||||
if (enabledSides[0]) // north
|
||||
addPlane(pos+Z*size, X*size, Y*size, Z, uvs[0], transform);
|
||||
if (enabledSides[1]) // south
|
||||
addPlane(pos-Z*size, -X*size, Y*size, -Z, uvs[1], transform);
|
||||
if (enabledSides[2]) // top
|
||||
addPlane(pos+Y*size, X*size, -Z*size, Y, uvs[2] * glm::vec2(-1), transform);
|
||||
if (enabledSides[3]) // bottom
|
||||
addPlane(pos-Y*size, X*size, Z*size, -Y, uvs[3] * glm::vec2(-1, 1), transform);
|
||||
if (enabledSides[4]) // west
|
||||
addPlane(pos+X*size, -Z*size, Y*size, X, uvs[4], transform);
|
||||
if (enabledSides[5]) // east
|
||||
addPlane(pos-X*size, Z*size, Y*size, -X, uvs[5] * glm::vec2(-1, 1), transform);
|
||||
if (enabledSides[0]) // east
|
||||
addPlane(pos-X*size, Z*size, Y*size, -X, uvs[0], transform);
|
||||
if (enabledSides[1]) // west
|
||||
addPlane(pos+X*size, -Z*size, Y*size, X, uvs[1] * glm::vec2(-1, 1), transform);
|
||||
if (enabledSides[2]) // bottom
|
||||
addPlane(pos-Y*size, X*size, Z*size, -Y, uvs[2], transform);
|
||||
if (enabledSides[3]) // top
|
||||
addPlane(pos+Y*size, X*size, -Z*size, Y, uvs[3] * glm::vec2(-1, 1), transform);
|
||||
if (enabledSides[4]) // south
|
||||
addPlane(pos-Z*size, -X*size, Y*size, -Z, uvs[4], transform);
|
||||
if (enabledSides[5]) // north
|
||||
addPlane(pos+Z*size, X*size, Y*size, Z, uvs[5] * glm::vec2(-1, 1), transform);
|
||||
}
|
||||
|
||||
void Mesh::scale(const glm::vec3& size) {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ Mesh<VertexStructure>::~Mesh() {
|
|||
MeshStats::meshesCount--;
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
for (int i = ibos.size() - 1; i >= 0; i--) {
|
||||
for (int i = 0; i < ibos.size(); i++) {
|
||||
glDeleteBuffers(1, &ibos[i].ibo);
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ void Mesh<VertexStructure>::reload(
|
|||
glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
for (int i = indices.size(); i < ibos.size(); i++) {
|
||||
for (int i = 0; i < ibos.size(); i++) {
|
||||
glDeleteBuffers(1, &ibos[i].ibo);
|
||||
}
|
||||
ibos.clear();
|
||||
|
|
|
|||
|
|
@ -271,8 +271,7 @@ void Decorator::updateBlockEmitters(const Camera& camera) {
|
|||
remove = true;
|
||||
}
|
||||
} else {
|
||||
iter = blockEmitters.erase(iter);
|
||||
continue;
|
||||
remove = true;
|
||||
}
|
||||
if (util::distance2(iter->first, glm::ivec3(camera.position)) >
|
||||
UPDATE_AREA_DIAMETER * UPDATE_AREA_DIAMETER) {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ static inline void update_particle(
|
|||
|
||||
void ParticlesRenderer::updateParticles(float delta) {
|
||||
std::vector<const Texture*> unusedTextures;
|
||||
visibleParticles = 0;
|
||||
|
||||
for (auto& [texture, vec] : particles) {
|
||||
if (vec.empty()) {
|
||||
|
|
@ -186,7 +187,6 @@ void ParticlesRenderer::update(const Camera& camera, float delta) {
|
|||
|
||||
void ParticlesRenderer::render(const Camera& camera) {
|
||||
aliveEmitters = emitters.size();
|
||||
visibleParticles = 0;
|
||||
|
||||
bool backlight = settings.backlight.get();
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ FullCheckBox::FullCheckBox(
|
|||
|
||||
add(checkbox);
|
||||
|
||||
auto& checkboxActions = actions;
|
||||
label->setMargin(glm::vec4(5.f, 5.f, 0.f, 0.f));
|
||||
label->listenAction(UIAction::CLICK, [&checkboxActions](auto& gui) {
|
||||
checkboxActions.notify(UIAction::CLICK, gui);
|
||||
});
|
||||
add(label);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,12 +83,12 @@ static util::TextureRegion determine_texture_region(
|
|||
const Assets& assets, const std::string& texture
|
||||
) {
|
||||
static std::array<std::string, 6> faces {
|
||||
"blocks:dbg_north",
|
||||
"blocks:dbg_south",
|
||||
"blocks:dbg_top",
|
||||
"blocks:dbg_bottom",
|
||||
"blocks:dbg_west",
|
||||
"blocks:dbg_east",
|
||||
"blocks:dbg_west",
|
||||
"blocks:dbg_bottom",
|
||||
"blocks:dbg_top",
|
||||
"blocks:dbg_south",
|
||||
"blocks:dbg_north",
|
||||
};
|
||||
|
||||
if (texture.length() < 2 || texture.at(0) != '$') {
|
||||
|
|
|
|||
|
|
@ -889,8 +889,8 @@ static std::shared_ptr<UINode> read_iframe(
|
|||
return iframe;
|
||||
}
|
||||
|
||||
UiXmlReader::UiXmlReader(gui::GUI& gui, scriptenv&& env)
|
||||
: gui(gui), env(std::move(env)) {
|
||||
UiXmlReader::UiXmlReader(gui::GUI& gui, const scriptenv& env)
|
||||
: gui(gui), env(env) {
|
||||
contextStack.emplace("");
|
||||
add("image", read_image);
|
||||
add("canvas", read_canvas);
|
||||
|
|
@ -922,8 +922,7 @@ void UiXmlReader::addIgnore(const std::string& tag) {
|
|||
ignored.insert(tag);
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element
|
||||
) {
|
||||
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element) {
|
||||
if (element.has("if")) {
|
||||
const auto& cond = element.attr("if").getText();
|
||||
if (cond.empty() || cond == "false" || cond == "nil") return nullptr;
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ namespace gui {
|
|||
std::unordered_set<std::string> ignored;
|
||||
std::stack<std::string> contextStack;
|
||||
std::string filename;
|
||||
scriptenv env;
|
||||
const scriptenv& env;
|
||||
public:
|
||||
UiXmlReader(gui::GUI& gui, scriptenv&& env);
|
||||
UiXmlReader(gui::GUI& gui, const scriptenv& env);
|
||||
|
||||
void add(const std::string& tag, uinode_reader reader);
|
||||
bool hasReader(const std::string& tag) const;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
|||
|
||||
builder.addSection("audio");
|
||||
builder.add("enabled", &settings.audio.enabled, false);
|
||||
builder.add("recording-enabled", &settings.audio.recordingEnabled);
|
||||
builder.add("volume-master", &settings.audio.volumeMaster);
|
||||
builder.add("volume-regular", &settings.audio.volumeRegular);
|
||||
builder.add("volume-ui", &settings.audio.volumeUI);
|
||||
|
|
@ -101,6 +102,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
|||
builder.addSection("system");
|
||||
builder.add("max-bg-asset-loaders", &settings.system.maxBgAssetLoaders);
|
||||
builder.add("preserve-assets-during-frame", &settings.system.preserveAssetsDuringFrame);
|
||||
builder.add("direct-scripting-data-access", &settings.system.directScriptingDataAccess);
|
||||
}
|
||||
|
||||
dv::value SettingsHandler::getValue(const std::string& name) const {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void LightSolver::remove(int x, int y, int z) {
|
|||
}
|
||||
|
||||
void LightSolver::solve(Chunk* prevailingChunk) {
|
||||
const int coords[] = {
|
||||
static const int coords[] = {
|
||||
0, 0, 1,
|
||||
0, 0,-1,
|
||||
0, 1, 0,
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@
|
|||
|
||||
static debug::Logger logger("lighting");
|
||||
|
||||
Lighting::Lighting(const Content& content, Chunks& chunks)
|
||||
: content(content), chunks(chunks) {
|
||||
auto& indices = *content.getIndices();
|
||||
Lighting::Lighting(const ContentIndices& indices, Chunks& chunks)
|
||||
: indices(indices), chunks(chunks) {
|
||||
solverR = std::make_unique<LightSolver>(indices, chunks, 0);
|
||||
solverG = std::make_unique<LightSolver>(indices, chunks, 1);
|
||||
solverB = std::make_unique<LightSolver>(indices, chunks, 2);
|
||||
|
|
@ -70,7 +69,7 @@ void Lighting::prebuildSkyLight(Chunk& chunk, const ContentIndices& indices) {
|
|||
}
|
||||
|
||||
void Lighting::buildSkyLight(int cx, int cz){
|
||||
const auto blockDefs = content.getIndices()->blocks.getDefs();
|
||||
const auto blockDefs = indices.blocks.getDefs();
|
||||
|
||||
Chunk* chunk = chunks.getChunk(cx, cz);
|
||||
if (chunk == nullptr) {
|
||||
|
|
@ -110,7 +109,7 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand) {
|
|||
auto& solverB = *this->solverB;
|
||||
auto& solverS = *this->solverS;
|
||||
|
||||
auto blockDefs = content.getIndices()->blocks.getDefs();
|
||||
auto blockDefs = indices.blocks.getDefs();
|
||||
auto chunk = chunks.getChunk(cx, cz);
|
||||
if (chunk == nullptr) {
|
||||
logger.error() << "attempted to build lights to chunk missing in local matrix";
|
||||
|
|
@ -174,69 +173,72 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand) {
|
|||
}
|
||||
|
||||
void Lighting::onBlockSet(int x, int y, int z, blockid_t id){
|
||||
const auto& block = content.getIndices()->blocks.require(id);
|
||||
solverR->remove(x,y,z);
|
||||
solverG->remove(x,y,z);
|
||||
solverB->remove(x,y,z);
|
||||
const auto& block = indices.blocks.require(id);
|
||||
|
||||
if (id == 0){
|
||||
auto chunk = chunks.getChunkByVoxel(glm::ivec3{x, y, z});
|
||||
solverR->solve(chunk);
|
||||
solverG->solve(chunk);
|
||||
solverB->solve(chunk);
|
||||
if (chunks.getLight(x,y+1,z, 3) == 0xF){
|
||||
for (int i = y; i >= 0; i--){
|
||||
voxel* vox = chunks.get(x,i,z);
|
||||
if ((vox == nullptr || vox->id != 0) && block.skyLightPassing)
|
||||
auto chunk = chunks.getChunkByVoxel(glm::ivec3{x, y, z});
|
||||
|
||||
if (block.skyLightPassing) {
|
||||
if (chunks.getLight(x, y + 1, z, 3) == 0xF) {
|
||||
for (int i = y; i >= 0; i--) {
|
||||
voxel* vox = chunks.get(x, i, z);
|
||||
if (vox == nullptr ||
|
||||
indices.blocks.require(vox->id).skyLightPassing ==
|
||||
false)
|
||||
break;
|
||||
solverS->add(x,i,z, 0xF);
|
||||
solverS->add(x, i, z, 0xF);
|
||||
}
|
||||
}
|
||||
const int coords[] = {
|
||||
0, 0, 1,
|
||||
0, 0,-1,
|
||||
0, 1, 0,
|
||||
0,-1, 0,
|
||||
1, 0, 0,
|
||||
-1, 0, 0
|
||||
};
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int lx = x + coords[i * 3];
|
||||
int ly = y + coords[i * 3 + 1];
|
||||
int lz = z + coords[i * 3 + 2];
|
||||
|
||||
solverR->add(lx, ly, lz);
|
||||
solverG->add(lx, ly, lz);
|
||||
solverB->add(lx, ly, lz);
|
||||
solverS->add(lx, ly, lz);
|
||||
solverR->solve(chunk);
|
||||
solverG->solve(chunk);
|
||||
solverB->solve(chunk);
|
||||
solverS->solve(chunk);
|
||||
}
|
||||
} else {
|
||||
auto chunk = chunks.getChunkByVoxel(glm::ivec3{x, y, z});
|
||||
if (!block.skyLightPassing){
|
||||
solverS->remove(x,y,z);
|
||||
for (int i = y-1; i >= 0; i--){
|
||||
solverS->remove(x,i,z);
|
||||
if (i == 0 || chunks.get(x,i-1,z)->id != 0){
|
||||
break;
|
||||
}
|
||||
solverS->remove(x, y, z);
|
||||
for (int i = y - 1; i >= 0; i--) {
|
||||
voxel* vox = chunks.get(x, i, z);
|
||||
if (vox == nullptr ||
|
||||
indices.blocks.require(vox->id).skyLightPassing == false) {
|
||||
break;
|
||||
}
|
||||
solverS->solve(chunk);
|
||||
}
|
||||
solverR->solve(chunk);
|
||||
solverG->solve(chunk);
|
||||
solverB->solve(chunk);
|
||||
|
||||
if (block.emission[0] || block.emission[1] || block.emission[2]){
|
||||
solverR->add(x,y,z,block.emission[0]);
|
||||
solverG->add(x,y,z,block.emission[1]);
|
||||
solverB->add(x,y,z,block.emission[2]);
|
||||
solverR->solve(chunk);
|
||||
solverG->solve(chunk);
|
||||
solverB->solve(chunk);
|
||||
solverS->remove(x, i, z);
|
||||
}
|
||||
solverS->solve();
|
||||
}
|
||||
|
||||
solverR->remove(x, y, z);
|
||||
solverG->remove(x, y, z);
|
||||
solverB->remove(x, y, z);
|
||||
|
||||
solverR->solve(chunk);
|
||||
solverG->solve(chunk);
|
||||
solverB->solve(chunk);
|
||||
|
||||
static const int coords[] = {
|
||||
0, 0, 1,
|
||||
0, 0,-1,
|
||||
0, 1, 0,
|
||||
0,-1, 0,
|
||||
1, 0, 0,
|
||||
-1, 0, 0
|
||||
};
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int lx = x + coords[i * 3];
|
||||
int ly = y + coords[i * 3 + 1];
|
||||
int lz = z + coords[i * 3 + 2];
|
||||
|
||||
solverR->add(lx, ly, lz);
|
||||
solverG->add(lx, ly, lz);
|
||||
solverB->add(lx, ly, lz);
|
||||
solverS->add(lx, ly, lz);
|
||||
}
|
||||
|
||||
if (block.emission[0]) {
|
||||
solverR->add(x, y, z, block.emission[0]);
|
||||
}
|
||||
if (block.emission[1]) {
|
||||
solverG->add(x, y, z, block.emission[1]);
|
||||
}
|
||||
if (block.emission[2]) {
|
||||
solverB->add(x, y, z, block.emission[2]);
|
||||
}
|
||||
solverR->solve(chunk);
|
||||
solverG->solve(chunk);
|
||||
solverB->solve(chunk);
|
||||
solverS->solve(chunk);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,20 @@
|
|||
|
||||
#include "typedefs.hpp"
|
||||
|
||||
class Content;
|
||||
class ContentIndices;
|
||||
class Chunk;
|
||||
class Chunks;
|
||||
class LightSolver;
|
||||
|
||||
class Lighting {
|
||||
const Content& content;
|
||||
const ContentIndices& indices;
|
||||
Chunks& chunks;
|
||||
std::unique_ptr<LightSolver> solverR;
|
||||
std::unique_ptr<LightSolver> solverG;
|
||||
std::unique_ptr<LightSolver> solverB;
|
||||
std::unique_ptr<LightSolver> solverS;
|
||||
public:
|
||||
Lighting(const Content& content, Chunks& chunks);
|
||||
Lighting(const ContentIndices& indices, Chunks& chunks);
|
||||
~Lighting();
|
||||
|
||||
void clear();
|
||||
|
|
|
|||
|
|
@ -392,8 +392,11 @@ void EngineController::reconfigPacks(
|
|||
auto& manager = contentControl.scan();
|
||||
reconfig_packs_inside(manager, names, packsToAdd, packsToRemove);
|
||||
|
||||
const auto& settings = engine.getSettings();
|
||||
auto& wfile = *world->wfile;
|
||||
wfile.removeIndices(packsToRemove);
|
||||
if (!settings.debug.generatorTestMode.get()) {
|
||||
wfile.removeIndices(packsToRemove);
|
||||
}
|
||||
wfile.writePacks(manager.getAll(names));
|
||||
reopenWorld(world);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include "content/Content.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "engine/EnginePaths.hpp"
|
||||
|
|
@ -41,7 +42,7 @@ LevelController::LevelController(
|
|||
|
||||
if (clientPlayer) {
|
||||
chunks->lighting = std::make_unique<Lighting>(
|
||||
level->content, *clientPlayer->chunks
|
||||
*level->content.getIndices(), *clientPlayer->chunks
|
||||
);
|
||||
}
|
||||
blocks = std::make_unique<BlocksController>(
|
||||
|
|
|
|||
|
|
@ -1116,28 +1116,34 @@ static int l_gui_load_document(lua::State* L) {
|
|||
auto args = lua::tovalue(L, 3);
|
||||
auto prefix = filename.entryPoint();
|
||||
|
||||
auto env = scripting::get_root_environment();
|
||||
auto parentEnv = scripting::get_root_environment();
|
||||
if (content) {
|
||||
if (auto runtime = content->getPackRuntime(prefix)) {
|
||||
env = runtime->getEnvironment();
|
||||
parentEnv = runtime->getEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
auto documentPtr = UiDocument::read(
|
||||
engine->getGUI(), std::move(env), alias, filename, filename.string()
|
||||
);
|
||||
auto document = documentPtr.get();
|
||||
engine->requireAssets().store(std::move(documentPtr), alias);
|
||||
|
||||
auto env = scripting::create_doc_environment(parentEnv, alias);
|
||||
// namespace extension
|
||||
if (lua::istable(L, 4)) {
|
||||
if (lua::get_from(L, "table", "merge")) {
|
||||
lua::pushenv(L, *document->getEnvironment());
|
||||
if (lua::get_from(L, "table", "extend")) {
|
||||
lua::pushenv(L, *env);
|
||||
lua::pushvalue(L, 4);
|
||||
lua::call(L, 2, 0);
|
||||
lua::pop(L);
|
||||
}
|
||||
}
|
||||
auto documentPtr = UiDocument::read(
|
||||
engine->getGUI(),
|
||||
nullptr,
|
||||
alias,
|
||||
filename,
|
||||
filename.string(),
|
||||
std::move(env)
|
||||
);
|
||||
auto document = documentPtr.get();
|
||||
engine->requireAssets().store(std::move(documentPtr), alias);
|
||||
|
||||
scripting::on_ui_open(document, {args});
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,11 +62,20 @@ static int l_utc_offset(lua::State* L) {
|
|||
return lua::pushnumber(L, offset);
|
||||
}
|
||||
|
||||
static auto start_time = std::chrono::steady_clock::now();
|
||||
|
||||
static int l_precise_time(lua::State* L) {
|
||||
auto time = std::chrono::steady_clock::now();
|
||||
std::chrono::duration<double> delta = time - start_time;
|
||||
return lua::pushnumber(L, delta.count());
|
||||
}
|
||||
|
||||
const luaL_Reg timelib[] = {
|
||||
{"uptime", lua::wrap<l_uptime>},
|
||||
{"delta", lua::wrap<l_delta>},
|
||||
{"utc_time", lua::wrap<l_utc_time>},
|
||||
{"utc_offset", lua::wrap<l_utc_offset>},
|
||||
{"local_time", lua::wrap<l_local_time>},
|
||||
{"precise_time", lua::wrap<l_precise_time>},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
#error LuaJIT required
|
||||
#endif
|
||||
|
||||
#ifndef LUA_TCDATA
|
||||
// unsafe, use for filtering only
|
||||
#define LUA_TCDATA 10
|
||||
#endif
|
||||
|
||||
namespace lua {
|
||||
class luaerror : public std::runtime_error {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -15,8 +15,12 @@
|
|||
#include "usertypes/lua_type_pcmstream.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
|
||||
static debug::Logger logger("lua-state");
|
||||
static lua::State* main_thread = nullptr;
|
||||
namespace {
|
||||
debug::Logger logger("lua-state");
|
||||
lua::State* main_thread = nullptr;
|
||||
bool headless_mode = false;
|
||||
const std::unordered_map<std::string, std::string>* project_args;
|
||||
}
|
||||
|
||||
using namespace lua;
|
||||
|
||||
|
|
@ -146,20 +150,53 @@ void lua::init_state(State* L, StateType stateType) {
|
|||
newusertype<LuaHeightmap>(L);
|
||||
newusertype<LuaVoxelFragment>(L);
|
||||
newusertype<LuaCanvas>(L);
|
||||
|
||||
pushboolean(L, headless_mode);
|
||||
setglobal(L, "__VC_HEADLESS");
|
||||
|
||||
createtable(L, 0, project_args->size());
|
||||
for (const auto& [key, value] : *project_args) {
|
||||
pushstring(L, value);
|
||||
setfield(L, key);
|
||||
}
|
||||
setglobal(L, "__VC_PROJECT_ARGS");
|
||||
|
||||
auto file = "res:scripts/stdmin.lua";
|
||||
auto src = io::read_string(file);
|
||||
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
|
||||
|
||||
newusertype<LuaRandom>(L);
|
||||
if (getglobal(L, "random")) {
|
||||
if (getglobal(L, "__vc_Random")) {
|
||||
setfield(L, "Random");
|
||||
}
|
||||
pop(L);
|
||||
}
|
||||
newusertype<LuaPCMStream>(L);
|
||||
if (getglobal(L, "audio")) {
|
||||
if (getglobal(L, "__vc_PCMStream")) {
|
||||
setfield(L, "PCMStream");
|
||||
}
|
||||
pop(L);
|
||||
}
|
||||
|
||||
if (stateType == StateType::GENERATOR) {
|
||||
pushnil(L);
|
||||
setglobal(L, "ffi");
|
||||
}
|
||||
}
|
||||
|
||||
void lua::initialize(const EnginePaths& paths, const CoreParameters& params) {
|
||||
logger.info() << LUA_VERSION;
|
||||
logger.info() << LUAJIT_VERSION;
|
||||
|
||||
headless_mode = params.headless;
|
||||
project_args = ¶ms.projectArgs;
|
||||
main_thread = create_state(
|
||||
paths, params.headless ? StateType::SCRIPT : StateType::BASE
|
||||
);
|
||||
lua::pushstring(main_thread, params.scriptFile.stem().u8string());
|
||||
lua::setglobal(main_thread, "__VC_SCRIPT_NAME");
|
||||
|
||||
lua::pushboolean(main_thread, params.headless);
|
||||
lua::setglobal(main_thread, "__VC_HEADLESS");
|
||||
}
|
||||
|
||||
void lua::finalize() {
|
||||
|
|
@ -191,29 +228,5 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) {
|
|||
throw luaerror("could not initialize Lua state");
|
||||
}
|
||||
init_state(L, stateType);
|
||||
|
||||
auto file = "res:scripts/stdmin.lua";
|
||||
auto src = io::read_string(file);
|
||||
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
|
||||
|
||||
newusertype<LuaRandom>(L);
|
||||
if (getglobal(L, "random")) {
|
||||
if (getglobal(L, "__vc_Random")) {
|
||||
setfield(L, "Random");
|
||||
}
|
||||
pop(L);
|
||||
}
|
||||
newusertype<LuaPCMStream>(L);
|
||||
if (getglobal(L, "audio")) {
|
||||
if (getglobal(L, "__vc_PCMStream")) {
|
||||
setfield(L, "PCMStream");
|
||||
}
|
||||
pop(L);
|
||||
}
|
||||
|
||||
if (stateType == StateType::GENERATOR) {
|
||||
pushnil(L);
|
||||
setglobal(L, "ffi");
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "util/stringutil.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
|
||||
using namespace lua;
|
||||
|
||||
|
|
@ -12,6 +14,8 @@ static int next_environment = 1;
|
|||
|
||||
std::unordered_map<std::type_index, std::string> lua::usertypeNames;
|
||||
|
||||
static debug::Logger logger("lua-util");
|
||||
|
||||
int lua::userdata_destructor(lua::State* L) {
|
||||
if (auto obj = touserdata<Userdata>(L, 1)) {
|
||||
obj->~Userdata();
|
||||
|
|
@ -76,6 +80,10 @@ int lua::pushwstring(State* L, const std::wstring& str) {
|
|||
return pushstring(L, util::wstr2str_utf8(str));
|
||||
}
|
||||
|
||||
static std::string to_ptr_string(State* L, int idx) {
|
||||
return std::to_string(reinterpret_cast<ptrdiff_t>(lua_topointer(L, idx)));
|
||||
}
|
||||
|
||||
dv::value lua::tovalue(State* L, int idx) {
|
||||
using dv::value_type;
|
||||
auto type = lua::type(L, idx);
|
||||
|
|
@ -95,11 +103,16 @@ dv::value lua::tovalue(State* L, int idx) {
|
|||
}
|
||||
}
|
||||
case LUA_TFUNCTION:
|
||||
return "<function " +
|
||||
std::to_string(
|
||||
reinterpret_cast<ptrdiff_t>(lua_topointer(L, idx))
|
||||
) +
|
||||
">";
|
||||
return "<function " + to_ptr_string(L, idx) + ">";
|
||||
case LUA_TTHREAD:
|
||||
return "<thread " + to_ptr_string(L, idx) + ">";
|
||||
case LUA_TUSERDATA:
|
||||
if (auto userdata = touserdata<Userdata>(L, idx)) {
|
||||
return "<userdata:" + userdata->getTypeName() + " " + to_ptr_string(L, idx) + ">";
|
||||
}
|
||||
return "<userdata " + to_ptr_string(L, idx) + ">";
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
return "<lightuserdata " + to_ptr_string(L, idx) + ">";
|
||||
case LUA_TSTRING:
|
||||
return std::string(tostring(L, idx));
|
||||
case LUA_TTABLE: {
|
||||
|
|
@ -369,3 +382,55 @@ void lua::remove_environment(State* L, int id) {
|
|||
pushnil(L);
|
||||
store_env(L, id);
|
||||
}
|
||||
|
||||
static inline std::string_view bytearray_as_string_indirect(lua::State* L, int idx) {
|
||||
requireglobal(L, "Bytearray_as_string");
|
||||
pushvalue(L, -2);
|
||||
call(L, 1, 1);
|
||||
auto view = tolstring(L, -1);
|
||||
pop(L, 2);
|
||||
return view;
|
||||
}
|
||||
|
||||
std::string_view lua::bytearray_as_string(lua::State* L, int idx) {
|
||||
const auto& settings = scripting::engine->getSettings();
|
||||
|
||||
int luaType = type(L, idx);
|
||||
if (luaType == LUA_TSTRING) {
|
||||
return tolstring(L, idx);
|
||||
} else if (luaType == LUA_TTABLE) {
|
||||
return bytearray_as_string_indirect(L, idx);
|
||||
}
|
||||
pushvalue(L, idx);
|
||||
|
||||
if (settings.system.directScriptingDataAccess.get()) {
|
||||
requireglobal(L, "Bytearray_as_ptr");
|
||||
pushvalue(L, -2);
|
||||
call(L, 1, 2);
|
||||
auto view = tolstring(L, -2);
|
||||
if (view == "0") {
|
||||
if (luaType == LUA_TCDATA) {
|
||||
logger.error() << "FFI-based Bytearray_as_ptr returned null-pointer";
|
||||
}
|
||||
pop(L, 2);
|
||||
return bytearray_as_string_indirect(L, idx);
|
||||
}
|
||||
uint64_t size = touinteger(L, -1);
|
||||
auto ptr = (const char*)std::stoull(std::string(view), nullptr, 16);
|
||||
pop(L, 3);
|
||||
return std::string_view(ptr, size);
|
||||
} else {
|
||||
return bytearray_as_string_indirect(L, idx);
|
||||
}
|
||||
}
|
||||
|
||||
void lua::loadbuffer(
|
||||
lua::State* L, int env, const std::string& src, const std::string& file
|
||||
) {
|
||||
if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) {
|
||||
throw luaerror(tostring(L, -1));
|
||||
}
|
||||
if (env && getregistry(L, ENVS_TABLE, env_name(env))) {
|
||||
lua_setfenv(L, -2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -555,16 +555,9 @@ namespace lua {
|
|||
return lua_setfenv(L, idx);
|
||||
}
|
||||
|
||||
inline void loadbuffer(
|
||||
void loadbuffer(
|
||||
lua::State* L, int env, const std::string& src, const std::string& file
|
||||
) {
|
||||
if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) {
|
||||
throw luaerror(tostring(L, -1));
|
||||
}
|
||||
if (env && getregistry(L, ENVS_TABLE, env_name(env))) {
|
||||
lua_setfenv(L, -2);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
inline void store_in(
|
||||
lua::State* L, const std::string& tableName, const std::string& name
|
||||
|
|
@ -828,16 +821,5 @@ namespace lua {
|
|||
return create_bytearray(L, bytes.data(), bytes.size());
|
||||
}
|
||||
|
||||
inline std::string_view bytearray_as_string(lua::State* L, int idx) {
|
||||
if (type(L, idx) == LUA_TSTRING) {
|
||||
return tolstring(L, idx);
|
||||
}
|
||||
pushvalue(L, idx);
|
||||
requireglobal(L, "Bytearray_as_string");
|
||||
pushvalue(L, -2);
|
||||
call(L, 1, 1);
|
||||
auto view = tolstring(L, -1);
|
||||
pop(L, 2);
|
||||
return view;
|
||||
}
|
||||
std::string_view bytearray_as_string(lua::State* L, int idx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ std::unique_ptr<IClientProjectScript> scripting::load_client_project_script(
|
|||
auto source = io::read_string(script);
|
||||
auto env = create_environment(nullptr);
|
||||
lua::pushenv(L, *env);
|
||||
if (lua::getglobal(L, "__vc_app")) {
|
||||
if (lua::getregistry(L, "app")) {
|
||||
lua::setfield(L, "app");
|
||||
}
|
||||
lua::pop(L);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
struct AudioSettings {
|
||||
/// @brief try to initialize AL backend
|
||||
FlagSetting enabled {true};
|
||||
FlagSetting recordingEnabled {false};
|
||||
|
||||
NumberSetting volumeMaster {1.0f, 0.0f, 1.0f, setting_format::percent};
|
||||
NumberSetting volumeRegular {1.0f, 0.0f, 1.0f, setting_format::percent};
|
||||
|
|
@ -126,6 +127,8 @@ struct SystemSettings {
|
|||
IntegerSetting maxBgAssetLoaders {3, -4, 16};
|
||||
/// @brief Preserve assets during current frame from being destroyed
|
||||
FlagSetting preserveAssetsDuringFrame {true};
|
||||
/// @brief Allow luajit cdata objects direct data access optimizations
|
||||
FlagSetting directScriptingDataAccess {true};
|
||||
};
|
||||
|
||||
struct EngineSettings {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ namespace util {
|
|||
return last[0] == '-';
|
||||
}
|
||||
|
||||
bool isNextKeywordArg() const {
|
||||
if (pos >= argc) {
|
||||
throw std::runtime_error("unexpected end");
|
||||
}
|
||||
return argv[pos][0] == '-';
|
||||
}
|
||||
|
||||
std::string next() {
|
||||
if (pos >= argc) {
|
||||
throw std::runtime_error("unexpected end");
|
||||
|
|
|
|||
|
|
@ -97,11 +97,32 @@ static bool perform_keyword(
|
|||
throw std::runtime_error("unknown argument " + keyword);
|
||||
}
|
||||
|
||||
static void parse_project_args(util::ArgsReader& reader, CoreParameters& params) {
|
||||
while (reader.hasNext()) {
|
||||
std::string key = reader.next();
|
||||
if (!reader.isKeywordArg()) {
|
||||
std::cerr << "--<keyword> argument expected" << std::endl;
|
||||
return;
|
||||
}
|
||||
key = key.substr(2);
|
||||
if (!reader.hasNext() || reader.isNextKeywordArg()) {
|
||||
params.projectArgs[std::move(key)] = "";
|
||||
continue;
|
||||
}
|
||||
std::string value = reader.next();
|
||||
params.projectArgs[std::move(key)] = std::move(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool parse_cmdline(int argc, char** argv, CoreParameters& params) {
|
||||
util::ArgsReader reader(argc, argv);
|
||||
reader.skip();
|
||||
while (reader.hasNext()) {
|
||||
std::string token = reader.next();
|
||||
if (token == "--") {
|
||||
parse_project_args(reader, params);
|
||||
return true;
|
||||
}
|
||||
if (reader.isKeywordArg()) {
|
||||
if (!perform_keyword(reader, token, params)) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <random>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace util {
|
||||
template <
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue