diff --git a/assets/base/script/modules/string.lua b/assets/base/script/modules/string.lua index 3a634c16..6b7c924e 100644 --- a/assets/base/script/modules/string.lua +++ b/assets/base/script/modules/string.lua @@ -15,4 +15,16 @@ string.split = function(input, sep, op) for str in string.gmatch(input, '([^'..sep..']+)') do table.insert(t, op and op(str) or str) end return t +end + +-- string.escape +-- Escapes a string, replacing all graves with grave literals. +string.escape = function(str) + return str:gsub('%`', '``') +end + +-- string.starts_with +-- Checks if a string starts with the specified substring. +string.starts_with = function(str, substr) + return str:sub(1, substr:len()) == substr end \ No newline at end of file diff --git a/assets/base/script/modules/vector.lua b/assets/base/script/modules/vector.lua index 9eea73a9..9c162a03 100644 --- a/assets/base/script/modules/vector.lua +++ b/assets/base/script/modules/vector.lua @@ -50,7 +50,7 @@ vector.__unm = vector.negative -- vector.subtract -- Subtract v2 from v1 function vector.subtract(v1, v2) - return vector.add(v1, vector.negative(v2)) + return vector.add(v1, -v2) end vector.__sub = vector.subtract @@ -59,11 +59,8 @@ vector.__sub = vector.subtract -- Multiply v1 by a vector or number function vector.multiply(v1, m) assert(vector.is_vector(v1)) - if vector.is_vector(m) then - return create_vector(rawget(v1, 1) * rawget(m, 1), rawget(v1, 2) * rawget(m, 2), rawget(v1, 3) * rawget(m, 3)) - elseif type(m) == "number" then - return create_vector(rawget(v1, 1) * m, rawget(v1, 2) * m, rawget(v1, 3) * m) - end + if vector.is_vector(m) then return create_vector(rawget(v1, 1) * rawget(m, 1), rawget(v1, 2) * rawget(m, 2), rawget(v1, 3) * rawget(m, 3)) + elseif type(m) == "number" then return create_vector(rawget(v1, 1) * m, rawget(v1, 2) * m, rawget(v1, 3) * m) end end vector.__mul = vector.multiply @@ -176,10 +173,10 @@ end function vector:__tostring() return table.concat({ - "{ ", + "{", tostring(rawget(self, 1)), ", ", tostring(rawget(self, 2)), ", ", - tostring(rawget(self, 3)), " }" + tostring(rawget(self, 3)), "}" }) end @@ -202,7 +199,7 @@ vector.new = function(x, y, z) -- Invalid type passed to function, return nil elseif type(x) ~= "number" and type(x) ~= "table" then return nil -- Passed a table as x with at least x and y parameters, z will be set to table value or 0 - elseif type(x) == "table" and (x.__is_vector or (type(x[1]) == "number" and type(x[2]) == "number")) then return create_vector(x[1], x[2], x[3] or 0) + elseif type(x) == "table" and (vector.is_vector(x) or (type(x[1]) == "number" and type(x[2]) == "number")) then return create_vector(x[1], x[2], x[3] or 0) -- Only one number was passed, give a vector with all three values set to it elseif y == nil then return create_vector(x, x, x) -- Invalid type passed to function, return nil diff --git a/assets/shader/world/entity.fs b/assets/shader/world/entity.fs index d4f75275..13d13afe 100644 --- a/assets/shader/world/entity.fs +++ b/assets/shader/world/entity.fs @@ -15,11 +15,11 @@ uniform sampler2D tex; void main() { if (useTex > 0.5) { vec4 spec = texture(tex, colorData.xy) * vec4(colorBlend, colorData.w); - if (spec.a < 0.1) discard; + if (spec.a < 0.01) discard; gSpecular = spec; } else { - if (colorData.a < 0.1) discard; + if (colorData.a < 0.01) discard; gSpecular = colorData * vec4(colorBlend, 1); } gPosition = vec4(fragPos, 1); diff --git a/assets/textures/ui/font.png b/assets/textures/ui/font.png index ca0ad9fb..870e4b5b 100644 Binary files a/assets/textures/ui/font.png and b/assets/textures/ui/font.png differ diff --git a/assets/textures/ui/font.xcf b/assets/textures/ui/font.xcf index 111791bf..90477bda 100644 Binary files a/assets/textures/ui/font.xcf and b/assets/textures/ui/font.xcf differ diff --git a/src/client/entity/WireframeEntity.cpp b/src/client/entity/WireframeEntity.cpp index c485cc11..a142986d 100644 --- a/src/client/entity/WireframeEntity.cpp +++ b/src/client/entity/WireframeEntity.cpp @@ -1,79 +1,114 @@ -// -// Created by aurailus on 08/04/19. -// - #include "WireframeEntity.h" -#include "world/dim/ent/DrawableEntity.h" - void WireframeEntity::updateMesh(const std::vector& boxes, float width) { - this->width = width; - buildMesh(boxes); + this->model->fromMesh(WireframeEntity::createMesh(boxes, width)); } - -void WireframeEntity::buildMesh(const std::vector& boxes) { - indOffset = 0; +uptr WireframeEntity::createMesh(const vec& boxes, f32 wireWidth, vec3 stroke, vec4 fill) { + vec indices {}; + indices.reserve(boxes.size() * 36 * (12 + fill.a ? 1 : 0)); + vec vertices {}; + vertices.reserve(boxes.size() * 8 * 12 + (fill.a ? 24 : 0)); - vertices.clear(); - indices.clear(); + for (const let& box : boxes) WireframeEntity::createSelectionBoxVertices( + box, wireWidth, vec4(stroke, 1), fill, vertices, indices); - for (auto& box : boxes) { - glm::vec3 a = box.a; - glm::vec3 b = box.b - box.a; - - createBox(a, b, 0, 0, 0, 0, b.y, 0); - createBox(a, b, b.x, 0, 0, 0, b.y, 0); - createBox(a, b, b.x, 0, b.z, 0, b.y, 0); - createBox(a, b, 0, 0, b.z, 0, b.y, 0); - - createBox(a, b, 0, 0, 0, b.x, 0, 0); - createBox(a, b, 0, b.y, 0, b.x, 0, 0); - createBox(a, b, 0, b.y, b.z, b.x, 0, 0); - createBox(a, b, 0, 0, b.z, b.x, 0, 0); - - createBox(a, b, 0, 0, 0, 0, 0, b.z); - createBox(a, b, 0, b.y, 0, 0, 0, b.z); - createBox(a, b, b.x, b.y, 0, 0, 0, b.z); - createBox(a, b, b.x, 0, 0, 0, 0, b.z); - } - - - std::unique_ptr mesh = std::make_unique(); + uptr mesh = make_unique(); mesh->create(vertices, indices); - this->model->fromMesh(std::move(mesh)); + return mesh; } -void -WireframeEntity::createBox(glm::vec3 a, glm::vec3 b, float x, float y, float z, float xSize, float ySize, float zSize) { - float hw = (width / 2.0f); - float w = width; - glm::vec3 c = color; +uptr WireframeEntity::createMesh(const SelectionBox& box, f32 wireWidth, vec3 stroke, vec4 fill) { + return WireframeEntity::createMesh(vec { box }, wireWidth, stroke, fill); +} + +void WireframeEntity::createSelectionBoxVertices(const SelectionBox& box, f32 wireWidth, + vec4 stroke, vec4 fill, vec& vertices, vec& indices) { - std::vector myVerts{ - /*0*/ - {{ x - hw + a.x, y - hw + a.y, z - hw + a.z }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false, { 0, 1, 0 }, {}, {}}, - /*1*/{{ x - hw + a.x + xSize + w, y - hw + a.y, z - hw + a.z }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false, - { 0, 1, 0 }, {}, {}}, - /*2*/ - {{ x - hw + a.x + xSize + w, y - hw + a.y, z - hw + a.z + zSize + w }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false, - { 0, 1, 0 }, {}, {}}, - /*3*/{{ x - hw + a.x, y - hw + a.y, z - hw + a.z + zSize + w }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false, - { 0, 1, 0 }, {}, {}}, + let& a = box.a; + let& b = box.b; + + createStrokeVertices({ a.x, a.y, a.z }, { b.x, a.y, a.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ a.x, a.y, b.z }, { b.x, a.y, b.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ a.x, a.y, a.z }, { a.x, a.y, b.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ b.x, a.y, a.z }, { b.x, a.y, b.z }, wireWidth, stroke, vertices, indices); + + createStrokeVertices({ a.x, b.y, a.z }, { b.x, b.y, a.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ a.x, b.y, b.z }, { b.x, b.y, b.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ a.x, b.y, a.z }, { a.x, b.y, b.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ b.x, b.y, a.z }, { b.x, b.y, b.z }, wireWidth, stroke, vertices, indices); + + createStrokeVertices({ a.x, a.y, a.z }, { a.x, b.y, a.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ b.x, a.y, a.z }, { b.x, b.y, a.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ b.x, a.y, b.z }, { b.x, b.y, b.z }, wireWidth, stroke, vertices, indices); + createStrokeVertices({ a.x, a.y, b.z }, { a.x, b.y, b.z }, wireWidth, stroke, vertices, indices); + + if (fill.a) { + vec3 nml = { 0, 1, 0 }; + f32 off = wireWidth / 2; + usize indOffset = vertices.size(); - /*4*/{{ x - hw + a.x, y - hw + a.y + ySize + w, z - hw + a.z }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false, - { 0, 1, 0 }, {}, {}}, - /*5*/ - {{ x - hw + a.x + xSize + w, y - hw + a.y + ySize + w, z - hw + a.z }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false, - { 0, 1, 0 }, {}, {}}, - /*6*/{{ x - hw + a.x + xSize + w, y - hw + a.y + ySize + w, z - hw + a.z + zSize + w }, { c.x, c.y, c.z, 1 }, - { 1, 1, 1 }, false, { 0, 1, 0 }, {}, {}}, - /*7*/ - {{ x - hw + a.x, y - hw + a.y + ySize + w, z - hw + a.z + zSize + w }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false, - { 0, 1, 0 }, {}, {}}, - }; + vertices.push_back({{ a.x, a.y, a.z - off }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x, b.y, a.z - off }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x, b.y, a.z - off }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x, a.y, a.z - off }, fill, vec3(1), false, nml, {}, {}}); + + vertices.push_back({{ a.x, a.y, b.z + off }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x, b.y, b.z + off }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x, b.y, b.z + off }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x, a.y, b.z + off }, fill, vec3(1), false, nml, {}, {}}); + + vertices.push_back({{ a.x - off, a.y, a.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x - off, b.y, a.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x - off, b.y, b.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x - off, a.y, b.z }, fill, vec3(1), false, nml, {}, {}}); + + vertices.push_back({{ b.x + off, a.y, a.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x + off, b.y, a.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x + off, b.y, b.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x + off, a.y, b.z }, fill, vec3(1), false, nml, {}, {}}); + + vertices.push_back({{ a.x, a.x - off, a.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x, a.x - off, a.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x, a.x - off, b.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x, a.x - off, b.z }, fill, vec3(1), false, nml, {}, {}}); + + vertices.push_back({{ a.x, b.y + off, a.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x, b.y + off, a.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x, b.y + off, b.z }, fill, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x, b.y + off, b.z }, fill, vec3(1), false, nml, {}, {}}); + + const static array boxIndices { + 0, 1, 2, 2, 3, 0, + 4, 7, 6, 6, 5, 4, + 8, 11, 10, 10, 9, 8, + 12, 13, 14, 14, 15, 12, + 16, 17, 18, 18, 19, 16, + 20, 23, 22, 22, 21, 20 + }; + + for (u32 i : boxIndices) indices.push_back(i + indOffset); + } +} + +void WireframeEntity::createStrokeVertices(vec3 a, vec3 b, f32 wireWidth, + vec4 color, vec& vertices, vec& indices) { - std::vector myInds{ + f32 off = wireWidth / 2.f; + vec3 nml = { 0, 1, 0 }; + usize indOffset = vertices.size(); + + vertices.push_back({{ a.x - off, a.y - off, a.z - off }, color, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x + off, a.y - off, a.z - off }, color, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x + off, a.y - off, b.z + off }, color, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x - off, a.y - off, b.z + off }, color, vec3(1), false, nml, {}, {}}); + + vertices.push_back({{ a.x - off, b.y + off, a.z - off }, color, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x + off, b.y + off, a.z - off }, color, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ b.x + off, b.y + off, b.z + off }, color, vec3(1), false, nml, {}, {}}); + vertices.push_back({{ a.x - off, b.y + off, b.z + off }, color, vec3(1), false, nml, {}, {}}); + + const static array boxIndices { 0, 1, 2, 2, 3, 0, 4, 7, 6, 6, 5, 4, 0, 4, 5, 5, 1, 0, @@ -82,8 +117,5 @@ WireframeEntity::createBox(glm::vec3 a, glm::vec3 b, float x, float y, float z, 1, 5, 6, 6, 2, 1, }; - vertices.insert(vertices.end(), myVerts.begin(), myVerts.end()); - for (auto i : myInds) indices.push_back(i + indOffset); - - indOffset += 8; + for (u32 i : boxIndices) indices.push_back(i + indOffset); } \ No newline at end of file diff --git a/src/client/entity/WireframeEntity.h b/src/client/entity/WireframeEntity.h index 62ca3352..72503344 100644 --- a/src/client/entity/WireframeEntity.h +++ b/src/client/entity/WireframeEntity.h @@ -1,7 +1,3 @@ -// -// Created by aurailus on 08/04/19. -// - #pragma once #include "world/dim/ent/DrawableEntity.h" @@ -11,22 +7,24 @@ class WireframeEntity : public DrawableEntity { public: - WireframeEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 color) : - DrawableEntity(game, dim, std::make_shared()), Entity(game, dim), - color(color) {}; + WireframeEntity(SubgamePtr game, DimensionPtr dim, vec3 stroke, vec4 fill = vec4(0)) : + DrawableEntity(game, dim, std::make_shared()), Entity(game, dim), stroke(stroke), fill(fill) {}; - void updateMesh(const std::vector& boxes, float width); + void updateMesh(const vec& boxes, f32 width); + + static uptr createMesh(const vec& boxes, + f32 wireWidth, vec3 stroke = vec3(1), vec4 fill = vec4(0)); + + static uptr createMesh(const SelectionBox& box, + f32 wireWidth, vec3 stroke = vec3(1), vec4 fill = vec4(0)); private: - std::vector vertices{}; - std::vector indices{}; + static void createSelectionBoxVertices(const SelectionBox& box, f32 wireWidth, + vec4 stroke, vec4 fill, vec& vertices, vec& indices); - void buildMesh(const std::vector& boxes); + static void createStrokeVertices(vec3 a, vec3 b, f32 wireWidth, + vec4 color, vec& vertices, vec& indices); - void createBox(glm::vec3 a, glm::vec3 b, float x, float y, float z, float xSize, float ySize, float zSize); - - glm::vec3 color{}; - - float width = 0.5; - int indOffset = 0; + vec3 stroke {}; + vec4 fill {}; }; diff --git a/src/client/graph/Renderer.cpp b/src/client/graph/Renderer.cpp index 66fc908b..f2e88ffe 100644 --- a/src/client/graph/Renderer.cpp +++ b/src/client/graph/Renderer.cpp @@ -93,6 +93,8 @@ void Renderer::beginChunkDeferredCalls() { } void Renderer::beginEntityDeferredCalls() { + glEnable(GL_BLEND); + currentModelUniform = entity.uniforms.model; setShader(entity); @@ -101,6 +103,8 @@ void Renderer::beginEntityDeferredCalls() { } void Renderer::endDeferredCalls() { + glDisable(GL_BLEND); + activeTexture = nullptr; glBindFramebuffer(GL_FRAMEBUFFER, ssao.fbo); @@ -154,6 +158,7 @@ void Renderer::endDeferredCalls() { glBindTexture(GL_TEXTURE_2D, blur.colorBuffer); glEnable(GL_BLEND); + renderQuad(); } diff --git a/src/client/gui/DebugGui.cpp b/src/client/gui/DebugGui.cpp index 70b0ac6c..b1ffc1f1 100644 --- a/src/client/gui/DebugGui.cpp +++ b/src/client/gui/DebugGui.cpp @@ -21,11 +21,11 @@ DebugGui::DebugGui(u16vec2 buffer, SubgamePtr game, LocalWorld& world, vectextures, fontRef); auto crosshairText = make_shared("crosshairText"); - crosshairText->create({ 2, 2 }, {}, { 0.2, 0.2, 0.2, 0.5 }, { 1, 1, 1, 1 }, f); + crosshairText->create({ 2, 2 }, {}, { 1, 1, 1, 1 }, { 0.2, 0.2, 0.2, 0.5 }, f); add(crosshairText); auto dataText = make_shared("dataText"); - dataText->create({ 2, 2 }, {}, { 0.2, 0.2, 0.2, 0.5 }, { 1, 1, 1, 1 }, f); + dataText->create({ 2, 2 }, {}, { 1, 1, 1, 1 }, { 0.2, 0.2, 0.2, 0.5 }, f); add(dataText); auto interpGraph = make_shared("interpGraph"); @@ -219,7 +219,8 @@ void DebugGui::update(sptr player, f64 delta, u32 interpolatedChunk if (target.type == Target::Type::BLOCK) { const auto& def = game->getDefs().blockFromId(world.getActiveDimension()->getBlock(target.data.block.pos)); - get("crosshairText")->setText(def.name + " (" + def.identifier + ") [" + std::to_string(def.index) + "]"); + get("crosshairText")->setText( + "`b" + def.name + " (`r` `c7" + def.identifier + "`cr - " + std::to_string(def.index) + "` `b)"); } else { get("crosshairText")->setText(""); diff --git a/src/client/gui/basic/GuiInventoryItem.cpp b/src/client/gui/basic/GuiInventoryItem.cpp index a396a5e6..ab50fccf 100644 --- a/src/client/gui/basic/GuiInventoryItem.cpp +++ b/src/client/gui/basic/GuiInventoryItem.cpp @@ -43,7 +43,7 @@ void GuiInventoryItem::create(glm::vec2 scale, unsigned short count, ItemDef& de if (count > 1) { auto text = std::make_shared("count"); - text->create(scale, {}, {}, { 1, 1, 1, 1 }, f); + text->create(scale, {}, { 1, 1, 1, 1 }, {}, f); text->setText(std::to_string(count)); add(text); text->setPos({ (19 - text->getWidth()) * scale.x, 9 * scale.y }); diff --git a/src/client/gui/basic/GuiText.cpp b/src/client/gui/basic/GuiText.cpp index a98f7702..e9407ed9 100644 --- a/src/client/gui/basic/GuiText.cpp +++ b/src/client/gui/basic/GuiText.cpp @@ -1,9 +1,3 @@ -// -// Created by aurailus on 25/12/18. -// - -#include - #include "GuiText.h" #include "util/Util.h" @@ -12,178 +6,260 @@ #include "game/atlas/asset/AtlasRef.h" #include "world/dim/ent/AnimationSegment.h" -GuiText::GuiText(const std::string& key) : GuiComponent(key) {} - -void GuiText::create(glm::vec2 scale, glm::vec4 padding, glm::vec4 bgcolor, glm::vec4 color, Font font) { - // Text Constructor - // Creates a GuiText object. - - this->scale = scale; +void GuiText::create(vec2 scale, vec4 padding, vec4 textColor, vec4 backgroundColor, Font font) { this->padding = padding; this->font = std::move(font); - this->bgcolor = bgcolor; - this->color = color; + this->textColor = textColor; + this->backgroundColor = backgroundColor; - setScale(scale); setText(""); + setScale(scale); } -std::shared_ptr GuiText::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds) { - glm::vec2 pos = SerialGui::get(elem, "position", bounds); - glm::vec2 offset = SerialGui::get(elem, "position_anchor"); - glm::vec2 size = SerialGui::get(elem, "size", bounds); - glm::vec4 padding = SerialGui::get(elem, "padding", bounds); - glm::vec2 scale = SerialGui::get(elem, "scale"); - if (scale == glm::vec2{ 0, 0 }) scale = { 1, 1 }; - +sptr GuiText::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, ivec2 bounds) { + vec2 pos = SerialGui::get(elem, "position", bounds); + vec2 offset = SerialGui::get(elem, "position_anchor"); + vec2 size = SerialGui::get(elem, "size", bounds); + vec4 padding = SerialGui::get(elem, "padding", bounds); + vec2 scale = SerialGui::get(elem, "scale") * vec2(0.33); + + if (scale.x == 0 && scale.y == 0) scale = vec2 { 1, 1 }; pos -= offset * size; - - glm::vec4 background_color = Util::hexToColorVec(elem.get_or("background", "#0000")); - glm::vec4 color = Util::hexToColorVec(elem.get_or("color", "#fff")); - std::string content = elem.get_or("content", ""); - + + vec4 backgroundColor = Util::hexToColorVec(elem.get_or("background", "#0000")); + vec4 textColor = Util::hexToColorVec(elem.get_or("color", "#fff")); + string content = elem.get_or("content", ""); + auto text = std::make_shared(elem.key); - text->create(scale * SerialGui::SCALE_MODIFIER, padding, background_color, color, { textures, textures["font"] }); + text->create(scale * SerialGui::SCALE_MODIFIER, padding, + textColor, backgroundColor, { textures, textures["font"] }); text->setText(content); text->setPos(pos); - + return text; } -void GuiText::setText(std::string text) { - this->text = std::move(text); - unsigned int indOffset = 0; +void GuiText::setText(string newText) { + text = newText; + u32 ind = 0; - maxLineWidth = 0; + width = 0; - std::vector textVertices; - textVertices.reserve(text.length() * 8 + 200); - std::vector textIndices; - textIndices.reserve(text.length() * 12 + 240); + vec vertices; + vertices.reserve(text.length() * 8 + 200); + vec indices; + indices.reserve(text.length() * 12 + 240); - //Draw background & Measure Line Width - int lineWidth = 0; - int xOffset = 0, yOffset = 0; - int h = Font::charHeight; - - for (unsigned int i = 0; i < this->text.length() + 1; i++) { - char c = this->text[i]; - - //TODO: Proper font handling. - if (c == '\t') c = ' '; - - if (c == '\n' || i == this->text.length()) { - if (lineWidth > 0) { - lineWidth += 2; - - if (lineWidth > maxLineWidth) maxLineWidth = lineWidth; - - if (bgcolor.w != 0) { - textVertices.emplace_back(glm::vec3{ -1, yOffset - 1, 0 }, bgcolor, glm::vec3(1), 0.f, glm::vec3{}, - glm::ivec4{}, glm::vec4{}); - textVertices.emplace_back(glm::vec3{ -1, yOffset + h + 1, 0 }, bgcolor, glm::vec3(1), 0.f, - glm::vec3{}, glm::ivec4{}, glm::vec4{}); - textVertices.emplace_back(glm::vec3{ lineWidth + 1, yOffset + h + 1, 0 }, bgcolor, glm::vec3(1), - 0.f, glm::vec3{}, glm::ivec4{}, glm::vec4{}); - textVertices.emplace_back(glm::vec3{ lineWidth + 1, yOffset - 1, 0 }, bgcolor, glm::vec3(1), 0.f, - glm::vec3{}, glm::ivec4{}, glm::vec4{}); - - textIndices.emplace_back(indOffset); - textIndices.emplace_back(indOffset + 1); - textIndices.emplace_back(indOffset + 2); - textIndices.emplace_back(indOffset + 2); - textIndices.emplace_back(indOffset + 3); - textIndices.emplace_back(indOffset); - - indOffset += 4; - } - yOffset += h + 2; - } - else { - yOffset += h / 2; //Pad out the height if using just newlines. - } - - lineWidth = 0; - } - else lineWidth += font.getCharWidth(c) + 1; + vec lines; + { + std::stringstream textStream(text); + string line; + while (std::getline(textStream, line, '\n')) lines.emplace_back(line); } - //Draw Characters + vec3 offset = {}; + u32 h = Font::charHeight; - bool emptyLine = true; - xOffset = 0; - yOffset = 0; + bool bold = false; + bool italic = false; + i32 underline = -1; + i32 strikethrough = -1; + u32 strikethroughVertStart = 0; + vec4 color = textColor; - for (unsigned int i = 0; i < this->text.length() + 1; i++) { - char c = this->text[i]; + for (usize i = 0; i < lines.size(); i++) { + let& line = lines[i]; + bool empty = line.find_first_not_of(" \t\n") == -1; - //TODO: Proper font handling. - if (c == '\t') c = ' '; - - unsigned int h = Font::charHeight; - - if (c == '\n' || i == this->text.length()) { - yOffset += (emptyLine) ? h / 2 : h + 2; - xOffset = 0; - emptyLine = true; + if (empty) { + offset.x = 0; + offset.y += h / 2; continue; } - else { - emptyLine = false; + + u32 bgVertStart = 0; + if (backgroundColor.w != 0) { + bgVertStart = vertices.size(); + for (u32 i = 0; i < 4; i++) vertices.push_back({}); + for (u32 i : INDICES) indices.push_back(i + ind); + ind += 4; } - - auto charWidth = font.getCharWidth(c) + 1; - auto charUVs = font.getCharUVs(c); - - for (unsigned int j = 0; j <= 1; j++) { - glm::vec3 c = { this->color.x, this->color.y, this->color.z }; + + for (usize j = 0; j < line.length() + 1; j++) { + char c = j < line.length() ? line[j] : ' '; + if (c == '\t') c = ' '; - if (j == 0) { - c *= glm::vec3{ 0.4, 0.4, 0.45 }; - xOffset += 1; - yOffset += 1; - } - else { - xOffset -= 1; - yOffset -= 1; + if (c == '`') { + bool flushDecorators = j == line.length(); + + char d = line[++j]; + if (d == '`') goto escape_formatting; + else if (d == ' ') offset.x++; + else if (d == 'b') bold = true; + else if (d == 'i') italic = true; + else if (d == 'u') underline = offset.x; + else if (d == 's') { + strikethrough = offset.x; + strikethroughVertStart = vertices.size(); + for (u32 i = 0; i < 4; i++) vertices.push_back({}); + for (u32 i : INDICES) indices.push_back(i + ind); + ind += 4; + } + else if (d == 'c') flushDecorators = true; + else if (d == 'r') { + bold = false; + italic = false; + flushDecorators = true; + } + + if (flushDecorators) { + if (underline != -1) { + GuiText::drawRect({ underline, h - 1, offset.x, h }, color, vertices, indices, ind); + GuiText::drawRect({ underline + 1, h, offset.x + 1, h + 1 }, + color * BG_MULTIPLE, vertices, indices, ind); + underline = offset.x; + } + + if (strikethrough != -1) { + GuiText::drawRect({ strikethrough, h / 2, offset.x, h / 2 + 1 }, + color, vertices, indices, ind); + GuiText::drawRect({ strikethrough + 1, h / 2 + 1, offset.x + 1, h / 2 + 2 }, + color * BG_MULTIPLE, vertices, indices, ind, strikethroughVertStart); + strikethrough = offset.x; + } + + if (d == 'r') { + color = textColor; + underline = -1; + strikethrough = -1; + } + } + + if (d == 'c') { + char code = line[++j]; + if (code == 'r') color = textColor; + else { + u32 v; + std::stringstream ss; + ss << std::hex << code; + ss >> v; + color = COLORS[v]; + } + } + + continue; } - textVertices.emplace_back(glm::vec3{ xOffset, yOffset, 0 }, glm::vec4{ charUVs.x, charUVs.y, 0, color.w }, - c, 1.f, glm::vec3{}, glm::ivec4{}, glm::vec4{}); - textVertices.emplace_back(glm::vec3{ xOffset, yOffset + h, 0 }, - glm::vec4{ charUVs.x, charUVs.w, 0, color.w }, c, 1.f, glm::vec3{}, glm::ivec4{}, glm::vec4{}); - textVertices.emplace_back(glm::vec3{ xOffset + charWidth, yOffset + h, 0 }, - glm::vec4{ charUVs.z, charUVs.w, 0, color.w }, c, 1.f, glm::vec3{}, glm::ivec4{}, glm::vec4{}); - textVertices.emplace_back(glm::vec3{ xOffset + charWidth, yOffset, 0 }, - glm::vec4{ charUVs.z, charUVs.y, 0, color.w }, c, 1.f, glm::vec3{}, glm::ivec4{}, glm::vec4{}); - - textIndices.emplace_back(indOffset); - textIndices.emplace_back(indOffset + 1); - textIndices.emplace_back(indOffset + 2); - textIndices.emplace_back(indOffset + 2); - textIndices.emplace_back(indOffset + 3); - textIndices.emplace_back(indOffset); - - indOffset += 4; + escape_formatting: + if (j == line.length()) continue; + + u32 w = font.getCharWidth(c) + 1; + vec4 UV = font.getCharUVs(c); + + for (u32 k = 0; k < (bold ? 4 : 2); k++) { + vec4 c = color; + + if (k == 0 || (k == 1 && bold)) c *= BG_MULTIPLE; + + if (k == 0) { + offset.x += 1; + offset.y += 1; + } + else if ((k == 1 || k == 3) && bold) { + offset.x += 1; + } + else if ((k == 1 && !bold) || (k == 2 && bold)) { + offset.x -= bold ? 2 : 1; + offset.y -= 1; + } + + vertices.emplace_back(offset + vec3(italic ? 2 : 0, 0, 0), vec4 { UV.x, UV.y, 0, c.w }, + vec3(c), 1.f, vec3 {}, ivec4 {}, vec4 {}); + + vertices.emplace_back(offset + vec3(0, h, 0), vec4 { UV.x, UV.w, 0, c.w }, + vec3(c), 1.f, vec3 {}, ivec4 {}, vec4 {}); + + vertices.emplace_back(offset + vec3(w, h, 0), vec4 { UV.z, UV.w, 0, c.w }, + vec3(c), 1.f, vec3 {}, ivec4 {}, vec4 {}); + + vertices.emplace_back(offset + vec3(w + (italic ? 2 : 0), 0, 0), vec4 { UV.z, UV.y, 0, c.w }, + vec3(c), 1.f, vec3 {}, ivec4 {}, vec4 {}); + + for (u32 i : INDICES) indices.push_back(i + ind); + ind += 4; + } + + offset.x += w; } - xOffset += charWidth; + if (backgroundColor.w != 0) GuiText::drawRect({ -1, offset.y - 1, offset.x + 2, offset.y + h + 1 }, + backgroundColor, vertices, indices, ind, bgVertStart); + + if (offset.x > width) width = offset.x; + offset.x = 0; + offset.y += h + 2; } - auto m = std::make_unique(); - m->create(textVertices, textIndices); + let m = make_unique(); + m->create(vertices, indices); - auto model = std::make_shared(); + let model = make_shared(); model->fromMesh(std::move(m)); entity.setModel(model); } -std::string GuiText::getText() { +string GuiText::getText() { return text; } -unsigned int GuiText::getWidth() { - return maxLineWidth; +u32 GuiText::getWidth() { + return width; } + +void GuiText::drawRect(const vec4 pos, const vec4 color, + vec& vertices, vec& indices, u32& ind, const u32 insert) { + + vec myVerts = { + { vec3 { pos.x, pos.y, 0 }, color, vec3(1), 0.f, vec3 {}, ivec4 {}, vec4 {} }, + { vec3 { pos.x, pos.w, 0 }, color, vec3(1), 0.f, vec3 {}, ivec4 {}, vec4 {} }, + { vec3 { pos.z, pos.w, 0 }, color, vec3(1), 0.f, vec3 {}, ivec4 {}, vec4 {} }, + { vec3 { pos.z, pos.y, 0 }, color, vec3(1), 0.f, vec3 {}, ivec4 {}, vec4 {} } + }; + + if (insert != -1) { + vertices[insert] = myVerts[0]; + vertices[insert + 1] = myVerts[1]; + vertices[insert + 2] = myVerts[2]; + vertices[insert + 3] = myVerts[3]; + } + else { + for (EntityVertex& vert : myVerts) vertices.emplace_back(vert); + for (u32 i : INDICES) indices.push_back(i + ind); + ind += 4; + } +} + +const array GuiText::COLORS = { + Util::hexToColorVec("#000000"), + Util::hexToColorVec("#0000AA"), + Util::hexToColorVec("#00AA00"), + Util::hexToColorVec("#00AAAA"), + Util::hexToColorVec("#AA0000"), + Util::hexToColorVec("#b05cff"), + Util::hexToColorVec("#FFAA00"), + Util::hexToColorVec("#cccccc"), + Util::hexToColorVec("#555555"), + Util::hexToColorVec("#33a2f5"), + Util::hexToColorVec("#9fff80"), + Util::hexToColorVec("#7df4ff"), + Util::hexToColorVec("#ff739f"), + Util::hexToColorVec("#fd7dff"), + Util::hexToColorVec("#fffb82"), + Util::hexToColorVec("#ffffff") +}; + +const array GuiText::INDICES = { 0, 1, 2, 2, 3, 0 }; + +const vec4 GuiText::BG_MULTIPLE = { 0.3, 0.3, 0.35, 0.75 }; \ No newline at end of file diff --git a/src/client/gui/basic/GuiText.h b/src/client/gui/basic/GuiText.h index 46b6dbcd..1e2dd8aa 100644 --- a/src/client/gui/basic/GuiText.h +++ b/src/client/gui/basic/GuiText.h @@ -1,7 +1,3 @@ -// -// Created by aurailus on 25/12/18. -// - #pragma once #include "client/gui/GuiComponent.h" @@ -9,32 +5,58 @@ #include "client/graph/Font.h" class TextureAtlas; - class LuaGuiElement; +/** + * Renders text, with formatting escape codes. + * + * `` - Raw grave character + * ` - Single pixel space + * `c[0-f] - Preset colors + * `cr - Reset to the global text color + * `#[hex code] - Color with an arbitrary hex code + * `b - Bold + * `i - Italic + * `u - Underline + * `s - Strikethrough + * `r - Reset to default formatting + */ + class GuiText : public GuiComponent { - public: +public: GuiText() = default; - explicit GuiText(const std::string& key); + explicit GuiText(const string& key) : GuiComponent(key) {}; + + /** Creates a text component from a serialized lua element. */ + static sptr fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, ivec2 bounds); + + /** Creates a new text component. */ + void create(vec2 scale, vec4 padding, vec4 textColor, vec4 backgroundColor, Font font); + + /** Returns the width in display pixels of the text. */ + u32 getWidth(); - static std::shared_ptr - fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds); + /** Sets the text to the string provided. */ + void setText(string text); - void create(glm::vec2 scale, glm::vec4 padding, glm::vec4 bgcolor, glm::vec4 color, Font font); + /** Returns the current text string. */ + string getText(); - unsigned int getWidth(); - - void setText(std::string text); - - std::string getText(); - - private: +private: Font font; - glm::vec4 bgcolor{}; - glm::vec4 color{}; - std::string text; - unsigned int maxLineWidth = 0; + void drawRect(const vec4 pos, const vec4 color, + vec& vertices, vec& indices, u32& ind, const u32 insert = -1); + + string text; + vec4 textColor {}; + vec4 backgroundColor {}; + + u32 width = 0; + + static const array COLORS; + static const array INDICES; + static const vec4 BG_MULTIPLE; }; diff --git a/src/client/gui/compound/GuiCellGraph.cpp b/src/client/gui/compound/GuiCellGraph.cpp index 35c64e05..990b18a3 100644 --- a/src/client/gui/compound/GuiCellGraph.cpp +++ b/src/client/gui/compound/GuiCellGraph.cpp @@ -18,7 +18,7 @@ void GuiCellGraph::create(f32 scale, vec4 padding, u16 count, const string& titl add(background); let label = make_shared(); - label->create({ 2, 2 }, {}, {}, { 1, 1, 1, 1 }, this->font); + label->create({ 2, 2 }, {}, { 1, 1, 1, 1 }, {}, this->font); label->setPos({ 4, 8 }); label->setText(title); add(label); diff --git a/src/client/gui/compound/GuiLabelledGraph.cpp b/src/client/gui/compound/GuiLabelledGraph.cpp index d1e873f6..059521a7 100644 --- a/src/client/gui/compound/GuiLabelledGraph.cpp +++ b/src/client/gui/compound/GuiLabelledGraph.cpp @@ -34,7 +34,7 @@ void GuiLabelledGraph::create(glm::vec2 scale, glm::vec4 padding, const std::str graph->setPos({ GRAPH_PAD_X, GRAPH_PAD_Y }); auto label = std::make_shared("label"); - label->create({ 2, 2 }, {}, {}, { 1, 1, 1, 1 }, this->font); + label->create({ 2, 2 }, {}, { 1, 1, 1, 1 }, {}, this->font); add(label); label->setPos({ TEXT_PAD_X, TEXT_PAD_Y }); diff --git a/src/client/gui/compound/GuiPerfGraph.cpp b/src/client/gui/compound/GuiPerfGraph.cpp index 7d3b8ccb..0c6b957e 100644 --- a/src/client/gui/compound/GuiPerfGraph.cpp +++ b/src/client/gui/compound/GuiPerfGraph.cpp @@ -30,15 +30,14 @@ void GuiPerfGraph::create(f32 scale, vec4 padding, const vec& sections, meter->setPos({ GRAPH_PAD_X, GRAPH_PAD_Y }); auto label = std::make_shared("label"); - label->create({ 2, 2 }, {}, {}, { 1, 1, 1, 1 }, this->font); + label->create({ 2, 2 }, {}, { 1, 1, 1, 1 }, {}, this->font); label->setText(title); add(label); label->setPos({ TEXT_PAD_X, TEXT_PAD_Y }); for (usize i = 0; i < sections.size(); i++) { auto label = std::make_shared(); - label->create({ 2, 2 }, {}, vec4(GuiMeter::COLORS[i % GuiMeter::COLORS.size()], 1), - { 1, 1, 1, 1 }, this->font); + label->create({ 2, 2 }, {}, vec4(GuiMeter::COLORS[i % GuiMeter::COLORS.size()], 1), {}, this->font); label->setText(sections[i]); add(label); label->setPos({ TEXT_PAD_X + scale * (i % 2) / 2, TEXT_PAD_Y + GRAPH_PAD_Y + (i / 2) * 24 + 2 }); diff --git a/src/client/scene/ConnectScene.cpp b/src/client/scene/ConnectScene.cpp index 6ed59d61..4f272df3 100644 --- a/src/client/scene/ConnectScene.cpp +++ b/src/client/scene/ConnectScene.cpp @@ -33,7 +33,7 @@ ConnectScene::ConnectScene(Client& client, Address addr) : Scene(client), Font f(client.game->textures, client.game->textures["font"]); auto statusText = std::make_shared("statusText"); - statusText->create({ 2, 2 }, {}, {}, { 1, 1, 1, 1 }, f); + statusText->create({ 2, 2 }, {}, { 1, 1, 1, 1 }, {}, f); statusText->setText("Connecting..."); statusText->setPos({ 32, 24 }); components.add(statusText); diff --git a/src/client/scene/MainMenuScene.cpp b/src/client/scene/MainMenuScene.cpp index 3e331f04..4c0084ba 100644 --- a/src/client/scene/MainMenuScene.cpp +++ b/src/client/scene/MainMenuScene.cpp @@ -34,12 +34,12 @@ MainMenuScene::MainMenuScene(Client& client) : components->add(branding); { auto zephaText = make_shared("zephaText"); - zephaText->create({ GS, GS }, {}, {}, { 1, 1, 1, 1 }, f); + zephaText->create({ GS, GS }, {}, { 1, 1, 1, 1 }, {}, f); zephaText->setText("Zepha"); branding->add(zephaText); auto alphaText = make_shared("alphaText"); - alphaText->create({ GS, GS }, {}, {}, { 1, 0.5, 0.7, 1 }, f); + alphaText->create({ GS, GS }, {}, { 1, 0.5, 0.7, 1 }, {}, f); alphaText->setText("ALPHA"); alphaText->setPos({ 25 * GS, 0 }); branding->add(alphaText); diff --git a/src/game/atlas/TextureAtlas.cpp b/src/game/atlas/TextureAtlas.cpp index 76d36f3a..42ba257d 100644 --- a/src/game/atlas/TextureAtlas.cpp +++ b/src/game/atlas/TextureAtlas.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "TextureAtlas.h" @@ -181,7 +183,7 @@ std::shared_ptr TextureAtlas::generateTexture(std::string req) { std::string paramsString = req.substr(paramsBegin + 1, paramsEnd - paramsBegin - 1); std::vector params; - std::string::size_type pos = 0; + std::string::size_type pos; while ((pos = paramsString.find(',')) != std::string::npos) { params.push_back(paramsString.substr(0, pos)); paramsString.erase(0, pos + 1); @@ -197,9 +199,22 @@ std::shared_ptr TextureAtlas::generateTexture(std::string req) { auto data = getBytesAtPos({ src->pos.x + loc.x, src->pos.y + loc.y }, { loc.z, loc.w }).data; return addImage(data, req, false, loc.z, loc.w); } + else if (paramName == "multiply") { + if (params.size() != 2) throw std::runtime_error("multiply() requires 2 parameters."); + vec4 multiple = Util::hexToColorVec(params[1]); + auto tex = getBytesOfTex(params[0]); + + for (int i = 0; i < tex.width * tex.height; i++) { + tex.data[i * 4 + 0] *= multiple.x; + tex.data[i * 4 + 1] *= multiple.y; + tex.data[i * 4 + 2] *= multiple.z; + tex.data[i * 4 + 3] *= multiple.w; + } + + return addImage(tex.data, req, false, tex.width, tex.height); + } else { throw std::runtime_error("Invalid parameter."); - return nullptr; } } @@ -236,7 +251,6 @@ TextureAtlas::RawTexData TextureAtlas::getBytesAtPos(glm::ivec2 pos, glm::ivec2 } data.data = pixels; - return data; } diff --git a/src/lua/usertype/Dimension.cpp b/src/lua/usertype/Dimension.cpp index 609052a4..9df9751a 100644 --- a/src/lua/usertype/Dimension.cpp +++ b/src/lua/usertype/Dimension.cpp @@ -65,11 +65,14 @@ sol::table Api::Usertype::Dimension::add_entity_c(sol::this_state s, glm::vec3 p auto displayType = luaEntity.get>("display"); if (!displayType) throw std::runtime_error("entity '" + identifier + "' is missing the display property."); - auto displayObject = luaEntity.get>("display_object"); - if (!displayObject) throw std::runtime_error("entity '" + identifier + "' is missing the display_object property."); + auto displayObject = luaEntity.get>( + (*displayType == "wireframe") ? "display_stroke" : "display_object"); + if (!displayObject) throw std::runtime_error( + "entity '" + identifier + "' is missing the display_object/display_color property."); - auto displayTexture = luaEntity.get>("display_texture"); - if (strncmp(displayType->data(), "model", 5) == 0 && !displayTexture) + auto displayTexture = luaEntity.get>( + (*displayType == "wireframe") ? "display_fill" : "display_texture"); + if (displayType == "model" && !displayTexture) throw std::runtime_error("entity '" + identifier + "' is missing the display_texture property."); auto entity = std::make_shared<::LocalLuaEntity>(dim->getGame(), dim); @@ -105,11 +108,13 @@ sol::table Api::Usertype::Dimension::add_entity_s(sol::this_state s, glm::vec3 p auto displayType = luaEntity.get>("display"); if (!displayType) throw std::runtime_error("entity '" + identifier + "' is missing the display property."); - auto displayObject = luaEntity.get>("display_object"); - if (!displayObject) throw std::runtime_error("entity '" + identifier + "' is missing the display_object property."); + auto displayObject = luaEntity.get>( + (*displayType == "wireframe") ? "display_color" : "display_object"); + if (!displayObject) throw std::runtime_error( + "entity '" + identifier + "' is missing the display_object/display_color property."); auto displayTexture = luaEntity.get>("display_texture"); - if (strncmp(displayType->data(), "model", 5) == 0 && !displayTexture) + if (displayType == "model" && !displayTexture) throw std::runtime_error("entity '" + identifier + "' is missing the display_texture property."); unsigned int ind = dim->nextEntityInd(); diff --git a/src/lua/usertype/Entity.cpp b/src/lua/usertype/Entity.cpp index b2ccd7b8..27552651 100644 --- a/src/lua/usertype/Entity.cpp +++ b/src/lua/usertype/Entity.cpp @@ -141,16 +141,18 @@ void Api::Usertype::Entity::snap_roll(float rot) { entity->setRotateZ(rot); } -float Api::Usertype::Entity::get_scale() { - return entity->getScale().x; +glm::vec3 Api::Usertype::Entity::get_scale() { + return entity->getScale(); } -void Api::Usertype::Entity::set_scale(float scale) { - entity->setScale(scale); +void Api::Usertype::Entity::set_scale(sol::object scale) { + if (scale.is()) entity->setScale(scale.as()); + else entity->setScale(scale.as()); } -void Api::Usertype::Entity::snap_scale(float scale) { - entity->setScale(scale); +void Api::Usertype::Entity::snap_scale(sol::object scale) { + if (scale.is()) entity->setScale(scale.as()); + else entity->setScale(scale.as()); } Api::Usertype::Dimension Api::Usertype::Entity::get_dimension() { @@ -179,6 +181,9 @@ void Api::Usertype::Entity::set_display_type(const std::string& mode, else if (mode == "model" && argB) { entity->setAppearance("model", argA, *argB); } + else if (mode == "wireframe") { + entity->setAppearance("wireframe", argA, argB ? *argB : ""); + } else throw std::runtime_error("Invalid display type parameters."); } diff --git a/src/lua/usertype/Entity.h b/src/lua/usertype/Entity.h index c5debe1c..47c762bb 100644 --- a/src/lua/usertype/Entity.h +++ b/src/lua/usertype/Entity.h @@ -166,7 +166,7 @@ namespace Api::Usertype { * @returns the scale multiplier of the entity's model. */ - float get_scale(); + glm::vec3 get_scale(); /** * Sets the scale of the entity's model, @@ -174,14 +174,14 @@ namespace Api::Usertype { * @param scale - The desired scale multiplier. */ - void set_scale(float scale); + void set_scale(sol::object scale); /** * Sets the scale of the entity's model, without any interpolation. * @param scale - The desired scale multiplier. */ - void snap_scale(float scale); + void snap_scale(sol::object scale); /** * Gets the entity's true visual-offset, which may be different from diff --git a/src/lua/usertype/LuaGuiElement.cpp b/src/lua/usertype/LuaGuiElement.cpp index d57afe94..513df659 100644 --- a/src/lua/usertype/LuaGuiElement.cpp +++ b/src/lua/usertype/LuaGuiElement.cpp @@ -80,8 +80,8 @@ sol::object LuaGuiElement::get_child(sol::this_state s, sol::object key) { void LuaGuiElement::append(sol::this_state s, sol::object elem) { if (elem.is>()) children.push_back(elem.as>()); - else if (elem.is()) - children.push_back(call(s, elem.as()).as>()); + else if (elem.is()) + children.push_back(call(s, elem.as()).as>()); else throw std::runtime_error("Append arg is not an element or a function to generate one."); children.back()->parent = this; @@ -124,6 +124,16 @@ void LuaGuiElement::remove(sol::this_state s, sol::object elem) { } } +void LuaGuiElement::clear(sol::this_state s) { + for (auto it = children.cbegin(); it != children.cend();) { + (*it)->parent = nullptr; + (*it)->updateFunction = nullptr; + it = children.erase(it); + } + + if (updateFunction) updateFunction(); +} + Any LuaGuiElement::getAsAny(const std::string& key) const { if (!traits.count(key)) return Any(); auto object = traits.at(key); @@ -167,4 +177,4 @@ Any LuaGuiElement::getAsAny(const std::string& key) const { } throw std::runtime_error("Invalid type requested in getAsAny"); -} +} \ No newline at end of file diff --git a/src/lua/usertype/LuaGuiElement.h b/src/lua/usertype/LuaGuiElement.h index 0e28e663..51b6f706 100644 --- a/src/lua/usertype/LuaGuiElement.h +++ b/src/lua/usertype/LuaGuiElement.h @@ -30,6 +30,8 @@ class LuaGuiElement { void remove(sol::this_state s, sol::object elem); + void clear(sol::this_state s); + std::string type{}, key{}; LuaGuiElement* parent = nullptr; @@ -75,7 +77,8 @@ namespace ClientApi { "get", &LuaGuiElement::get_child, "append", &LuaGuiElement::append, "prepend", &LuaGuiElement::prepend, - "remove", &LuaGuiElement::remove + "remove", &LuaGuiElement::remove, + "clear", &LuaGuiElement::clear ); } } diff --git a/src/lua/usertype/Player.cpp b/src/lua/usertype/Player.cpp index 18b32462..7dd907f5 100644 --- a/src/lua/usertype/Player.cpp +++ b/src/lua/usertype/Player.cpp @@ -16,6 +16,10 @@ unsigned int Api::Usertype::ServerPlayer::get_id() { return player->getId(); } +string Api::Usertype::ServerPlayer::get_username() { + return player->getUsername(); +} + glm::vec3 Api::Usertype::ServerPlayer::get_pos() { return player->getPos(); } @@ -122,6 +126,7 @@ bool Api::Usertype::ServerPlayer::get_flying() { void Api::Usertype::ServerPlayer::bind(State, sol::state& lua, sol::table& core) { lua.new_usertype("Player", "get_id", &ServerPlayer::get_id, + "get_username", &ServerPlayer::get_username, "get_pos", &ServerPlayer::get_pos, "get_block_pos", &ServerPlayer::get_block_pos, "set_pos", &ServerPlayer::set_pos, @@ -180,6 +185,7 @@ void Api::Usertype::LocalPlayer::set_hud(std::shared_ptr hud) { void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core) { lua.new_usertype("Player", "get_id", &LocalPlayer::get_id, + "get_username", &LocalPlayer::get_username, "get_pos", &LocalPlayer::get_pos, "get_block_pos", &LocalPlayer::get_block_pos, "set_pos", &LocalPlayer::set_pos, diff --git a/src/lua/usertype/Player.h b/src/lua/usertype/Player.h index 65ff9dbe..dad4e38e 100644 --- a/src/lua/usertype/Player.h +++ b/src/lua/usertype/Player.h @@ -15,75 +15,80 @@ class LuaGuiElement; namespace Api::Usertype { - class ServerPlayer : public SubgameUsertype { - public: - ServerPlayer(PlayerPtr player) : player(player) {} - - PlayerPtr player; - - unsigned int get_id(); - - glm::vec3 get_pos(); - - glm::vec3 get_block_pos(); - - void set_pos(glm::vec3 pos); - - glm::vec3 get_vel(); - - void set_vel(glm::vec3 vel); - - float get_look_yaw(); - - void set_look_yaw(float rot); - - float get_look_pitch(); - - void set_look_pitch(float rot); - - sol::object get_hand_list(sol::this_state s); - - sol::object get_hand_stack(sol::this_state s); - - void set_hand_list(sol::optional list); - - sol::object get_wield_list(sol::this_state s); - - sol::object get_wield_stack(sol::this_state s); - - void set_wield_list(sol::optional list); - - Inventory get_inventory(); - - Dimension get_dimension(); - - void set_dimension(const std::string& identifier); - - unsigned int get_wield_index(); - - void set_wield_index(unsigned int index); - - void set_flying(bool shouldFly); - - bool get_flying(); - - static void bind(State state, sol::state& lua, sol::table& core); - }; + class ServerPlayer; + class LocalPlayer; +} + +class Api::Usertype::ServerPlayer : public SubgameUsertype { +public: + ServerPlayer(PlayerPtr player) : player(player) {} - class LocalPlayer : public ServerPlayer { - public: - LocalPlayer(PlayerPtr player) : ServerPlayer(player) {} - - bool is_in_menu(); - - void show_menu(std::shared_ptr root); - - void close_menu(); - - std::shared_ptr get_hud(); - - void set_hud(std::shared_ptr hud); - - static void bind(State state, sol::state& lua, sol::table& core); - }; -} \ No newline at end of file + PlayerPtr player; + + unsigned int get_id(); + + string get_username(); + + glm::vec3 get_pos(); + + glm::vec3 get_block_pos(); + + void set_pos(glm::vec3 pos); + + glm::vec3 get_vel(); + + void set_vel(glm::vec3 vel); + + float get_look_yaw(); + + void set_look_yaw(float rot); + + float get_look_pitch(); + + void set_look_pitch(float rot); + + sol::object get_hand_list(sol::this_state s); + + sol::object get_hand_stack(sol::this_state s); + + void set_hand_list(sol::optional list); + + sol::object get_wield_list(sol::this_state s); + + sol::object get_wield_stack(sol::this_state s); + + void set_wield_list(sol::optional list); + + Inventory get_inventory(); + + Dimension get_dimension(); + + void set_dimension(const std::string& identifier); + + unsigned int get_wield_index(); + + void set_wield_index(unsigned int index); + + void set_flying(bool shouldFly); + + bool get_flying(); + + static void bind(State state, sol::state& lua, sol::table& core); +}; + +class Api::Usertype::LocalPlayer : public ServerPlayer { +public: + LocalPlayer(PlayerPtr player) : ServerPlayer(player) {} + + bool is_in_menu(); + + void show_menu(std::shared_ptr root); + + void close_menu(); + + std::shared_ptr get_hud(); + + void set_hud(std::shared_ptr hud); + + static void bind(State state, sol::state& lua, sol::table& core); +}; \ No newline at end of file diff --git a/src/server/Server.cpp b/src/server/Server.cpp index 2dfa3e58..b3d78d52 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -32,7 +32,7 @@ Server::Server(u16 port, const std::string& subgame) : void Server::update() { const static i64 interval_ns = static_cast((1000 / 60.f) * 1000000L); Timer loop(""); - + world.s()->update(delta); game.s()->update(delta); @@ -58,9 +58,8 @@ void Server::update() { PacketView p(event.packet); auto client = static_cast(event.peer->data); - if (client->player) return playerPacketReceived(p, clients.getClient(client->id)->player); - - if (infoSender.handlePacket(*client, p)) { + if (client->player) playerPacketReceived(p, clients.getClient(client->id)->player); + else if (infoSender.handlePacket(*client, p)) { auto clientShr = clients.getClient(client->id); clients.createPlayer(clientShr, world->getDefaultDimension()); } @@ -93,7 +92,7 @@ void Server::update() { playersUpdated.clear(); - u64 sleep_for = (std::max)(interval_ns - static_cast(loop.elapsedNs()), 0L); + i64 sleep_for = (std::max)(interval_ns - static_cast(loop.elapsedNs()), 0L); if (sleep_for > 0) std::this_thread::sleep_for(std::chrono::nanoseconds(sleep_for)); delta = loop.elapsedNs() / 1000000.f / 1000.f; @@ -164,6 +163,7 @@ void Server::playerPacketReceived(PacketView& p, sptr player) { } case Packet::Type::INV_INTERACT: { + // TODO: When reading these parameters, there's a bad_alloc error. bool primary = p.d.read(); string source = p.d.read(); string list = p.d.read(); @@ -174,9 +174,10 @@ void Server::playerPacketReceived(PacketView& p, sptr player) { case Packet::Type::MOD_MESSAGE: { string source = p.d.read(); - string list = p.d.read(); + string message = p.d.read(); game->getParser().safe_function(game->getParser().core["trigger"], "message", - source, game->getParser().safe_function(game->getParser().core["deserialize"], list)); + source, game->getParser().safe_function(game->getParser().core["deserialize"], message), + Api::Usertype::ServerPlayer(player)); break; } } diff --git a/src/server/stream/ServerGenStream.cpp b/src/server/stream/ServerGenStream.cpp index 4f630dab..9567cac1 100644 --- a/src/server/stream/ServerGenStream.cpp +++ b/src/server/stream/ServerGenStream.cpp @@ -16,7 +16,6 @@ ServerGenStream::ServerGenStream(ServerSubgame& game, ServerWorld& world) : bool ServerGenStream::queue(u16 dimension, ivec3 pos) { auto v4 = ivec4(pos, dimension); -// if (!queuedMap.count(v4)) { if (queuedMap.find(v4) == queuedMap.end() && inProgressMap.find(v4) == inProgressMap.end()) { queuedTasks.push(v4); queuedMap.emplace(v4); @@ -28,6 +27,7 @@ bool ServerGenStream::queue(u16 dimension, ivec3 pos) { uptr> ServerGenStream::update() { auto created = make_unique>(); + usize dequeued = 0; for (usize i = 0; i < THREAD_QUEUE_SIZE; i++) { for (auto& t : threads) { auto& j = t.jobs[i]; @@ -43,6 +43,7 @@ uptr> ServerGenStream::update() { queuedMap.erase(pos); inProgressMap.emplace(pos); queuedTasks.pop(); + dequeued++; j.pos = ivec3(pos); j.gen = world.getDimension(pos.w)->getGen(); @@ -52,6 +53,9 @@ uptr> ServerGenStream::update() { } } + if (dequeued >= THREAD_QUEUE_SIZE * THREADS) + std::cout << Log::err << "Server threads were idle!" << Log::endl; + return created; } diff --git a/src/server/stream/ServerGenStream.h b/src/server/stream/ServerGenStream.h index 0f366843..ef9b5a35 100644 --- a/src/server/stream/ServerGenStream.h +++ b/src/server/stream/ServerGenStream.h @@ -18,7 +18,7 @@ class ServerSubgame; class ServerGenStream { public: static const usize THREADS = 4; - static const usize THREAD_QUEUE_SIZE = 16; + static const usize THREAD_QUEUE_SIZE = 4; struct FinishedJob { FinishedJob(u16 dim, ivec3 pos, uptr created) : @@ -37,13 +37,13 @@ public: std::unique_ptr> update(); - private: +private: struct Job { bool locked = false; uptr created = nullptr; u16 dim; - ivec3 pos{}; + ivec3 pos {}; sptr gen; }; diff --git a/src/util/Bounds.cpp b/src/util/Bounds.cpp index adae3408..7ecc9f8c 100644 --- a/src/util/Bounds.cpp +++ b/src/util/Bounds.cpp @@ -54,6 +54,6 @@ void Bounds::setB(glm::vec3 vecB) { bool Bounds::intersects(glm::vec3 test) { return (test.x >= a.x && test.x <= b.x - && test.y >= a.y && test.y <= b.y - && test.z >= a.z && test.z <= b.z); + && test.y >= a.y && test.y <= b.y + && test.z >= a.z && test.z <= b.z); } diff --git a/src/util/Util.h b/src/util/Util.h index 8d071f28..0cca4976 100644 --- a/src/util/Util.h +++ b/src/util/Util.h @@ -38,8 +38,9 @@ namespace Util { return toFixed(val); } - template && - std::is_same_v, V>, bool> = true> + template + || std::is_same_v) + && std::is_same_v, V>, bool> = true> static string toString(V vec) { std::ostringstream out; out << "[ "; @@ -48,8 +49,9 @@ namespace Util { return out.str(); } - template && - std::is_same_v, A>, bool> = true> + template + || std::is_same_v) + && std::is_same_v, A>, bool> = true> static string toString(A arr) { std::ostringstream out; for (usize i = 0; i < arr.size(); i++) out << (i == 0 ? "" : ", ") << arr[i]; @@ -122,7 +124,7 @@ namespace Util { color.g = intFromHexSegment(g) / 255.f; color.b = intFromHexSegment(b) / 255.f; color.a = intFromHexSegment(a) / 255.f; - + return color; } diff --git a/src/world/ServerWorld.cpp b/src/world/ServerWorld.cpp index 012ed160..4eb99910 100644 --- a/src/world/ServerWorld.cpp +++ b/src/world/ServerWorld.cpp @@ -66,23 +66,29 @@ void ServerWorld::update(f64 delta) { refs->update(); u32 genCount = 0; - std::unordered_set updatedChunks {}; auto finishedGen = genStream->update(); + std::unordered_set chunksDirtied {}; Timer t("Finishing Generation"); for (auto& data : *finishedGen) { let dim = getDimension(data.dim); + for (const auto& chunkPair : *data.created) { - updatedChunks.insert(ivec4(chunkPair.first, data.dim)); dim->setChunk(chunkPair.second); + let chunkMapBlockPos = Space::MapBlock::world::fromChunk(chunkPair.first); + if (chunkMapBlockPos != data.pos) { + let chunkMapBlock = dim->getMapBlock(chunkMapBlockPos); + if (chunkMapBlock->generated) chunksDirtied.insert(ivec4(chunkPair.first, data.dim)); + } } - auto mapBlock = dim->getMapBlock(ivec3(data.pos)); + + let mapBlock = dim->getMapBlock(ivec3(data.pos)); + assert(mapBlock); if (!mapBlock->generated) { mapBlock->generated = true; - assert(mapBlock); Serializer s {}; for (u16 i = 0; i < 64; i++) { @@ -102,50 +108,32 @@ void ServerWorld::update(f64 delta) { totalGens++; } } - if (!finishedGen->empty()) { - t.printElapsedMs(); - std::cout << totalGens << std::endl; - } - -// auto finishedPackets = packetStream->update(); -// if (finishedPackets->size()) std::cout << finishedPackets->size() << " finished packets" << std::endl; -// for (auto& data : *finishedPackets) { -// for (auto& client : clients.getClients()) { -// if (!client.second->player) continue; -// data->packet->sendTo(client.second->peer, Packet::Channel::WORLD); -// } -// } generatedMapBlocks = genCount; -// for (auto& chunkPos : updatedChunks) { -// std::cout << Util::toString(chunkPos) << std::endl; -// ivec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunkPos); -// auto dim = getDimension(chunkPos.w); -// auto chunk = dim->getChunk(ivec3(chunkPos)); -// -// assert(chunk != nullptr); -// -//// bool sentAlready = false; -//// for (auto& mapBlock : generatedMapBlocks) if (mapBlock == mapBlockPos) { sentAlready = true; break; } -//// if (sentAlready) continue; -// -// Packet p(Packet::Type::CHUNK); -// p.data = chunk->compress(); -// -// for (auto& client : clients.getClients()) { -// if (!client.second->player) continue; -// + for (auto& chunkPos : chunksDirtied) { + ivec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunkPos); + auto dim = getDimension(chunkPos.w); + auto chunk = dim->getChunk(ivec3(chunkPos)); + assert(chunk); + + Packet p(Packet::Type::CHUNK); + p.data = chunk->compressToString(); + + for (auto& client : clients.getClients()) { + if (!client.second->player) continue; +// std::cout << "dirtied" << chunk->getPos() << std::endl; + // auto myChunk = Space::Chunk::world::fromBlock(client.second->player->getPos()); -// + // std::pair bounds = { // {myChunk.x - activeChunkRange.x, myChunk.y - activeChunkRange.y, myChunk.z - activeChunkRange.x}, // {myChunk.x + activeChunkRange.x, myChunk.y + activeChunkRange.y, myChunk.z + activeChunkRange.x}}; -// -//// if (isInBounds(chunkPos, bounds)) -// p.sendTo(client.second->peer, Packet::Channel::WORLD); -// } -// } + +// if (isInBounds(chunkPos, bounds)) + p.sendTo(client.second->peer, Packet::Channel::WORLD); + } + } Packet r = Serializer().append(generatedMapBlocks).packet(Packet::Type::SERVER_INFO); @@ -178,7 +166,6 @@ void ServerWorld::update(f64 delta) { } // Update clients with removed entities. - Serializer rem; rem.append(ind); for (i64 entity : dimension->getRemovedEntities()) rem.append(entity); @@ -240,32 +227,29 @@ void ServerWorld::sendChunksToPlayer(ServerPlayer& client) { ivec3 playerPos = Space::MapBlock::world::fromBlock(client.getPos()); ivec3 lastPlayerPos = Space::MapBlock::world::fromBlock(client.lastPos); - Bounds newBounds = { playerPos - ivec3{ sendRange.x, sendRange.y, sendRange.x }, - playerPos + ivec3{ sendRange.x, sendRange.y, sendRange.x }}; - Bounds oldBounds = { lastPlayerPos - ivec3{ sendRange.x, sendRange.y, sendRange.x }, - lastPlayerPos + ivec3{ sendRange.x, sendRange.y, sendRange.x }}; + Bounds newBounds = { playerPos - ivec3 { sendRange.x, sendRange.y, sendRange.x }, + playerPos + ivec3 { sendRange.x, sendRange.y, sendRange.x }}; + Bounds oldBounds = { lastPlayerPos - ivec3 { sendRange.x, sendRange.y, sendRange.x }, + lastPlayerPos + ivec3 { sendRange.x, sendRange.y, sendRange.x }}; for (auto& pos : generateOrder) { if (oldBounds.intersects(playerPos + pos) || !newBounds.intersects(playerPos + pos)) continue; -// packetStream->queue(client.getDim()->getInd(), pos + playerPos); -// auto dim = client.getDim(); -// std::cout << dim->getInd() << std::endl; -// auto mb = dim->getMapBlock(pos); -// std::cout << mb << std::endl; -// if (!mb) return; -// Serializer s {}; -// for (u16 i = 0; i < 64; i++) { -// auto chunk = mb->get(i); -// if (chunk) s.append(chunk->compressToString()); -// } -// -// let packet = make_unique(Packet::Type::MAPBLOCK); -// -// for (auto& client : clients.getClients()) { -// if (!client.second->player) continue; -// packet->sendTo(client.second->peer, Packet::Channel::WORLD); -// } + auto dim = client.getDim(); + auto mb = dim->getMapBlock(playerPos + pos); + if (!mb) return; +// std::cout << "sending " << pos << " to " << client.getId() << std::endl; + Serializer s {}; + for (u16 i = 0; i < 64; i++) { + auto chunk = mb->get(i); + if (chunk) s.append(chunk->compressToString()); + } + let packet = s.packet(Packet::Type::MAPBLOCK); + + for (auto& client : clients.getClients()) { + if (!client.second->player) continue; + packet.sendTo(client.second->peer, Packet::Channel::WORLD); + } } } diff --git a/src/world/dim/LocalDimension.cpp b/src/world/dim/LocalDimension.cpp index 3c64d45e..a8d50295 100644 --- a/src/world/dim/LocalDimension.cpp +++ b/src/world/dim/LocalDimension.cpp @@ -83,6 +83,13 @@ void LocalDimension::update(f64 delta) { } void LocalDimension::setChunk(sptr chunk) { + let clientMapBlock = Space::MapBlock::world::fromBlock(static_cast(world).getPlayer()->getPos()); + let mapBlockPos = Space::MapBlock::world::fromChunk(chunk->getPos()); + + if (abs(clientMapBlock.x - mapBlockPos.x) > retainMapBlockRange.x || + abs(clientMapBlock.y - mapBlockPos.y) > retainMapBlockRange.y || + abs(clientMapBlock.z - mapBlockPos.z) > retainMapBlockRange.x) return; + Dimension::setChunk(chunk); meshChunk(chunk); } diff --git a/src/world/dim/ServerDimension.h b/src/world/dim/ServerDimension.h index 9dd7af0e..1dc6e615 100644 --- a/src/world/dim/ServerDimension.h +++ b/src/world/dim/ServerDimension.h @@ -53,7 +53,7 @@ private: std::list luaEntities{}; std::list removedEntities{}; - const ivec2 retainMapBlockRange = { 4, 4 }; + const ivec2 retainMapBlockRange = { 6, 6 }; i64 entityInd = 1; }; diff --git a/src/world/dim/chunk/Chunk.cpp b/src/world/dim/chunk/Chunk.cpp index 2e7a0eb0..f62f5efa 100644 --- a/src/world/dim/chunk/Chunk.cpp +++ b/src/world/dim/chunk/Chunk.cpp @@ -65,7 +65,6 @@ void Chunk::combineWith(sptr o) { generationState = GenerationState::GENERATED; countRenderableBlocks(); } - else generationState = GenerationState::PARTIAL; } diff --git a/src/world/dim/ent/DrawableEntity.cpp b/src/world/dim/ent/DrawableEntity.cpp index 48f9f642..a66adc32 100644 --- a/src/world/dim/ent/DrawableEntity.cpp +++ b/src/world/dim/ent/DrawableEntity.cpp @@ -95,7 +95,6 @@ void DrawableEntity::interpScale(float scale) { void DrawableEntity::setScale(glm::vec3 scale) { visualScale = scale; Entity::setScale(scale); - } void DrawableEntity::interpScale(glm::vec3 scale) { diff --git a/src/world/dim/ent/LocalLuaEntity.cpp b/src/world/dim/ent/LocalLuaEntity.cpp index 3a5f6237..9b80781c 100644 --- a/src/world/dim/ent/LocalLuaEntity.cpp +++ b/src/world/dim/ent/LocalLuaEntity.cpp @@ -12,7 +12,21 @@ LocalLuaEntity::LocalLuaEntity(SubgamePtr game, DimensionPtr dim) : LuaEntity(game, dim), DrawableEntity(game, dim), Entity(game, dim) {} -void LocalLuaEntity::setAppearance(const std::string& mode, const std::string& argA, const std::string& argB) { +void LocalLuaEntity::setScale(f32 newScale) { + if (appearance == "wireframe") model->fromMesh( + WireframeEntity::createMesh({ {}, vec3(newScale) }, 0.035, wfStroke, wfFill)); + else DrawableEntity::setScale(scale); +} + +void LocalLuaEntity::setScale(vec3 newScale) { + if (appearance == "wireframe") model->fromMesh( + WireframeEntity::createMesh({ {}, newScale }, 0.035, wfStroke, wfFill)); + else DrawableEntity::setScale(scale); +} + +void LocalLuaEntity::setAppearance(const string& mode, const string& argA, const string& argB) { + this->appearance = mode; + if (mode == "gameobject" && (argA == "block" || argA == "craftitem")) { ItemDef& def = getGame()->getDefs().fromStr(argB); setModel(def.entityModel); @@ -22,5 +36,12 @@ void LocalLuaEntity::setAppearance(const std::string& mode, const std::string& a model->fromSerialized(getGame().l()->models.models[argA], { getGame().l()->textures[argB] }); setModel(model); } + else if (mode == "wireframe") { + wfStroke = Util::hexToColorVec(argA); + wfFill = argB.empty() ? vec4() : Util::hexToColorVec(argB); + auto model = std::make_shared(); + model->fromMesh(WireframeEntity::createMesh({ {}, scale }, 0.035, wfStroke, wfFill)); + setModel(model); + } else throw std::runtime_error("Invalid appearance arguments specified."); -} \ No newline at end of file +} diff --git a/src/world/dim/ent/LocalLuaEntity.h b/src/world/dim/ent/LocalLuaEntity.h index c975ab8f..091e3d9f 100644 --- a/src/world/dim/ent/LocalLuaEntity.h +++ b/src/world/dim/ent/LocalLuaEntity.h @@ -11,5 +11,14 @@ class LocalLuaEntity : public virtual DrawableEntity, public LuaEntity { public: LocalLuaEntity(SubgamePtr game, DimensionPtr dim); + virtual void setScale(float newScale) override; + + virtual void setScale(vec3 newScale) override; + virtual void setAppearance(const std::string& dMode, const std::string& argA, const std::string& argB) override; + +protected: + string appearance; + vec3 wfStroke; + vec4 wfFill; }; diff --git a/src/world/gen/MapGen.cpp b/src/world/gen/MapGen.cpp index 20c823bb..bd2e0d42 100644 --- a/src/world/gen/MapGen.cpp +++ b/src/world/gen/MapGen.cpp @@ -35,7 +35,8 @@ MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set let biomeFractal = FastNoise::New(); biomeFractal->SetSource(biomeScale); - biomeFractal->SetOctaveCount(4); + biomeFractal->SetOctaveCount(5); + biomeFractal->SetLacunarity(3); biomeGenerator = biomeFractal; } diff --git a/src/world/gen/NoiseSample.cpp b/src/world/gen/NoiseSample.cpp index e47aea95..7a0c5cb9 100644 --- a/src/world/gen/NoiseSample.cpp +++ b/src/world/gen/NoiseSample.cpp @@ -3,8 +3,8 @@ #include "NoiseSample.h" - -NoiseSample::NoiseSample(u16vec2 size, u16 precision) : NoiseSample({ size.x, 0, size.y }, precision) {} +NoiseSample::NoiseSample(u16vec2 size, u16 precision): + NoiseSample({ size.x, 0, size.y }, precision) {} NoiseSample::NoiseSample(u16vec3 size, u16 precision): size(size), precision(precision), data((size.x + 1) * (size.y + 1) * (size.z + 1), 0) { @@ -23,7 +23,7 @@ void NoiseSample::generate(ivec3 pos, const FastNoise::SmartNode<>& generator) { interpolateData(); } -void NoiseSample::fill(const NoiseSample::fill_function& fill) { +void NoiseSample::fill(const std::function& fill) { u16vec3 pos {}; for (pos.x = 0; pos.x < size.x + 1; pos.x += precision) for (pos.y = 0; pos.y < size.y + 1; pos.y += precision) @@ -41,8 +41,8 @@ void NoiseSample::interpolateData() { if (pos.x % precision == 0 && pos.y % precision == 0 && pos.z % precision == 0) continue; vec3 frac = vec3(pos) / static_cast(precision); - u16vec3 a = u16vec3(glm::floor(frac)) * static_cast(precision); - u16vec3 b = u16vec3(glm::ceil(frac)) * static_cast(precision); + u16vec3 a = u16vec3(glm::floor(frac)) * precision; + u16vec3 b = u16vec3(glm::ceil(frac)) * precision; vec3 factor = frac - glm::floor(frac); data[index(pos)] = Interp::trilerp( diff --git a/src/world/gen/NoiseSample.h b/src/world/gen/NoiseSample.h index a9fd233f..21534b95 100644 --- a/src/world/gen/NoiseSample.h +++ b/src/world/gen/NoiseSample.h @@ -6,67 +6,49 @@ #include "util/Types.h" #include "util/Interp.h" +/** + * Stores a 2d or 3d array of noise data that can be accessed by local position or index. + * Noise will only be sampled every `precision` blocks, and interpolated between them. + * Generates 1 block larger on each access due to interpolation, but the index signature + * will access it as though it was exactly `size` blocks wide. + */ + class NoiseSample { public: - typedef std::function fill_function; - NoiseSample(u16vec2 size, u16 precision); NoiseSample(u16vec3 size, u16 precision); + /** Populates the data with a noise generator. */ void generate(ivec3 pos, const FastNoise::SmartNode<>& generator); - void fill(const fill_function& fill); + /** Populates the data with a fill function. */ + void fill(const std::function& fill); + /** Retrieves the value from a local position. */ inline f32 operator[](u16vec3 pos) { return data[index(pos)]; } + /** Retrieves the value from an index into a `size`-sized cuboid. */ inline f32 operator[](u32 ind) { return data[shiftIndexByOne(ind)]; } -// inline f32 get(vec3 pos) { -// vec3 scaled = pos * vec3(precision) / scaleBy; -// -// ivec3 a = { scaled.x, scaled.y, scaled.z }; -// vec3 factor = { scaled.x - a.x, scaled.y - a.y, scaled.z - a.z }; -// ivec3 b = { -// (std::min)(static_cast(std::ceil(scaled.x)), precision.x), -// (std::min)(static_cast(std::ceil(scaled.y)), precision.y), -// (std::min)(static_cast(std::ceil(scaled.z)), precision.z) }; -// -// assert(index(b.x, b.y, b.z) < data.size()); -// -// // No vertical interpolation -// if (precision.y == 0) -// return Interp::bilerp( -// data[index(a.x, a.y, a.z)], data[index(b.x, a.y, a.z)], -// data[index(a.x, a.y, b.z)], data[index(b.x, a.y, b.z)], -// factor.x, factor.z); -// -// return Interp::trilerp( -// data[index(a.x, a.y, a.z)], data[index(b.x, a.y, a.z)], -// data[index(a.x, a.y, b.z)], data[index(b.x, a.y, b.z)], -// data[index(a.x, b.y, a.z)], data[index(b.x, b.y, a.z)], -// data[index(a.x, b.y, b.z)], data[index(b.x, b.y, b.z)], -// factor.x, factor.z, factor.y); -// } - private: + /** Interpolates the data between sampled points. */ void interpolateData(); -// inline u32 innerIndex(u16 x, u16 y, u16 z) { -// return static_cast(x) * size.x * size.y + y * size.x + z; -// }; - + /** Retrieves the index for a position vector. */ inline u32 index(u16vec3 pos) { return index(pos.x, pos.y, pos.z); }; + /** Retrieves the index for the inner data from position coordinates. */ inline u32 index(u16 x, u16 y, u16 z) { return static_cast(x) * (size.x + 1) * (size.y + 1) + y * (size.x + 1) + z; }; + /** Shifts an index value from the provided `size` to the internal dimensions. */ inline u32 shiftIndexByOne(u32 ind) { u16vec3 vec = {}; @@ -80,8 +62,13 @@ private: return index(vec); }; + /** The specified size of the Sample. The actual size is 1 larger on each axis. */ u16vec3 size; + + /** The precision at which points are sampled. */ u16 precision; + + /** The point data. */ vec data {}; }; diff --git a/src/world/player/LocalPlayer.cpp b/src/world/player/LocalPlayer.cpp index 57cc4f47..c5fc081e 100644 --- a/src/world/player/LocalPlayer.cpp +++ b/src/world/player/LocalPlayer.cpp @@ -47,6 +47,10 @@ void LocalPlayer::update(Input& input, f64 delta, vec2 mouseDelta) { if (!gameGui.isInMenu()) updateInteract(input, delta); } +string LocalPlayer::getUsername() { + return "UNIMPLEMENTED"; +} + void LocalPlayer::setPos(vec3 pos, bool assert) { Player::setPos(pos, assert); renderer.camera.setPos(pos + getLookOffset()); @@ -447,4 +451,4 @@ void LocalPlayer::updateInteract(Input& input, f64 delta) { dim->wieldItemUse(target, static_cast(dim->getWorld()).getPlayer()); } } -} \ No newline at end of file +} diff --git a/src/world/player/LocalPlayer.h b/src/world/player/LocalPlayer.h index 0f2ed2bf..9b581719 100644 --- a/src/world/player/LocalPlayer.h +++ b/src/world/player/LocalPlayer.h @@ -47,6 +47,8 @@ public: void update(Input& input, f64 delta, vec2 mouseDelta); + virtual string getUsername() override; + /** The following setters call Player setters, but updates some rendering-related information. */ virtual void setPos(vec3 pos, bool assert = false) override; diff --git a/src/world/player/Player.h b/src/world/player/Player.h index dadcf041..ae541ca7 100644 --- a/src/world/player/Player.h +++ b/src/world/player/Player.h @@ -22,6 +22,8 @@ public: this->id = id; } + virtual string getUsername() = 0; + virtual void setDim(DimensionPtr dim, bool assert = false); virtual void setPos(vec3 pos, bool assert = false); diff --git a/src/world/player/ServerPlayer.cpp b/src/world/player/ServerPlayer.cpp index 23716d71..0b4a54fd 100644 --- a/src/world/player/ServerPlayer.cpp +++ b/src/world/player/ServerPlayer.cpp @@ -14,6 +14,10 @@ ServerPlayer::ServerPlayer(ServerClient& client, World& world, SubgamePtr game, inventory->createList("cursor", 1, 1); } +string ServerPlayer::getUsername() { + return client.username; +} + void ServerPlayer::assertField(Packet packet) { packet.type = Packet::Type::THIS_PLAYER_INFO; packet.sendTo(getPeer(), Packet::Channel::INTERACT); @@ -90,4 +94,4 @@ InventoryPtr ServerPlayer::getInventory() { ENetPeer* ServerPlayer::getPeer() { return client.peer; -} \ No newline at end of file +} diff --git a/src/world/player/ServerPlayer.h b/src/world/player/ServerPlayer.h index 126081e1..afa6d495 100644 --- a/src/world/player/ServerPlayer.h +++ b/src/world/player/ServerPlayer.h @@ -23,6 +23,8 @@ class ServerPlayer : public Player { public: ServerPlayer(ServerClient& client, World& world, SubgamePtr game, DimensionPtr dim); + virtual string getUsername() override; + virtual void assertField(Packet packet) override; virtual void handleAssertion(Deserializer& d) override; diff --git a/subgames/zeus/mods/auri_chat/conf.json b/subgames/zeus/mods/auri_chat/conf.json new file mode 100644 index 00000000..0be42906 --- /dev/null +++ b/subgames/zeus/mods/auri_chat/conf.json @@ -0,0 +1,5 @@ +{ + "name": "@auri:chat", + "description": "A simple chat interface and API supporting messaging and commands.", + "version": "0.0.1" +} diff --git a/subgames/zeus/mods/auri_chat/script/api.lua b/subgames/zeus/mods/auri_chat/script/api.lua new file mode 100644 index 00000000..383feef8 --- /dev/null +++ b/subgames/zeus/mods/auri_chat/script/api.lua @@ -0,0 +1,8 @@ +-- The global chat object. +_G['chat'] = { + channels = {}, + channel_order = {}, +} + +if zepha.server then runfile(_PATH .. 'api_server') +else runfile(_PATH .. 'api_client') end \ No newline at end of file diff --git a/subgames/zeus/mods/auri_chat/script/api_client.lua b/subgames/zeus/mods/auri_chat/script/api_client.lua new file mode 100644 index 00000000..71a2289e --- /dev/null +++ b/subgames/zeus/mods/auri_chat/script/api_client.lua @@ -0,0 +1,58 @@ +chat.open = false +chat.current_channel = nil +chat._message_persist_time = 5 + +-- Toggles the chat being open and listening for input. +chat.set_open = function(open) + if open == nil then chat.open = not chat.open + else chat.open = open end + chat._refresh() +end + +-- Sends a message from the player to the chat channel. +chat.send = function(message) + chat.send_channel(nil, message) +end + +-- Sends a message from player to the channel provided. +chat.send_channel = function(channel_name, message) + zepha.send_message('@auri:chat:message', { + channel = channel_name, + content = message + }) +end + +local function add_channel(channel) + print(channel.identifier) + chat.channels[channel.identifier] = { + name = channel.name, + icon = channel.icon, + history = {}, + _current_history_head = 1 + } + + chat.channel_order = channel.order + if chat.current_channel == nil then chat.current_channel = channel.identifier end + chat._refresh() +end + +local function add_message(message) + local channel = chat.channels[message.channel] + if not channel then return end + + table.insert(channel.history, { + from = message.from, + content = message.content, + time = zepha.time.s() + }) + + chat._refresh() + zepha.after(chat._refresh, chat._message_persist_time) +end + +zepha.bind('message', function(channel, message) + if not channel:starts_with('@auri:chat') then return end + + if channel == '@auri:chat:new_channel' then add_channel(message) end + if channel == '@auri:chat:message' then add_message(message) end +end) \ No newline at end of file diff --git a/subgames/zeus/mods/auri_chat/script/api_server.lua b/subgames/zeus/mods/auri_chat/script/api_server.lua new file mode 100644 index 00000000..9318c38f --- /dev/null +++ b/subgames/zeus/mods/auri_chat/script/api_server.lua @@ -0,0 +1,63 @@ +-- Creates a new chat channel with the name and options provided. +chat.create_channel = function(identifier, options) + chat.channels[identifier] = { + name = options.name or identifier, + icon = options.icon, + history = {}, + } + + table.insert(chat.channel_order, identifier) + + zepha.send_message('@auri:chat:new_channel', { + identifier = identifier, + name = options.name or identifier, + icon = options.icon, + order = chat.channel_order + }) +end + +-- Sends a message from the sender specified to the chat channel. +chat.send = function(sender, message) + chat.send_channel(sender, nil, message) +end + +-- Sends a message from the sender specified to the channel provided. +chat.send_channel = function(sender, channel_name, message) + if not channel_name then channel_name = 'chat' end + local channel = chat.channels[channel_name] + if not channel then return end + + table.insert(channel.history, { + from = sender, + content = message, + time = zepha.time.s() + }) + + zepha.send_message('@auri:chat:message', { + channel = channel_name, + from = sender, + content = message + }) +end + +zepha.bind('player_join', function(player) + for _, identifier in ipairs(chat.channel_order) do + local channel = chat.channels[identifier] + zepha.send_message('@auri:chat:new_channel', { + identifier = identifier, + name = channel.name or identifier, + icon = channel.icon, + order = chat.channel_order + }) + end +end) + +zepha.bind('message', function(channel, message, player) + if not channel:starts_with('@auri:chat') then return end + + if channel == '@auri:chat:message' then + local user = player:get_username() + local color = user:sub(16, 16) + chat.send_channel('`b`c' .. color .. user, message.channel, message.content) + end +end) \ No newline at end of file diff --git a/subgames/zeus/mods/auri_chat/script/category_icon.xcf b/subgames/zeus/mods/auri_chat/script/category_icon.xcf new file mode 100644 index 00000000..ebea6994 Binary files /dev/null and b/subgames/zeus/mods/auri_chat/script/category_icon.xcf differ diff --git a/subgames/zeus/mods/auri_chat/script/gui.lua b/subgames/zeus/mods/auri_chat/script/gui.lua new file mode 100644 index 00000000..8be99ef1 --- /dev/null +++ b/subgames/zeus/mods/auri_chat/script/gui.lua @@ -0,0 +1,102 @@ +local max_messages = 8 + +local chat_wrap = zepha.build_gui(function() + return Gui.Rect { + position = { 4, '100%' }, + position_anchor = { 0, '200%' }, + size = { 256, 23 + max_messages * 8 }, + + Gui.Rect { + key = 'chat_tabs', + position = { 0, -10 } + }, + + Gui.Rect { + key = 'chat_box', + size = { 256, 2 + max_messages * 8 } + }, + + Gui.Rect { + key = 'chat_input', + size = { 256, 10 }, + position = { 0, 3 + max_messages * 8 } + } + } +end) + +local chat_box = chat_wrap:get('chat_box') +local chat_tabs = chat_wrap:get('chat_tabs') +local chat_input = chat_wrap:get('chat_input') + +-- Rerenders the chat gui. +chat._refresh = function() + chat_box:clear() + chat_tabs:clear() + + if chat.open then + local i = 0 + for _, identifier in ipairs(chat.channel_order) do + local channel = chat.channels[identifier] + chat_tabs:append(function() + return Gui.Rect { + size = { 48, 10 }, + position = { i * 49, 0 }, + background = (chat.current_channel == identifier) and '#0005' or '#0002', + + Gui.Rect { + position = { 2, 2 }, + size = { 8 * (2/3), 8 * (2/3) }, + background = 'multiply(' .. channel.icon .. ', ' .. + (chat.current_channel == identifier and '#ffe791' or '#fff') .. ')' + }, + + Gui.Text { + color = (chat.current_channel == identifier) and '#ffe791' or '#fff', + position = { 8, 2 }, + scale = { 2.02/3, 2.02/3 }, + content = channel.name + } + } + end) + i = i + 1 + end + end + + local channel = chat.channels[chat.current_channel] + if not channel then return end + + local now = zepha.time.s() + local count = 0 + + local start = math.max(chat.open and 1 or channel._current_history_head, #channel.history - max_messages + 1) + + for i = #channel.history, start, -1 do + local message = channel.history[i] + if now - message.time > chat._message_persist_time and not chat.open then + channel._current_history_head = i + 1 + else + chat_box:append(function() + return Gui.Text { + position = { 2, 2 + (max_messages - count - 1) * 8 }, + background = chat.open and '#0000' or '#0003', + scale = { 2.02/3, 2.02/3 }, + content = '`c7[` `r' .. message.from .. '`r` `c7]`cr ' .. message.content .. '`r' + } + end) + count = count + 1 + end + end + + chat_box.background = chat.open and '#0005' or '#0000' + chat_input.background = chat.open and '#0005' or '#0000' +end + +zepha.player:get_hud():append(chat_wrap) +chat._refresh() + +-- Keyboard shortcut to toggle the chat. +zepha.register_keybind(":open_chat", { + description = "Open Chat", + default = zepha.keys.p, + on_press = chat.set_open +}) \ No newline at end of file diff --git a/subgames/zeus/mods/auri_chat/script/init.lua b/subgames/zeus/mods/auri_chat/script/init.lua new file mode 100644 index 00000000..398fd4a0 --- /dev/null +++ b/subgames/zeus/mods/auri_chat/script/init.lua @@ -0,0 +1,8 @@ +runfile(_PATH .. 'api') +if zepha.client then runfile(_PATH .. 'gui') end + +if zepha.server then + chat.create_channel('chat', { name = 'Chat', icon = '@auri:chat:chat_icon' }) +end + +runfile(_PATH .. 'test') \ No newline at end of file diff --git a/subgames/zeus/mods/auri_chat/script/test.lua b/subgames/zeus/mods/auri_chat/script/test.lua new file mode 100644 index 00000000..8038f065 --- /dev/null +++ b/subgames/zeus/mods/auri_chat/script/test.lua @@ -0,0 +1,29 @@ +if zepha.server then + chat.create_channel('commands', { name = 'Commands', icon = '@auri:chat:commands_icon' }) + chat.create_channel('debug', { name = 'Debug', icon = '@auri:chat:debug_icon' }) +-- +-- local random_messages = { +-- { '`b`cbA`cdu`cfr`cdi`cb!', 'the quick brown fox jumps over the lazy dog' }, +-- { '`b`cbA`cdu`cfr`cdi`cb!', 'lorum ipsum dolor sit amet consequitor lorem ipsum dolor sit amet' }, +-- { '`b`cbZ`cay`cet`cch`cdi`c5a', '`iomg shut the fuck up`r' }, +-- { '`b`cbA`cdu`cfr`cdi`cb!', 'lol epic' }, +-- { '`b`cbA`cdu`cfr`cdi`cb!', 'chat mod' }, +-- { '`b`cbZ`cay`cet`cch`cdi`c5a', 'testing testing 123' }, +-- { '`bJAYCEE', 'PENIS!' }, +-- { '`b`cbA`cdu`cfr`cdi`cb!', '#epic' }, +-- { 'alphabet', '`bABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789' } +-- } +-- +-- local function random_message() +-- local message = random_messages[math.floor(math.random() * #random_messages) + 1] +-- chat.send(message[1], message[2]) +-- zepha.after(random_message, math.random() > 0.5 and math.random() * 1 or math.random() * 2) +-- end +-- random_message() +elseif zepha.client then + zepha.register_keybind(":send_test_message", { + description = "Send test message", + default = zepha.keys.j, + on_press = function() chat.send('hihihih') end + }) +end \ No newline at end of file diff --git a/subgames/zeus/mods/auri_chat/textures/chat_icon.png b/subgames/zeus/mods/auri_chat/textures/chat_icon.png new file mode 100644 index 00000000..4976b923 Binary files /dev/null and b/subgames/zeus/mods/auri_chat/textures/chat_icon.png differ diff --git a/subgames/zeus/mods/auri_chat/textures/commands_icon.png b/subgames/zeus/mods/auri_chat/textures/commands_icon.png new file mode 100644 index 00000000..bd823787 Binary files /dev/null and b/subgames/zeus/mods/auri_chat/textures/commands_icon.png differ diff --git a/subgames/zeus/mods/auri_chat/textures/debug_icon.png b/subgames/zeus/mods/auri_chat/textures/debug_icon.png new file mode 100644 index 00000000..d4af8254 Binary files /dev/null and b/subgames/zeus/mods/auri_chat/textures/debug_icon.png differ diff --git a/subgames/zeus/mods/auri_world_edit/script/init.lua b/subgames/zeus/mods/auri_world_edit/script/init.lua new file mode 100644 index 00000000..d2118d85 --- /dev/null +++ b/subgames/zeus/mods/auri_world_edit/script/init.lua @@ -0,0 +1,48 @@ +local box = nil +local pos1 = nil +local pos2 = nil + +zepha.register_entity('@auri:world_edit:box', { + display = 'wireframe', + display_stroke = '#0e7', + + update_pos = function(self) + if pos2 == nil then + self.object.pos = pos1 + self.object.scale = 1 + else + local min = V(math.min(pos1.x, pos2.x), math.min(pos1.y, pos2.y), math.min(pos1.z, pos2.z)) + local max = V(math.max(pos1.x, pos2.x), math.max(pos1.y, pos2.y), math.max(pos1.z, pos2.z)) + local scale = max - min + 1 + + self.object.pos = min + self.object.scale = scale + end + end +}) + +zepha.register_item(':wand', { + name = 'World Edit Wand', + textures = { '@auri:world_edit:wand' }, + stack = 1, + + on_use_client = function(stack, target, player) + if box == nil then + box = zepha.player.dim:add_entity(V(), '@auri:world_edit:box') + end + + if pos1 == nil or pos2 ~= nil then + pos2 = nil + pos1 = V(target.pos or player.pos):floor() + else + pos2 = V(target.pos or player.pos):floor() + end + + box:update_pos() + end +}) + +zepha.bind('new_player', function(player) + local inv = player:get_inventory():get_list('hot_wheel_1') + inv:add_stack({ '@auri:world_edit:wand', 1 }) +end) diff --git a/subgames/zeus/mods/auri_world_edit/textures/wand.png b/subgames/zeus/mods/auri_world_edit/textures/wand.png new file mode 100644 index 00000000..0e864dd7 Binary files /dev/null and b/subgames/zeus/mods/auri_world_edit/textures/wand.png differ diff --git a/subgames/zeus/mods/zeus_flowers/textures/pink.png b/subgames/zeus/mods/zeus_flowers/textures/pink.png new file mode 100755 index 00000000..a78e9d1f Binary files /dev/null and b/subgames/zeus/mods/zeus_flowers/textures/pink.png differ diff --git a/subgames/zeus/mods/zeus_inventory/textures/player_frame.png b/subgames/zeus/mods/zeus_inventory/textures/player_frame.png new file mode 100644 index 00000000..0495fc62 Binary files /dev/null and b/subgames/zeus/mods/zeus_inventory/textures/player_frame.png differ diff --git a/subgames/zeus/mods/zeus_world/script/biomes/desert.lua b/subgames/zeus/mods/zeus_world/script/biomes/desert.lua index eb045dde..59afe444 100644 --- a/subgames/zeus/mods/zeus_world/script/biomes/desert.lua +++ b/subgames/zeus/mods/zeus_world/script/biomes/desert.lua @@ -1,104 +1,105 @@ -local identifier = "zeus:world:desert" - -local structures = {} - -table.insert(structures, zepha.create_structure({ - origin = V(), - probability = 0.001, - layout = {{{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}} -})) - -table.insert(structures, zepha.create_structure({ - origin = V(), - probability = 0.001, - layout = {{{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}} -})) - -table.insert(structures, zepha.create_structure({ - origin = V(), - probability = 0.001, - layout = {{{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}} -})) - -local noise = { --- heightmap = { --- module = "add", --- sources = {{ --- module = "min", --- sources = {{ --- module = "turbulence", --- power = 1, --- frequency = 0.3, +-- local identifier = "zeus:world:desert" +-- +-- local structures = {} +-- +-- table.insert(structures, zepha.create_structure({ +-- origin = V(), +-- probability = 0.001, +-- layout = {{{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}} +-- })) +-- +-- table.insert(structures, zepha.create_structure({ +-- origin = V(), +-- probability = 0.001, +-- layout = {{{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}} +-- })) +-- +-- table.insert(structures, zepha.create_structure({ +-- origin = V(), +-- probability = 0.001, +-- layout = {{{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}, {{ "zeus:default:cactus" }}} +-- })) +-- +-- local noise = { +-- -- heightmap = runfile(_PATH .. 'world_noise') +-- -- heightmap = { +-- -- module = "add", +-- -- sources = {{ +-- -- module = "min", +-- -- sources = {{ +-- -- module = "turbulence", +-- -- power = 1, +-- -- frequency = 0.3, +-- -- source = { +-- -- module = "add", +-- -- sources = {{ +-- -- -- Elevation +-- -- module = "scale_bias", +-- -- source = { +-- -- module = "spheres", +-- -- frequency = 0.2 +-- -- }, +-- -- scale = 20 +-- -- }, { +-- -- -- Features +-- -- module = "scale_bias", +-- -- source = { +-- -- module = "perlin", +-- -- frequency = 0.1, +-- -- octaves = 6, +-- -- }, +-- -- scale = 8 +-- -- }} +-- -- } +-- -- }, { +-- -- module = "scale_bias", +-- -- scale = 1, +-- -- bias = 1000, +-- -- source = { +-- -- module = "perlin", +-- -- frequency = 0.2 +-- -- } +-- -- }} +-- -- }, { +-- -- module = "const", +-- -- value = -40 +-- -- }} +-- -- } +-- volume = { +-- module = "scale", +-- y_scale = 2, +-- source = { +-- module = "add", +-- scalar = -2200, +-- source = { +-- module = "multiply", +-- scalar = 3000, -- source = { --- module = "add", --- sources = {{ --- -- Elevation --- module = "scale_bias", --- source = { --- module = "spheres", --- frequency = 0.2 --- }, --- scale = 20 --- }, { --- -- Features --- module = "scale_bias", --- source = { --- module = "perlin", --- frequency = 0.1, --- octaves = 6, --- }, --- scale = 8 --- }} +-- module = "simplex", +-- frequency = 0.0025, +-- octaves = 6, +-- lacunarity = 2 -- } --- }, { --- module = "scale_bias", --- scale = 1, --- bias = 1000, --- source = { --- module = "perlin", --- frequency = 0.2 --- } --- }} --- }, { --- module = "const", --- value = -40 --- }} +-- } +-- } -- } - volume = { - module = "scale", - y_scale = 2, - source = { - module = "add", - scalar = -2200, - source = { - module = "multiply", - scalar = 3000, - source = { - module = "simplex", - frequency = 0.0025, - octaves = 6, - lacunarity = 2 - } - } - } - } -} - -zepha.register_biome(identifier, { - environment = { - temperature = 40/100, - humidity = 20/100, - roughness = 10/100 - }, - blocks = { - top = "zeus:default:sand", - soil = "zeus:default:sand", - rock = "zeus:default:sandstone" - }, - tags = { natural = 1, default = 1 }, - biome_tint = "#e6fa61", - noise = noise, - structures = structures -}) - -return identifier; +-- } +-- +-- zepha.register_biome(identifier, { +-- environment = { +-- temperature = 40/100, +-- humidity = 20/100, +-- roughness = 10/100 +-- }, +-- blocks = { +-- top = "zeus:default:sand", +-- soil = "zeus:default:sand", +-- rock = "zeus:default:sandstone" +-- }, +-- tags = { natural = 1, default = 1 }, +-- biome_tint = "#e6fa61", +-- noise = noise, +-- structures = structures +-- }) +-- +-- return identifier; diff --git a/subgames/zeus/mods/zeus_world/script/biomes/plains.lua b/subgames/zeus/mods/zeus_world/script/biomes/plains.lua index 9442f181..bf2a7457 100644 --- a/subgames/zeus/mods/zeus_world/script/biomes/plains.lua +++ b/subgames/zeus/mods/zeus_world/script/biomes/plains.lua @@ -19,26 +19,6 @@ local structures = {} -- layout = {{{ "zeus:flowers:flower_geranium" }}} -- })) -for i = 1, 5 do - table.insert(structures, zepha.create_structure({ - origin = V(), - probability = 0.1, - layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}} - })) -end --- -table.insert(structures, zepha.create_structure({ - origin = V(), - probability = 0.025, - layout = {{{ "zeus:flowers:flower_geranium" }}} -})) - -table.insert(structures, zepha.create_structure({ - origin = V(), - probability = 0.025, - layout = {{{ "zeus:flowers:flower_white_dandelion" }}} -})) - table.insert(structures, zepha.create_structure({ origin = V(1), probability = 0.025, @@ -141,26 +121,70 @@ table.insert(structures, zepha.create_structure({ } })) +for i = 1, 5 do + table.insert(structures, zepha.create_structure({ + origin = V(), + probability = 0.1, + layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}} + })) +end +-- +table.insert(structures, zepha.create_structure({ + origin = V(), + probability = 0.025, + layout = {{{ "zeus:flowers:flower_geranium" }}} +})) + +table.insert(structures, zepha.create_structure({ + origin = V(), + probability = 0.025, + layout = {{{ "zeus:flowers:flower_white_dandelion" }}} +})) + local noise = { --- heightmap = runfile(_PATH .. 'world_noise'), - volume = { - module = "scale", - y_scale = 2, - source = { - module = "add", - scalar = -2200, - source = { - module = "multiply", - scalar = 3000, + heightmap = { + module = "add", + sources = { + runfile(_PATH .. 'world_noise'), + { + module = "max", + scalar = 0, source = { - module = "simplex", - frequency = 0.0025, - octaves = 6, - lacunarity = 2 + module = "add", + scalar = -150, + source = { + module = "multiply", + scalar = 400, + source = { + module = "simplex", + frequency = 0.00025, + lacunarity = 2.5, + octaves = 8, + persistence = 0.55 + } + } } } } } +-- volume = { +-- module = "scale", +-- y_scale = 2, +-- source = { +-- module = "add", +-- scalar = -2200, +-- source = { +-- module = "multiply", +-- scalar = 3000, +-- source = { +-- module = "simplex", +-- frequency = 0.0025, +-- octaves = 6, +-- lacunarity = 2 +-- } +-- } +-- } +-- } } zepha.register_biome(identifier, { diff --git a/subgames/zeus/mods/zeus_world/script/biomes/world_noise.lua b/subgames/zeus/mods/zeus_world/script/biomes/world_noise.lua index cb1eb88c..51d370a6 100644 --- a/subgames/zeus/mods/zeus_world/script/biomes/world_noise.lua +++ b/subgames/zeus/mods/zeus_world/script/biomes/world_noise.lua @@ -1,24 +1,11 @@ return { - module = "add", - sources = {{ - -- Elevation - module = "scale_bias", - source = { - module = "perlin", - frequency = 0.002, - octaves = 8 - }, - scale = 250, - bias = -32 - }, { - -- Features - module = "scale_bias", - source = { - module = "perlin", - frequency = 0.2, - octaves = 3, - }, - scale = 6, - bias = 6 - }} + module = "multiply", + scalar = 100, + source = { + module = "simplex", + frequency = 0.0002, + octaves = 5, + lacunarity = 3, + persistence = 0.45 + } }; \ No newline at end of file diff --git a/subgames/zeus/mods/zeus_world/script/init.lua b/subgames/zeus/mods/zeus_world/script/init.lua index 831756cd..49e73745 100644 --- a/subgames/zeus/mods/zeus_world/script/init.lua +++ b/subgames/zeus/mods/zeus_world/script/init.lua @@ -5,8 +5,8 @@ zepha.create_dimension('zeus:world:default', { biomes = { '#natural', '#default' } }) -zepha.create_dimension('zeus:world:endless_desert', { - biomes = { 'zeus:world:desert' } -}) +-- zepha.create_dimension('zeus:world:endless_desert', { +-- biomes = { 'zeus:world:desert' } +-- }) zepha.set_default_dimension('zeus:world:default') \ No newline at end of file