mirror of
https://github.com/luanti-org/luanti.git
synced 2025-07-02 16:38:41 +00:00
CAO 'node' visual (#15683)
This commit is contained in:
parent
5a8720a484
commit
27bbe3a873
14 changed files with 267 additions and 91 deletions
|
@ -1522,7 +1522,7 @@ There are a bunch of different looking node types.
|
||||||
* `allfaces`
|
* `allfaces`
|
||||||
* Often used for partially-transparent nodes.
|
* Often used for partially-transparent nodes.
|
||||||
* External sides of textures, and unlike other drawtypes, the external sides
|
* External sides of textures, and unlike other drawtypes, the external sides
|
||||||
of other blocks, are visible from the inside.
|
of other nodes, are visible from the inside.
|
||||||
* `allfaces_optional`
|
* `allfaces_optional`
|
||||||
* Often used for leaves nodes.
|
* Often used for leaves nodes.
|
||||||
* This switches between `normal`, `glasslike` and `allfaces` according to
|
* This switches between `normal`, `glasslike` and `allfaces` according to
|
||||||
|
@ -9233,7 +9233,7 @@ Player properties need to be saved manually.
|
||||||
-- Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`.
|
-- Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`.
|
||||||
-- Can be overridden by the `pointabilities` of the held item.
|
-- Can be overridden by the `pointabilities` of the held item.
|
||||||
|
|
||||||
visual = "cube" / "sprite" / "upright_sprite" / "mesh" / "wielditem" / "item",
|
visual = "",
|
||||||
-- "cube" is a node-sized cube.
|
-- "cube" is a node-sized cube.
|
||||||
-- "sprite" is a flat texture always facing the player.
|
-- "sprite" is a flat texture always facing the player.
|
||||||
-- "upright_sprite" is a vertical flat texture.
|
-- "upright_sprite" is a vertical flat texture.
|
||||||
|
@ -9255,6 +9255,8 @@ Player properties need to be saved manually.
|
||||||
-- Wielditems are scaled a bit. If you want a wielditem to appear
|
-- Wielditems are scaled a bit. If you want a wielditem to appear
|
||||||
-- to be as large as a node, use `0.667` in `visual_size`
|
-- to be as large as a node, use `0.667` in `visual_size`
|
||||||
-- "item" is similar to "wielditem" but ignores the 'wield_image' parameter.
|
-- "item" is similar to "wielditem" but ignores the 'wield_image' parameter.
|
||||||
|
-- "node" looks exactly like a node in-world (supported since 5.12.0)
|
||||||
|
-- Note that visual effects like waving or liquid reflections will not work.
|
||||||
|
|
||||||
visual_size = {x = 1, y = 1, z = 1},
|
visual_size = {x = 1, y = 1, z = 1},
|
||||||
-- Multipliers for the visual size. If `z` is not specified, `x` will be used
|
-- Multipliers for the visual size. If `z` is not specified, `x` will be used
|
||||||
|
@ -9264,7 +9266,7 @@ Player properties need to be saved manually.
|
||||||
-- File name of mesh when using "mesh" visual
|
-- File name of mesh when using "mesh" visual
|
||||||
|
|
||||||
textures = {},
|
textures = {},
|
||||||
-- Number of required textures depends on visual.
|
-- Number of required textures depends on visual:
|
||||||
-- "cube" uses 6 textures just like a node, but all 6 must be defined.
|
-- "cube" uses 6 textures just like a node, but all 6 must be defined.
|
||||||
-- "sprite" uses 1 texture.
|
-- "sprite" uses 1 texture.
|
||||||
-- "upright_sprite" uses 2 textures: {front, back}.
|
-- "upright_sprite" uses 2 textures: {front, back}.
|
||||||
|
@ -9274,11 +9276,14 @@ Player properties need to be saved manually.
|
||||||
colors = {},
|
colors = {},
|
||||||
-- Currently unused.
|
-- Currently unused.
|
||||||
|
|
||||||
|
node = {name = "ignore", param1=0, param2=0},
|
||||||
|
-- Node to show when using the "node" visual
|
||||||
|
|
||||||
use_texture_alpha = false,
|
use_texture_alpha = false,
|
||||||
-- Use texture's alpha channel.
|
-- Use texture's alpha channel for transparency blending.
|
||||||
-- Excludes "upright_sprite" and "wielditem".
|
|
||||||
-- Note: currently causes visual issues when viewed through other
|
-- Note: currently causes visual issues when viewed through other
|
||||||
-- semi-transparent materials such as water.
|
-- semi-transparent materials such as water.
|
||||||
|
-- Note: ignored for "item", "wielditem" and "node" visual.
|
||||||
|
|
||||||
spritediv = {x = 1, y = 1},
|
spritediv = {x = 1, y = 1},
|
||||||
-- Used with spritesheet textures for animation and/or frame selection
|
-- Used with spritesheet textures for animation and/or frame selection
|
||||||
|
@ -9295,7 +9300,7 @@ Player properties need to be saved manually.
|
||||||
-- If false, object is invisible and can't be pointed.
|
-- If false, object is invisible and can't be pointed.
|
||||||
|
|
||||||
makes_footstep_sound = false,
|
makes_footstep_sound = false,
|
||||||
-- If true, is able to make footstep sounds of nodes
|
-- If true, object is able to make footstep sounds of nodes
|
||||||
-- (see node sound definition for details).
|
-- (see node sound definition for details).
|
||||||
|
|
||||||
automatic_rotate = 0,
|
automatic_rotate = 0,
|
||||||
|
@ -9318,6 +9323,7 @@ Player properties need to be saved manually.
|
||||||
|
|
||||||
backface_culling = true,
|
backface_culling = true,
|
||||||
-- Set to false to disable backface_culling for model
|
-- Set to false to disable backface_culling for model
|
||||||
|
-- Note: only used by "mesh" and "cube" visual
|
||||||
|
|
||||||
glow = 0,
|
glow = 0,
|
||||||
-- Add this much extra lighting when calculating texture color.
|
-- Add this much extra lighting when calculating texture color.
|
||||||
|
@ -9353,6 +9359,7 @@ Player properties need to be saved manually.
|
||||||
|
|
||||||
shaded = true,
|
shaded = true,
|
||||||
-- Setting this to 'false' disables diffuse lighting of entity
|
-- Setting this to 'false' disables diffuse lighting of entity
|
||||||
|
-- Note: ignored for "item", "wielditem" and "node" visual
|
||||||
|
|
||||||
show_on_minimap = false,
|
show_on_minimap = false,
|
||||||
-- Defaults to true for players, false for other entities.
|
-- Defaults to true for players, false for other entities.
|
||||||
|
|
|
@ -66,6 +66,15 @@ core.register_entity("testentities:mesh_unshaded", {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
core.register_entity("testentities:node", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "node",
|
||||||
|
node = { name = "stairs:stair_stone" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
-- More complex meshes
|
||||||
|
|
||||||
core.register_entity("testentities:sam", {
|
core.register_entity("testentities:sam", {
|
||||||
initial_properties = {
|
initial_properties = {
|
||||||
visual = "mesh",
|
visual = "mesh",
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "client/sound.h"
|
#include "client/sound.h"
|
||||||
#include "client/texturesource.h"
|
#include "client/texturesource.h"
|
||||||
#include "client/mapblock_mesh.h"
|
#include "client/mapblock_mesh.h"
|
||||||
|
#include "client/content_mapblock.h"
|
||||||
|
#include "client/meshgen/collector.h"
|
||||||
#include "util/basic_macros.h"
|
#include "util/basic_macros.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
|
@ -180,6 +182,60 @@ static void setColorParam(scene::ISceneNode *node, video::SColor color)
|
||||||
node->getMaterial(i).ColorParam = color;
|
node->getMaterial(i).ColorParam = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static scene::SMesh *generateNodeMesh(Client *client, MapNode n,
|
||||||
|
std::vector<MeshAnimationInfo> &animation)
|
||||||
|
{
|
||||||
|
auto *ndef = client->ndef();
|
||||||
|
auto *shdsrc = client->getShaderSource();
|
||||||
|
|
||||||
|
MeshCollector collector(v3f(0), v3f());
|
||||||
|
{
|
||||||
|
MeshMakeData mmd(ndef, 1, MeshGrid{1});
|
||||||
|
n.setParam1(0xff);
|
||||||
|
mmd.fillSingleNode(n);
|
||||||
|
MapblockMeshGenerator(&mmd, &collector).generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mesh = make_irr<scene::SMesh>();
|
||||||
|
animation.clear();
|
||||||
|
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
|
||||||
|
for (PreMeshBuffer &p : collector.prebuffers[layer]) {
|
||||||
|
// reset the pre-computed light data stored in the vertex color,
|
||||||
|
// since we do that ourselves via updateLight().
|
||||||
|
for (auto &v : p.vertices)
|
||||||
|
v.Color.set(0xFFFFFFFF);
|
||||||
|
// but still apply the tile color
|
||||||
|
p.applyTileColor();
|
||||||
|
|
||||||
|
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
|
||||||
|
const FrameSpec &frame = (*p.layer.frames)[0];
|
||||||
|
p.layer.texture = frame.texture;
|
||||||
|
|
||||||
|
animation.emplace_back(MeshAnimationInfo{mesh->getMeshBufferCount(), 0, p.layer});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buf = make_irr<scene::SMeshBuffer>();
|
||||||
|
buf->append(&p.vertices[0], p.vertices.size(),
|
||||||
|
&p.indices[0], p.indices.size());
|
||||||
|
|
||||||
|
// Set up material
|
||||||
|
auto &mat = buf->Material;
|
||||||
|
mat.setTexture(0, p.layer.texture);
|
||||||
|
u32 shader_id = shdsrc->getShader("object_shader", p.layer.material_type, NDT_NORMAL);
|
||||||
|
mat.MaterialType = shdsrc->getShaderInfo(shader_id).material;
|
||||||
|
if (layer == 1) {
|
||||||
|
mat.PolygonOffsetSlopeScale = -1;
|
||||||
|
mat.PolygonOffsetDepthBias = -1;
|
||||||
|
}
|
||||||
|
p.layer.applyMaterialOptionsWithShaders(mat);
|
||||||
|
|
||||||
|
mesh->addMeshBuffer(buf.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mesh->recalculateBoundingBox();
|
||||||
|
return mesh.release();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TestCAO
|
TestCAO
|
||||||
*/
|
*/
|
||||||
|
@ -572,6 +628,8 @@ void GenericCAO::removeFromScene(bool permanent)
|
||||||
m_spritenode = nullptr;
|
m_spritenode = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_meshnode_animation.clear();
|
||||||
|
|
||||||
if (m_matrixnode) {
|
if (m_matrixnode) {
|
||||||
m_matrixnode->remove();
|
m_matrixnode->remove();
|
||||||
m_matrixnode->drop();
|
m_matrixnode->drop();
|
||||||
|
@ -602,8 +660,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
|
|
||||||
infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl;
|
infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl;
|
||||||
|
|
||||||
m_material_type_param = 0.5f; // May cut off alpha < 128 depending on m_material_type
|
if (m_prop.visual != "node" && m_prop.visual != "wielditem" && m_prop.visual != "item")
|
||||||
|
|
||||||
{
|
{
|
||||||
IShaderSource *shader_source = m_client->getShaderSource();
|
IShaderSource *shader_source = m_client->getShaderSource();
|
||||||
MaterialType material_type;
|
MaterialType material_type;
|
||||||
|
@ -617,14 +674,16 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
|
|
||||||
u32 shader_id = shader_source->getShader("object_shader", material_type, NDT_NORMAL);
|
u32 shader_id = shader_source->getShader("object_shader", material_type, NDT_NORMAL);
|
||||||
m_material_type = shader_source->getShaderInfo(shader_id).material;
|
m_material_type = shader_source->getShaderInfo(shader_id).material;
|
||||||
|
} else {
|
||||||
|
// Not used, so make sure it's not valid
|
||||||
|
m_material_type = EMT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto grabMatrixNode = [this] {
|
|
||||||
m_matrixnode = m_smgr->addDummyTransformationSceneNode();
|
m_matrixnode = m_smgr->addDummyTransformationSceneNode();
|
||||||
m_matrixnode->grab();
|
m_matrixnode->grab();
|
||||||
};
|
|
||||||
|
|
||||||
auto setMaterial = [this] (video::SMaterial &mat) {
|
auto setMaterial = [this] (video::SMaterial &mat) {
|
||||||
|
if (m_material_type != EMT_INVALID)
|
||||||
mat.MaterialType = m_material_type;
|
mat.MaterialType = m_material_type;
|
||||||
mat.FogEnable = true;
|
mat.FogEnable = true;
|
||||||
mat.forEachTexture([] (auto &tex) {
|
mat.forEachTexture([] (auto &tex) {
|
||||||
|
@ -638,7 +697,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (m_prop.visual == "sprite") {
|
if (m_prop.visual == "sprite") {
|
||||||
grabMatrixNode();
|
|
||||||
m_spritenode = m_smgr->addBillboardSceneNode(
|
m_spritenode = m_smgr->addBillboardSceneNode(
|
||||||
m_matrixnode, v2f(1, 1), v3f(0,0,0), -1);
|
m_matrixnode, v2f(1, 1), v3f(0,0,0), -1);
|
||||||
m_spritenode->grab();
|
m_spritenode->grab();
|
||||||
|
@ -658,7 +716,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
txs, tys, 0, 0);
|
txs, tys, 0, 0);
|
||||||
}
|
}
|
||||||
} else if (m_prop.visual == "upright_sprite") {
|
} else if (m_prop.visual == "upright_sprite") {
|
||||||
grabMatrixNode();
|
|
||||||
auto mesh = make_irr<scene::SMesh>();
|
auto mesh = make_irr<scene::SMesh>();
|
||||||
f32 dx = BS * m_prop.visual_size.X / 2;
|
f32 dx = BS * m_prop.visual_size.X / 2;
|
||||||
f32 dy = BS * m_prop.visual_size.Y / 2;
|
f32 dy = BS * m_prop.visual_size.Y / 2;
|
||||||
|
@ -700,7 +757,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode);
|
m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode);
|
||||||
m_meshnode->grab();
|
m_meshnode->grab();
|
||||||
} else if (m_prop.visual == "cube") {
|
} else if (m_prop.visual == "cube") {
|
||||||
grabMatrixNode();
|
|
||||||
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
|
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
|
||||||
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
|
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
|
||||||
m_meshnode->grab();
|
m_meshnode->grab();
|
||||||
|
@ -714,7 +770,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
mat.BackfaceCulling = m_prop.backface_culling;
|
mat.BackfaceCulling = m_prop.backface_culling;
|
||||||
});
|
});
|
||||||
} else if (m_prop.visual == "mesh") {
|
} else if (m_prop.visual == "mesh") {
|
||||||
grabMatrixNode();
|
|
||||||
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
|
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
|
||||||
if (mesh) {
|
if (mesh) {
|
||||||
if (!checkMeshNormals(mesh)) {
|
if (!checkMeshNormals(mesh)) {
|
||||||
|
@ -741,7 +796,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
} else
|
} else
|
||||||
errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
|
errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
|
||||||
} else if (m_prop.visual == "wielditem" || m_prop.visual == "item") {
|
} else if (m_prop.visual == "wielditem" || m_prop.visual == "item") {
|
||||||
grabMatrixNode();
|
|
||||||
ItemStack item;
|
ItemStack item;
|
||||||
if (m_prop.wield_item.empty()) {
|
if (m_prop.wield_item.empty()) {
|
||||||
// Old format, only textures are specified.
|
// Old format, only textures are specified.
|
||||||
|
@ -761,6 +815,18 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
(m_prop.visual == "wielditem"));
|
(m_prop.visual == "wielditem"));
|
||||||
|
|
||||||
m_wield_meshnode->setScale(m_prop.visual_size / 2.0f);
|
m_wield_meshnode->setScale(m_prop.visual_size / 2.0f);
|
||||||
|
} else if (m_prop.visual == "node") {
|
||||||
|
auto *mesh = generateNodeMesh(m_client, m_prop.node, m_meshnode_animation);
|
||||||
|
assert(mesh);
|
||||||
|
|
||||||
|
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
|
||||||
|
m_meshnode->setSharedMaterials(true);
|
||||||
|
m_meshnode->grab();
|
||||||
|
mesh->drop();
|
||||||
|
|
||||||
|
m_meshnode->setScale(m_prop.visual_size);
|
||||||
|
|
||||||
|
setSceneNodeMaterials(m_meshnode);
|
||||||
} else {
|
} else {
|
||||||
infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
|
infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
|
||||||
<<"\" not supported"<<std::endl;
|
<<"\" not supported"<<std::endl;
|
||||||
|
@ -789,7 +855,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||||
updateTextures(m_current_texture_modifier);
|
updateTextures(m_current_texture_modifier);
|
||||||
|
|
||||||
if (scene::ISceneNode *node = getSceneNode()) {
|
if (scene::ISceneNode *node = getSceneNode()) {
|
||||||
if (m_matrixnode)
|
|
||||||
node->setParent(m_matrixnode);
|
node->setParent(m_matrixnode);
|
||||||
|
|
||||||
if (auto shadow = RenderingEngine::get_shadow_renderer())
|
if (auto shadow = RenderingEngine::get_shadow_renderer())
|
||||||
|
@ -861,8 +926,7 @@ void GenericCAO::updateLight(u32 day_night_ratio)
|
||||||
if (!pos_ok)
|
if (!pos_ok)
|
||||||
light_at_pos = LIGHT_SUN;
|
light_at_pos = LIGHT_SUN;
|
||||||
|
|
||||||
// Initialize with full alpha, otherwise entity won't be visible
|
video::SColor light;
|
||||||
video::SColor light{0xFFFFFFFF};
|
|
||||||
|
|
||||||
// Encode light into color, adding a small boost
|
// Encode light into color, adding a small boost
|
||||||
// based on the entity glow.
|
// based on the entity glow.
|
||||||
|
@ -965,6 +1029,7 @@ void GenericCAO::updateNodePos()
|
||||||
scene::ISceneNode *node = getSceneNode();
|
scene::ISceneNode *node = getSceneNode();
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
|
assert(m_matrixnode);
|
||||||
v3s16 camera_offset = m_env->getCameraOffset();
|
v3s16 camera_offset = m_env->getCameraOffset();
|
||||||
v3f pos = pos_translator.val_current -
|
v3f pos = pos_translator.val_current -
|
||||||
intToFloat(camera_offset, BS);
|
intToFloat(camera_offset, BS);
|
||||||
|
@ -1153,7 +1218,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
|
||||||
m_anim_frame = 0;
|
m_anim_frame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTexturePos();
|
updateTextureAnim();
|
||||||
|
|
||||||
if(m_reset_textures_timer >= 0)
|
if(m_reset_textures_timer >= 0)
|
||||||
{
|
{
|
||||||
|
@ -1214,7 +1279,7 @@ static void setMeshBufferTextureCoords(scene::IMeshBuffer *buf, const v2f *uv, u
|
||||||
buf->setDirty(scene::EBT_VERTEX);
|
buf->setDirty(scene::EBT_VERTEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericCAO::updateTexturePos()
|
void GenericCAO::updateTextureAnim()
|
||||||
{
|
{
|
||||||
if(m_spritenode)
|
if(m_spritenode)
|
||||||
{
|
{
|
||||||
|
@ -1279,6 +1344,23 @@ void GenericCAO::updateTexturePos()
|
||||||
auto mesh = m_meshnode->getMesh();
|
auto mesh = m_meshnode->getMesh();
|
||||||
setMeshBufferTextureCoords(mesh->getMeshBuffer(0), t, 4);
|
setMeshBufferTextureCoords(mesh->getMeshBuffer(0), t, 4);
|
||||||
setMeshBufferTextureCoords(mesh->getMeshBuffer(1), t, 4);
|
setMeshBufferTextureCoords(mesh->getMeshBuffer(1), t, 4);
|
||||||
|
} else if (m_prop.visual == "node") {
|
||||||
|
// same calculation as MapBlockMesh::animate() with a global timer
|
||||||
|
const float time = m_client->getAnimationTime();
|
||||||
|
for (auto &it : m_meshnode_animation) {
|
||||||
|
const TileLayer &tile = it.tile;
|
||||||
|
int frameno = (int)(time * 1000 / tile.animation_frame_length_ms)
|
||||||
|
% tile.animation_frame_count;
|
||||||
|
|
||||||
|
if (frameno == it.frame)
|
||||||
|
continue;
|
||||||
|
it.frame = frameno;
|
||||||
|
|
||||||
|
auto *buf = m_meshnode->getMesh()->getMeshBuffer(it.i);
|
||||||
|
|
||||||
|
const FrameSpec &frame = (*tile.frames)[frameno];
|
||||||
|
buf->getMaterial().setTexture(0, frame.texture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1304,7 +1386,6 @@ void GenericCAO::updateTextures(std::string mod)
|
||||||
|
|
||||||
video::SMaterial &material = m_spritenode->getMaterial(0);
|
video::SMaterial &material = m_spritenode->getMaterial(0);
|
||||||
material.MaterialType = m_material_type;
|
material.MaterialType = m_material_type;
|
||||||
material.MaterialTypeParam = m_material_type_param;
|
|
||||||
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
||||||
|
|
||||||
material.forEachTexture([=] (auto &tex) {
|
material.forEachTexture([=] (auto &tex) {
|
||||||
|
@ -1333,7 +1414,6 @@ void GenericCAO::updateTextures(std::string mod)
|
||||||
// Set material flags and texture
|
// Set material flags and texture
|
||||||
video::SMaterial &material = m_animated_meshnode->getMaterial(i);
|
video::SMaterial &material = m_animated_meshnode->getMaterial(i);
|
||||||
material.MaterialType = m_material_type;
|
material.MaterialType = m_material_type;
|
||||||
material.MaterialTypeParam = m_material_type_param;
|
|
||||||
material.TextureLayers[0].Texture = texture;
|
material.TextureLayers[0].Texture = texture;
|
||||||
material.BackfaceCulling = m_prop.backface_culling;
|
material.BackfaceCulling = m_prop.backface_culling;
|
||||||
|
|
||||||
|
@ -1365,7 +1445,6 @@ void GenericCAO::updateTextures(std::string mod)
|
||||||
// Set material flags and texture
|
// Set material flags and texture
|
||||||
video::SMaterial &material = m_meshnode->getMaterial(i);
|
video::SMaterial &material = m_meshnode->getMaterial(i);
|
||||||
material.MaterialType = m_material_type;
|
material.MaterialType = m_material_type;
|
||||||
material.MaterialTypeParam = m_material_type_param;
|
|
||||||
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
||||||
material.getTextureMatrix(0).makeIdentity();
|
material.getTextureMatrix(0).makeIdentity();
|
||||||
|
|
||||||
|
@ -1532,7 +1611,7 @@ bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const
|
||||||
/* Visuals do not need to be expired for:
|
/* Visuals do not need to be expired for:
|
||||||
* - nametag props: handled by updateNametag()
|
* - nametag props: handled by updateNametag()
|
||||||
* - textures: handled by updateTextures()
|
* - textures: handled by updateTextures()
|
||||||
* - sprite props: handled by updateTexturePos()
|
* - sprite props: handled by updateTextureAnim()
|
||||||
* - glow: handled by updateLight()
|
* - glow: handled by updateLight()
|
||||||
* - any other properties that do not change appearance
|
* - any other properties that do not change appearance
|
||||||
*/
|
*/
|
||||||
|
@ -1542,9 +1621,10 @@ bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const
|
||||||
// Ordered to compare primitive types before std::vectors
|
// Ordered to compare primitive types before std::vectors
|
||||||
return old.backface_culling != new_.backface_culling ||
|
return old.backface_culling != new_.backface_culling ||
|
||||||
old.is_visible != new_.is_visible ||
|
old.is_visible != new_.is_visible ||
|
||||||
old.mesh != new_.mesh ||
|
|
||||||
old.shaded != new_.shaded ||
|
old.shaded != new_.shaded ||
|
||||||
old.use_texture_alpha != new_.use_texture_alpha ||
|
old.use_texture_alpha != new_.use_texture_alpha ||
|
||||||
|
old.node != new_.node ||
|
||||||
|
old.mesh != new_.mesh ||
|
||||||
old.visual != new_.visual ||
|
old.visual != new_.visual ||
|
||||||
old.visual_size != new_.visual_size ||
|
old.visual_size != new_.visual_size ||
|
||||||
old.wield_item != new_.wield_item ||
|
old.wield_item != new_.wield_item ||
|
||||||
|
@ -1655,7 +1735,7 @@ void GenericCAO::processMessage(const std::string &data)
|
||||||
m_anim_framelength = framelength;
|
m_anim_framelength = framelength;
|
||||||
m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
|
m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
|
||||||
|
|
||||||
updateTexturePos();
|
updateTextureAnim();
|
||||||
} else if (cmd == AO_CMD_SET_PHYSICS_OVERRIDE) {
|
} else if (cmd == AO_CMD_SET_PHYSICS_OVERRIDE) {
|
||||||
float override_speed = readF32(is);
|
float override_speed = readF32(is);
|
||||||
float override_jump = readF32(is);
|
float override_jump = readF32(is);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "clientobject.h"
|
#include "clientobject.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "itemgroup.h"
|
#include "itemgroup.h"
|
||||||
|
#include "client/tile.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -27,7 +28,7 @@ struct Nametag;
|
||||||
struct MinimapMarker;
|
struct MinimapMarker;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SmoothTranslator
|
SmoothTranslator and other helpers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -60,9 +61,21 @@ struct SmoothTranslatorWrappedv3f : SmoothTranslator<v3f>
|
||||||
void translate(f32 dtime);
|
void translate(f32 dtime);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MeshAnimationInfo {
|
||||||
|
u32 i; /// index of mesh buffer
|
||||||
|
int frame; /// last animation frame
|
||||||
|
TileLayer tile;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
GenericCAO
|
||||||
|
*/
|
||||||
|
|
||||||
class GenericCAO : public ClientActiveObject
|
class GenericCAO : public ClientActiveObject
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
static constexpr auto EMT_INVALID = video::EMT_FORCE_32BIT;
|
||||||
|
|
||||||
// Only set at initialization
|
// Only set at initialization
|
||||||
std::string m_name = "";
|
std::string m_name = "";
|
||||||
bool m_is_player = false;
|
bool m_is_player = false;
|
||||||
|
@ -73,6 +86,8 @@ private:
|
||||||
scene::ISceneManager *m_smgr = nullptr;
|
scene::ISceneManager *m_smgr = nullptr;
|
||||||
Client *m_client = nullptr;
|
Client *m_client = nullptr;
|
||||||
aabb3f m_selection_box = aabb3f(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.);
|
aabb3f m_selection_box = aabb3f(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.);
|
||||||
|
|
||||||
|
// Visuals
|
||||||
scene::IMeshSceneNode *m_meshnode = nullptr;
|
scene::IMeshSceneNode *m_meshnode = nullptr;
|
||||||
scene::IAnimatedMeshSceneNode *m_animated_meshnode = nullptr;
|
scene::IAnimatedMeshSceneNode *m_animated_meshnode = nullptr;
|
||||||
WieldMeshSceneNode *m_wield_meshnode = nullptr;
|
WieldMeshSceneNode *m_wield_meshnode = nullptr;
|
||||||
|
@ -80,6 +95,15 @@ private:
|
||||||
scene::IDummyTransformationSceneNode *m_matrixnode = nullptr;
|
scene::IDummyTransformationSceneNode *m_matrixnode = nullptr;
|
||||||
Nametag *m_nametag = nullptr;
|
Nametag *m_nametag = nullptr;
|
||||||
MinimapMarker *m_marker = nullptr;
|
MinimapMarker *m_marker = nullptr;
|
||||||
|
bool m_visuals_expired = false;
|
||||||
|
video::SColor m_last_light = video::SColor(0xFFFFFFFF);
|
||||||
|
bool m_is_visible = false;
|
||||||
|
std::vector<MeshAnimationInfo> m_meshnode_animation;
|
||||||
|
|
||||||
|
// Material
|
||||||
|
video::E_MATERIAL_TYPE m_material_type = EMT_INVALID;
|
||||||
|
|
||||||
|
// Movement
|
||||||
v3f m_position = v3f(0.0f, 10.0f * BS, 0);
|
v3f m_position = v3f(0.0f, 10.0f * BS, 0);
|
||||||
v3f m_velocity;
|
v3f m_velocity;
|
||||||
v3f m_acceleration;
|
v3f m_acceleration;
|
||||||
|
@ -87,18 +111,25 @@ private:
|
||||||
u16 m_hp = 1;
|
u16 m_hp = 1;
|
||||||
SmoothTranslator<v3f> pos_translator;
|
SmoothTranslator<v3f> pos_translator;
|
||||||
SmoothTranslatorWrappedv3f rot_translator;
|
SmoothTranslatorWrappedv3f rot_translator;
|
||||||
// Spritesheet/animation stuff
|
|
||||||
|
// Spritesheet stuff
|
||||||
v2f m_tx_size = v2f(1,1);
|
v2f m_tx_size = v2f(1,1);
|
||||||
v2s16 m_tx_basepos;
|
v2s16 m_tx_basepos;
|
||||||
bool m_initial_tx_basepos_set = false;
|
bool m_initial_tx_basepos_set = false;
|
||||||
bool m_tx_select_horiz_by_yawpitch = false;
|
bool m_tx_select_horiz_by_yawpitch = false;
|
||||||
|
bool m_animation_loop = true;
|
||||||
v2f m_animation_range;
|
v2f m_animation_range;
|
||||||
float m_animation_speed = 15.0f;
|
float m_animation_speed = 15.0f;
|
||||||
float m_animation_blend = 0.0f;
|
float m_animation_blend = 0.0f;
|
||||||
bool m_animation_loop = true;
|
int m_anim_frame = 0;
|
||||||
|
int m_anim_num_frames = 1;
|
||||||
|
float m_anim_framelength = 0.2f;
|
||||||
|
float m_anim_timer = 0.0f;
|
||||||
|
|
||||||
// stores position and rotation for each bone name
|
// stores position and rotation for each bone name
|
||||||
BoneOverrideMap m_bone_override;
|
BoneOverrideMap m_bone_override;
|
||||||
|
|
||||||
|
// Attachments
|
||||||
object_t m_attachment_parent_id = 0;
|
object_t m_attachment_parent_id = 0;
|
||||||
std::unordered_set<object_t> m_attachment_child_ids;
|
std::unordered_set<object_t> m_attachment_child_ids;
|
||||||
std::string m_attachment_bone = "";
|
std::string m_attachment_bone = "";
|
||||||
|
@ -107,23 +138,13 @@ private:
|
||||||
bool m_attached_to_local = false;
|
bool m_attached_to_local = false;
|
||||||
bool m_force_visible = false;
|
bool m_force_visible = false;
|
||||||
|
|
||||||
int m_anim_frame = 0;
|
|
||||||
int m_anim_num_frames = 1;
|
|
||||||
float m_anim_framelength = 0.2f;
|
|
||||||
float m_anim_timer = 0.0f;
|
|
||||||
ItemGroupList m_armor_groups;
|
ItemGroupList m_armor_groups;
|
||||||
float m_reset_textures_timer = -1.0f;
|
float m_reset_textures_timer = -1.0f;
|
||||||
// stores texture modifier before punch update
|
// stores texture modifier before punch update
|
||||||
std::string m_previous_texture_modifier = "";
|
std::string m_previous_texture_modifier = "";
|
||||||
// last applied texture modifier
|
// last applied texture modifier
|
||||||
std::string m_current_texture_modifier = "";
|
std::string m_current_texture_modifier = "";
|
||||||
bool m_visuals_expired = false;
|
|
||||||
float m_step_distance_counter = 0.0f;
|
float m_step_distance_counter = 0.0f;
|
||||||
video::SColor m_last_light = video::SColor(0xFFFFFFFF);
|
|
||||||
bool m_is_visible = false;
|
|
||||||
// Material
|
|
||||||
video::E_MATERIAL_TYPE m_material_type;
|
|
||||||
f32 m_material_type_param;
|
|
||||||
|
|
||||||
bool visualExpiryRequired(const ObjectProperties &newprops) const;
|
bool visualExpiryRequired(const ObjectProperties &newprops) const;
|
||||||
|
|
||||||
|
@ -255,7 +276,7 @@ public:
|
||||||
|
|
||||||
void step(float dtime, ClientEnvironment *env) override;
|
void step(float dtime, ClientEnvironment *env) override;
|
||||||
|
|
||||||
void updateTexturePos();
|
void updateTextureAnim();
|
||||||
|
|
||||||
// ffs this HAS TO BE a string copy! See #5739 if you think otherwise
|
// ffs this HAS TO BE a string copy! See #5739 if you think otherwise
|
||||||
// Reason: updateTextures(m_previous_texture_modifier);
|
// Reason: updateTextures(m_previous_texture_modifier);
|
||||||
|
|
|
@ -426,20 +426,6 @@ void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *dat
|
||||||
tile.rotation = tile.world_aligned ? TileRotation::None : dir_to_tile[facedir][dir_i].rotation;
|
tile.rotation = tile.world_aligned ? TileRotation::None : dir_to_tile[facedir][dir_i].rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void applyTileColor(PreMeshBuffer &pmb)
|
|
||||||
{
|
|
||||||
video::SColor tc = pmb.layer.color;
|
|
||||||
if (tc == video::SColor(0xFFFFFFFF))
|
|
||||||
return;
|
|
||||||
for (video::S3DVertex &vertex : pmb.vertices) {
|
|
||||||
video::SColor *c = &vertex.Color;
|
|
||||||
c->set(c->getAlpha(),
|
|
||||||
c->getRed() * tc.getRed() / 255,
|
|
||||||
c->getGreen() * tc.getGreen() / 255,
|
|
||||||
c->getBlue() * tc.getBlue() / 255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MapBlockBspTree
|
MapBlockBspTree
|
||||||
*/
|
*/
|
||||||
|
@ -668,7 +654,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
|
||||||
{
|
{
|
||||||
PreMeshBuffer &p = collector.prebuffers[layer][i];
|
PreMeshBuffer &p = collector.prebuffers[layer][i];
|
||||||
|
|
||||||
applyTileColor(p);
|
p.applyTileColor();
|
||||||
|
|
||||||
// Generate animation data
|
// Generate animation data
|
||||||
// - Cracks
|
// - Cracks
|
||||||
|
|
|
@ -18,6 +18,21 @@ struct PreMeshBuffer
|
||||||
|
|
||||||
PreMeshBuffer() = default;
|
PreMeshBuffer() = default;
|
||||||
explicit PreMeshBuffer(const TileLayer &layer) : layer(layer) {}
|
explicit PreMeshBuffer(const TileLayer &layer) : layer(layer) {}
|
||||||
|
|
||||||
|
/// @brief Colorizes vertices as indicated by tile layer
|
||||||
|
void applyTileColor()
|
||||||
|
{
|
||||||
|
video::SColor tc = layer.color;
|
||||||
|
if (tc == video::SColor(0xFFFFFFFF))
|
||||||
|
return;
|
||||||
|
for (auto &vertex : vertices) {
|
||||||
|
video::SColor *c = &vertex.Color;
|
||||||
|
c->set(c->getAlpha(),
|
||||||
|
c->getRed() * tc.getRed() / 255U,
|
||||||
|
c->getGreen() * tc.getGreen() / 255U,
|
||||||
|
c->getBlue() * tc.getBlue() / 255U);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MeshCollector
|
struct MeshCollector
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <SMaterial.h>
|
#include <SMaterial.h>
|
||||||
|
|
||||||
enum MaterialType{
|
enum MaterialType : u8 {
|
||||||
TILE_MATERIAL_BASIC,
|
TILE_MATERIAL_BASIC,
|
||||||
TILE_MATERIAL_ALPHA,
|
TILE_MATERIAL_ALPHA,
|
||||||
TILE_MATERIAL_LIQUID_TRANSPARENT,
|
TILE_MATERIAL_LIQUID_TRANSPARENT,
|
||||||
|
@ -98,9 +98,10 @@ struct TileLayer
|
||||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||||
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
||||||
return true;
|
return true;
|
||||||
}
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ordered for size, please do not reorder
|
// Ordered for size, please do not reorder
|
||||||
|
|
||||||
|
@ -113,13 +114,14 @@ struct TileLayer
|
||||||
u16 animation_frame_length_ms = 0;
|
u16 animation_frame_length_ms = 0;
|
||||||
u16 animation_frame_count = 1;
|
u16 animation_frame_count = 1;
|
||||||
|
|
||||||
u8 material_type = TILE_MATERIAL_BASIC;
|
MaterialType material_type = TILE_MATERIAL_BASIC;
|
||||||
u8 material_flags =
|
u8 material_flags =
|
||||||
//0 // <- DEBUG, Use the one below
|
//0 // <- DEBUG, Use the one below
|
||||||
MATERIAL_FLAG_BACKFACE_CULLING |
|
MATERIAL_FLAG_BACKFACE_CULLING |
|
||||||
MATERIAL_FLAG_TILEABLE_HORIZONTAL|
|
MATERIAL_FLAG_TILEABLE_HORIZONTAL|
|
||||||
MATERIAL_FLAG_TILEABLE_VERTICAL;
|
MATERIAL_FLAG_TILEABLE_VERTICAL;
|
||||||
|
|
||||||
|
/// @note not owned by this struct
|
||||||
std::vector<FrameSpec> *frames = nullptr;
|
std::vector<FrameSpec> *frames = nullptr;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -145,7 +145,7 @@ struct alignas(u32) MapNode
|
||||||
|
|
||||||
MapNode() = default;
|
MapNode() = default;
|
||||||
|
|
||||||
MapNode(content_t content, u8 a_param1=0, u8 a_param2=0) noexcept
|
constexpr MapNode(content_t content, u8 a_param1=0, u8 a_param2=0) noexcept
|
||||||
: param0(content),
|
: param0(content),
|
||||||
param1(a_param1),
|
param1(a_param1),
|
||||||
param2(a_param2)
|
param2(a_param2)
|
||||||
|
@ -157,6 +157,10 @@ struct alignas(u32) MapNode
|
||||||
&& param1 == other.param1
|
&& param1 == other.param1
|
||||||
&& param2 == other.param2);
|
&& param2 == other.param2);
|
||||||
}
|
}
|
||||||
|
bool operator!=(const MapNode &other) const noexcept
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
// To be used everywhere
|
// To be used everywhere
|
||||||
content_t getContent() const noexcept
|
content_t getContent() const noexcept
|
||||||
|
|
|
@ -669,7 +669,7 @@ void ContentFeatures::deSerialize(std::istream &is, u16 protocol_version)
|
||||||
#if CHECK_CLIENT_BUILD()
|
#if CHECK_CLIENT_BUILD()
|
||||||
static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer,
|
static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer,
|
||||||
const TileSpec &tile, const TileDef &tiledef, video::SColor color,
|
const TileSpec &tile, const TileDef &tiledef, video::SColor color,
|
||||||
u8 material_type, u32 shader_id, bool backface_culling,
|
MaterialType material_type, u32 shader_id, bool backface_culling,
|
||||||
const TextureSettings &tsettings)
|
const TextureSettings &tsettings)
|
||||||
{
|
{
|
||||||
layer->shader_id = shader_id;
|
layer->shader_id = shader_id;
|
||||||
|
|
|
@ -63,6 +63,8 @@ std::string ObjectProperties::dump() const
|
||||||
os << ", static_save=" << static_save;
|
os << ", static_save=" << static_save;
|
||||||
os << ", eye_height=" << eye_height;
|
os << ", eye_height=" << eye_height;
|
||||||
os << ", zoom_fov=" << zoom_fov;
|
os << ", zoom_fov=" << zoom_fov;
|
||||||
|
os << ", node=(" << (int)node.getContent() << ", " << (int)node.getParam1()
|
||||||
|
<< ", " << (int)node.getParam2() << ")";
|
||||||
os << ", use_texture_alpha=" << use_texture_alpha;
|
os << ", use_texture_alpha=" << use_texture_alpha;
|
||||||
os << ", damage_texture_modifier=" << damage_texture_modifier;
|
os << ", damage_texture_modifier=" << damage_texture_modifier;
|
||||||
os << ", shaded=" << shaded;
|
os << ", shaded=" << shaded;
|
||||||
|
@ -79,8 +81,8 @@ static auto tie(const ObjectProperties &o)
|
||||||
o.nametag_color, o.nametag_bgcolor, o.spritediv, o.initial_sprite_basepos,
|
o.nametag_color, o.nametag_bgcolor, o.spritediv, o.initial_sprite_basepos,
|
||||||
o.stepheight, o.automatic_rotate, o.automatic_face_movement_dir_offset,
|
o.stepheight, o.automatic_rotate, o.automatic_face_movement_dir_offset,
|
||||||
o.automatic_face_movement_max_rotation_per_sec, o.eye_height, o.zoom_fov,
|
o.automatic_face_movement_max_rotation_per_sec, o.eye_height, o.zoom_fov,
|
||||||
o.hp_max, o.breath_max, o.glow, o.pointable, o.physical, o.collideWithObjects,
|
o.node, o.hp_max, o.breath_max, o.glow, o.pointable, o.physical,
|
||||||
o.rotate_selectionbox, o.is_visible, o.makes_footstep_sound,
|
o.collideWithObjects, o.rotate_selectionbox, o.is_visible, o.makes_footstep_sound,
|
||||||
o.automatic_face_movement_dir, o.backface_culling, o.static_save, o.use_texture_alpha,
|
o.automatic_face_movement_dir, o.backface_culling, o.static_save, o.use_texture_alpha,
|
||||||
o.shaded, o.show_on_minimap
|
o.shaded, o.show_on_minimap
|
||||||
);
|
);
|
||||||
|
@ -170,6 +172,7 @@ void ObjectProperties::serialize(std::ostream &os) const
|
||||||
writeU8(os, shaded);
|
writeU8(os, shaded);
|
||||||
writeU8(os, show_on_minimap);
|
writeU8(os, show_on_minimap);
|
||||||
|
|
||||||
|
// use special value to tell apart nil, fully transparent and other colors
|
||||||
if (!nametag_bgcolor)
|
if (!nametag_bgcolor)
|
||||||
writeARGB8(os, NULL_BGCOLOR);
|
writeARGB8(os, NULL_BGCOLOR);
|
||||||
else if (nametag_bgcolor.value().getAlpha() == 0)
|
else if (nametag_bgcolor.value().getAlpha() == 0)
|
||||||
|
@ -178,8 +181,31 @@ void ObjectProperties::serialize(std::ostream &os) const
|
||||||
writeARGB8(os, nametag_bgcolor.value());
|
writeARGB8(os, nametag_bgcolor.value());
|
||||||
|
|
||||||
writeU8(os, rotate_selectionbox);
|
writeU8(os, rotate_selectionbox);
|
||||||
|
writeU16(os, node.getContent());
|
||||||
|
writeU8(os, node.getParam1());
|
||||||
|
writeU8(os, node.getParam2());
|
||||||
|
|
||||||
// Add stuff only at the bottom.
|
// Add stuff only at the bottom.
|
||||||
// Never remove anything, because we don't want new versions of this
|
// Never remove anything, because we don't want new versions of this!
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Type-safe wrapper for bools as u8
|
||||||
|
inline bool readBool(std::istream &is)
|
||||||
|
{
|
||||||
|
return readU8(is) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper for primitive reading functions that don't throw (awful)
|
||||||
|
template <typename T, T (reader)(std::istream& is)>
|
||||||
|
bool tryRead(T& val, std::istream& is)
|
||||||
|
{
|
||||||
|
T tmp = reader(is);
|
||||||
|
if (is.eof())
|
||||||
|
return false;
|
||||||
|
val = tmp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectProperties::deSerialize(std::istream &is)
|
void ObjectProperties::deSerialize(std::istream &is)
|
||||||
|
@ -229,16 +255,18 @@ void ObjectProperties::deSerialize(std::istream &is)
|
||||||
eye_height = readF32(is);
|
eye_height = readF32(is);
|
||||||
zoom_fov = readF32(is);
|
zoom_fov = readF32(is);
|
||||||
use_texture_alpha = readU8(is);
|
use_texture_alpha = readU8(is);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
damage_texture_modifier = deSerializeString16(is);
|
damage_texture_modifier = deSerializeString16(is);
|
||||||
u8 tmp = readU8(is);
|
} catch (SerializationError &e) {
|
||||||
if (is.eof())
|
|
||||||
return;
|
return;
|
||||||
shaded = tmp;
|
}
|
||||||
tmp = readU8(is);
|
|
||||||
if (is.eof())
|
if (!tryRead<bool, readBool>(shaded, is))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!tryRead<bool, readBool>(show_on_minimap, is))
|
||||||
return;
|
return;
|
||||||
show_on_minimap = tmp;
|
|
||||||
|
|
||||||
auto bgcolor = readARGB8(is);
|
auto bgcolor = readARGB8(is);
|
||||||
if (bgcolor != NULL_BGCOLOR)
|
if (bgcolor != NULL_BGCOLOR)
|
||||||
|
@ -246,9 +274,13 @@ void ObjectProperties::deSerialize(std::istream &is)
|
||||||
else
|
else
|
||||||
nametag_bgcolor = std::nullopt;
|
nametag_bgcolor = std::nullopt;
|
||||||
|
|
||||||
tmp = readU8(is);
|
if (!tryRead<bool, readBool>(rotate_selectionbox, is))
|
||||||
if (is.eof())
|
|
||||||
return;
|
return;
|
||||||
rotate_selectionbox = tmp;
|
|
||||||
} catch (SerializationError &e) {}
|
if (!tryRead<content_t, readU16>(node.param0, is))
|
||||||
|
return;
|
||||||
|
node.param1 = readU8(is);
|
||||||
|
node.param2 = readU8(is);
|
||||||
|
|
||||||
|
// Add new properties down here and remember to use either tryRead<> or a try-catch.
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "util/pointabilities.h"
|
#include "util/pointabilities.h"
|
||||||
|
#include "mapnode.h"
|
||||||
|
|
||||||
struct ObjectProperties
|
struct ObjectProperties
|
||||||
{
|
{
|
||||||
|
@ -39,6 +40,7 @@ struct ObjectProperties
|
||||||
f32 automatic_face_movement_max_rotation_per_sec = -1.0f;
|
f32 automatic_face_movement_max_rotation_per_sec = -1.0f;
|
||||||
float eye_height = 1.625f;
|
float eye_height = 1.625f;
|
||||||
float zoom_fov = 0.0f;
|
float zoom_fov = 0.0f;
|
||||||
|
MapNode node = MapNode(CONTENT_IGNORE);
|
||||||
u16 hp_max = 1;
|
u16 hp_max = 1;
|
||||||
u16 breath_max = 0;
|
u16 breath_max = 0;
|
||||||
s8 glow = 0;
|
s8 glow = 0;
|
||||||
|
|
|
@ -294,11 +294,13 @@ const std::array<const char *, 33> object_property_keys = {
|
||||||
"shaded",
|
"shaded",
|
||||||
"damage_texture_modifier",
|
"damage_texture_modifier",
|
||||||
"show_on_minimap",
|
"show_on_minimap",
|
||||||
|
// "node" is intentionally not here as it's gated behind `fallback` below!
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void read_object_properties(lua_State *L, int index,
|
void read_object_properties(lua_State *L, int index,
|
||||||
ServerActiveObject *sao, ObjectProperties *prop, IItemDefManager *idef)
|
ServerActiveObject *sao, ObjectProperties *prop, IItemDefManager *idef,
|
||||||
|
bool fallback)
|
||||||
{
|
{
|
||||||
if(index < 0)
|
if(index < 0)
|
||||||
index = lua_gettop(L) + 1 + index;
|
index = lua_gettop(L) + 1 + index;
|
||||||
|
@ -399,6 +401,16 @@ void read_object_properties(lua_State *L, int index,
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
// This hack exists because the name 'node' easily collides with mods own
|
||||||
|
// usage (or in this case literally builtin/game/falling.lua).
|
||||||
|
if (!fallback) {
|
||||||
|
lua_getfield(L, -1, "node");
|
||||||
|
if (lua_istable(L, -1)) {
|
||||||
|
prop->node = readnode(L, -1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
lua_getfield(L, -1, "spritediv");
|
lua_getfield(L, -1, "spritediv");
|
||||||
if(lua_istable(L, -1))
|
if(lua_istable(L, -1))
|
||||||
prop->spritediv = read_v2s16(L, -1);
|
prop->spritediv = read_v2s16(L, -1);
|
||||||
|
@ -513,6 +525,8 @@ void push_object_properties(lua_State *L, const ObjectProperties *prop)
|
||||||
}
|
}
|
||||||
lua_setfield(L, -2, "colors");
|
lua_setfield(L, -2, "colors");
|
||||||
|
|
||||||
|
pushnode(L, prop->node);
|
||||||
|
lua_setfield(L, -2, "node");
|
||||||
push_v2s16(L, prop->spritediv);
|
push_v2s16(L, prop->spritediv);
|
||||||
lua_setfield(L, -2, "spritediv");
|
lua_setfield(L, -2, "spritediv");
|
||||||
push_v2s16(L, prop->initial_sprite_basepos);
|
push_v2s16(L, prop->initial_sprite_basepos);
|
||||||
|
|
|
@ -99,10 +99,10 @@ void read_item_definition(lua_State *L, int index,
|
||||||
void push_item_definition(lua_State *L, const ItemDefinition &i);
|
void push_item_definition(lua_State *L, const ItemDefinition &i);
|
||||||
void push_item_definition_full(lua_State *L, const ItemDefinition &i);
|
void push_item_definition_full(lua_State *L, const ItemDefinition &i);
|
||||||
|
|
||||||
|
/// @param fallback set to true if reading from bare entity table (not initial_properties)
|
||||||
void read_object_properties(lua_State *L, int index,
|
void read_object_properties(lua_State *L, int index,
|
||||||
ServerActiveObject *sao,
|
ServerActiveObject *sao, ObjectProperties *prop,
|
||||||
ObjectProperties *prop,
|
IItemDefManager *idef, bool fallback = false);
|
||||||
IItemDefManager *idef);
|
|
||||||
|
|
||||||
void push_object_properties(lua_State *L, const ObjectProperties *prop);
|
void push_object_properties(lua_State *L, const ObjectProperties *prop);
|
||||||
|
|
||||||
|
|
|
@ -197,13 +197,17 @@ void ScriptApiEntity::luaentity_GetProperties(u16 id,
|
||||||
// Set default values that differ from ObjectProperties defaults
|
// Set default values that differ from ObjectProperties defaults
|
||||||
prop->hp_max = 10;
|
prop->hp_max = 10;
|
||||||
|
|
||||||
|
auto *idef = getServer()->idef();
|
||||||
|
|
||||||
// Deprecated: read object properties directly
|
// Deprecated: read object properties directly
|
||||||
|
// TODO: this should be changed to not read the legacy place
|
||||||
|
// if `initial_properties` exists!
|
||||||
logDeprecationForExistingProperties(L, -1, entity_name);
|
logDeprecationForExistingProperties(L, -1, entity_name);
|
||||||
read_object_properties(L, -1, self, prop, getServer()->idef());
|
read_object_properties(L, -1, self, prop, idef, true);
|
||||||
|
|
||||||
// Read initial_properties
|
// Read initial_properties
|
||||||
lua_getfield(L, -1, "initial_properties");
|
lua_getfield(L, -1, "initial_properties");
|
||||||
read_object_properties(L, -1, self, prop, getServer()->idef());
|
read_object_properties(L, -1, self, prop, idef);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue