Read description VVV
World edit mod, only selects for now. Text Formatting Tweak default font to look good in bold. Fix Server locking up when too many player packets are sent. Added chat mod, which *almost* works. Update world noise.master
|
@ -16,3 +16,15 @@ string.split = function(input, sep, op)
|
|||
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
|
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Before Width: | Height: | Size: 953 B After Width: | Height: | Size: 1.6 KiB |
|
@ -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<SelectionBox>& boxes, float width) {
|
||||
this->width = width;
|
||||
buildMesh(boxes);
|
||||
this->model->fromMesh(WireframeEntity::createMesh(boxes, width));
|
||||
}
|
||||
|
||||
uptr<EntityMesh> WireframeEntity::createMesh(const vec<SelectionBox>& boxes, f32 wireWidth, vec3 stroke, vec4 fill) {
|
||||
vec<u32> indices {};
|
||||
indices.reserve(boxes.size() * 36 * (12 + fill.a ? 1 : 0));
|
||||
vec<EntityVertex> vertices {};
|
||||
vertices.reserve(boxes.size() * 8 * 12 + (fill.a ? 24 : 0));
|
||||
|
||||
void WireframeEntity::buildMesh(const std::vector<SelectionBox>& boxes) {
|
||||
indOffset = 0;
|
||||
for (const let& box : boxes) WireframeEntity::createSelectionBoxVertices(
|
||||
box, wireWidth, vec4(stroke, 1), fill, vertices, indices);
|
||||
|
||||
vertices.clear();
|
||||
indices.clear();
|
||||
|
||||
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<EntityMesh> mesh = std::make_unique<EntityMesh>();
|
||||
uptr<EntityMesh> mesh = make_unique<EntityMesh>();
|
||||
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<EntityMesh> WireframeEntity::createMesh(const SelectionBox& box, f32 wireWidth, vec3 stroke, vec4 fill) {
|
||||
return WireframeEntity::createMesh(vec<SelectionBox> { box }, wireWidth, stroke, fill);
|
||||
}
|
||||
|
||||
std::vector<EntityVertex> 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 }, {}, {}},
|
||||
void WireframeEntity::createSelectionBoxVertices(const SelectionBox& box, f32 wireWidth,
|
||||
vec4 stroke, vec4 fill, vec<EntityVertex>& vertices, vec<u32>& indices) {
|
||||
|
||||
/*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 }, {}, {}},
|
||||
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();
|
||||
|
||||
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<u32, 36> 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
|
||||
};
|
||||
|
||||
std::vector<unsigned int> myInds{
|
||||
for (u32 i : boxIndices) indices.push_back(i + indOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void WireframeEntity::createStrokeVertices(vec3 a, vec3 b, f32 wireWidth,
|
||||
vec4 color, vec<EntityVertex>& vertices, vec<u32>& indices) {
|
||||
|
||||
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<u32, 36> 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);
|
||||
}
|
|
@ -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<Model>()), Entity(game, dim),
|
||||
color(color) {};
|
||||
WireframeEntity(SubgamePtr game, DimensionPtr dim, vec3 stroke, vec4 fill = vec4(0)) :
|
||||
DrawableEntity(game, dim, std::make_shared<Model>()), Entity(game, dim), stroke(stroke), fill(fill) {};
|
||||
|
||||
void updateMesh(const std::vector<SelectionBox>& boxes, float width);
|
||||
void updateMesh(const vec<SelectionBox>& boxes, f32 width);
|
||||
|
||||
static uptr<EntityMesh> createMesh(const vec<SelectionBox>& boxes,
|
||||
f32 wireWidth, vec3 stroke = vec3(1), vec4 fill = vec4(0));
|
||||
|
||||
static uptr<EntityMesh> createMesh(const SelectionBox& box,
|
||||
f32 wireWidth, vec3 stroke = vec3(1), vec4 fill = vec4(0));
|
||||
|
||||
private:
|
||||
std::vector<EntityVertex> vertices{};
|
||||
std::vector<unsigned int> indices{};
|
||||
static void createSelectionBoxVertices(const SelectionBox& box, f32 wireWidth,
|
||||
vec4 stroke, vec4 fill, vec<EntityVertex>& vertices, vec<u32>& indices);
|
||||
|
||||
void buildMesh(const std::vector<SelectionBox>& boxes);
|
||||
static void createStrokeVertices(vec3 a, vec3 b, f32 wireWidth,
|
||||
vec4 color, vec<EntityVertex>& vertices, vec<u32>& 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 {};
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,11 @@ DebugGui::DebugGui(u16vec2 buffer, SubgamePtr game, LocalWorld& world, vec<strin
|
|||
Font f(game.l()->textures, fontRef);
|
||||
|
||||
auto crosshairText = make_shared<GuiText>("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<GuiText>("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<GuiLabelledGraph>("interpGraph");
|
||||
|
@ -219,7 +219,8 @@ void DebugGui::update(sptr<LocalPlayer> 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<GuiText>("crosshairText")->setText(def.name + " (" + def.identifier + ") [" + std::to_string(def.index) + "]");
|
||||
get<GuiText>("crosshairText")->setText(
|
||||
"`b" + def.name + " (`r` `c7" + def.identifier + "`cr - " + std::to_string(def.index) + "` `b)");
|
||||
}
|
||||
else {
|
||||
get<GuiText>("crosshairText")->setText("");
|
||||
|
|
|
@ -43,7 +43,7 @@ void GuiInventoryItem::create(glm::vec2 scale, unsigned short count, ItemDef& de
|
|||
|
||||
if (count > 1) {
|
||||
auto text = std::make_shared<GuiText>("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 });
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
//
|
||||
// Created by aurailus on 25/12/18.
|
||||
//
|
||||
|
||||
#include <utility>
|
||||
|
||||
#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> GuiText::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds) {
|
||||
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
|
||||
glm::vec2 offset = SerialGui::get<glm::vec2>(elem, "position_anchor");
|
||||
glm::vec2 size = SerialGui::get<glm::vec2>(elem, "size", bounds);
|
||||
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
|
||||
glm::vec2 scale = SerialGui::get<glm::vec2>(elem, "scale");
|
||||
if (scale == glm::vec2{ 0, 0 }) scale = { 1, 1 };
|
||||
sptr<GuiText> GuiText::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, ivec2 bounds) {
|
||||
vec2 pos = SerialGui::get<vec2>(elem, "position", bounds);
|
||||
vec2 offset = SerialGui::get<vec2>(elem, "position_anchor");
|
||||
vec2 size = SerialGui::get<vec2>(elem, "size", bounds);
|
||||
vec4 padding = SerialGui::get<vec4>(elem, "padding", bounds);
|
||||
vec2 scale = SerialGui::get<vec2>(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<std::string>("background", "#0000"));
|
||||
glm::vec4 color = Util::hexToColorVec(elem.get_or<std::string>("color", "#fff"));
|
||||
std::string content = elem.get_or<std::string>("content", "");
|
||||
vec4 backgroundColor = Util::hexToColorVec(elem.get_or<string>("background", "#0000"));
|
||||
vec4 textColor = Util::hexToColorVec(elem.get_or<string>("color", "#fff"));
|
||||
string content = elem.get_or<string>("content", "");
|
||||
|
||||
auto text = std::make_shared<GuiText>(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<EntityVertex> textVertices;
|
||||
textVertices.reserve(text.length() * 8 + 200);
|
||||
std::vector<unsigned int> textIndices;
|
||||
textIndices.reserve(text.length() * 12 + 240);
|
||||
vec<EntityVertex> vertices;
|
||||
vertices.reserve(text.length() * 8 + 200);
|
||||
vec<u32> 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.
|
||||
vec<string> lines;
|
||||
{
|
||||
std::stringstream textStream(text);
|
||||
string line;
|
||||
while (std::getline(textStream, line, '\n')) lines.emplace_back(line);
|
||||
}
|
||||
|
||||
lineWidth = 0;
|
||||
}
|
||||
else lineWidth += font.getCharWidth(c) + 1;
|
||||
}
|
||||
vec3 offset = {};
|
||||
u32 h = Font::charHeight;
|
||||
|
||||
//Draw Characters
|
||||
bool bold = false;
|
||||
bool italic = false;
|
||||
i32 underline = -1;
|
||||
i32 strikethrough = -1;
|
||||
u32 strikethroughVertStart = 0;
|
||||
vec4 color = textColor;
|
||||
|
||||
bool emptyLine = true;
|
||||
xOffset = 0;
|
||||
yOffset = 0;
|
||||
for (usize i = 0; i < lines.size(); i++) {
|
||||
let& line = lines[i];
|
||||
bool empty = line.find_first_not_of(" \t\n") == -1;
|
||||
|
||||
for (unsigned int i = 0; i < this->text.length() + 1; i++) {
|
||||
char c = this->text[i];
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (usize j = 0; j < line.length() + 1; j++) {
|
||||
char c = j < line.length() ? line[j] : ' ';
|
||||
if (c == '\t') c = ' ';
|
||||
|
||||
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 {
|
||||
emptyLine = false;
|
||||
u32 v;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << code;
|
||||
ss >> v;
|
||||
color = COLORS[v];
|
||||
}
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
if (j == 0) {
|
||||
c *= glm::vec3{ 0.4, 0.4, 0.45 };
|
||||
xOffset += 1;
|
||||
yOffset += 1;
|
||||
}
|
||||
else {
|
||||
xOffset -= 1;
|
||||
yOffset -= 1;
|
||||
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{});
|
||||
escape_formatting:
|
||||
if (j == line.length()) continue;
|
||||
|
||||
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);
|
||||
u32 w = font.getCharWidth(c) + 1;
|
||||
vec4 UV = font.getCharUVs(c);
|
||||
|
||||
indOffset += 4;
|
||||
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;
|
||||
}
|
||||
|
||||
xOffset += charWidth;
|
||||
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;
|
||||
}
|
||||
|
||||
auto m = std::make_unique<EntityMesh>();
|
||||
m->create(textVertices, textIndices);
|
||||
offset.x += w;
|
||||
}
|
||||
|
||||
auto model = std::make_shared<Model>();
|
||||
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;
|
||||
}
|
||||
|
||||
let m = make_unique<EntityMesh>();
|
||||
m->create(vertices, indices);
|
||||
|
||||
let model = make_shared<Model>();
|
||||
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<EntityVertex>& vertices, vec<u32>& indices, u32& ind, const u32 insert) {
|
||||
|
||||
vec<EntityVertex> 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<vec4, 16> 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<u32, 6> GuiText::INDICES = { 0, 1, 2, 2, 3, 0 };
|
||||
|
||||
const vec4 GuiText::BG_MULTIPLE = { 0.3, 0.3, 0.35, 0.75 };
|
|
@ -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:
|
||||
GuiText() = default;
|
||||
|
||||
explicit GuiText(const std::string& key);
|
||||
explicit GuiText(const string& key) : GuiComponent(key) {};
|
||||
|
||||
static std::shared_ptr<GuiText>
|
||||
fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds);
|
||||
/** Creates a text component from a serialized lua element. */
|
||||
static sptr<GuiText> fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, ivec2 bounds);
|
||||
|
||||
void create(glm::vec2 scale, glm::vec4 padding, glm::vec4 bgcolor, glm::vec4 color, Font font);
|
||||
/** Creates a new text component. */
|
||||
void create(vec2 scale, vec4 padding, vec4 textColor, vec4 backgroundColor, Font font);
|
||||
|
||||
unsigned int getWidth();
|
||||
/** Returns the width in display pixels of the text. */
|
||||
u32 getWidth();
|
||||
|
||||
void setText(std::string text);
|
||||
/** Sets the text to the string provided. */
|
||||
void setText(string text);
|
||||
|
||||
std::string getText();
|
||||
/** Returns the current text string. */
|
||||
string getText();
|
||||
|
||||
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<EntityVertex>& vertices, vec<u32>& indices, u32& ind, const u32 insert = -1);
|
||||
|
||||
string text;
|
||||
vec4 textColor {};
|
||||
vec4 backgroundColor {};
|
||||
|
||||
u32 width = 0;
|
||||
|
||||
static const array<vec4, 16> COLORS;
|
||||
static const array<u32, 6> INDICES;
|
||||
static const vec4 BG_MULTIPLE;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ void GuiCellGraph::create(f32 scale, vec4 padding, u16 count, const string& titl
|
|||
add(background);
|
||||
|
||||
let label = make_shared<GuiText>();
|
||||
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);
|
||||
|
|
|
@ -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<GuiText>("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 });
|
||||
|
||||
|
|
|
@ -30,15 +30,14 @@ void GuiPerfGraph::create(f32 scale, vec4 padding, const vec<string>& sections,
|
|||
meter->setPos({ GRAPH_PAD_X, GRAPH_PAD_Y });
|
||||
|
||||
auto label = std::make_shared<GuiText>("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<GuiText>();
|
||||
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 });
|
||||
|
|
|
@ -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<GuiText>("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);
|
||||
|
|
|
@ -34,12 +34,12 @@ MainMenuScene::MainMenuScene(Client& client) :
|
|||
components->add(branding);
|
||||
{
|
||||
auto zephaText = make_shared<GuiText>("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<GuiText>("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);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <algorithm>
|
||||
#include <stb_image/stb_image.h>
|
||||
#include <cute_files/cute_files.h>
|
||||
#include <util/Types.h>
|
||||
#include <util/Util.h>
|
||||
|
||||
#include "TextureAtlas.h"
|
||||
|
||||
|
@ -181,7 +183,7 @@ std::shared_ptr<AtlasRef> TextureAtlas::generateTexture(std::string req) {
|
|||
std::string paramsString = req.substr(paramsBegin + 1, paramsEnd - paramsBegin - 1);
|
||||
|
||||
std::vector<std::string> 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<AtlasRef> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,11 +65,14 @@ sol::table Api::Usertype::Dimension::add_entity_c(sol::this_state s, glm::vec3 p
|
|||
auto displayType = luaEntity.get<sol::optional<std::string>>("display");
|
||||
if (!displayType) throw std::runtime_error("entity '" + identifier + "' is missing the display property.");
|
||||
|
||||
auto displayObject = luaEntity.get<sol::optional<std::string>>("display_object");
|
||||
if (!displayObject) throw std::runtime_error("entity '" + identifier + "' is missing the display_object property.");
|
||||
auto displayObject = luaEntity.get<sol::optional<std::string>>(
|
||||
(*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<sol::optional<std::string>>("display_texture");
|
||||
if (strncmp(displayType->data(), "model", 5) == 0 && !displayTexture)
|
||||
auto displayTexture = luaEntity.get<sol::optional<std::string>>(
|
||||
(*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<sol::optional<std::string>>("display");
|
||||
if (!displayType) throw std::runtime_error("entity '" + identifier + "' is missing the display property.");
|
||||
|
||||
auto displayObject = luaEntity.get<sol::optional<std::string>>("display_object");
|
||||
if (!displayObject) throw std::runtime_error("entity '" + identifier + "' is missing the display_object property.");
|
||||
auto displayObject = luaEntity.get<sol::optional<std::string>>(
|
||||
(*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<sol::optional<std::string>>("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();
|
||||
|
|
|
@ -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<glm::vec3>()) entity->setScale(scale.as<glm::vec3>());
|
||||
else entity->setScale(scale.as<f32>());
|
||||
}
|
||||
|
||||
void Api::Usertype::Entity::snap_scale(float scale) {
|
||||
entity->setScale(scale);
|
||||
void Api::Usertype::Entity::snap_scale(sol::object scale) {
|
||||
if (scale.is<glm::vec3>()) entity->setScale(scale.as<glm::vec3>());
|
||||
else entity->setScale(scale.as<f32>());
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<std::shared_ptr<LuaGuiElement>>()) children.push_back(elem.as<std::shared_ptr<LuaGuiElement>>());
|
||||
else if (elem.is<sol::function>())
|
||||
children.push_back(call(s, elem.as<sol::function>()).as<std::shared_ptr<LuaGuiElement>>());
|
||||
else if (elem.is<sol::protected_function>())
|
||||
children.push_back(call(s, elem.as<sol::protected_function>()).as<std::shared_ptr<LuaGuiElement>>());
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ServerPlayer>("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<LuaGuiElement> hud) {
|
|||
void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core) {
|
||||
lua.new_usertype<LocalPlayer>("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,
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
class LuaGuiElement;
|
||||
|
||||
namespace Api::Usertype {
|
||||
class ServerPlayer : public SubgameUsertype {
|
||||
class ServerPlayer;
|
||||
class LocalPlayer;
|
||||
}
|
||||
|
||||
class Api::Usertype::ServerPlayer : public SubgameUsertype {
|
||||
public:
|
||||
ServerPlayer(PlayerPtr player) : player(player) {}
|
||||
|
||||
|
@ -23,6 +27,8 @@ namespace Api::Usertype {
|
|||
|
||||
unsigned int get_id();
|
||||
|
||||
string get_username();
|
||||
|
||||
glm::vec3 get_pos();
|
||||
|
||||
glm::vec3 get_block_pos();
|
||||
|
@ -70,7 +76,7 @@ namespace Api::Usertype {
|
|||
static void bind(State state, sol::state& lua, sol::table& core);
|
||||
};
|
||||
|
||||
class LocalPlayer : public ServerPlayer {
|
||||
class Api::Usertype::LocalPlayer : public ServerPlayer {
|
||||
public:
|
||||
LocalPlayer(PlayerPtr player) : ServerPlayer(player) {}
|
||||
|
||||
|
@ -86,4 +92,3 @@ namespace Api::Usertype {
|
|||
|
||||
static void bind(State state, sol::state& lua, sol::table& core);
|
||||
};
|
||||
}
|
|
@ -58,9 +58,8 @@ void Server::update() {
|
|||
PacketView p(event.packet);
|
||||
|
||||
auto client = static_cast<ServerClient*>(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<i64>(loop.elapsedNs()), 0L);
|
||||
i64 sleep_for = (std::max)(interval_ns - static_cast<i64>(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<ServerPlayer> player) {
|
|||
}
|
||||
|
||||
case Packet::Type::INV_INTERACT: {
|
||||
// TODO: When reading these parameters, there's a bad_alloc error.
|
||||
bool primary = p.d.read<bool>();
|
||||
string source = p.d.read<string>();
|
||||
string list = p.d.read<string>();
|
||||
|
@ -174,9 +174,10 @@ void Server::playerPacketReceived(PacketView& p, sptr<ServerPlayer> player) {
|
|||
|
||||
case Packet::Type::MOD_MESSAGE: {
|
||||
string source = p.d.read<string>();
|
||||
string list = p.d.read<string>();
|
||||
string message = p.d.read<string>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<vec<ServerGenStream::FinishedJob>> ServerGenStream::update() {
|
||||
auto created = make_unique<vec<FinishedJob>>();
|
||||
|
||||
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<vec<ServerGenStream::FinishedJob>> 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<vec<ServerGenStream::FinishedJob>> ServerGenStream::update() {
|
|||
}
|
||||
}
|
||||
|
||||
if (dequeued >= THREAD_QUEUE_SIZE * THREADS)
|
||||
std::cout << Log::err << "Server threads were idle!" << Log::endl;
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<MapGen::ChunkMap> created) :
|
||||
|
|
|
@ -38,8 +38,9 @@ namespace Util {
|
|||
return toFixed<T>(val);
|
||||
}
|
||||
|
||||
template <typename V, std::enable_if_t<std::is_trivially_copyable_v<typename V::value_type> &&
|
||||
std::is_same_v<vec<typename V::value_type>, V>, bool> = true>
|
||||
template <typename V, std::enable_if_t<(std::is_trivially_copyable_v<typename V::value_type>
|
||||
|| std::is_same_v<typename V::value_type, string>)
|
||||
&& std::is_same_v<vec<typename V::value_type>, V>, bool> = true>
|
||||
static string toString(V vec) {
|
||||
std::ostringstream out;
|
||||
out << "[ ";
|
||||
|
@ -48,8 +49,9 @@ namespace Util {
|
|||
return out.str();
|
||||
}
|
||||
|
||||
template <typename A, std::enable_if_t<std::is_trivially_copyable_v<typename A::value_type> &&
|
||||
std::is_same_v<array<typename A::value_type, A::size_type>, A>, bool> = true>
|
||||
template <typename A, std::enable_if_t<(std::is_trivially_copyable_v<typename A::value_type>
|
||||
|| std::is_same_v<typename A::value_type, string>)
|
||||
&& std::is_same_v<array<typename A::value_type, A::size_type>, A>, bool> = true>
|
||||
static string toString(A arr) {
|
||||
std::ostringstream out;
|
||||
for (usize i = 0; i < arr.size(); i++) out << (i == 0 ? "" : ", ") << arr[i];
|
||||
|
|
|
@ -66,23 +66,29 @@ void ServerWorld::update(f64 delta) {
|
|||
refs->update();
|
||||
|
||||
u32 genCount = 0;
|
||||
std::unordered_set<ivec4, Vec::ivec4> updatedChunks {};
|
||||
|
||||
auto finishedGen = genStream->update();
|
||||
std::unordered_set<ivec4, Vec::ivec4> 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<ivec3, ivec3> 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<i64>(entity);
|
||||
|
@ -247,25 +234,22 @@ void ServerWorld::sendChunksToPlayer(ServerPlayer& client) {
|
|||
|
||||
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>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,13 @@ void LocalDimension::update(f64 delta) {
|
|||
}
|
||||
|
||||
void LocalDimension::setChunk(sptr<Chunk> chunk) {
|
||||
let clientMapBlock = Space::MapBlock::world::fromBlock(static_cast<LocalWorld&>(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);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ private:
|
|||
std::list<Api::Usertype::Entity> luaEntities{};
|
||||
std::list<i64> removedEntities{};
|
||||
|
||||
const ivec2 retainMapBlockRange = { 4, 4 };
|
||||
const ivec2 retainMapBlockRange = { 6, 6 };
|
||||
i64 entityInd = 1;
|
||||
};
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ void Chunk::combineWith(sptr<Chunk> o) {
|
|||
generationState = GenerationState::GENERATED;
|
||||
countRenderableBlocks();
|
||||
}
|
||||
|
||||
else generationState = GenerationState::PARTIAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>();
|
||||
model->fromMesh(WireframeEntity::createMesh({ {}, scale }, 0.035, wfStroke, wfFill));
|
||||
setModel(model);
|
||||
}
|
||||
else throw std::runtime_error("Invalid appearance arguments specified.");
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -35,7 +35,8 @@ MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string>
|
|||
|
||||
let biomeFractal = FastNoise::New<FastNoise::FractalFBm>();
|
||||
biomeFractal->SetSource(biomeScale);
|
||||
biomeFractal->SetOctaveCount(4);
|
||||
biomeFractal->SetOctaveCount(5);
|
||||
biomeFractal->SetLacunarity(3);
|
||||
|
||||
biomeGenerator = biomeFractal;
|
||||
}
|
||||
|
|
|
@ -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<f32(ivec3)>& 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<f32>(precision);
|
||||
u16vec3 a = u16vec3(glm::floor(frac)) * static_cast<u16>(precision);
|
||||
u16vec3 b = u16vec3(glm::ceil(frac)) * static_cast<u16>(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(
|
||||
|
|
|
@ -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<f32(ivec3 pos)> 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<f32(ivec3)>& 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<i32>(std::ceil(scaled.x)), precision.x),
|
||||
// (std::min)(static_cast<i32>(std::ceil(scaled.y)), precision.y),
|
||||
// (std::min)(static_cast<i32>(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<u32>(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<u32>(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<f32> data {};
|
||||
};
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "@auri:chat",
|
||||
"description": "A simple chat interface and API supporting messaging and commands.",
|
||||
"version": "0.0.1"
|
||||
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
||||
})
|
|
@ -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')
|
|
@ -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
|
After Width: | Height: | Size: 525 B |
After Width: | Height: | Size: 541 B |
After Width: | Height: | Size: 546 B |
|
@ -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)
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 334 B |
After Width: | Height: | Size: 6.9 KiB |
|
@ -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",
|
||||
-- sources = {{
|
||||
-- -- Elevation
|
||||
-- module = "scale_bias",
|
||||
-- scalar = -2200,
|
||||
-- source = {
|
||||
-- module = "spheres",
|
||||
-- frequency = 0.2
|
||||
-- },
|
||||
-- scale = 20
|
||||
-- }, {
|
||||
-- -- Features
|
||||
-- module = "scale_bias",
|
||||
-- module = "multiply",
|
||||
-- scalar = 3000,
|
||||
-- source = {
|
||||
-- module = "perlin",
|
||||
-- frequency = 0.1,
|
||||
-- module = "simplex",
|
||||
-- frequency = 0.0025,
|
||||
-- octaves = 6,
|
||||
-- lacunarity = 2
|
||||
-- }
|
||||
-- }
|
||||
-- }
|
||||
-- }
|
||||
-- }
|
||||
--
|
||||
-- zepha.register_biome(identifier, {
|
||||
-- environment = {
|
||||
-- temperature = 40/100,
|
||||
-- humidity = 20/100,
|
||||
-- roughness = 10/100
|
||||
-- },
|
||||
-- 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 = "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;
|
||||
-- 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;
|
||||
|
|
|
@ -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,27 +121,71 @@ 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,
|
||||
heightmap = {
|
||||
module = "add",
|
||||
sources = {
|
||||
runfile(_PATH .. 'world_noise'),
|
||||
{
|
||||
module = "max",
|
||||
scalar = 0,
|
||||
source = {
|
||||
module = "add",
|
||||
scalar = -2200,
|
||||
scalar = -150,
|
||||
source = {
|
||||
module = "multiply",
|
||||
scalar = 3000,
|
||||
scalar = 400,
|
||||
source = {
|
||||
module = "simplex",
|
||||
frequency = 0.0025,
|
||||
octaves = 6,
|
||||
lacunarity = 2
|
||||
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, {
|
||||
environment = {
|
||||
|
|
|
@ -1,24 +1,11 @@
|
|||
return {
|
||||
module = "add",
|
||||
sources = {{
|
||||
-- Elevation
|
||||
module = "scale_bias",
|
||||
module = "multiply",
|
||||
scalar = 100,
|
||||
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 = "simplex",
|
||||
frequency = 0.0002,
|
||||
octaves = 5,
|
||||
lacunarity = 3,
|
||||
persistence = 0.45
|
||||
}
|
||||
};
|
|
@ -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')
|