mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-04 18:41:51 +00:00
Merge branch 'main' into animation
This commit is contained in:
commit
a5b1259c5b
24 changed files with 111 additions and 28 deletions
|
|
@ -4,14 +4,15 @@
|
|||
|
||||
The appearance of 3D text, is configured via a table, like [particles](particles.md). All fields are optional.
|
||||
|
||||
| Field | Description | Default |
|
||||
| --------------- | ---------------------------- | ---------------- |
|
||||
| display | Display format | static_billboard |
|
||||
| color | Text color | {1, 1, 1, 1} |
|
||||
| scale | Text scale | 1 |
|
||||
| render_distance | Text rendering distance | 32 |
|
||||
| xray_opacity | Visibility through obstacles | 0 |
|
||||
| perspective | Perspective coefficient | 1 |
|
||||
| Field | Description | Default |
|
||||
| --------------- | ---------------------------------------- | ---------------- |
|
||||
| display | Display format | static_billboard |
|
||||
| color | Text color | {1, 1, 1, 1} |
|
||||
| scale | Text scale | 1 |
|
||||
| render_distance | Text rendering distance | 32 |
|
||||
| xray_opacity | Visibility through obstacles | 0 |
|
||||
| perspective | Perspective coefficient | 1 |
|
||||
| font | Font. If absent, the default one is used | "" |
|
||||
|
||||
Available display formats:
|
||||
|
||||
|
|
|
|||
|
|
@ -61,12 +61,16 @@ Determines how the physics engine will work with it.
|
|||
|
||||
### *blocking*
|
||||
|
||||
Determines whether the entity blocks installation of blocks.
|
||||
If true - the entity blocks the placement of a block that intersects with the entity's hitbox.
|
||||
|
||||
*In the future will also block other entities movement.*
|
||||
|
||||
Default value: *true*.
|
||||
|
||||
### *selectable*
|
||||
|
||||
If set to `false` the cursor will ignore the entity, passing the ray.
|
||||
|
||||
### *sensors*
|
||||
|
||||
A sensor is an area attached to a physical body that detects the entry of other bodies into it.
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ world.raycast(
|
|||
-- exclusion filtering mode:
|
||||
-- if true, filter_entities defines the list of ignored entity types
|
||||
entities_exclusion: bool = false,
|
||||
-- include entities with selectable=false
|
||||
nonselect_entities: bool = false;
|
||||
|
||||
[==[ additional parameters (blocks) ]==]
|
||||
-- id of the block types used for filtering
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
| render_distance | Дистанция отрисовки текста | 32 |
|
||||
| xray_opacity | Коэффициент видимости через препятствия (просвечивание) | 0 |
|
||||
| perspective | Коэффициент перспективы | 1 |
|
||||
| font | Шрифт. При отсутствии используется основной | "" |
|
||||
|
||||
Доступные форматы отображения:
|
||||
|
||||
|
|
|
|||
|
|
@ -61,12 +61,16 @@
|
|||
|
||||
### Блокирование - *blocking*
|
||||
|
||||
Определяет блокирует ли сущность установку блоков.
|
||||
Определяет, блокирует ли сущность установку блока, пересекающегося с хитбоксом сущности.
|
||||
|
||||
*В будущем будет также блокировать движение других сущностей.*
|
||||
|
||||
Значение по-умолчанию: *true*.
|
||||
|
||||
### Выделяемость - *selectable*
|
||||
|
||||
При значении в `false` курсор будет игнорировать cущность, пропуская луч далее.
|
||||
|
||||
### Список сенсоров - *sensors*
|
||||
|
||||
Сенсор - область пространства, привязанная к физическому телу, детектирующее попадание в него других тел.
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ world.raycast(
|
|||
-- исключающий режим фильтрации:
|
||||
-- при значении (true) filter_entities определяет список игнорируемых
|
||||
entities_exclusion: bool = false,
|
||||
-- учитывать сущности с selectable=false
|
||||
nonselect_entities: bool = false;
|
||||
|
||||
[==[ дополнительные параметры (блоки) ]==]
|
||||
-- id типов блоков используемых для фильтрации
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ dropitem = ARGS
|
|||
if dropitem.item then
|
||||
dropitem.id = item.index(dropitem.item)
|
||||
end
|
||||
if dropitem then
|
||||
if dropitem then
|
||||
timer = dropitem.pickup_delay or timer
|
||||
end
|
||||
if SAVED_DATA.item then
|
||||
|
|
@ -26,6 +26,7 @@ function on_save()
|
|||
end
|
||||
|
||||
if vc.is_client() then
|
||||
local SCALE = 0.3
|
||||
local scale = {1, 1, 1}
|
||||
local rotation = mat4.rotate({
|
||||
math.random(), math.random(), math.random()
|
||||
|
|
@ -35,7 +36,7 @@ if vc.is_client() then
|
|||
local matrix = mat4.idt()
|
||||
rig:set_model(0, item.model_name(dropitem.id))
|
||||
local bodysize = math.min(scale[1], scale[2], scale[3])
|
||||
body:set_size({scale[1], bodysize, scale[3]})
|
||||
body:set_size(vec3.mul({scale[1], bodysize, scale[3]}, SCALE))
|
||||
mat4.mul(matrix, rotation, matrix)
|
||||
mat4.scale(matrix, scale, matrix)
|
||||
rig:set_matrix(0, matrix)
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ public:
|
|||
ContentUnitDefs<GeneratorDef> generators;
|
||||
std::unique_ptr<DrawGroups> const drawGroups;
|
||||
ResourceIndicesSet resourceIndices {};
|
||||
std::set<std::string> components {};
|
||||
|
||||
Content(
|
||||
std::unique_ptr<ContentIndices> indices,
|
||||
|
|
|
|||
|
|
@ -26,17 +26,18 @@ std::unique_ptr<Content> ContentBuilder::build() {
|
|||
def.rt.tags.insert(tags.add(tag));
|
||||
}
|
||||
|
||||
auto isSolid = [](const Variant& variant) {
|
||||
return variant.model.type == BlockModelType::BLOCK ||
|
||||
variant.culling == CullingMode::OPTIONAL;
|
||||
};
|
||||
|
||||
if (def.variants) {
|
||||
for (auto& variant : def.variants->variants) {
|
||||
variant.rt.solid =
|
||||
variant.model.type == BlockModelType::BLOCK ||
|
||||
def.explictlySolid;
|
||||
variant.rt.solid = isSolid(variant) || def.explictlySolid;
|
||||
}
|
||||
def.defaults = def.variants->variants.at(0);
|
||||
} else {
|
||||
def.defaults.rt.solid =
|
||||
def.defaults.model.type == BlockModelType::BLOCK ||
|
||||
def.explictlySolid;
|
||||
def.defaults.rt.solid = isSolid(def.defaults) || def.explictlySolid;
|
||||
}
|
||||
|
||||
const float EPSILON = 0.01f;
|
||||
|
|
|
|||
|
|
@ -506,6 +506,7 @@ void ContentLoader::loadScripts(Content& content) {
|
|||
scripting::on_scripts_loading();
|
||||
load_scripts(content, content.blocks);
|
||||
load_scripts(content, content.items);
|
||||
auto& tmpContent = content;
|
||||
|
||||
for (const auto& [packid, runtime] : content.getPacks()) {
|
||||
auto env = runtime->getEnvironment();
|
||||
|
|
@ -516,7 +517,7 @@ void ContentLoader::loadScripts(Content& content) {
|
|||
|
||||
// Load entity components
|
||||
io::path componentsDir = folder / "scripts/components";
|
||||
foreach_file(componentsDir, [&pack, env](const io::path& file) {
|
||||
foreach_file(componentsDir, [&pack, env, &tmpContent](const io::path& file) {
|
||||
auto name = pack.id + ":" + file.stem();
|
||||
scripting::load_entity_component(
|
||||
env,
|
||||
|
|
@ -524,9 +525,21 @@ void ContentLoader::loadScripts(Content& content) {
|
|||
file,
|
||||
pack.id + ":scripts/components/" + file.name()
|
||||
);
|
||||
tmpContent.components.insert(name);
|
||||
});
|
||||
}
|
||||
|
||||
for (const auto& [eid, def] : content.entities.getDefs()) {
|
||||
for (const auto& instance : def->components) {
|
||||
if (content.components.find(instance.component) == content.components.end()) {
|
||||
throw std::runtime_error(
|
||||
"component " + instance.component +
|
||||
" is not available (required by entity " + eid + ")"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scripting::on_content_loaded();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ template<> void ContentUnitLoader<EntityDef>::loadUnit(
|
|||
root.at("skeleton-name").get(def.skeletonName);
|
||||
root.at("material").get(def.material);
|
||||
root.at("blocking").get(def.blocking);
|
||||
root.at("selectable").get(def.selectable);
|
||||
root.at("solid").get(def.solid);
|
||||
root.at("mass").get(def.mass);
|
||||
root.at("elasticity").get(def.elasticity);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ void ContentGfxCache::refreshVariant(
|
|||
uint8_t variantIndex,
|
||||
const Atlas& atlas
|
||||
) {
|
||||
std::unordered_map<std::string, std::string> optionalTextures;
|
||||
bool denseRender = settings.denseRender.get();
|
||||
for (uint side = 0; side < 6; side++) {
|
||||
std::string tex = variant.textureFaces[side];
|
||||
|
|
@ -43,6 +44,7 @@ void ContentGfxCache::refreshVariant(
|
|||
texOpaque = tex;
|
||||
} else if (variant.culling == CullingMode::OPTIONAL && !denseRender) {
|
||||
tex = texOpaque;
|
||||
optionalTextures[variant.textureFaces[side]] = texOpaque;
|
||||
}
|
||||
size_t index = getRegionIndex(def.rt.id, variantIndex, side, false);
|
||||
sideregions[index] = atlas.get(tex);
|
||||
|
|
@ -56,7 +58,12 @@ void ContentGfxCache::refreshVariant(
|
|||
if (pos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
if (auto region = atlas.getIf(mesh.texture.substr(pos+1))) {
|
||||
std::string texture = mesh.texture.substr(pos+1);
|
||||
const auto& found = optionalTextures.find(texture);
|
||||
if (found != optionalTextures.end()) {
|
||||
texture = found->second;
|
||||
}
|
||||
if (auto region = atlas.getIf(texture)) {
|
||||
for (auto& vertex : mesh.vertices) {
|
||||
vertex.uv = region->apply(vertex.uv);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,6 +162,8 @@ static inline void draw_text(
|
|||
const FontStylesScheme* styles,
|
||||
size_t styleMapOffset
|
||||
) {
|
||||
bool is3d = std::is_same<Batch, Batch3D>();
|
||||
|
||||
static FontStylesScheme defStyles {{{}}, {0}};
|
||||
|
||||
if (styles == nullptr) {
|
||||
|
|
@ -194,13 +196,26 @@ static inline void draw_text(
|
|||
float advance = baseAdvance;
|
||||
if (auto glyph = font.getGlyph(c)) {
|
||||
yOffset = glyph->yOffset;
|
||||
advance = glyph->xAdvance;
|
||||
advance = glyph->xAdvance /
|
||||
static_cast<float>(font.getLineHeight()) * 2.0f *
|
||||
baseAdvance;
|
||||
}
|
||||
uint charpage = c >> 8;
|
||||
if (charpage == page){
|
||||
batch.texture(font.getPage(charpage));
|
||||
draw_glyph(
|
||||
batch, pos, glm::vec2(x, y - yOffset / static_cast<float>(font.getLineHeight())), c, right, up, interval, style
|
||||
batch,
|
||||
pos,
|
||||
glm::vec2(
|
||||
x,
|
||||
y - yOffset * (is3d ? -1 : 1) /
|
||||
static_cast<float>(font.getLineHeight())
|
||||
),
|
||||
c,
|
||||
right,
|
||||
up,
|
||||
interval,
|
||||
style
|
||||
);
|
||||
}
|
||||
else if (charpage > page && charpage < next){
|
||||
|
|
|
|||
|
|
@ -538,7 +538,6 @@ void BlocksRenderer::render(
|
|||
break;
|
||||
}
|
||||
case BlockModelType::CUSTOM: {
|
||||
if (!denseRender)
|
||||
blockCustomModel(
|
||||
{x, y, z},
|
||||
def,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,10 @@ void TextsRenderer::renderNote(
|
|||
}
|
||||
opacity = preset.xrayOpacity;
|
||||
}
|
||||
auto& font = assets.require<Font>(FONT_DEFAULT);
|
||||
|
||||
auto specifiedFont = assets.get<Font>(preset.font);
|
||||
auto& font =
|
||||
specifiedFont ? *specifiedFont : assets.require<Font>(FONT_DEFAULT);
|
||||
|
||||
glm::vec3 xvec = note.getAxisX();
|
||||
glm::vec3 yvec = note.getAxisY();
|
||||
|
|
@ -76,7 +79,10 @@ void TextsRenderer::renderNote(
|
|||
yvec = camera.up;
|
||||
}
|
||||
float scale =
|
||||
(1.0f - preset.perspective) * glm::pow(glm::distance(camera.position, pos), 1.0f-preset.perspective);
|
||||
(1.0f - preset.perspective) *
|
||||
glm::pow(
|
||||
glm::distance(camera.position, pos), 1.0f - preset.perspective
|
||||
);
|
||||
xvec *= 1.0f + scale;
|
||||
yvec *= 1.0f + scale;
|
||||
}
|
||||
|
|
@ -118,6 +124,7 @@ void TextsRenderer::renderNote(
|
|||
}
|
||||
auto color = preset.color;
|
||||
batch.setColor(glm::vec4(color.r, color.g, color.b, color.a * opacity));
|
||||
|
||||
font.draw(
|
||||
batch,
|
||||
text,
|
||||
|
|
|
|||
|
|
@ -311,6 +311,10 @@ static int l_world_raycast(lua::State* L) {
|
|||
entityRaycast.entityFilterExcludeMode = lua::toboolean(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
if (lua::getfield(L, "nonselect_entities", 1)) {
|
||||
entityRaycast.includeNonSelectable = lua::toboolean(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
if (lua::getfield(L, "filter_blocks", 1)) {
|
||||
load_blocks_filter(L, -1, filteredBlocks);
|
||||
blocksRaycast.filter = &filteredBlocks;
|
||||
|
|
|
|||
|
|
@ -744,9 +744,10 @@ void scripting::load_entity_component(
|
|||
const io::path& file,
|
||||
const std::string& fileName
|
||||
) {
|
||||
logger.info() << "script (component) " << file.string();
|
||||
|
||||
auto L = lua::get_main_state();
|
||||
std::string src = io::read_string(file);
|
||||
logger.info() << "script (component) " << file.string();
|
||||
lua::loadbuffer(L, *env, src, fileName);
|
||||
lua::store_in_registry(L, lua::CHUNKS_TABLE, name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,12 @@ void scripting::on_entity_spawn(
|
|||
lua::call(L, 1);
|
||||
}
|
||||
for (auto& component : components) {
|
||||
create_component(L, -1, *component, args, saved);
|
||||
try {
|
||||
create_component(L, -1, *component, args, saved);
|
||||
} catch (const std::runtime_error& err) {
|
||||
logger.error() << "could not to initialize user component "
|
||||
<< component->name << ": " << err.what();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [packid, pack] : content->getPacks()) {
|
||||
|
|
@ -171,6 +176,9 @@ static void process_entity_callback(
|
|||
const std::string& name,
|
||||
std::function<int(lua::State*)> args
|
||||
) {
|
||||
if (env == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto L = lua::get_main_state();
|
||||
lua::pushenv(L, *env);
|
||||
if (lua::hasfield(L, "__disabled")) {
|
||||
|
|
|
|||
|
|
@ -176,7 +176,8 @@ std::optional<Entities::RaycastResult> Entities::rayCast(
|
|||
|
||||
for (auto [entity, eid, transform, body] : view.each()) {
|
||||
if (eid.uid == settings.ignoredUid || !body.enabled ||
|
||||
(settings.solidEntitiesOnly && !eid.def.solid)) {
|
||||
(settings.solidEntitiesOnly && !eid.def.solid) ||
|
||||
(!eid.def.selectable && !settings.includeNonSelectable)) {
|
||||
continue;
|
||||
}
|
||||
if (settings.entitiesFilter) {
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ public:
|
|||
bool solidEntitiesOnly = false;
|
||||
bool entityFilterExcludeMode = false;
|
||||
const std::set<entitydefid_t>* entitiesFilter = nullptr;
|
||||
bool includeNonSelectable = false;
|
||||
};
|
||||
|
||||
struct RaycastResult {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ dv::value Entity::serialize() const {
|
|||
if (!scripts.components.empty()) {
|
||||
auto& compsMap = root.object("comps");
|
||||
for (auto& comp : scripts.components) {
|
||||
if (comp->env == nullptr) {
|
||||
continue;
|
||||
}
|
||||
auto data =
|
||||
scripting::get_component_value(comp->env, SAVED_DATA_VARNAME);
|
||||
compsMap[comp->name] = data;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ struct EntityDef {
|
|||
/// @brief Solid entity material material
|
||||
std::string material;
|
||||
|
||||
/// @brief Can the entity be interacted with cursor (on_attack, on_use)
|
||||
bool selectable = true;
|
||||
|
||||
/// @brief Does entity prevent blocks setup
|
||||
bool blocking = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ dv::value NotePreset::serialize() const {
|
|||
{"render_distance", renderDistance},
|
||||
{"xray_opacity", xrayOpacity},
|
||||
{"perspective", perspective},
|
||||
{"font", font},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -27,4 +28,5 @@ void NotePreset::deserialize(const dv::value& src) {
|
|||
src.at("render_distance").get(renderDistance);
|
||||
src.at("xray_opacity").get(xrayOpacity);
|
||||
src.at("perspective").get(perspective);
|
||||
src.at("font").get(font);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ struct NotePreset : public Serializable {
|
|||
float renderDistance = 32.0f;
|
||||
float xrayOpacity = 0.0f;
|
||||
float perspective = 1.0f;
|
||||
std::string font {};
|
||||
|
||||
dv::value serialize() const override;
|
||||
void deserialize(const dv::value& src) override;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue