1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-08-01 17:38:41 +00:00

Merge remote-tracking branch 'upstream/master' into Visuals-Vol-2

This commit is contained in:
Gefüllte Taubenbrust 2025-01-14 20:31:26 +01:00
commit 6b1785eb2c
128 changed files with 1273 additions and 1076 deletions

View file

@ -417,7 +417,6 @@ set(independent_SRCS
hud.cpp
inventory.cpp
itemstackmetadata.cpp
lighting.cpp
log.cpp
metadata.cpp
modchannels.cpp

View file

@ -5,7 +5,6 @@
#pragma once
#include <memory>
#include "debug.h"
#include "util/container.h"
#include "irrlichttypes.h"
#include "util/basic_macros.h"

View file

@ -112,7 +112,8 @@ public:
void resize(u32 scrollback);
protected:
// Get the current scroll position
s32 getScrollPosition() const { return m_scroll; }
s32 getTopScrollPos() const;
s32 getBottomScrollPos() const;

View file

@ -4,10 +4,9 @@
#pragma once
#include "util/container.h"
#include <string>
#include <queue>
#include "irrlichttypes.h"
#include "util/container.h" // MutexedQueue
#include <string>
enum ChatEventType {
CET_CHAT,

View file

@ -37,6 +37,7 @@
#include "profiler.h"
#include "shader.h"
#include "gettext.h"
#include "gettime.h"
#include "clientdynamicinfo.h"
#include "clientmap.h"
#include "clientmedia.h"

View file

@ -91,8 +91,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
init_args(start_data, cmd_args);
#if USE_SOUND
if (g_settings->getBool("enable_sound"))
g_sound_manager_singleton = createSoundManagerSingleton();
g_sound_manager_singleton = createSoundManagerSingleton();
#endif
if (!init_engine())

View file

@ -445,8 +445,8 @@ void Clouds::readSettings()
// chosen to avoid exactly that.
// refer to vertex_count in updateMesh()
m_enable_3d = g_settings->getBool("enable_3d_clouds");
const u16 maximum = m_enable_3d ? 62 : 25;
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, maximum);
const u16 maximum = !m_enable_3d ? 62 : 25;
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 8, maximum);
invalidateMesh();
}

View file

@ -656,25 +656,33 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
}
} else if (m_prop.visual == "upright_sprite") {
grabMatrixNode();
scene::SMesh *mesh = new scene::SMesh();
double dx = BS * m_prop.visual_size.X / 2;
double dy = BS * m_prop.visual_size.Y / 2;
auto mesh = make_irr<scene::SMesh>();
f32 dx = BS * m_prop.visual_size.X / 2;
f32 dy = BS * m_prop.visual_size.Y / 2;
video::SColor c(0xFFFFFFFF);
{ // Front
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::S3DVertex vertices[4] = {
video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1),
video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1),
video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0),
video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0),
};
if (m_is_player) {
// Move minimal Y position to 0 (feet position)
for (video::S3DVertex &vertex : vertices)
vertex.Pos.Y += dy;
video::S3DVertex vertices[4] = {
video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1),
video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1),
video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0),
video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0),
};
if (m_is_player) {
// Move minimal Y position to 0 (feet position)
for (auto &vertex : vertices)
vertex.Pos.Y += dy;
}
const u16 indices[] = {0,1,2,2,3,0};
for (int face : {0, 1}) {
auto buf = make_irr<scene::SMeshBuffer>();
// Front (0) or Back (1)
if (face == 1) {
for (auto &v : vertices)
v.Normal *= -1;
for (int i : {0, 2})
std::swap(vertices[i].Pos, vertices[i+1].Pos);
}
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
@ -682,36 +690,12 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
buf->getMaterial().ColorParam = c;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
mesh->addMeshBuffer(buf.get());
}
{ // Back
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::S3DVertex vertices[4] = {
video::S3DVertex( dx,-dy, 0, 0,0,-1, c, 1,1),
video::S3DVertex(-dx,-dy, 0, 0,0,-1, c, 0,1),
video::S3DVertex(-dx, dy, 0, 0,0,-1, c, 0,0),
video::S3DVertex( dx, dy, 0, 0,0,-1, c, 1,0),
};
if (m_is_player) {
// Move minimal Y position to 0 (feet position)
for (video::S3DVertex &vertex : vertices)
vertex.Pos.Y += dy;
}
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
setMaterial(buf->getMaterial());
buf->getMaterial().ColorParam = c;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
mesh->recalculateBoundingBox();
m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode);
m_meshnode->grab();
mesh->drop();
} else if (m_prop.visual == "cube") {
grabMatrixNode();
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));

View file

@ -4,15 +4,23 @@
#pragma once
#include <map>
#include "irrlichttypes_extrabloated.h"
#include "clientobject.h"
#include "EMaterialTypes.h"
#include "IDummyTransformationSceneNode.h"
#include "irrlichttypes.h"
#include "object_properties.h"
#include "itemgroup.h"
#include "clientobject.h"
#include "constants.h"
#include "itemgroup.h"
#include <cassert>
#include <map>
#include <memory>
namespace irr::scene {
class IMeshSceneNode;
class IBillboardSceneNode;
}
class Camera;
class Client;
struct Nametag;

View file

@ -62,46 +62,44 @@ const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_railli
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output):
data(input),
collector(output),
nodedef(data->nodedef),
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE),
smooth_liquids(g_settings->getBool("enable_water_reflections"))
nodedef(data->m_nodedef),
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE)
{
}
void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special)
void MapblockMeshGenerator::useTile(TileSpec *tile_ret, int index, u8 set_flags,
u8 reset_flags, bool special)
{
if (special)
getSpecialTile(index, &cur_node.tile, cur_node.p == data->m_crack_pos_relative);
getSpecialTile(index, tile_ret, cur_node.p == data->m_crack_pos_relative);
else
getTile(index, &cur_node.tile);
if (!data->m_smooth_lighting)
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
getTile(index, tile_ret);
for (auto &layer : cur_node.tile.layers) {
for (auto &layer : tile_ret->layers) {
layer.material_flags |= set_flags;
layer.material_flags &= ~reset_flags;
}
}
// Returns a tile, ready for use, non-rotated.
void MapblockMeshGenerator::getTile(int index, TileSpec *tile)
void MapblockMeshGenerator::getTile(int index, TileSpec *tile_ret)
{
getNodeTileN(cur_node.n, cur_node.p, index, data, *tile);
getNodeTileN(cur_node.n, cur_node.p, index, data, *tile_ret);
}
// Returns a tile, ready for use, rotated according to the node facedir.
void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile)
void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile_ret)
{
getNodeTile(cur_node.n, cur_node.p, direction, data, *tile);
getNodeTile(cur_node.n, cur_node.p, direction, data, *tile_ret);
}
// Returns a special tile, ready for use, non-rotated.
void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply_crack)
void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack)
{
*tile = cur_node.f->special_tiles[index];
*tile_ret = cur_node.f->special_tiles[index];
TileLayer *top_layer = nullptr;
for (auto &layernum : tile->layers) {
for (auto &layernum : tile_ret->layers) {
TileLayer *layer = &layernum;
if (layer->texture_id == 0)
continue;
@ -114,7 +112,7 @@ void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply
top_layer->material_flags |= MATERIAL_FLAG_CRACK;
}
void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
void MapblockMeshGenerator::drawQuad(const TileSpec &tile, v3f *coords, const v3s16 &normal,
float vertical_tiling)
{
const v2f tcoords[4] = {v2f(0.0, 0.0), v2f(1.0, 0.0),
@ -128,15 +126,17 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
if (data->m_smooth_lighting)
vertices[j].Color = blendLightColor(coords[j]);
else
vertices[j].Color = cur_node.color;
vertices[j].Color = cur_node.lcolor;
if (shade_face)
applyFacesShading(vertices[j].Color, normal2);
vertices[j].TCoords = tcoords[j];
}
collector->append(cur_node.tile, vertices, 4, quad_indices, 6);
collector->append(tile, vertices, 4, quad_indices, 6);
}
static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box, const f32 *txc, TileSpec *tiles, int tilecount) {
static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box,
const f32 *txc, const TileSpec *tiles, int tilecount)
{
v3f min = box.MinEdge;
v3f max = box.MaxEdge;
@ -218,7 +218,7 @@ enum class QuadDiagonal {
// and to choose diagonal to split the quad at.
template <typename Fn>
void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter)
const TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter)
{
assert(tilecount >= 1 && tilecount <= 6); // pre-condition
@ -238,16 +238,16 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
void MapblockMeshGenerator::getSmoothLightFrame()
{
for (int k = 0; k < 8; ++k)
cur_node.frame.sunlight[k] = false;
cur_node.lframe.sunlight[k] = false;
for (int k = 0; k < 8; ++k) {
LightPair light(getSmoothLightTransparent(blockpos_nodes + cur_node.p, light_dirs[k], data));
cur_node.frame.lightsDay[k] = light.lightDay;
cur_node.frame.lightsNight[k] = light.lightNight;
cur_node.lframe.lightsDay[k] = light.lightDay;
cur_node.lframe.lightsNight[k] = light.lightNight;
// If there is direct sunlight and no ambient occlusion at some corner,
// mark the vertical edge (top and bottom corners) containing it.
if (light.lightDay == 255) {
cur_node.frame.sunlight[k] = true;
cur_node.frame.sunlight[k ^ 2] = true;
cur_node.lframe.sunlight[k] = true;
cur_node.lframe.sunlight[k ^ 2] = true;
}
}
}
@ -270,9 +270,9 @@ LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos)
f32 dy = (k & 2) ? y : 1 - y;
f32 dz = (k & 1) ? z : 1 - z;
// Use direct sunlight (255), if any; use daylight otherwise.
f32 light_boosted = cur_node.frame.sunlight[k] ? 255 : cur_node.frame.lightsDay[k];
lightDay += dx * dy * dz * cur_node.frame.lightsDay[k];
lightNight += dx * dy * dz * cur_node.frame.lightsNight[k];
f32 light_boosted = cur_node.lframe.sunlight[k] ? 255 : cur_node.lframe.lightsDay[k];
lightDay += dx * dy * dz * cur_node.lframe.lightsDay[k];
lightNight += dx * dy * dz * cur_node.lframe.lightsNight[k];
lightBoosted += dx * dy * dz * light_boosted;
}
return LightInfo{lightDay, lightNight, lightBoosted};
@ -280,7 +280,6 @@ LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos)
// Calculates vertex color to be used in mapblock mesh
// vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so)
// tile_color - node's tile color
video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos)
{
LightInfo light = blendLight(vertex_pos);
@ -323,8 +322,14 @@ static inline int lightDiff(LightPair a, LightPair b)
return abs(a.lightDay - b.lightDay) + abs(a.lightNight - b.lightNight);
}
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
TileSpec *tiles, int tile_count, u8 mask)
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const TileSpec &tile,
const f32 *txc, u8 mask)
{
drawAutoLightedCuboid(box, &tile, 1, txc, mask);
}
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box,
const TileSpec *tiles, int tile_count, const f32 *txc, u8 mask)
{
bool scale = std::fabs(cur_node.f->visual_scale - 1.0f) > 1e-3f;
f32 texture_coord_buf[24];
@ -348,10 +353,6 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
generateCuboidTextureCoords(box, texture_coord_buf);
txc = texture_coord_buf;
}
if (!tiles) {
tiles = &cur_node.tile;
tile_count = 1;
}
if (data->m_smooth_lighting) {
LightInfo lights[8];
for (int j = 0; j < 8; ++j) {
@ -377,7 +378,7 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
});
} else {
drawCuboid(box, tiles, tile_count, txc, mask, [&] (int face, video::S3DVertex vertices[4]) {
video::SColor color = encode_light(cur_node.light, cur_node.f->light_source);
video::SColor color = cur_node.lcolor;
if (!cur_node.f->light_source)
applyFacesShading(color, vertices[0].Normal);
for (int j = 0; j < 4; j++) {
@ -540,19 +541,20 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing()
if (data->m_smooth_lighting)
return; // don't need to pre-compute anything in this case
auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
if (cur_node.f->light_source != 0) {
// If this liquid emits light and doesn't contain light, draw
// it at what it emits, for an increased effect
u8 e = decode_light(cur_node.f->light_source);
cur_node.light = LightPair(std::max(e, cur_node.light.lightDay),
std::max(e, cur_node.light.lightNight));
light = LightPair(std::max(e, light.lightDay),
std::max(e, light.lightNight));
} else if (nodedef->getLightingFlags(ntop).has_light) {
// Otherwise, use the light of the node on top if possible
cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef));
light = LightPair(getInteriorLight(ntop, 0, nodedef));
}
cur_liquid.color_top = encode_light(cur_node.light, cur_node.f->light_source);
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
cur_liquid.color_top = encode_light(light, cur_node.f->light_source);
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
}
void MapblockMeshGenerator::getLiquidNeighborhood()
@ -695,10 +697,18 @@ void MapblockMeshGenerator::drawLiquidSides()
v += 0.5f - cur_liquid.corner_levels[base.Z][base.X];
}
video::SColor color;
if (data->m_smooth_lighting)
cur_node.color = blendLightColor(pos);
color = blendLightColor(pos);
else
color = cur_node.lcolor;
pos += cur_node.origin;
vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, face.dir.X, face.dir.Y, face.dir.Z, cur_node.color, vertex.u, v);
vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z,
face.dir.X, face.dir.Y, face.dir.Z,
color,
vertex.u, v);
};
collector->append(cur_liquid.tile, vertices, 4, quad_indices, 6);
}
@ -722,7 +732,7 @@ void MapblockMeshGenerator::drawLiquidTop()
int u = corner_resolve[i][0];
int w = corner_resolve[i][1];
if (smooth_liquids) {
if (data->m_enable_water_reflections) {
int x = vertices[i].Pos.X > 0;
int z = vertices[i].Pos.Z > 0;
@ -774,7 +784,7 @@ void MapblockMeshGenerator::drawLiquidTop()
vertex.TCoords += tcoord_translate;
if (!smooth_liquids) {
if (!data->m_enable_water_reflections) {
vertex.Normal = v3f(dx, 1., dz).normalize();
}
}
@ -816,7 +826,8 @@ void MapblockMeshGenerator::drawLiquidNode()
void MapblockMeshGenerator::drawGlasslikeNode()
{
useTile(0, 0, 0);
TileSpec tile;
useTile(&tile, 0, 0, 0);
for (int face = 0; face < 6; face++) {
// Check this neighbor
@ -850,7 +861,7 @@ void MapblockMeshGenerator::drawGlasslikeNode()
vertex.rotateXZBy(-90); break;
}
}
drawQuad(vertices, dir);
drawQuad(tile, vertices, dir);
}
}
@ -860,9 +871,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
for (int face = 0; face < 6; face++)
getTile(g_6dirs[face], &tiles[face]);
if (!data->m_smooth_lighting)
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
TileSpec glass_tiles[6];
for (auto &glass_tile : glass_tiles)
glass_tile = tiles[4];
@ -934,7 +942,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
{0, 1, 8}, {0, 4, 16}, {3, 4, 17}, {3, 1, 9},
};
cur_node.tile = tiles[1];
for (int edge = 0; edge < FRAMED_EDGE_COUNT; edge++) {
bool edge_invisible;
if (nb[nb_triplet[edge][2]])
@ -943,14 +950,13 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
edge_invisible = nb[nb_triplet[edge][0]] ^ nb[nb_triplet[edge][1]];
if (edge_invisible)
continue;
drawAutoLightedCuboid(frame_edges[edge]);
drawAutoLightedCuboid(frame_edges[edge], tiles[1]);
}
for (int face = 0; face < 6; face++) {
if (nb[face])
continue;
cur_node.tile = glass_tiles[face];
// Face at Z-
v3f vertices[4] = {
v3f(-a, a, -g),
@ -976,7 +982,7 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
}
}
v3s16 dir = g_6dirs[face];
drawQuad(vertices, dir);
drawQuad(glass_tiles[face], vertices, dir);
}
// Optionally render internal liquid level defined by param2
@ -986,13 +992,18 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
// Internal liquid level has param2 range 0 .. 63,
// convert it to -0.5 .. 0.5
float vlev = (param2 / 63.0f) * 2.0f - 1.0f;
getSpecialTile(0, &cur_node.tile);
drawAutoLightedCuboid(aabb3f(-(nb[5] ? g : b),
-(nb[4] ? g : b),
-(nb[3] ? g : b),
(nb[2] ? g : b),
(nb[1] ? g : b) * vlev,
(nb[0] ? g : b)));
TileSpec tile;
getSpecialTile(0, &tile);
drawAutoLightedCuboid(
aabb3f(
-(nb[5] ? g : b),
-(nb[4] ? g : b),
-(nb[3] ? g : b),
(nb[2] ? g : b),
(nb[1] ? g : b) * vlev,
(nb[0] ? g : b)
),
tile);
}
}
@ -1007,7 +1018,8 @@ void MapblockMeshGenerator::drawTorchlikeNode()
case DWM_S2: tileindex = 0; break; // floor, but rotated
default: tileindex = 2; // side (or invalid, shouldn't happen)
}
useTile(tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
TileSpec tile;
useTile(&tile, tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
float size = BS / 2 * cur_node.f->visual_scale;
v3f vertices[4] = {
@ -1054,13 +1066,14 @@ void MapblockMeshGenerator::drawTorchlikeNode()
break;
}
}
drawQuad(vertices);
drawQuad(tile, vertices);
}
void MapblockMeshGenerator::drawSignlikeNode()
{
u8 wall = cur_node.n.getWallMounted(nodedef);
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
TileSpec tile;
useTile(&tile, 0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
static const float offset = BS / 16;
float size = BS / 2 * cur_node.f->visual_scale;
// Wall at X+ of node
@ -1091,13 +1104,13 @@ void MapblockMeshGenerator::drawSignlikeNode()
vertex.rotateXYBy(-90); vertex.rotateXZBy(-90); break;
}
}
drawQuad(vertices);
drawQuad(tile, vertices);
}
void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
bool offset_top_only)
void MapblockMeshGenerator::drawPlantlikeQuad(const TileSpec &tile,
float rotation, float quad_offset, bool offset_top_only)
{
const f32 scale = cur_node.scale;
const f32 scale = cur_plant.scale;
v3f vertices[4] = {
v3f(-scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0),
v3f( scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0),
@ -1147,14 +1160,14 @@ void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
}
}
drawQuad(vertices, v3s16(0, 0, 0), cur_plant.plant_height);
drawQuad(tile, vertices, v3s16(0, 0, 0), cur_plant.plant_height);
}
void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
void MapblockMeshGenerator::drawPlantlike(const TileSpec &tile, bool is_rooted)
{
cur_plant.draw_style = PLANT_STYLE_CROSS;
cur_node.scale = BS / 2 * cur_node.f->visual_scale;
cur_plant.offset = v3f(0, 0, 0);
cur_plant.scale = BS / 2 * cur_node.f->visual_scale;
cur_plant.rotate_degree = 0.0f;
cur_plant.random_offset_Y = false;
cur_plant.face_num = 0;
@ -1164,7 +1177,7 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
case CPT2_MESHOPTIONS:
cur_plant.draw_style = PlantlikeStyle(cur_node.n.param2 & MO_MASK_STYLE);
if (cur_node.n.param2 & MO_BIT_SCALE_SQRT2)
cur_node.scale *= 1.41421;
cur_plant.scale *= 1.41421;
if (cur_node.n.param2 & MO_BIT_RANDOM_OFFSET) {
PseudoRandom rng(cur_node.p.X << 8 | cur_node.p.Z | cur_node.p.Y << 16);
cur_plant.offset.X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
@ -1205,63 +1218,66 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
switch (cur_plant.draw_style) {
case PLANT_STYLE_CROSS:
drawPlantlikeQuad(46);
drawPlantlikeQuad(-44);
drawPlantlikeQuad(tile, 46);
drawPlantlikeQuad(tile, -44);
break;
case PLANT_STYLE_CROSS2:
drawPlantlikeQuad(91);
drawPlantlikeQuad(1);
drawPlantlikeQuad(tile, 91);
drawPlantlikeQuad(tile, 1);
break;
case PLANT_STYLE_STAR:
drawPlantlikeQuad(121);
drawPlantlikeQuad(241);
drawPlantlikeQuad(1);
drawPlantlikeQuad(tile, 121);
drawPlantlikeQuad(tile, 241);
drawPlantlikeQuad(tile, 1);
break;
case PLANT_STYLE_HASH:
drawPlantlikeQuad( 1, BS / 4);
drawPlantlikeQuad( 91, BS / 4);
drawPlantlikeQuad(181, BS / 4);
drawPlantlikeQuad(271, BS / 4);
drawPlantlikeQuad(tile, 1, BS / 4);
drawPlantlikeQuad(tile, 91, BS / 4);
drawPlantlikeQuad(tile, 181, BS / 4);
drawPlantlikeQuad(tile, 271, BS / 4);
break;
case PLANT_STYLE_HASH2:
drawPlantlikeQuad( 1, -BS / 2, true);
drawPlantlikeQuad( 91, -BS / 2, true);
drawPlantlikeQuad(181, -BS / 2, true);
drawPlantlikeQuad(271, -BS / 2, true);
drawPlantlikeQuad(tile, 1, -BS / 2, true);
drawPlantlikeQuad(tile, 91, -BS / 2, true);
drawPlantlikeQuad(tile, 181, -BS / 2, true);
drawPlantlikeQuad(tile, 271, -BS / 2, true);
break;
}
}
void MapblockMeshGenerator::drawPlantlikeNode()
{
useTile();
drawPlantlike();
TileSpec tile;
useTile(&tile);
drawPlantlike(tile);
}
void MapblockMeshGenerator::drawPlantlikeRootedNode()
{
drawSolidNode();
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true);
TileSpec tile;
useTile(&tile, 0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true);
cur_node.origin += v3f(0.0, BS, 0.0);
cur_node.p.Y++;
if (data->m_smooth_lighting) {
getSmoothLightFrame();
} else {
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p);
cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef));
auto light = LightPair(getInteriorLight(ntop, 0, nodedef));
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
}
drawPlantlike(true);
drawPlantlike(tile, true);
cur_node.p.Y--;
}
void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle,
float offset_h, float offset_v)
void MapblockMeshGenerator::drawFirelikeQuad(const TileSpec &tile, float rotation,
float opening_angle, float offset_h, float offset_v)
{
const f32 scale = cur_node.scale;
const f32 scale = BS / 2 * cur_node.f->visual_scale;
v3f vertices[4] = {
v3f(-scale, -BS / 2 + scale * 2, 0),
v3f( scale, -BS / 2 + scale * 2, 0),
@ -1275,13 +1291,13 @@ void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle
vertex.rotateXZBy(rotation);
vertex.Y += offset_v;
}
drawQuad(vertices);
drawQuad(tile, vertices);
}
void MapblockMeshGenerator::drawFirelikeNode()
{
useTile();
cur_node.scale = BS / 2 * cur_node.f->visual_scale;
TileSpec tile;
useTile(&tile);
// Check for adjacent nodes
bool neighbors = false;
@ -1300,41 +1316,41 @@ void MapblockMeshGenerator::drawFirelikeNode()
bool drawBottomFire = neighbor[D6D_YP];
if (drawBasicFire || neighbor[D6D_ZP])
drawFirelikeQuad(0, -10, 0.4 * BS);
drawFirelikeQuad(tile, 0, -10, 0.4 * BS);
else if (drawBottomFire)
drawFirelikeQuad(0, 70, 0.47 * BS, 0.484 * BS);
drawFirelikeQuad(tile, 0, 70, 0.47 * BS, 0.484 * BS);
if (drawBasicFire || neighbor[D6D_XN])
drawFirelikeQuad(90, -10, 0.4 * BS);
drawFirelikeQuad(tile, 90, -10, 0.4 * BS);
else if (drawBottomFire)
drawFirelikeQuad(90, 70, 0.47 * BS, 0.484 * BS);
drawFirelikeQuad(tile, 90, 70, 0.47 * BS, 0.484 * BS);
if (drawBasicFire || neighbor[D6D_ZN])
drawFirelikeQuad(180, -10, 0.4 * BS);
drawFirelikeQuad(tile, 180, -10, 0.4 * BS);
else if (drawBottomFire)
drawFirelikeQuad(180, 70, 0.47 * BS, 0.484 * BS);
drawFirelikeQuad(tile, 180, 70, 0.47 * BS, 0.484 * BS);
if (drawBasicFire || neighbor[D6D_XP])
drawFirelikeQuad(270, -10, 0.4 * BS);
drawFirelikeQuad(tile, 270, -10, 0.4 * BS);
else if (drawBottomFire)
drawFirelikeQuad(270, 70, 0.47 * BS, 0.484 * BS);
drawFirelikeQuad(tile, 270, 70, 0.47 * BS, 0.484 * BS);
if (drawBasicFire) {
drawFirelikeQuad(45, 0, 0.0);
drawFirelikeQuad(-45, 0, 0.0);
drawFirelikeQuad(tile, 45, 0, 0.0);
drawFirelikeQuad(tile, -45, 0, 0.0);
}
}
void MapblockMeshGenerator::drawFencelikeNode()
{
useTile(0, 0, 0);
TileSpec tile_nocrack = cur_node.tile;
TileSpec tile_nocrack;
useTile(&tile_nocrack, 0, 0, 0);
for (auto &layer : tile_nocrack.layers)
layer.material_flags &= ~MATERIAL_FLAG_CRACK;
// Put wood the right way around in the posts
TileSpec tile_rot = cur_node.tile;
TileSpec tile_rot = tile_nocrack;
tile_rot.rotation = TileRotation::R90;
static const f32 post_rad = BS / 8;
@ -1352,10 +1368,7 @@ void MapblockMeshGenerator::drawFencelikeNode()
0.500, 0.000, 0.750, 1.000,
0.750, 0.000, 1.000, 1.000,
};
cur_node.tile = tile_rot;
drawAutoLightedCuboid(post, postuv);
cur_node.tile = tile_nocrack;
drawAutoLightedCuboid(post, tile_rot, postuv);
// Now a section of fence, +X, if there's a post there
v3s16 p2 = cur_node.p;
@ -1375,8 +1388,8 @@ void MapblockMeshGenerator::drawFencelikeNode()
0.000, 0.500, 1.000, 0.625,
0.000, 0.875, 1.000, 1.000,
};
drawAutoLightedCuboid(bar_x1, xrailuv);
drawAutoLightedCuboid(bar_x2, xrailuv);
drawAutoLightedCuboid(bar_x1, tile_nocrack, xrailuv);
drawAutoLightedCuboid(bar_x2, tile_nocrack, xrailuv);
}
// Now a section of fence, +Z, if there's a post there
@ -1397,8 +1410,8 @@ void MapblockMeshGenerator::drawFencelikeNode()
0.3750, 0.3750, 0.5000, 0.5000,
0.6250, 0.6250, 0.7500, 0.7500,
};
drawAutoLightedCuboid(bar_z1, zrailuv);
drawAutoLightedCuboid(bar_z2, zrailuv);
drawAutoLightedCuboid(bar_z1, tile_nocrack, zrailuv);
drawAutoLightedCuboid(bar_z2, tile_nocrack, zrailuv);
}
}
@ -1480,7 +1493,8 @@ void MapblockMeshGenerator::drawRaillikeNode()
angle = rail_kinds[code].angle;
}
useTile(tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
TileSpec tile;
useTile(&tile, tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
static const float offset = BS / 64;
static const float size = BS / 2;
@ -1494,7 +1508,7 @@ void MapblockMeshGenerator::drawRaillikeNode()
if (angle)
for (v3f &vertex : vertices)
vertex.rotateXZBy(angle);
drawQuad(vertices);
drawQuad(tile, vertices);
}
namespace {
@ -1526,7 +1540,7 @@ void MapblockMeshGenerator::drawAllfacesNode()
getTile(nodebox_tile_dirs[face], &tiles[face]);
if (data->m_smooth_lighting)
getSmoothLightFrame();
drawAutoLightedCuboid(box, nullptr, tiles, 6);
drawAutoLightedCuboid(box, tiles, 6);
}
void MapblockMeshGenerator::drawNodeboxNode()
@ -1633,7 +1647,7 @@ void MapblockMeshGenerator::drawNodeboxNode()
for (auto &box : boxes) {
u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors);
drawAutoLightedCuboid(box, nullptr, tiles, 6, mask);
drawAutoLightedCuboid(box, tiles, 6, nullptr, mask);
}
}
@ -1678,29 +1692,35 @@ void MapblockMeshGenerator::drawMeshNode()
for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) {
// Only up to 6 tiles are supported
const u32 tile = mesh->getTextureSlot(j);
useTile(MYMIN(tile, 5));
const u32 tile_idx = mesh->getTextureSlot(j);
TileSpec tile;
useTile(&tile, MYMIN(tile_idx, 5));
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
u32 vertex_count = buf->getVertexCount();
// Mesh is always private here. So the lighting is applied to each
// vertex right here.
if (data->m_smooth_lighting) {
// Mesh is always private here. So the lighting is applied to each
// vertex right here.
for (u32 k = 0; k < vertex_count; k++) {
video::S3DVertex &vertex = vertices[k];
vertex.Color = blendLightColor(vertex.Pos, vertex.Normal);
vertex.Pos += cur_node.origin;
}
collector->append(cur_node.tile, vertices, vertex_count,
buf->getIndices(), buf->getIndexCount());
} else {
// Let the collector process colors, etc.
collector->append(cur_node.tile, vertices, vertex_count,
buf->getIndices(), buf->getIndexCount(), cur_node.origin,
cur_node.color, cur_node.f->light_source);
bool is_light_source = cur_node.f->light_source != 0;
for (u32 k = 0; k < vertex_count; k++) {
video::S3DVertex &vertex = vertices[k];
video::SColor color = cur_node.lcolor;
if (!is_light_source)
applyFacesShading(color, vertex.Normal);
vertex.Color = color;
vertex.Pos += cur_node.origin;
}
}
collector->append(tile, vertices, vertex_count,
buf->getIndices(), buf->getIndexCount());
}
mesh->drop();
}
@ -1725,10 +1745,12 @@ void MapblockMeshGenerator::drawNode()
break;
}
cur_node.origin = intToFloat(cur_node.p, BS);
if (data->m_smooth_lighting)
if (data->m_smooth_lighting) {
getSmoothLightFrame();
else
cur_node.light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
} else {
auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
}
switch (cur_node.f->drawtype) {
case NDT_FLOWINGLIQUID: drawLiquidNode(); break;
case NDT_GLASSLIKE: drawGlasslikeNode(); break;
@ -1751,19 +1773,11 @@ void MapblockMeshGenerator::generate()
{
ZoneScoped;
for (cur_node.p.Z = 0; cur_node.p.Z < data->side_length; cur_node.p.Z++)
for (cur_node.p.Y = 0; cur_node.p.Y < data->side_length; cur_node.p.Y++)
for (cur_node.p.X = 0; cur_node.p.X < data->side_length; cur_node.p.X++) {
for (cur_node.p.Z = 0; cur_node.p.Z < data->m_side_length; cur_node.p.Z++)
for (cur_node.p.Y = 0; cur_node.p.Y < data->m_side_length; cur_node.p.Y++)
for (cur_node.p.X = 0; cur_node.p.X < data->m_side_length; cur_node.p.X++) {
cur_node.n = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p);
cur_node.f = &nodedef->get(cur_node.n);
drawNode();
}
}
void MapblockMeshGenerator::renderSingle(content_t node, u8 param2)
{
cur_node.p = {0, 0, 0};
cur_node.n = MapNode(node, 0xff, param2);
cur_node.f = &nodedef->get(cur_node.n);
drawNode();
}

View file

@ -47,7 +47,6 @@ class MapblockMeshGenerator
public:
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
void generate();
void renderSingle(content_t node, u8 param2 = 0x00);
private:
MeshMakeData *const data;
@ -59,15 +58,12 @@ private:
// current node
struct {
v3s16 p;
v3f origin;
v3s16 p; // relative to blockpos_nodes
v3f origin; // p in BS space
MapNode n;
const ContentFeatures *f;
LightPair light;
LightFrame frame;
video::SColor color;
TileSpec tile;
f32 scale;
LightFrame lframe; // smooth lighting
video::SColor lcolor; // unsmooth lighting
} cur_node;
// lighting
@ -76,21 +72,23 @@ private:
video::SColor blendLightColor(const v3f &vertex_pos);
video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal);
void useTile(int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY,
void useTile(TileSpec *tile_ret, int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY,
u8 reset_flags = 0, bool special = false);
void getTile(int index, TileSpec *tile);
void getTile(v3s16 direction, TileSpec *tile);
void getSpecialTile(int index, TileSpec *tile, bool apply_crack = false);
void getTile(int index, TileSpec *tile_ret);
void getTile(v3s16 direction, TileSpec *tile_ret);
void getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack = false);
// face drawing
void drawQuad(v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0),
void drawQuad(const TileSpec &tile, v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0),
float vertical_tiling = 1.0);
// cuboid drawing!
template <typename Fn>
void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter);
void drawCuboid(const aabb3f &box, const TileSpec *tiles, int tilecount,
const f32 *txc, u8 mask, Fn &&face_lighter);
void generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
void drawAutoLightedCuboid(aabb3f box, f32 const *txc = nullptr, TileSpec *tiles = nullptr, int tile_count = 0, u8 mask = 0);
void drawAutoLightedCuboid(aabb3f box, const TileSpec &tile, f32 const *txc = nullptr, u8 mask = 0);
void drawAutoLightedCuboid(aabb3f box, const TileSpec *tiles, int tile_count, f32 const *txc = nullptr, u8 mask = 0);
u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const;
// liquid-specific
@ -113,7 +111,6 @@ private:
f32 corner_levels[2][2];
};
LiquidData cur_liquid;
bool smooth_liquids = false;
void prepareLiquidNodeDrawing();
void getLiquidNeighborhood();
@ -136,6 +133,7 @@ private:
struct PlantlikeData {
PlantlikeStyle draw_style;
v3f offset;
float scale;
float rotate_degree;
bool random_offset_Y;
int face_num;
@ -143,12 +141,12 @@ private:
};
PlantlikeData cur_plant;
void drawPlantlikeQuad(float rotation, float quad_offset = 0,
void drawPlantlikeQuad(const TileSpec &tile, float rotation, float quad_offset = 0,
bool offset_top_only = false);
void drawPlantlike(bool is_rooted = false);
void drawPlantlike(const TileSpec &tile, bool is_rooted = false);
// firelike-specific
void drawFirelikeQuad(float rotation, float opening_angle,
void drawFirelikeQuad(const TileSpec &tile, float rotation, float opening_angle,
float offset_h, float offset_v = 0.0);
// drawtypes

View file

@ -472,6 +472,8 @@ public:
const static float object_hit_delay = 0.2;
const static u16 bbox_debug_flag = scene::EDS_BBOX_ALL;
/* The reason the following structs are not anonymous structs within the
* class is that they are not used by the majority of member functions and
* many functions that do require objects of thse types do not modify them
@ -680,6 +682,8 @@ protected:
private:
struct Flags {
bool disable_camera_update = false;
/// 0 = no debug text active, see toggleDebug() for the rest
int debug_state = 0;
};
void pauseAnimation();
@ -782,11 +786,8 @@ private:
* (as opposed to the this local caching). This can be addressed in
* a later release.
*/
bool m_cache_disable_escape_sequences;
bool m_cache_doubletap_jump;
bool m_cache_enable_clouds;
bool m_cache_enable_joysticks;
bool m_cache_enable_particles;
bool m_cache_enable_fog;
bool m_cache_enable_noclip;
bool m_cache_enable_free_move;
@ -828,16 +829,10 @@ Game::Game() :
{
g_settings->registerChangedCallback("chat_log_level",
&settingChangedCallback, this);
g_settings->registerChangedCallback("disable_escape_sequences",
&settingChangedCallback, this);
g_settings->registerChangedCallback("doubletap_jump",
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_clouds",
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_joysticks",
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_particles",
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_fog",
&settingChangedCallback, this);
g_settings->registerChangedCallback("mouse_sensitivity",
@ -937,6 +932,10 @@ bool Game::startup(bool *kill,
runData.time_from_last_punch = 10.0;
m_game_ui->initFlags();
if (g_settings->getBool("show_debug")) {
m_flags.debug_state = 1;
m_game_ui->m_flags.show_minimal_debug = true;
}
m_first_loop_after_window_activation = true;
@ -1175,7 +1174,7 @@ bool Game::init(
bool Game::initSound()
{
#if USE_SOUND
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) {
if (g_sound_manager_singleton.get()) {
infostream << "Attempting to use OpenAL audio" << std::endl;
sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(),
std::make_unique<SoundFallbackPathProvider>());
@ -1333,8 +1332,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Clouds
*/
if (m_cache_enable_clouds)
clouds = make_irr<Clouds>(smgr, shader_src, -1, rand());
clouds = make_irr<Clouds>(smgr, shader_src, -1, myrand());
/* Skybox
*/
@ -1708,6 +1706,7 @@ void Game::updateDebugState()
hud->disableBlockBounds();
if (!has_debug) {
draw_control->show_wireframe = false;
smgr->setGlobalDebugData(0, bbox_debug_flag);
m_flags.disable_camera_update = false;
m_game_formspec.disableDebugView();
}
@ -1845,7 +1844,9 @@ void Game::processUserInput(f32 dtime)
m_game_focused = true;
}
if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen()) {
if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen()
&& !gui_chat_console->isMyChild(guienv->getFocus()))
{
gui_chat_console->closeConsoleAtOnce();
}
@ -1909,34 +1910,22 @@ void Game::processKeyInput()
toggleNoClip();
#if USE_SOUND
} else if (wasKeyDown(KeyType::MUTE)) {
if (g_settings->getBool("enable_sound")) {
bool new_mute_sound = !g_settings->getBool("mute_sound");
g_settings->setBool("mute_sound", new_mute_sound);
if (new_mute_sound)
m_game_ui->showTranslatedStatusText("Sound muted");
else
m_game_ui->showTranslatedStatusText("Sound unmuted");
} else {
m_game_ui->showTranslatedStatusText("Sound system is disabled");
}
bool new_mute_sound = !g_settings->getBool("mute_sound");
g_settings->setBool("mute_sound", new_mute_sound);
if (new_mute_sound)
m_game_ui->showTranslatedStatusText("Sound muted");
else
m_game_ui->showTranslatedStatusText("Sound unmuted");
} else if (wasKeyDown(KeyType::INC_VOLUME)) {
if (g_settings->getBool("enable_sound")) {
float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f;
g_settings->setFloat("sound_volume", new_volume);
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
m_game_ui->showStatusText(msg);
} else {
m_game_ui->showTranslatedStatusText("Sound system is disabled");
}
float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f;
g_settings->setFloat("sound_volume", new_volume);
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
m_game_ui->showStatusText(msg);
} else if (wasKeyDown(KeyType::DEC_VOLUME)) {
if (g_settings->getBool("enable_sound")) {
float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f;
g_settings->setFloat("sound_volume", new_volume);
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
m_game_ui->showStatusText(msg);
} else {
m_game_ui->showTranslatedStatusText("Sound system is disabled");
}
float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f;
g_settings->setFloat("sound_volume", new_volume);
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
m_game_ui->showStatusText(msg);
#else
} else if (wasKeyDown(KeyType::MUTE) || wasKeyDown(KeyType::INC_VOLUME)
|| wasKeyDown(KeyType::DEC_VOLUME)) {
@ -2267,45 +2256,44 @@ void Game::toggleDebug()
LocalPlayer *player = client->getEnv().getLocalPlayer();
bool has_debug = client->checkPrivilege("debug");
bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
// Initial: No debug info
// 1x toggle: Debug text
// 2x toggle: Debug text with profiler graph
// 3x toggle: Debug text and wireframe (needs "debug" priv)
// Next toggle: Back to initial
// 4x toggle: Debug text and bbox (needs "debug" priv)
//
// The debug text can be in 2 modes: minimal and basic.
// * Minimal: Only technical client info that not gameplay-relevant
// * Basic: Info that might give gameplay advantage, e.g. pos, angle
// Basic mode is used when player has the debug HUD flag set,
// otherwise the Minimal mode is used.
if (!m_game_ui->m_flags.show_minimal_debug) {
m_game_ui->m_flags.show_minimal_debug = true;
if (has_basic_debug)
m_game_ui->m_flags.show_basic_debug = true;
m_game_ui->m_flags.show_profiler_graph = false;
draw_control->show_wireframe = false;
auto &state = m_flags.debug_state;
state = (state + 1) % 5;
if (state >= 3 && !has_debug)
state = 0;
m_game_ui->m_flags.show_minimal_debug = state > 0;
m_game_ui->m_flags.show_basic_debug = state > 0 && has_basic_debug;
m_game_ui->m_flags.show_profiler_graph = state == 2;
draw_control->show_wireframe = state == 3;
smgr->setGlobalDebugData(state == 4 ? bbox_debug_flag : 0,
state == 4 ? 0 : bbox_debug_flag);
if (state == 1) {
m_game_ui->showTranslatedStatusText("Debug info shown");
} else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) {
if (has_basic_debug)
m_game_ui->m_flags.show_basic_debug = true;
m_game_ui->m_flags.show_profiler_graph = true;
} else if (state == 2) {
m_game_ui->showTranslatedStatusText("Profiler graph shown");
} else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) {
if (has_basic_debug)
m_game_ui->m_flags.show_basic_debug = true;
m_game_ui->m_flags.show_profiler_graph = false;
draw_control->show_wireframe = true;
m_game_ui->showTranslatedStatusText("Wireframe shown");
} else if (state == 3) {
if (driver->getDriverType() == video::EDT_OGLES2)
m_game_ui->showTranslatedStatusText("Wireframe not supported by video driver");
else
m_game_ui->showTranslatedStatusText("Wireframe shown");
} else if (state == 4) {
m_game_ui->showTranslatedStatusText("Bounding boxes shown");
} else {
m_game_ui->m_flags.show_minimal_debug = false;
m_game_ui->m_flags.show_basic_debug = false;
m_game_ui->m_flags.show_profiler_graph = false;
draw_control->show_wireframe = false;
if (has_debug) {
m_game_ui->showTranslatedStatusText("Debug info, profiler graph, and wireframe hidden");
} else {
m_game_ui->showTranslatedStatusText("Debug info and profiler graph hidden");
}
m_game_ui->showTranslatedStatusText("All debug info hidden");
}
}
@ -2896,9 +2884,6 @@ void Game::handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam)
{
if (!clouds)
return;
clouds->setDensity(event->cloud_params.density);
clouds->setColorBright(video::SColor(event->cloud_params.color_bright));
clouds->setColorAmbient(video::SColor(event->cloud_params.color_ambient));
@ -2935,10 +2920,7 @@ void Game::updateChat(f32 dtime)
std::vector<LogEntry> entries = m_chat_log_buf.take();
for (const auto& entry : entries) {
std::string line;
if (!m_cache_disable_escape_sequences) {
line.append(color_for(entry.level));
}
line.append(entry.combined);
line.append(color_for(entry.level)).append(entry.combined);
chat_backend->addMessage(L"", utf8_to_wide(line));
}
@ -3023,8 +3005,7 @@ void Game::updateCamera(f32 dtime)
client->updateCameraOffset(camera_offset);
client->getEnv().updateCameraOffset(camera_offset);
if (clouds)
clouds->updateCameraOffset(camera_offset);
clouds->updateCameraOffset(camera_offset);
}
}
}
@ -3683,10 +3664,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
} else {
runData.dig_time_complete = params.time;
if (m_cache_enable_particles) {
client->getParticleManager()->addNodeParticle(client,
player, nodepos, n, features);
}
client->getParticleManager()->addNodeParticle(client,
player, nodepos, n, features);
}
if (!runData.digging) {
@ -3771,11 +3750,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
client->interact(INTERACT_DIGGING_COMPLETED, pointed);
if (m_cache_enable_particles) {
client->getParticleManager()->addDiggingParticles(client,
player, nodepos, n, features);
}
client->getParticleManager()->addDiggingParticles(client,
player, nodepos, n, features);
// Send event to trigger sound
client->getEventManager()->put(new NodeDugEvent(nodepos, n));
@ -3866,8 +3842,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
/*
Update clouds
*/
if (clouds)
updateClouds(dtime);
updateClouds(dtime);
/*
Update particles
@ -4129,11 +4104,8 @@ void Game::readSettings()
}
m_chat_log_buf.setLogLevel(chat_log_level);
m_cache_disable_escape_sequences = g_settings->getBool("disable_escape_sequences");
m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
m_cache_enable_clouds = g_settings->getBool("enable_clouds");
m_cache_enable_joysticks = g_settings->getBool("enable_joysticks");
m_cache_enable_particles = g_settings->getBool("enable_particles");
m_cache_enable_fog = g_settings->getBool("enable_fog");
m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity", 0.001f, 10.0f);
m_cache_joystick_frustum_sensitivity = std::max(g_settings->getFloat("joystick_frustum_sensitivity"), 0.001f);

View file

@ -333,12 +333,11 @@ void GameFormSpec::showPauseMenu()
#ifndef __ANDROID__
#if USE_SOUND
if (g_settings->getBool("enable_sound")) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
<< strgettext("Sound Volume") << "]";
}
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
<< strgettext("Sound Volume") << "]";
#endif
#endif
if (g_touchcontrols) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;"
<< strgettext("Touchscreen Layout") << "]";

View file

@ -215,7 +215,6 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
void GameUI::initFlags()
{
m_flags = GameUI::Flags();
m_flags.show_minimal_debug = g_settings->getBool("show_debug");
}
void GameUI::showTranslatedStatusText(const char *str)

View file

@ -94,8 +94,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
auto it_img = g_imgCache.find(origname);
video::IImage *srcimg = (it_img != g_imgCache.end()) ? it_img->second : nullptr;
if (!srcimg) {
if (!g_settings->getBool("gui_scaling_filter_txr2img"))
return src;
// Download image from GPU
srcimg = driver->createImageFromData(src->getColorFormat(),
src->getSize(), src->lock(video::ETLM_READ_ONLY), false);
src->unlock();

View file

@ -5,6 +5,7 @@
#pragma once
#include "irrlichttypes.h"
#include "irr_v2d.h"
#include "joystick_controller.h"
#include <list>
#include "keycode.h"

View file

@ -4,7 +4,9 @@
#pragma once
#include "irrlichttypes_extrabloated.h"
#include <IEventReceiver.h>
#include "irrlichttypes.h"
#include "keys.h"
#include <bitset>
#include <vector>

View file

@ -26,10 +26,14 @@
MeshMakeData
*/
MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length):
side_length(side_length),
nodedef(ndef)
{}
MeshMakeData::MeshMakeData(const NodeDefManager *ndef,
u16 side_length, MeshGrid mesh_grid) :
m_side_length(side_length),
m_mesh_grid(mesh_grid),
m_nodedef(ndef)
{
assert(m_side_length > 0);
}
void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
{
@ -38,8 +42,9 @@ void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
m_vmanip.clear();
// extra 1 block thick layer around the mesh
VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
blockpos_nodes + v3s16(1,1,1) * (side_length + MAP_BLOCKSIZE /* extra layer of blocks around the mesh */) - v3s16(1,1,1));
blockpos_nodes + v3s16(1,1,1) * (m_side_length + MAP_BLOCKSIZE) - v3s16(1,1,1));
m_vmanip.addArea(voxel_area);
}
@ -52,17 +57,30 @@ void MeshMakeData::fillBlockData(const v3s16 &bp, MapNode *data)
m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
}
void MeshMakeData::fillSingleNode(MapNode data, MapNode padding)
{
m_blockpos = {0, 0, 0};
m_vmanip.clear();
// area around 0,0,0 so that this positon has neighbors
const s16 sz = 3;
m_vmanip.addArea({v3s16(-sz), v3s16(sz)});
u32 count = m_vmanip.m_area.getVolume();
for (u32 i = 0; i < count; i++) {
m_vmanip.m_data[i] = padding;
m_vmanip.m_flags[i] &= ~VOXELFLAG_NO_DATA;
}
m_vmanip.setNodeNoEmerge({0, 0, 0}, data);
}
void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
{
if (crack_level >= 0)
m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
}
void MeshMakeData::setSmoothLighting(bool smooth_lighting)
{
m_smooth_lighting = smooth_lighting;
}
/*
Light and vertex color functions
*/
@ -133,7 +151,7 @@ u16 getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef)
static u16 getSmoothLightCombined(const v3s16 &p,
const std::array<v3s16,8> &dirs, MeshMakeData *data)
{
const NodeDefManager *ndef = data->nodedef;
const NodeDefManager *ndef = data->m_nodedef;
u16 ambient_occlusion = 0;
u16 light_count = 0;
@ -321,7 +339,7 @@ void final_color_blend(video::SColor *result,
*/
void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
{
const NodeDefManager *ndef = data->nodedef;
const NodeDefManager *ndef = data->m_nodedef;
const ContentFeatures &f = ndef->get(mn);
tile = f.tiles[tileindex];
bool has_crack = p == data->m_crack_pos_relative;
@ -341,7 +359,7 @@ void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data,
*/
void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *data, TileSpec &tile)
{
const NodeDefManager *ndef = data->nodedef;
const NodeDefManager *ndef = data->m_nodedef;
// Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
// (0,0,1), (0,0,-1) or (0,0,0)
@ -593,7 +611,7 @@ void PartialMeshBuffer::draw(video::IVideoDriver *driver) const
MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offset):
m_tsrc(client->getTextureSource()),
m_shdrsrc(client->getShaderSource()),
m_bounding_sphere_center((data->side_length * 0.5f - 0.5f) * BS),
m_bounding_sphere_center((data->m_side_length * 0.5f - 0.5f) * BS),
m_animation_force_timer(0), // force initial animation
m_last_crack(-1)
{
@ -602,10 +620,12 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
for (auto &m : m_mesh)
m = make_irr<scene::SMesh>();
auto mesh_grid = client->getMeshGrid();
auto mesh_grid = data->m_mesh_grid;
v3s16 bp = data->m_blockpos;
// Only generate minimap mapblocks at even coordinates.
if (mesh_grid.isMeshPos(bp) && client->getMinimap()) {
// Only generate minimap mapblocks at grid aligned coordinates.
// FIXME: ^ doesn't really make sense. and in practice, bp is always aligned
if (mesh_grid.isMeshPos(bp) && data->m_generate_minimap) {
// meshgen area always fits into a grid cell
m_minimap_mapblocks.resize(mesh_grid.getCellVolume(), nullptr);
v3s16 ofs;
@ -622,17 +642,13 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
}
}
// algin vertices to mesh grid, not meshgen area
v3f offset = intToFloat((data->m_blockpos - mesh_grid.getMeshPos(data->m_blockpos)) * MAP_BLOCKSIZE, BS);
MeshCollector collector(m_bounding_sphere_center, offset);
/*
Add special graphics:
- torches
- flowing water
- fences
- whatever
*/
{
// Generate everything
MapblockMeshGenerator(data, &collector).generate();
}
@ -640,9 +656,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
Convert MeshCollector to SMesh
*/
const bool desync_animations = g_settings->getBool(
"desynchronize_mapblock_texture_animation");
m_bounding_radius = std::sqrt(collector.m_bounding_radius_sq);
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
@ -679,16 +692,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
auto &info = m_animation_info[{layer, i}];
info.tile = p.layer;
info.frame = 0;
if (desync_animations) {
// Get starting position from noise
info.frame_offset =
100000 * (2.0 + noise3d(
data->m_blockpos.X, data->m_blockpos.Y,
data->m_blockpos.Z, 0));
} else {
// Play all synchronized
info.frame_offset = 0;
}
info.frame_offset = 0;
// Replace tile texture with the first animation frame
p.layer.texture = (*p.layer.frames)[0].texture;
}
@ -702,6 +706,16 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
tex.MagFilter = video::ETMAGF_NEAREST;
});
/*
* The second layer is for overlays, but uses the same vertex positions
* as the first, which quickly leads to z-fighting.
* To fix this we can offset the polygons in the direction of the camera.
* This only affects the depth buffer and leads to no visual gaps in geometry.
*/
if (layer == 1) {
material.PolygonOffsetSlopeScale = -1;
material.PolygonOffsetDepthBias = -1;
}
{
material.MaterialType = m_shdrsrc->getShaderInfo(
@ -738,7 +752,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
}
}
m_bsp_tree.buildTree(&m_transparent_triangles, data->side_length);
m_bsp_tree.buildTree(&m_transparent_triangles, data->m_side_length);
// Check if animation is required for this mesh
m_has_animation =
@ -947,21 +961,22 @@ video::SColor encode_light(u16 light, u8 emissive_light)
u8 get_solid_sides(MeshMakeData *data)
{
std::unordered_map<v3s16, u8> results;
v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
const NodeDefManager *ndef = data->nodedef;
const NodeDefManager *ndef = data->m_nodedef;
u8 result = 0x3F; // all sides solid;
const u16 side = data->m_side_length;
assert(data->m_vmanip.m_area.contains(blockpos_nodes + v3s16(side - 1)));
for (s16 i = 0; i < data->side_length && result != 0; i++)
for (s16 j = 0; j < data->side_length && result != 0; j++) {
u8 result = 0x3F; // all sides solid
for (s16 i = 0; i < side && result != 0; i++)
for (s16 j = 0; j < side && result != 0; j++) {
v3s16 positions[6] = {
v3s16(0, i, j),
v3s16(data->side_length - 1, i, j),
v3s16(side - 1, i, j),
v3s16(i, 0, j),
v3s16(i, data->side_length - 1, j),
v3s16(i, side - 1, j),
v3s16(i, j, 0),
v3s16(i, j, data->side_length - 1)
v3s16(i, j, side - 1)
};
for (u8 k = 0; k < 6; k++) {

View file

@ -4,8 +4,11 @@
#pragma once
#include "irrlichttypes_extrabloated.h"
#include "irrlichttypes.h"
#include "irr_ptr.h"
#include "IMesh.h"
#include "SMeshBuffer.h"
#include "util/numeric.h"
#include "client/tile.h"
#include "voxel.h"
@ -13,6 +16,10 @@
#include <map>
#include <unordered_map>
namespace irr::video {
class IVideoDriver;
}
class Client;
class NodeDefManager;
class IShaderSource;
@ -29,14 +36,25 @@ struct MinimapMapblock;
struct MeshMakeData
{
VoxelManipulator m_vmanip;
// base pos of meshgen area, in blocks
v3s16 m_blockpos = v3s16(-1337,-1337,-1337);
// size of meshgen area, in nodes.
// vmanip will have at least an extra 1 node onion layer.
// area is expected to fit into mesh grid cell.
u16 m_side_length;
// vertex positions will be relative to this grid
MeshGrid m_mesh_grid;
// relative to blockpos
v3s16 m_crack_pos_relative = v3s16(-1337,-1337,-1337);
bool m_generate_minimap = false;
bool m_smooth_lighting = false;
u16 side_length;
bool m_enable_water_reflections = false;
const NodeDefManager *nodedef;
const NodeDefManager *m_nodedef;
MeshMakeData(const NodeDefManager *ndef, u16 side_length);
MeshMakeData(const NodeDefManager *ndef, u16 side_lingth, MeshGrid mesh_grid);
/*
Copy block data manually (to allow optimizations by the caller)
@ -44,15 +62,15 @@ struct MeshMakeData
void fillBlockDataBegin(const v3s16 &blockpos);
void fillBlockData(const v3s16 &bp, MapNode *data);
/*
Prepare block data for rendering a single node located at (0,0,0).
*/
void fillSingleNode(MapNode data, MapNode padding = MapNode(CONTENT_AIR));
/*
Set the (node) position of a crack
*/
void setCrack(int crack_level, v3s16 crack_pos);
/*
Enable or disable smooth lighting
*/
void setSmoothLighting(bool smooth_lighting);
};
// represents a triangle as indexes into the vertex buffer in SMeshBuffer

View file

@ -3,7 +3,6 @@
// Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
#include "mesh.h"
#include "S3DVertex.h"
#include "debug.h"
#include "log.h"
#include <cmath>
@ -11,6 +10,9 @@
#include <IAnimatedMesh.h>
#include <SAnimatedMesh.h>
#include <IAnimatedMeshSceneNode.h>
#include "S3DVertex.h"
#include "SMesh.h"
#include "SMeshBuffer.h"
inline static void applyShadeFactor(video::SColor& color, float factor)
{

View file

@ -4,10 +4,20 @@
#pragma once
#include "SColor.h"
#include "SMaterialLayer.h"
#include "irrlichttypes_extrabloated.h"
#include "nodedef.h"
namespace irr {
namespace scene {
class IAnimatedMesh;
class IMesh;
class IMeshBuffer;
}
}
using namespace irr;
/*!
* Applies shading to a color based on the surface's
* normal vector.

View file

@ -40,6 +40,7 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client):
m_client(client)
{
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
m_cache_enable_water_reflections = g_settings->getBool("enable_water_reflections");
}
MeshUpdateQueue::~MeshUpdateQueue()
@ -176,7 +177,8 @@ void MeshUpdateQueue::done(v3s16 pos)
void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
{
auto mesh_grid = m_client->getMeshGrid();
MeshMakeData *data = new MeshMakeData(m_client->ndef(), MAP_BLOCKSIZE * mesh_grid.cell_size);
MeshMakeData *data = new MeshMakeData(m_client->ndef(),
MAP_BLOCKSIZE * mesh_grid.cell_size, mesh_grid);
q->data = data;
data->fillBlockDataBegin(q->p);
@ -191,7 +193,9 @@ void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
}
data->setCrack(q->crack_level, q->crack_pos);
data->setSmoothLighting(m_cache_smooth_lighting);
data->m_generate_minimap = !!m_client->getMinimap();
data->m_smooth_lighting = m_cache_smooth_lighting;
data->m_enable_water_reflections = m_cache_enable_water_reflections;
}
/*

View file

@ -69,8 +69,9 @@ private:
std::unordered_set<v3s16> m_inflight_blocks;
std::mutex m_mutex;
// TODO: Add callback to update these when g_settings changes
// TODO: Add callback to update these when g_settings changes, and update all meshes
bool m_cache_smooth_lighting;
bool m_cache_enable_water_reflections;
void fillDataFromMapBlocks(QueuedMeshUpdate *q);
};

View file

@ -41,45 +41,6 @@ void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *verti
p.indices.push_back(indices[i] + vertex_count);
}
void MeshCollector::append(const TileSpec &tile, const video::S3DVertex *vertices,
u32 numVertices, const u16 *indices, u32 numIndices, v3f pos,
video::SColor c, u8 light_source)
{
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
const TileLayer *layer = &tile.layers[layernum];
if (layer->texture_id == 0)
continue;
append(*layer, vertices, numVertices, indices, numIndices, pos, c,
light_source, layernum, tile.world_aligned);
}
}
void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *vertices,
u32 numVertices, const u16 *indices, u32 numIndices, v3f pos,
video::SColor c, u8 light_source, u8 layernum, bool use_scale)
{
PreMeshBuffer &p = findBuffer(layer, layernum, numVertices);
f32 scale = 1.0f;
if (use_scale)
scale = 1.0f / layer.scale;
u32 vertex_count = p.vertices.size();
for (u32 i = 0; i < numVertices; i++) {
video::SColor color = c;
if (!light_source)
applyFacesShading(color, vertices[i].Normal);
auto vpos = vertices[i].Pos + pos + offset;
p.vertices.emplace_back(vpos, vertices[i].Normal, color,
scale * vertices[i].TCoords);
m_bounding_radius_sq = std::max(m_bounding_radius_sq,
(vpos - m_center_pos).getLengthSQ());
}
for (u32 i = 0; i < numIndices; i++)
p.indices.push_back(indices[i] + vertex_count);
}
PreMeshBuffer &MeshCollector::findBuffer(
const TileLayer &layer, u8 layernum, u32 numVertices)
{

View file

@ -35,21 +35,12 @@ struct MeshCollector
void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices);
void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
v3f pos, video::SColor c, u8 light_source);
private:
void append(const TileLayer &material,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
u8 layernum, bool use_scale = false);
void append(const TileLayer &material,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
v3f pos, video::SColor c, u8 light_source,
u8 layernum, bool use_scale = false);
PreMeshBuffer &findBuffer(const TileLayer &layer, u8 layernum, u32 numVertices);
};

View file

@ -4,18 +4,35 @@
#pragma once
#include "../hud.h"
#include "irrlichttypes_extrabloated.h"
#include "irrlichttypes.h"
#include "irr_ptr.h"
#include "rect.h"
#include "SMeshBuffer.h"
#include "../hud.h"
#include "mapnode.h"
#include "util/thread.h"
#include "voxel.h"
#include <map>
#include <string>
#include <vector>
namespace irr {
namespace video {
class IVideoDriver;
class IImage;
class ITexture;
}
namespace scene {
class ISceneNode;
}
}
class Client;
class NodeDefManager;
class ITextureSource;
class IShaderSource;
class VoxelManipulator;
#define MINIMAP_MAX_SX 512
#define MINIMAP_MAX_SY 512

View file

@ -22,6 +22,8 @@
#include "settings.h"
#include "profiler.h"
#include "SMeshBuffer.h"
using BlendMode = ParticleParamTypes::BlendMode;
ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc)

View file

@ -4,12 +4,21 @@
#pragma once
#include "irrlichttypes_bloated.h"
#include "irr_ptr.h"
#include "ISceneNode.h"
#include "S3DVertex.h"
#include "SMeshBuffer.h"
#include <mutex>
#include <vector>
#include <unordered_map>
#include "irrlichttypes_extrabloated.h"
#include "irr_ptr.h"
#include "../particles.h"
namespace irr::video {
class ITexture;
}
struct ClientEvent;
class ParticleManager;
class ClientEnvironment;

View file

@ -18,7 +18,7 @@ void SetColorMaskStep::run(PipelineContext &context)
{
video::SOverrideMaterial &mat = context.device->getVideoDriver()->getOverrideMaterial();
mat.reset();
mat.Material.ColorMask = color_mask;
mat.Material.ColorMask = static_cast<video::E_COLOR_PLANE>(color_mask);
mat.EnableProps = video::EMP_COLOR_MASK;
mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID |
scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT;

View file

@ -21,7 +21,7 @@ PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_t
void PostProcessingStep::configureMaterial()
{
material.UseMipMaps = false;
material.ZBuffer = true;
material.ZBuffer = video::ECFN_LESSEQUAL;
material.ZWriteEnable = video::EZW_ON;
for (u32 k = 0; k < texture_map.size(); ++k) {
material.TextureLayers[k].AnisotropicFilter = 0;
@ -196,7 +196,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
}
if (enable_volumetric_light) {
buffer->setTexture(TEXTURE_VOLUME, scale, "volume", color_format);
buffer->setTexture(TEXTURE_VOLUME, scale, "volume", bloom_format);
shader_id = client->getShaderSource()->getShaderRaw("volumetric_light");
auto volume = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_DEPTH });

View file

@ -50,8 +50,7 @@ void FpsControl::limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused)
if (busy_time < frametime_min) {
sleep_time = frametime_min - busy_time;
if (sleep_time > 0)
sleep_us(sleep_time);
porting::preciseSleepUs(sleep_time);
} else {
sleep_time = 0;
}

View file

@ -687,13 +687,23 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
case TILE_MATERIAL_WAVING_LIQUID_BASIC:
case TILE_MATERIAL_LIQUID_TRANSPARENT:
shaders_header << "#define MATERIAL_WAVING_LIQUID 1\n";
break;
default:
shaders_header << "#define MATERIAL_WAVING_LIQUID 0\n";
break;
}
switch (material_type) {
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
case TILE_MATERIAL_WAVING_LIQUID_BASIC:
case TILE_MATERIAL_LIQUID_TRANSPARENT:
shaders_header << "#define MATERIAL_WATER_REFLECTIONS 1\n";
break;
default:
shaders_header << "#define MATERIAL_WATER_REFLECTIONS 0\n";
break;
}
shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";

View file

@ -13,18 +13,6 @@
using m4f = core::matrix4;
static v3f quantizeDirection(v3f direction, float step)
{
float yaw = std::atan2(direction.Z, direction.X);
float pitch = std::asin(direction.Y); // assume look is normalized
yaw = std::floor(yaw / step) * step;
pitch = std::floor(pitch / step) * step;
return v3f(std::cos(yaw)*std::cos(pitch), std::sin(pitch), std::sin(yaw)*std::cos(pitch));
}
void DirectionalLight::createSplitMatrices(const Camera *cam)
{
static const float COS_15_DEG = 0.965926f;
@ -74,7 +62,7 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
v3f boundVec = (cam_pos_scene + farCorner * sfFar) - center_scene;
float radius = boundVec.getLength();
float length = radius * 3.0f;
v3f eye_displacement = quantizeDirection(direction, M_PI / 2880 /*15 seconds*/) * length;
v3f eye_displacement = direction * length;
// we must compute the viewmat with the position - the camera offset
// but the future_frustum position must be the actual world position

View file

@ -27,7 +27,7 @@ static video::SMaterial baseMaterial()
video::SMaterial mat;
mat.ZBuffer = video::ECFN_DISABLED;
mat.ZWriteEnable = video::EZW_OFF;
mat.AntiAliasing = 0;
mat.AntiAliasing = video::EAAM_OFF;
mat.TextureLayers[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
mat.TextureLayers[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
mat.BackfaceCulling = false;

View file

@ -50,6 +50,11 @@ struct FrameSpec
video::ITexture *texture = nullptr;
};
/**
* We have two tile layers:
* layer 0 = base
* layer 1 = overlay
*/
#define MAX_TILE_LAYERS 2
//! Defines a layer of a tile.

View file

@ -21,8 +21,8 @@
#include <IMeshManipulator.h>
#include "client/renderingengine.h"
#define WIELD_SCALE_FACTOR 30.0
#define WIELD_SCALE_FACTOR_EXTRUDED 40.0
#define WIELD_SCALE_FACTOR 30.0f
#define WIELD_SCALE_FACTOR_EXTRUDED 40.0f
#define MIN_EXTRUSION_MESH_RESOLUTION 16
#define MAX_EXTRUSION_MESH_RESOLUTION 512
@ -225,18 +225,6 @@ WieldMeshSceneNode::~WieldMeshSceneNode()
g_extrusion_mesh_cache = nullptr;
}
void WieldMeshSceneNode::setCube(const ContentFeatures &f,
v3f wield_scale)
{
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
scene::SMesh *copy = cloneMesh(cubemesh);
cubemesh->drop();
postProcessNodeMesh(copy, f, false, &m_material_type, &m_colors, true);
changeToMesh(copy);
copy->drop();
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
}
void WieldMeshSceneNode::setExtruded(const std::string &imagename,
const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc,
u8 num_frames)
@ -251,6 +239,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
core::dimension2d<u32> dim = texture->getSize();
// Detect animation texture and pull off top frame instead of using entire thing
// FIXME: this is quite unportable, we should be working with the original TileLayer if there's one
if (num_frames > 1) {
u32 frame_height = dim.Height / num_frames;
dim = core::dimension2d<u32>(dim.Width, frame_height);
@ -262,11 +251,13 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
mesh->getMeshBuffer(0)->getMaterial().setTexture(0,
tsrc->getTexture(imagename));
if (overlay_texture) {
// duplicate the extruded mesh for the overlay
scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0));
copy->getMaterial().setTexture(0, overlay_texture);
mesh->addMeshBuffer(copy);
copy->drop();
}
mesh->recalculateBoundingBox();
changeToMesh(mesh);
mesh->drop();
@ -292,14 +283,10 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
}
}
static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
static scene::SMesh *createGenericNodeMesh(Client *client, MapNode n,
std::vector<ItemPartColor> *colors, const ContentFeatures &f)
{
MeshMakeData mesh_make_data(client->ndef(), 1);
MeshCollector collector(v3f(0.0f * BS), v3f());
mesh_make_data.setSmoothLighting(false);
MapblockMeshGenerator gen(&mesh_make_data, &collector);
n.setParam1(0xff);
if (n.getParam2()) {
// keep it
} else if (f.param_type_2 == CPT2_WALLMOUNTED ||
@ -313,29 +300,43 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
} else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) {
n.setParam2(1);
}
gen.renderSingle(n.getContent(), n.getParam2());
MeshCollector collector(v3f(0), v3f());
{
MeshMakeData mmd(client->ndef(), 1, MeshGrid{1});
mmd.fillSingleNode(n);
MapblockMeshGenerator(&mmd, &collector).generate();
}
colors->clear();
scene::SMesh *mesh = new scene::SMesh();
for (auto &prebuffers : collector.prebuffers)
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
auto &prebuffers = collector.prebuffers[layer];
for (PreMeshBuffer &p : prebuffers) {
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
const FrameSpec &frame = (*p.layer.frames)[0];
p.layer.texture = frame.texture;
}
for (video::S3DVertex &v : p.vertices) {
for (video::S3DVertex &v : p.vertices)
v.Color.setAlpha(255);
}
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
buf->Material.setTexture(0, p.layer.texture);
p.layer.applyMaterialOptions(buf->Material);
mesh->addMeshBuffer(buf);
auto buf = make_irr<scene::SMeshBuffer>();
buf->append(&p.vertices[0], p.vertices.size(),
&p.indices[0], p.indices.size());
buf->drop();
colors->push_back(
ItemPartColor(p.layer.has_color, p.layer.color));
// Set up material
buf->Material.setTexture(0, p.layer.texture);
if (layer == 1) {
buf->Material.PolygonOffsetSlopeScale = -1;
buf->Material.PolygonOffsetDepthBias = -1;
}
p.layer.applyMaterialOptions(buf->Material);
mesh->addMeshBuffer(buf.get());
colors->emplace_back(p.layer.has_color, p.layer.color);
}
}
mesh->recalculateBoundingBox();
return mesh;
}
@ -375,15 +376,12 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
}
// Handle nodes
// See also CItemDefManager::createClientCached()
if (def.type == ITEM_NODE) {
bool cull_backface = f.needsBackfaceCulling();
// Select rendering method
switch (f.drawtype) {
case NDT_AIRLIKE:
setExtruded("no_texture_airlike.png", "",
v3f(1.0, 1.0, 1.0), tsrc, 1);
v3f(1), tsrc, 1);
break;
case NDT_SIGNLIKE:
case NDT_TORCHLIKE:
@ -393,38 +391,33 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
v3f wscale = wield_scale;
if (f.drawtype == NDT_FLOWINGLIQUID)
wscale.Z *= 0.1f;
setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
tsrc->getTextureName(f.tiles[0].layers[1].texture_id),
wscale, tsrc,
f.tiles[0].layers[0].animation_frame_count);
// Add color
const TileLayer &l0 = f.tiles[0].layers[0];
m_colors.emplace_back(l0.has_color, l0.color);
const TileLayer &l1 = f.tiles[0].layers[1];
setExtruded(tsrc->getTextureName(l0.texture_id),
tsrc->getTextureName(l1.texture_id),
wscale, tsrc,
l0.animation_frame_count);
// Add color
m_colors.emplace_back(l0.has_color, l0.color);
m_colors.emplace_back(l1.has_color, l1.color);
break;
}
case NDT_PLANTLIKE_ROOTED: {
setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id),
"", wield_scale, tsrc,
f.special_tiles[0].layers[0].animation_frame_count);
// Add color
// use the plant tile
const TileLayer &l0 = f.special_tiles[0].layers[0];
setExtruded(tsrc->getTextureName(l0.texture_id),
"", wield_scale, tsrc,
l0.animation_frame_count);
m_colors.emplace_back(l0.has_color, l0.color);
break;
}
case NDT_NORMAL:
case NDT_ALLFACES:
case NDT_LIQUID:
setCube(f, wield_scale);
break;
default: {
// Render non-trivial drawtypes like the actual node
// Render all other drawtypes like the actual node
MapNode n(id);
if (def.place_param2)
n.setParam2(*def.place_param2);
mesh = createSpecialNodeMesh(client, n, &m_colors, f);
mesh = createGenericNodeMesh(client, n, &m_colors, f);
changeToMesh(mesh);
mesh->drop();
m_meshnode->setScale(
@ -437,9 +430,9 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
u32 material_count = m_meshnode->getMaterialCount();
for (u32 i = 0; i < material_count; ++i) {
video::SMaterial &material = m_meshnode->getMaterial(i);
// FIXME: overriding this breaks different alpha modes the mesh may have
material.MaterialType = m_material_type;
material.MaterialTypeParam = 0.5f;
material.BackfaceCulling = cull_backface;
material.forEachTexture([this] (auto &tex) {
setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter,
m_anisotropic_filter);
@ -550,8 +543,6 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
// Shading is on by default
result->needs_shading = true;
bool cull_backface = f.needsBackfaceCulling();
// If inventory_image is defined, it overrides everything else
const std::string inventory_image = item.getInventoryImage(idef);
const std::string inventory_overlay = item.getInventoryOverlay(idef);
@ -568,51 +559,32 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
result->needs_shading = false;
} else if (def.type == ITEM_NODE) {
switch (f.drawtype) {
case NDT_NORMAL:
case NDT_ALLFACES:
case NDT_LIQUID:
case NDT_FLOWINGLIQUID: {
scene::IMesh *cube = g_extrusion_mesh_cache->createCube();
mesh = cloneMesh(cube);
cube->drop();
if (f.drawtype == NDT_FLOWINGLIQUID) {
scaleMesh(mesh, v3f(1.2, 0.03, 1.2));
translateMesh(mesh, v3f(0, -0.57, 0));
} else
scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
// add overlays
postProcessNodeMesh(mesh, f, false, nullptr,
&result->buffer_colors, true);
if (f.drawtype == NDT_ALLFACES)
scaleMesh(mesh, v3f(f.visual_scale));
break;
}
case NDT_PLANTLIKE: {
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
tsrc->getTextureName(f.tiles[0].layers[1].texture_id));
// Add color
const TileLayer &l0 = f.tiles[0].layers[0];
result->buffer_colors.emplace_back(l0.has_color, l0.color);
const TileLayer &l1 = f.tiles[0].layers[1];
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(l0.texture_id),
tsrc->getTextureName(l1.texture_id));
// Add color
result->buffer_colors.emplace_back(l0.has_color, l0.color);
result->buffer_colors.emplace_back(l1.has_color, l1.color);
break;
}
case NDT_PLANTLIKE_ROOTED: {
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), "");
// Add color
// Use the plant tile
const TileLayer &l0 = f.special_tiles[0].layers[0];
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(l0.texture_id), "");
result->buffer_colors.emplace_back(l0.has_color, l0.color);
break;
}
default: {
// Render non-trivial drawtypes like the actual node
// Render all other drawtypes like the actual node
MapNode n(id);
if (def.place_param2)
n.setParam2(*def.place_param2);
mesh = createSpecialNodeMesh(client, n, &result->buffer_colors, f);
mesh = createGenericNodeMesh(client, n, &result->buffer_colors, f);
scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
break;
}
@ -621,13 +593,13 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
video::SMaterial &material = buf->getMaterial();
// FIXME: overriding this breaks different alpha modes the mesh may have
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialTypeParam = 0.5f;
material.forEachTexture([] (auto &tex) {
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
tex.MagFilter = video::ETMAGF_NEAREST;
});
material.BackfaceCulling = cull_backface;
}
rotateMeshXZby(mesh, -45);
@ -648,7 +620,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
const std::string &imagename, const std::string &overlay_name)
{
// check textures
video::ITexture *texture = tsrc->getTextureForMesh(imagename);
video::ITexture *texture = tsrc->getTexture(imagename);
if (!texture) {
return NULL;
}
@ -683,56 +655,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialTypeParam = 0.5f;
}
scaleMesh(mesh, v3f(2.0, 2.0, 2.0));
scaleMesh(mesh, v3f(2));
return mesh;
}
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
bool set_material, const video::E_MATERIAL_TYPE *mattype,
std::vector<ItemPartColor> *colors, bool apply_scale)
{
const u32 mc = mesh->getMeshBufferCount();
// Allocate colors for existing buffers
colors->clear();
colors->resize(mc);
for (u32 i = 0; i < mc; ++i) {
const TileSpec *tile = &(f.tiles[i]);
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
const TileLayer *layer = &tile->layers[layernum];
if (layer->texture_id == 0)
continue;
if (layernum != 0) {
scene::IMeshBuffer *copy = cloneMeshBuffer(buf);
copy->getMaterial() = buf->getMaterial();
mesh->addMeshBuffer(copy);
copy->drop();
buf = copy;
colors->emplace_back(layer->has_color, layer->color);
} else {
(*colors)[i] = ItemPartColor(layer->has_color, layer->color);
}
video::SMaterial &material = buf->getMaterial();
if (set_material)
layer->applyMaterialOptions(material);
if (mattype) {
material.MaterialType = *mattype;
}
if (layer->animation_frame_count > 1) {
const FrameSpec &animation_frame = (*layer->frames)[0];
material.setTexture(0, animation_frame.texture);
} else {
material.setTexture(0, layer->texture);
}
if (apply_scale && tile->world_aligned) {
u32 n = buf->getVertexCount();
for (u32 k = 0; k != n; ++k)
buf->getTCoords(k) /= layer->scale;
}
}
}
}

View file

@ -92,7 +92,6 @@ public:
WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id = -1);
virtual ~WieldMeshSceneNode();
void setCube(const ContentFeatures &f, v3f wield_scale);
void setExtruded(const std::string &imagename, const std::string &overlay_image,
v3f wield_scale, ITextureSource *tsrc, u8 num_frames);
void setItem(const ItemStack &item, Client *client,
@ -143,14 +142,3 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename,
const std::string &overlay_name);
/*!
* Applies overlays, textures and optionally materials to the given mesh and
* extracts tile colors for colorization.
* \param mattype overrides the buffer's material type, but can also
* be NULL to leave the original material.
* \param colors returns the colors of the mesh buffers in the mesh.
*/
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
bool set_material, const video::E_MATERIAL_TYPE *mattype,
std::vector<ItemPartColor> *colors, bool apply_scale = false);

View file

@ -3,9 +3,8 @@
// Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
#pragma once
#include "config.h"
#include "convert_json.h"
#include "irrlichttypes.h"
#include <string>
enum class ContentType
{

View file

@ -47,7 +47,7 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
}
// Add new mods
for (int want_from_modpack = 1; want_from_modpack >= 0; --want_from_modpack) {
for (bool want_from_modpack : {true, false}) {
// First iteration:
// Add all the mods that come from modpacks
// Second iteration:
@ -56,9 +56,12 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
std::set<std::string> seen_this_iteration;
for (const ModSpec &mod : new_mods) {
if (mod.part_of_modpack != (bool)want_from_modpack)
if (mod.part_of_modpack != want_from_modpack)
continue;
// unrelated to this code, but we want to assert it somewhere
assert(fs::IsPathAbsolute(mod.path));
if (existing_mods.count(mod.name) == 0) {
// GOOD CASE: completely new mod.
m_unsatisfied_mods.push_back(mod);

View file

@ -167,6 +167,7 @@ std::map<std::string, ModSpec> getModsInPath(
mod_path.clear();
mod_path.append(path).append(DIR_DELIM).append(modname);
mod_path = fs::AbsolutePath(mod_path);
mod_virtual_path.clear();
// Intentionally uses / to keep paths same on different platforms
@ -174,7 +175,7 @@ std::map<std::string, ModSpec> getModsInPath(
ModSpec spec(modname, mod_path, part_of_modpack, mod_virtual_path);
parseModContents(spec);
result.insert(std::make_pair(modname, spec));
result[modname] = std::move(spec);
}
return result;
}

View file

@ -25,7 +25,7 @@ struct ModSpec
{
std::string name;
std::string author;
std::string path;
std::string path; // absolute path on disk
std::string desc;
int release = 0;

View file

@ -22,9 +22,8 @@
namespace
{
bool getGameMinetestConfig(const std::string &game_path, Settings &conf)
bool getGameConfig(const std::string &game_path, Settings &conf)
{
// TODO: rename this
std::string conf_path = game_path + DIR_DELIM + "minetest.conf";
return conf.readConfigFile(conf_path.c_str());
}
@ -355,7 +354,7 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
game_settings = Settings::createLayer(SL_GAME);
}
getGameMinetestConfig(gamespec.path, *game_settings);
getGameConfig(gamespec.path, *game_settings);
game_settings->removeSecureSettings();
infostream << "Initializing world at " << final_path << std::endl;

View file

@ -6,8 +6,7 @@
#include <exception>
#include <cassert>
#include "gettime.h"
#include "log.h"
#include "log.h" // unused. for convenience.
#ifdef _MSC_VER
#define FUNCTION_NAME __FUNCTION__

View file

@ -82,7 +82,6 @@ void set_default_settings()
// Client
settings->setDefault("address", "");
settings->setDefault("enable_sound", "true");
#if defined(__unix__) && !defined(__APPLE__) && !defined (__ANDROID__)
// On Linux+X11 (not Linux+Wayland or Linux+XWayland), I've encountered a bug
// where fake mouse events were generated from touch events if in relative
@ -270,7 +269,6 @@ void set_default_settings()
settings->setDefault("cinematic", "false");
settings->setDefault("camera_smoothing", "0.0");
settings->setDefault("cinematic_camera_smoothing", "0.7");
settings->setDefault("enable_clouds", "true");
settings->setDefault("view_bobbing_amount", "1.0");
settings->setDefault("fall_bobbing_amount", "0.03");
settings->setDefault("enable_3d_clouds", "true");
@ -292,14 +290,11 @@ void set_default_settings()
settings->setDefault("hud_scaling", "1.0");
settings->setDefault("gui_scaling", "1.0");
settings->setDefault("gui_scaling_filter", "false");
settings->setDefault("gui_scaling_filter_txr2img", "true");
settings->setDefault("smooth_scrolling", "true");
settings->setDefault("desynchronize_mapblock_texture_animation", "false");
settings->setDefault("hud_hotbar_max_width", "1.0");
settings->setDefault("enable_local_map_saving", "false");
settings->setDefault("show_entity_selectionbox", "false");
settings->setDefault("ambient_occlusion_gamma", "1.8");
settings->setDefault("enable_particles", "true");
settings->setDefault("arm_inertia", "true");
settings->setDefault("show_nametag_backgrounds", "true");
settings->setDefault("show_block_bounds_radius_near", "4");
@ -350,7 +345,7 @@ void set_default_settings()
settings->setDefault("shadow_map_color", "false");
settings->setDefault("shadow_filters", "1");
settings->setDefault("shadow_poisson_filter", "true");
settings->setDefault("shadow_update_frames", "8");
settings->setDefault("shadow_update_frames", "16");
settings->setDefault("shadow_soft_radius", "5.0");
settings->setDefault("shadow_sky_body_orbit_tilt", "0.0");
settings->setDefault("enable_sun_tint", "false");
@ -420,7 +415,6 @@ void set_default_settings()
#endif
// Server
settings->setDefault("disable_escape_sequences", "false");
settings->setDefault("strip_color_codes", "false");
#ifndef NDEBUG
settings->setDefault("random_mod_load_order", "true");
@ -440,7 +434,6 @@ void set_default_settings()
settings->setDefault("protocol_version_min", "1");
settings->setDefault("player_transfer_distance", "0");
settings->setDefault("max_simultaneous_block_sends_per_client", "40");
settings->setDefault("time_send_interval", "5");
settings->setDefault("motd", "");
settings->setDefault("max_users", "15");

View file

@ -8,7 +8,6 @@
#include <mutex>
#include "network/networkprotocol.h"
#include "irr_v3d.h"
#include "util/container.h"
#include "util/metricsbackend.h"
#include "mapgen/mapgen.h" // for MapgenParams
#include "map.h"

View file

@ -16,6 +16,7 @@
#include "gettext.h"
#include "irrlicht_changes/CGUITTFont.h"
#include "util/string.h"
#include "guiScrollBar.h"
#include <string>
inline u32 clamp_u8(s32 value)
@ -28,6 +29,11 @@ inline bool isInCtrlKeys(const irr::EKEY_CODE& kc)
return kc == KEY_LCONTROL || kc == KEY_RCONTROL || kc == KEY_CONTROL;
}
inline u32 getScrollbarSize(IGUIEnvironment* env)
{
return env->getSkin()->getSize(gui::EGDS_SCROLLBAR_SIZE);
}
GUIChatConsole::GUIChatConsole(
gui::IGUIEnvironment* env,
gui::IGUIElement* parent,
@ -62,15 +68,14 @@ GUIChatConsole::GUIChatConsole(
}
const u16 chat_font_size = g_settings->getU16("chat_font_size");
m_font = g_fontengine->getFont(chat_font_size != 0 ?
rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono);
m_font.grab(g_fontengine->getFont(chat_font_size != 0 ?
rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono));
if (!m_font) {
errorstream << "GUIChatConsole: Unable to load mono font" << std::endl;
} else {
core::dimension2d<u32> dim = m_font->getDimension(L"M");
m_fontsize = v2u32(dim.Width, dim.Height);
m_font->grab();
}
m_fontsize.X = MYMAX(m_fontsize.X, 1);
m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
@ -81,12 +86,11 @@ GUIChatConsole::GUIChatConsole(
// track ctrl keys for mouse event
m_is_ctrl_down = false;
m_cache_clickable_chat_weblinks = g_settings->getBool("clickable_chat_weblinks");
}
GUIChatConsole::~GUIChatConsole()
{
if (m_font)
m_font->drop();
m_scrollbar.reset(new GUIScrollBar(env, this, -1, core::rect<s32>(0, 0, 30, m_height), false, true, tsrc));
m_scrollbar->setSubElement(true);
m_scrollbar->setLargeStep(1);
m_scrollbar->setSmallStep(1);
}
void GUIChatConsole::openConsole(f32 scale)
@ -121,6 +125,7 @@ void GUIChatConsole::closeConsole()
m_open = false;
Environment->removeFocus(this);
m_menumgr->deletingMenu(this);
m_scrollbar->setVisible(false);
}
void GUIChatConsole::closeConsoleAtOnce()
@ -180,6 +185,10 @@ void GUIChatConsole::draw()
m_screensize = screensize;
m_desired_height = m_desired_height_fraction * m_screensize.Y;
reformatConsole();
} else if (!m_scrollbar->getAbsolutePosition().isPointInside(core::vector2di(screensize.X, m_height))) {
// the height of the chat window is no longer the height of the scrollbar
// happens while opening/closing the window
updateScrollbar(true);
}
// Animation
@ -204,6 +213,9 @@ void GUIChatConsole::reformatConsole()
s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
if (cols <= 0 || rows <= 0)
cols = rows = 0;
updateScrollbar(true);
recalculateConsolePosition();
m_chat_backend->reformat(cols, rows);
}
@ -293,10 +305,17 @@ void GUIChatConsole::drawBackground()
void GUIChatConsole::drawText()
{
if (m_font == NULL)
if (!m_font)
return;
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
core::recti rect;
if (m_scrollbar->isVisible())
rect = core::rect<s32> (0, 0, m_screensize.X - getScrollbarSize(Environment), m_height);
else
rect = AbsoluteClippingRect;
for (u32 row = 0; row < buf.getRows(); ++row)
{
const ChatFormattedLine& line = buf.getFormattedLine(row);
@ -315,13 +334,13 @@ void GUIChatConsole::drawText()
if (m_font->getType() == irr::gui::EGFT_CUSTOM) {
// Draw colored text if possible
gui::CGUITTFont *tmp = static_cast<gui::CGUITTFont*>(m_font);
auto *tmp = static_cast<gui::CGUITTFont*>(m_font.get());
tmp->draw(
fragment.text,
destrect,
false,
false,
&AbsoluteClippingRect);
&rect);
} else {
// Otherwise use standard text
m_font->draw(
@ -330,10 +349,12 @@ void GUIChatConsole::drawText()
video::SColor(255, 255, 255, 255),
false,
false,
&AbsoluteClippingRect);
&rect);
}
}
}
updateScrollbar();
}
void GUIChatConsole::drawPrompt()
@ -680,6 +701,11 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
prompt.input(std::wstring(event.StringInput.Str->c_str()));
return true;
}
else if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED &&
(void*) event.GUIEvent.Caller == (void*) m_scrollbar.get())
{
m_chat_backend->getConsoleBuffer().scrollAbsolute(m_scrollbar->getPos());
}
return Parent ? Parent->OnEvent(event) : false;
}
@ -692,6 +718,7 @@ void GUIChatConsole::setVisible(bool visible)
m_height = 0;
recalculateConsolePosition();
}
m_scrollbar->setVisible(visible);
}
bool GUIChatConsole::weblinkClick(s32 col, s32 row)
@ -763,3 +790,18 @@ void GUIChatConsole::updatePrimarySelection()
std::string selected = wide_to_utf8(wselected);
Environment->getOSOperator()->copyToPrimarySelection(selected.c_str());
}
void GUIChatConsole::updateScrollbar(bool update_size)
{
ChatBuffer &buf = m_chat_backend->getConsoleBuffer();
m_scrollbar->setMin(buf.getTopScrollPos());
m_scrollbar->setMax(buf.getBottomScrollPos());
m_scrollbar->setPos(buf.getScrollPosition());
m_scrollbar->setPageSize(m_fontsize.Y * buf.getLineCount());
m_scrollbar->setVisible(m_scrollbar->getMin() != m_scrollbar->getMax());
if (update_size) {
const core::rect<s32> rect (m_screensize.X - getScrollbarSize(Environment), 0, m_screensize.X, m_height);
m_scrollbar->setRelativePosition(rect);
}
}

View file

@ -8,8 +8,10 @@
#include "modalMenu.h"
#include "chat.h"
#include "config.h"
#include "irr_ptr.h"
class Client;
class GUIScrollBar;
class GUIChatConsole : public gui::IGUIElement
{
@ -20,7 +22,6 @@ public:
ChatBackend* backend,
Client* client,
IMenuManager* menumgr);
virtual ~GUIChatConsole();
// Open the console (height = desired fraction of screen size)
// This doesn't open immediately but initiates an animation.
@ -76,10 +77,13 @@ private:
// If the selected text changed, we need to update the (X11) primary selection.
void updatePrimarySelection();
void updateScrollbar(bool update_size = false);
private:
ChatBackend* m_chat_backend;
Client* m_client;
IMenuManager* m_menumgr;
irr_ptr<GUIScrollBar> m_scrollbar;
// current screen size
v2u32 m_screensize;
@ -116,7 +120,7 @@ private:
video::SColor m_background_color = video::SColor(255, 0, 0, 0);
// font
gui::IGUIFont *m_font = nullptr;
irr_ptr<gui::IGUIFont> m_font;
v2u32 m_fontsize;
// Enable clickable chat weblinks

View file

@ -130,7 +130,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
// create soundmanager
#if USE_SOUND
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) {
if (g_sound_manager_singleton.get()) {
m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(),
std::make_unique<MenuMusicFetcher>());
}

View file

@ -11,6 +11,12 @@
#include <cassert>
#include <list>
#include "IGUIEnvironment.h"
namespace irr::gui {
class IGUIStaticText;
}
class IGameCallback
{
public:

View file

@ -4,8 +4,10 @@
#pragma once
#include "irrlichttypes_extrabloated.h"
#include "IGUIElement.h"
#include "irrlichttypes_bloated.h"
#include "irr_ptr.h"
#include "util/string.h"
#ifdef __ANDROID__
#include <porting_android.h>

View file

@ -13,6 +13,7 @@
class ISimpleTextureSource;
namespace irr::gui
{
class IGUIButton;
class IGUIImage;
}

View file

@ -1,14 +0,0 @@
// Luanti
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2021 x2048, Dmitry Kostenko <codeforsmile@gmail.com>
#include "lighting.h"
AutoExposure::AutoExposure()
: luminance_min(-3.f),
luminance_max(-3.f),
exposure_correction(0.0f),
speed_dark_bright(1000.f),
speed_bright_dark(1000.f),
center_weight_power(1.f)
{}

View file

@ -29,7 +29,14 @@ struct AutoExposure
/// @brief Power value for center-weighted metering. Value of 1.0 measures entire screen uniformly
float center_weight_power;
AutoExposure();
constexpr AutoExposure()
: luminance_min(-3.f),
luminance_max(-3.f),
exposure_correction(0.0f),
speed_dark_bright(1000.f),
speed_bright_dark(1000.f),
center_weight_power(1.f)
{}
};
/**

View file

@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map):
assert(map);
}
void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
bool load_if_inexistent)
void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent)
{
TimeTaker timer1("initialEmerge", &emerge_time);
assert(m_map);
// Units of these are MapBlocks
v3s16 p_min = blockpos_min;
v3s16 p_max = blockpos_max;
VoxelArea block_area_nodes
(p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
@ -775,6 +770,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
infostream<<std::endl;
}
const bool all_new = m_area.hasEmptyExtent() || block_area_nodes.contains(m_area);
addArea(block_area_nodes);
for(s32 z=p_min.Z; z<=p_max.Z; z++)
@ -812,16 +808,12 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
setFlags(a, VOXELFLAG_NO_DATA);
}
}
/*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
{
// Mark that block was loaded as blank
flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
}*/
m_loaded_blocks[p] = flags;
}
m_is_dirty = false;
if (all_new)
m_is_dirty = false;
}
void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
@ -834,6 +826,7 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
/*
Copy data of all blocks
*/
assert(!m_loaded_blocks.empty());
for (auto &loaded_block : m_loaded_blocks) {
v3s16 p = loaded_block.first;
MapBlock *block = m_map->getBlockNoCreateNoEx(p);

View file

@ -298,9 +298,6 @@ protected:
u32 needed_count);
};
#define VMANIP_BLOCK_DATA_INEXIST 1
#define VMANIP_BLOCK_CONTAINS_CIGNORE 2
class MMVManip : public VoxelManipulator
{
public:
@ -344,4 +341,8 @@ protected:
value = flags describing the block
*/
std::map<v3s16, u8> m_loaded_blocks;
enum : u8 {
VMANIP_BLOCK_DATA_INEXIST = 1 << 0,
};
};

View file

@ -73,6 +73,12 @@ MapBlock::~MapBlock()
porting::TrackFreedMemory(sizeof(MapNode) * nodecount);
}
static inline size_t get_max_objects_per_block()
{
u16 ret = g_settings->getU16("max_objects_per_block");
return MYMAX(256, ret);
}
bool MapBlock::onObjectsActivation()
{
// Ignore if no stored objects (to not set changed flag)
@ -84,7 +90,7 @@ bool MapBlock::onObjectsActivation()
<< "activating " << count << " objects in block " << getPos()
<< std::endl;
if (count > g_settings->getU16("max_objects_per_block")) {
if (count > get_max_objects_per_block()) {
errorstream << "suspiciously large amount of objects detected: "
<< count << " in " << getPos() << "; removing all of them."
<< std::endl;
@ -99,7 +105,7 @@ bool MapBlock::onObjectsActivation()
bool MapBlock::saveStaticObject(u16 id, const StaticObject &obj, u32 reason)
{
if (m_static_objects.getStoredSize() >= g_settings->getU16("max_objects_per_block")) {
if (m_static_objects.getStoredSize() >= get_max_objects_per_block()) {
warningstream << "MapBlock::saveStaticObject(): Trying to store id = " << id
<< " statically but block " << getPos() << " already contains "
<< m_static_objects.getStoredSize() << " objects."

View file

@ -179,130 +179,52 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
if (nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED) {
const auto &fixed = nodebox.fixed;
int facedir = n.getFaceDir(nodemgr, true);
u8 axisdir = facedir>>2;
facedir&=0x03;
u8 axisdir = facedir >> 2;
facedir &= 0x03;
boxes.reserve(boxes.size() + fixed.size());
for (aabb3f box : fixed) {
if (nodebox.type == NODEBOX_LEVELED)
box.MaxEdge.Y = (-0.5f + n.getLevel(nodemgr) / 64.0f) * BS;
if(facedir == 1) {
box.MinEdge.rotateXZBy(-90);
box.MaxEdge.rotateXZBy(-90);
} else if(facedir == 2) {
box.MinEdge.rotateXZBy(180);
box.MaxEdge.rotateXZBy(180);
} else if(facedir == 3) {
box.MinEdge.rotateXZBy(90);
box.MaxEdge.rotateXZBy(90);
}
switch (axisdir) {
case 0:
if(facedir == 1)
{
box.MinEdge.rotateXZBy(-90);
box.MaxEdge.rotateXZBy(-90);
}
else if(facedir == 2)
{
box.MinEdge.rotateXZBy(180);
box.MaxEdge.rotateXZBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateXZBy(90);
box.MaxEdge.rotateXZBy(90);
}
break;
case 1: // z+
box.MinEdge.rotateYZBy(90);
box.MaxEdge.rotateYZBy(90);
if(facedir == 1)
{
box.MinEdge.rotateXYBy(90);
box.MaxEdge.rotateXYBy(90);
}
else if(facedir == 2)
{
box.MinEdge.rotateXYBy(180);
box.MaxEdge.rotateXYBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateXYBy(-90);
box.MaxEdge.rotateXYBy(-90);
}
break;
case 2: //z-
box.MinEdge.rotateYZBy(-90);
box.MaxEdge.rotateYZBy(-90);
if(facedir == 1)
{
box.MinEdge.rotateXYBy(-90);
box.MaxEdge.rotateXYBy(-90);
}
else if(facedir == 2)
{
box.MinEdge.rotateXYBy(180);
box.MaxEdge.rotateXYBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateXYBy(90);
box.MaxEdge.rotateXYBy(90);
}
break;
case 3: //x+
box.MinEdge.rotateXYBy(-90);
box.MaxEdge.rotateXYBy(-90);
if(facedir == 1)
{
box.MinEdge.rotateYZBy(90);
box.MaxEdge.rotateYZBy(90);
}
else if(facedir == 2)
{
box.MinEdge.rotateYZBy(180);
box.MaxEdge.rotateYZBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateYZBy(-90);
box.MaxEdge.rotateYZBy(-90);
}
break;
case 4: //x-
box.MinEdge.rotateXYBy(90);
box.MaxEdge.rotateXYBy(90);
if(facedir == 1)
{
box.MinEdge.rotateYZBy(-90);
box.MaxEdge.rotateYZBy(-90);
}
else if(facedir == 2)
{
box.MinEdge.rotateYZBy(180);
box.MaxEdge.rotateYZBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateYZBy(90);
box.MaxEdge.rotateYZBy(90);
}
break;
case 5:
box.MinEdge.rotateXYBy(-180);
box.MaxEdge.rotateXYBy(-180);
if(facedir == 1)
{
box.MinEdge.rotateXZBy(90);
box.MaxEdge.rotateXZBy(90);
}
else if(facedir == 2)
{
box.MinEdge.rotateXZBy(180);
box.MaxEdge.rotateXZBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateXZBy(-90);
box.MaxEdge.rotateXZBy(-90);
}
break;
default:
break;
}
box.repair();
boxes.push_back(box);
}
@ -419,57 +341,47 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
boxes.reserve(boxes_size);
#define BOXESPUSHBACK(c) \
for (std::vector<aabb3f>::const_iterator \
it = (c).begin(); \
it != (c).end(); ++it) \
(boxes).push_back(*it);
auto boxes_insert = [&](const std::vector<aabb3f> &boxes_src) {
boxes.insert(boxes.end(), boxes_src.begin(), boxes_src.end());
};
BOXESPUSHBACK(nodebox.fixed);
boxes_insert(nodebox.fixed);
if (neighbors & 1) {
BOXESPUSHBACK(c.connect_top);
} else {
BOXESPUSHBACK(c.disconnected_top);
}
if (neighbors & 1)
boxes_insert(c.connect_top);
else
boxes_insert(c.disconnected_top);
if (neighbors & 2) {
BOXESPUSHBACK(c.connect_bottom);
} else {
BOXESPUSHBACK(c.disconnected_bottom);
}
if (neighbors & 2)
boxes_insert(c.connect_bottom);
else
boxes_insert(c.disconnected_bottom);
if (neighbors & 4) {
BOXESPUSHBACK(c.connect_front);
} else {
BOXESPUSHBACK(c.disconnected_front);
}
if (neighbors & 4)
boxes_insert(c.connect_front);
else
boxes_insert(c.disconnected_front);
if (neighbors & 8) {
BOXESPUSHBACK(c.connect_left);
} else {
BOXESPUSHBACK(c.disconnected_left);
}
if (neighbors & 8)
boxes_insert(c.connect_left);
else
boxes_insert(c.disconnected_left);
if (neighbors & 16) {
BOXESPUSHBACK(c.connect_back);
} else {
BOXESPUSHBACK(c.disconnected_back);
}
if (neighbors & 16)
boxes_insert(c.connect_back);
else
boxes_insert(c.disconnected_back);
if (neighbors & 32) {
BOXESPUSHBACK(c.connect_right);
} else {
BOXESPUSHBACK(c.disconnected_right);
}
if (neighbors & 32)
boxes_insert(c.connect_right);
else
boxes_insert(c.disconnected_right);
if (neighbors == 0) {
BOXESPUSHBACK(c.disconnected);
}
if (neighbors == 0)
boxes_insert(c.disconnected);
if (neighbors < 4) {
BOXESPUSHBACK(c.disconnected_sides);
}
if (neighbors < 4)
boxes_insert(c.disconnected_sides);
}
else // NODEBOX_REGULAR

View file

@ -18,6 +18,7 @@
#include "version.h"
#include "irrlicht_changes/printing.h"
#include "network/connection.h"
#include "network/networkpacket.h"
#include "network/networkprotocol.h"
#include "network/serveropcodes.h"
#include "server/player_sao.h"

View file

@ -474,21 +474,6 @@ struct ContentFeatures
}
}
bool needsBackfaceCulling() const
{
switch (drawtype) {
case NDT_TORCHLIKE:
case NDT_SIGNLIKE:
case NDT_FIRELIKE:
case NDT_RAILLIKE:
case NDT_PLANTLIKE:
case NDT_PLANTLIKE_ROOTED:
case NDT_MESH:
return false;
default:
return true;
}
}
bool isLiquid() const{
return (liquid_type != LIQUID_NONE);

View file

@ -6,6 +6,9 @@
#include "util/numeric.h"
#include "log.h"
#include "gamedef.h"
#include "porting.h" // strcasecmp
#include <cassert>
ObjDefManager::ObjDefManager(IGameDef *gamedef, ObjDefType type)
{

View file

@ -4,8 +4,9 @@
#pragma once
#include "util/basic_macros.h"
#include "porting.h"
#include "util/basic_macros.h" // DISABLE_CLASS_COPY
#include "irrlichttypes.h"
#include <string>
#include <vector>
class IGameDef;

View file

@ -32,12 +32,16 @@
#define sleep_ms(x) Sleep(x)
#define sleep_us(x) Sleep((x)/1000)
#define SLEEP_ACCURACY_US 2000
#define setenv(n,v,o) _putenv_s(n,v)
#define unsetenv(n) _putenv_s(n,"")
#else
#include <unistd.h>
#include <cstdlib> // setenv
#define SLEEP_ACCURACY_US 200
#define sleep_ms(x) usleep((x)*1000)
#define sleep_us(x) usleep(x)
#endif
@ -220,6 +224,21 @@ inline u64 getDeltaMs(u64 old_time_ms, u64 new_time_ms)
return (old_time_ms - new_time_ms);
}
inline void preciseSleepUs(u64 sleep_time)
{
if (sleep_time > 0)
{
u64 target_time = porting::getTimeUs() + sleep_time;
if (sleep_time > SLEEP_ACCURACY_US)
sleep_us(sleep_time - SLEEP_ACCURACY_US);
// Busy-wait the remaining time to adjust for sleep inaccuracies
// The target - now > 0 construct will handle overflow gracefully (even though it should
// never happen)
while ((s64)(target_time - porting::getTimeUs()) > 0) {}
}
}
inline const char *getPlatformName()
{
return

View file

@ -5,7 +5,8 @@
#pragma once
#include "util/container.h"
#include "irrlichttypes_bloated.h"
#include "irrlichttypes.h"
#include "irr_v3d.h"
class NodeDefManager;
class Map;

View file

@ -8,6 +8,7 @@
#include <algorithm>
#include "irr_v2d.h"
#include "network/connection.h"
#include "network/networkpacket.h"
#include "network/networkprotocol.h"
#include "network/serveropcodes.h"
#include "server/ban.h"
@ -624,6 +625,11 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
ZoneScoped;
auto framemarker = FrameMarker("Server::AsyncRunStep()-frame").started();
if (!m_async_fatal_error.get().empty()) {
infostream << "Refusing server step in error state" << std::endl;
return;
}
{
// Send blocks to clients
SendBlocks(dtime);
@ -649,9 +655,10 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
Send to clients at constant intervals
*/
static const float time_send_interval = 5.0f;
m_time_of_day_send_timer -= dtime;
if (m_time_of_day_send_timer < 0.0) {
m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
if (m_time_of_day_send_timer < 0) {
m_time_of_day_send_timer = time_send_interval;
u16 time = m_env->getTimeOfDay();
float time_speed = g_settings->getFloat("time_speed");
SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
@ -3862,6 +3869,14 @@ std::string Server::getBuiltinLuaPath()
return porting::path_share + DIR_DELIM + "builtin";
}
void Server::setAsyncFatalError(const std::string &error)
{
m_async_fatal_error.set(error);
// make sure server steps stop happening immediately
if (m_thread)
m_thread->stop();
}
// Not thread-safe.
void Server::addShutdownError(const ModError &e)
{

View file

@ -344,8 +344,7 @@ public:
void setStepSettings(StepSettings spdata) { m_step_settings.store(spdata); }
StepSettings getStepSettings() { return m_step_settings.load(); }
inline void setAsyncFatalError(const std::string &error)
{ m_async_fatal_error.set(error); }
void setAsyncFatalError(const std::string &error);
inline void setAsyncFatalError(const LuaError &e)
{
setAsyncFatalError(std::string("Lua: ") + e.what());

View file

@ -6,6 +6,7 @@
#include "clientiface.h"
#include "debug.h"
#include "network/connection.h"
#include "network/networkpacket.h"
#include "network/serveropcodes.h"
#include "remoteplayer.h"
#include "serialization.h" // SER_FMT_VER_INVALID

View file

@ -6,25 +6,25 @@
#include "irr_v3d.h" // for irrlicht datatypes
#include "constants.h"
#include "network/networkpacket.h"
#include "network/networkprotocol.h"
#include "network/address.h"
#include "network/networkprotocol.h" // session_t
#include "porting.h"
#include "threading/mutex_auto_lock.h"
#include "clientdynamicinfo.h"
#include <list>
#include <vector>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <memory>
#include <mutex>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
class MapBlock;
class ServerEnvironment;
class EmergeManager;
class MapBlock;
class NetworkPacket;
class ServerEnvironment;
/*
* State Transitions

View file

@ -8,8 +8,8 @@
#include <memory>
#include "map.h"
#include "util/container.h"
#include "util/metricsbackend.h"
#include "util/container.h" // UniqueQueue
#include "util/metricsbackend.h" // ptr typedefs
#include "map_settings_manager.h"
class Settings;

View file

@ -212,8 +212,6 @@ bool run_tests()
u64 t1 = porting::getTimeMs();
TestGameDef gamedef;
g_logger.setLevelSilenced(LL_ERROR, true);
u32 num_modules_failed = 0;
u32 num_total_tests_failed = 0;
u32 num_total_tests_run = 0;
@ -243,11 +241,9 @@ bool run_tests()
u64 tdiff = porting::getTimeMs() - t1;
g_logger.setLevelSilenced(LL_ERROR, false);
const char *overall_status = (num_modules_failed == 0) ? "PASSED" : "FAILED";
rawstream
rawstream << "\n"
<< "++++++++++++++++++++++++++++++++++++++++"
<< "++++++++++++++++++++++++++++++++++++++++" << std::endl
<< "Unit Test Results: " << overall_status << std::endl
@ -283,17 +279,15 @@ bool run_tests(const std::string &module_name)
return catch_test_failures == 0;
}
g_logger.setLevelSilenced(LL_ERROR, true);
u64 t1 = porting::getTimeMs();
bool ok = testmod->testModule(&gamedef);
u64 tdiff = porting::getTimeMs() - t1;
g_logger.setLevelSilenced(LL_ERROR, false);
const char *overall_status = ok ? "PASSED" : "FAILED";
rawstream
rawstream << "\n"
<< "++++++++++++++++++++++++++++++++++++++++"
<< "++++++++++++++++++++++++++++++++++++++++" << std::endl
<< "Unit Test Results: " << overall_status << std::endl

View file

@ -9,7 +9,7 @@
#include <sstream>
#include <vector>
#include "irrlichttypes_extrabloated.h"
#include "irrlichttypes_bloated.h"
#include "porting.h"
#include "filesys.h"
#include "mapnode.h"

View file

@ -6,7 +6,6 @@
#include <sstream>
#include "irrlichttypes_extrabloated.h"
#include "log.h"
#include "serialization.h"
#include "nodedef.h"

View file

@ -38,8 +38,10 @@ public:
MeshMakeData makeSingleNodeMMD(bool smooth_lighting = true)
{
MeshMakeData data{ndef(), 1};
data.setSmoothLighting(smooth_lighting);
MeshMakeData data{ndef(), 1, MeshGrid{1}};
data.m_generate_minimap = false;
data.m_smooth_lighting = smooth_lighting;
data.m_enable_water_reflections = false;
data.m_blockpos = {0, 0, 0};
for (s16 x = -1; x <= 1; x++)
for (s16 y = -1; y <= 1; y++)

View file

@ -98,10 +98,12 @@ void TestVoxelArea::test_addarea()
void TestVoxelArea::test_pad()
{
VoxelArea v1(v3s16(-1447, -9547, -875), v3s16(-147, 8854, 669));
auto old_extent = v1.getExtent();
v1.pad(v3s16(100, 200, 300));
UASSERT(v1.MinEdge == v3s16(-1547, -9747, -1175));
UASSERT(v1.MaxEdge == v3s16(-47, 9054, 969));
UASSERT(v1.getExtent() > old_extent);
}
void TestVoxelArea::test_extent()
@ -165,6 +167,12 @@ void TestVoxelArea::test_contains_point()
UASSERTEQ(bool, v1.contains(v3s16(-100, 100, 10000)), false);
UASSERTEQ(bool, v1.contains(v3s16(-100, 100, -10000)), false);
UASSERTEQ(bool, v1.contains(v3s16(10000, 100, 10)), false);
VoxelArea v2;
UASSERTEQ(bool, v2.contains(v3s16(-200, 10, 10)), false);
UASSERTEQ(bool, v2.contains(v3s16(0, 0, 0)), false);
UASSERTEQ(bool, v2.contains(v3s16(1, 1, 1)), false);
UASSERTEQ(bool, v2.contains(v3s16(-1, -1, -1)), false);
}
void TestVoxelArea::test_contains_i()
@ -180,6 +188,12 @@ void TestVoxelArea::test_contains_i()
UASSERTEQ(bool, v2.contains(10), true);
UASSERTEQ(bool, v2.contains(0), true);
UASSERTEQ(bool, v2.contains(-1), false);
VoxelArea v3;
UASSERTEQ(bool, v3.contains(0), false);
UASSERTEQ(bool, v3.contains(-1), false);
UASSERTEQ(bool, v3.contains(1), false);
UASSERTEQ(bool, v3.contains(2), false);
}
void TestVoxelArea::test_equal()
@ -244,6 +258,7 @@ void TestVoxelArea::test_intersect()
VoxelArea v3({11, 11, 11}, {11, 11, 11});
VoxelArea v4({-11, -2, -10}, {10, 2, 11});
UASSERT(v2.intersect(v1) == v2);
UASSERT(!v2.intersect(v1).hasEmptyExtent());
UASSERT(v1.intersect(v2) == v2.intersect(v1));
UASSERT(v1.intersect(v3).hasEmptyExtent());
UASSERT(v3.intersect(v1) == v1.intersect(v3));

View file

@ -113,6 +113,20 @@ void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef,
}
}
static inline void checkArea(const VoxelArea &a)
{
// won't overflow since cbrt(2^64) > 2^16
u64 real_volume = static_cast<u64>(a.getExtent().X) * a.getExtent().Y * a.getExtent().Z;
// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
// Note: the hard limit is somewhere around 2^31 due to s32 type
constexpr u64 MAX_ALLOWED = 4096000;
if (real_volume > MAX_ALLOWED) {
throw BaseException("VoxelManipulator: "
"Area volume exceeds allowed value of " + std::to_string(MAX_ALLOWED));
}
}
void VoxelManipulator::addArea(const VoxelArea &area)
{
// Cancel if requested area has zero volume
@ -124,18 +138,10 @@ void VoxelManipulator::addArea(const VoxelArea &area)
return;
// Calculate new area
VoxelArea new_area;
// New area is the requested area if m_area has zero volume
if(m_area.hasEmptyExtent())
{
new_area = area;
}
// Else add requested area to m_area
else
{
new_area = m_area;
new_area.addArea(area);
}
VoxelArea new_area = m_area;
new_area.addArea(area);
checkArea(new_area);
u32 new_size = new_area.getVolume();

View file

@ -103,6 +103,7 @@ public:
{
MinEdge -= d;
MaxEdge += d;
cacheExtent();
}
/*
@ -188,6 +189,7 @@ public:
ret.MaxEdge.Y = std::min(a.MaxEdge.Y, MaxEdge.Y);
ret.MinEdge.Z = std::max(a.MinEdge.Z, MinEdge.Z);
ret.MaxEdge.Z = std::min(a.MaxEdge.Z, MaxEdge.Z);
ret.cacheExtent();
return ret;
}
@ -457,7 +459,9 @@ public:
{
if(!m_area.contains(p))
return false;
m_data[m_area.index(p)] = n;
const s32 index = m_area.index(p);
m_data[index] = n;
m_flags[index] &= ~VOXELFLAG_NO_DATA;
return true;
}