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

Weather support

This commit is contained in:
proller 2013-07-27 22:34:30 +04:00
parent e65d8ad655
commit 3aedfac968
23 changed files with 552 additions and 91 deletions

View file

@ -28,6 +28,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "treegen.h" // For treegen::make_tree
#include "main.h" // for g_settings
#include "map.h"
#include "cpp_api/scriptapi.h"
#include "log.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@ -166,86 +168,220 @@ public:
}
};
class LiquidFlowABM : public ActiveBlockModifier
{
private:
std::set<std::string> contents;
class LiquidFlowABM : public ActiveBlockModifier {
private:
std::set<std::string> contents;
public:
LiquidFlowABM(ServerEnvironment *env, INodeDefManager *nodemgr)
{
std::set<content_t> liquids;
nodemgr->getIds("group:liquid", liquids);
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
contents.insert(nodemgr->get(*k).liquid_alternative_flowing);
}
virtual std::set<std::string> getTriggerContents()
{
return contents;
}
virtual float getTriggerInterval()
{ return 10.0; }
virtual u32 getTriggerChance()
{ return 10; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
{
ServerMap *map = &env->getServerMap();
if (map->transforming_liquid_size() > 500)
return;
map->transforming_liquid_add(p);
//if ((*map).m_transforming_liquid.size() < 500) (*map).m_transforming_liquid.push_back(p);
}
public:
LiquidFlowABM(ServerEnvironment *env, INodeDefManager *nodemgr) {
std::set<content_t> liquids;
nodemgr->getIds("group:liquid", liquids);
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
contents.insert(nodemgr->get(*k).liquid_alternative_flowing);
}
virtual std::set<std::string> getTriggerContents() {
return contents;
}
virtual float getTriggerInterval()
{ return 10.0; }
virtual u32 getTriggerChance()
{ return 10; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
ServerMap *map = &env->getServerMap();
if (map->transforming_liquid_size() > 500)
return;
map->transforming_liquid_add(p);
}
};
class LiquidDropABM : public ActiveBlockModifier
{
private:
std::set<std::string> contents;
class LiquidDropABM : public ActiveBlockModifier {
private:
std::set<std::string> contents;
public:
LiquidDropABM(ServerEnvironment *env, INodeDefManager *nodemgr)
{
std::set<content_t> liquids;
nodemgr->getIds("group:liquid", liquids);
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
contents.insert(nodemgr->get(*k).liquid_alternative_source);
}
virtual std::set<std::string> getTriggerContents()
{ return contents; }
virtual std::set<std::string> getRequiredNeighbors()
{
std::set<std::string> neighbors;
neighbors.insert("mapgen_air");
return neighbors;
}
virtual float getTriggerInterval()
{ return 20.0; }
virtual u32 getTriggerChance()
{ return 10; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
{
ServerMap *map = &env->getServerMap();
if (map->transforming_liquid_size() > 500)
return;
if ( map->getNodeNoEx(p - v3s16(0, 1, 0 )).getContent() != CONTENT_AIR // below
&& map->getNodeNoEx(p - v3s16(1, 0, 0 )).getContent() != CONTENT_AIR // right
&& map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent() != CONTENT_AIR // left
&& map->getNodeNoEx(p - v3s16(0, 0, 1 )).getContent() != CONTENT_AIR // back
&& map->getNodeNoEx(p - v3s16(0, 0, -1)).getContent() != CONTENT_AIR // front
)
return;
map->transforming_liquid_add(p);
}
public:
LiquidDropABM(ServerEnvironment *env, INodeDefManager *nodemgr) {
std::set<content_t> liquids;
nodemgr->getIds("group:liquid", liquids);
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
contents.insert(nodemgr->get(*k).liquid_alternative_source);
}
virtual std::set<std::string> getTriggerContents()
{ return contents; }
virtual std::set<std::string> getRequiredNeighbors() {
std::set<std::string> neighbors;
neighbors.insert("mapgen_air");
return neighbors;
}
virtual float getTriggerInterval()
{ return 20.0; }
virtual u32 getTriggerChance()
{ return 10; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
ServerMap *map = &env->getServerMap();
if (map->transforming_liquid_size() > 500)
return;
if ( map->getNodeNoEx(p - v3s16(0, 1, 0 )).getContent() != CONTENT_AIR // below
&& map->getNodeNoEx(p - v3s16(1, 0, 0 )).getContent() != CONTENT_AIR // right
&& map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent() != CONTENT_AIR // left
&& map->getNodeNoEx(p - v3s16(0, 0, 1 )).getContent() != CONTENT_AIR // back
&& map->getNodeNoEx(p - v3s16(0, 0, -1)).getContent() != CONTENT_AIR // front
)
return;
map->transforming_liquid_add(p);
}
};
void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef)
{
class LiquidFreeze : public ActiveBlockModifier {
public:
LiquidFreeze(ServerEnvironment *env, INodeDefManager *nodemgr) { }
virtual std::set<std::string> getTriggerContents() {
std::set<std::string> s;
s.insert("group:freezes");
return s;
}
virtual std::set<std::string> getRequiredNeighbors() {
std::set<std::string> s;
s.insert("mapgen_air");
s.insert("group:melts");
return s;
}
virtual float getTriggerInterval()
{ return 10.0; }
virtual u32 getTriggerChance()
{ return 20; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
ServerMap *map = &env->getServerMap();
INodeDefManager *ndef = env->getGameDef()->ndef();
float heat = map->getHeat(env, p);
//heater = rare
if (heat <= -1 && (heat <= -50 || ((myrand_range(-50, heat)) <= -30))) {
content_t c_self = n.getContent();
// making freeze not annoying, do not freeze random blocks in center of ocean
// todo: any block not water (dont freeze _source near _flowing)
content_t c;
bool allow = heat < -40;
// todo: make for(...)
if (!allow) {
c = map->getNodeNoEx(p - v3s16(0, 1, 0 )).getContent(); // below
if (c == CONTENT_AIR || c == CONTENT_IGNORE)
return; // do not freeze when falling
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
if (!allow) {
c = map->getNodeNoEx(p - v3s16(1, 0, 0 )).getContent(); // right
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
if (!allow) {
c = map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent(); // left
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
if (!allow) {
c = map->getNodeNoEx(p - v3s16(0, 0, 1 )).getContent(); // back
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
if (!allow) {
c = map->getNodeNoEx(p - v3s16(0, 0, -1)).getContent(); // front
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
}
}
}
}
}
if (allow) {
n.setContent(ndef->getId(ndef->get(n).freezemelt));
map->addNodeWithEvent(p, n);
}
}
}
};
class LiquidMeltWeather : public ActiveBlockModifier {
public:
LiquidMeltWeather(ServerEnvironment *env, INodeDefManager *nodemgr) { }
virtual std::set<std::string> getTriggerContents() {
std::set<std::string> s;
s.insert("group:melts");
return s;
}
virtual std::set<std::string> getRequiredNeighbors() {
std::set<std::string> s;
s.insert("mapgen_air");
s.insert("group:freezes");
return s;
}
virtual float getTriggerInterval()
{ return 10.0; }
virtual u32 getTriggerChance()
{ return 20; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
ServerMap *map = &env->getServerMap();
INodeDefManager *ndef = env->getGameDef()->ndef();
float heat = map->getHeat(env, p);
if (heat >= 1 && (heat >= 40 || ((myrand_range(heat, 40)) >= 20))) {
n.setContent(ndef->getId(ndef->get(n).freezemelt));
if (!n.getLevel(ndef))
n.addLevel(ndef);
map->addNodeWithEvent(p, n);
env->getScriptIface()->node_falling_update(p);
}
}
};
class LiquidMeltHot : public ActiveBlockModifier {
public:
LiquidMeltHot(ServerEnvironment *env, INodeDefManager *nodemgr) { }
virtual std::set<std::string> getTriggerContents() {
std::set<std::string> s;
s.insert("group:melts");
return s;
}
virtual std::set<std::string> getRequiredNeighbors() {
std::set<std::string> s;
s.insert("group:igniter");
s.insert("group:hot");
return s;
}
virtual float getTriggerInterval()
{ return 2.0; }
virtual u32 getTriggerChance()
{ return 4; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
ServerMap *map = &env->getServerMap();
INodeDefManager *ndef = env->getGameDef()->ndef();
n.setContent(ndef->getId(ndef->get(n).freezemelt));
if (!n.getLevel(ndef))
n.addLevel(ndef);
map->addNodeWithEvent(p, n);
env->getScriptIface()->node_falling_update(p);
}
};
class LiquidMeltAround : public LiquidMeltHot {
public:
LiquidMeltAround(ServerEnvironment *env, INodeDefManager *nodemgr)
: LiquidMeltHot(env, nodemgr) { }
virtual std::set<std::string> getRequiredNeighbors() {
std::set<std::string> s;
s.insert("group:melt_around");
return s;
}
virtual float getTriggerInterval()
{ return 40.0; }
virtual u32 getTriggerChance()
{ return 60; }
};
void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) {
env->addActiveBlockModifier(new GrowGrassABM());
env->addActiveBlockModifier(new RemoveGrassABM());
env->addActiveBlockModifier(new MakeTreesFromSaplingsABM(env, nodedef));
if (g_settings->getBool("liquid_finite")) {
env->addActiveBlockModifier(new LiquidFlowABM(env, nodedef));
env->addActiveBlockModifier(new LiquidDropABM(env, nodedef));
env->addActiveBlockModifier(new LiquidMeltHot(env, nodedef));
env->addActiveBlockModifier(new LiquidMeltAround(env, nodedef));
if (g_settings->getBool("weather")) {
env->addActiveBlockModifier(new LiquidFreeze(env, nodedef));
env->addActiveBlockModifier(new LiquidMeltWeather(env, nodedef));
}
}
}

View file

@ -178,6 +178,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
settings->setDefault("time_send_interval", "5");
settings->setDefault("time_speed", "72");
settings->setDefault("year_days", "30");
settings->setDefault("server_unload_unused_data_timeout", "29");
settings->setDefault("server_map_save_interval", "5.3");
settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");
@ -214,6 +215,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("liquid_relax", "2");
settings->setDefault("liquid_fast_flood", "1");
settings->setDefault("underground_springs", "1");
settings->setDefault("weather", "false");
//mapgen stuff
settings->setDefault("mg_name", "v6");

View file

@ -488,6 +488,14 @@ void *EmergeThread::Thread() {
if (block)
modified_blocks[p] = block;
// Update weather data in mapblock
for(std::map<v3s16, MapBlock *>::iterator
i = modified_blocks.begin();
i != modified_blocks.end(); ++i) {
map->getHeat(m_server->m_env, MAP_BLOCKSIZE*i->first ,i->second);
map->getHumidity(m_server->m_env, MAP_BLOCKSIZE*i->first, i->second);
}
// Set the modified blocks unsent for all the clients
for (std::map<u16, RemoteClient*>::iterator
i = m_server->m_clients.begin();

View file

@ -303,6 +303,7 @@ public:
//check if there's a line of sight between two positions
bool line_of_sight(v3f pos1, v3f pos2, float stepsize=1.0);
u32 getGameTime() { return m_game_time; }
private:
/*

View file

@ -2455,6 +2455,7 @@ void the_game(
camera.step(dtime);
v3f player_position = player->getPosition();
v3s16 pos_i = floatToInt(player_position, BS);
v3f camera_position = camera.getPosition();
v3f camera_direction = camera.getDirection();
f32 camera_fov = camera.getFovMax();
@ -3034,7 +3035,9 @@ void the_game(
<<", "<<(player_position.Y/BS)
<<", "<<(player_position.Z/BS)
<<") (yaw="<<(wrapDegrees_0_360(camera_yaw))
<<") (seed = "<<((unsigned long long)client.getMapSeed())
<<") (t="<<client.getEnv().getClientMap().getHeat(pos_i)
<<"C, h="<<client.getEnv().getClientMap().getHumidity(pos_i)
<<"%) (seed = "<<((unsigned long long)client.getMapSeed())
<<")";
guitext2->setText(narrow_to_wide(os.str()).c_str());
guitext2->setVisible(true);

View file

@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "mapgen_v6.h"
#include "mapgen_indev.h"
#include "biome.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@ -1087,6 +1088,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
/*
Add neighboring liquid nodes and the node itself if it is
liquid (=water node was added) to transform queue.
note: todo: for liquid_finite enough to add only self node
*/
v3s16 dirs[7] = {
v3s16(0,0,0), // self
@ -1278,6 +1280,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
/*
Add neighboring liquid nodes and this node to transform queue.
(it's vital for the node itself to get updated last.)
note: todo: for liquid_finite enough to add only self node
*/
v3s16 dirs[7] = {
v3s16(0,0,1), // back
@ -2364,6 +2367,26 @@ void Map::removeNodeTimer(v3s16 p)
block->m_node_timers.remove(p_rel);
}
s16 Map::getHeat(v3s16 p)
{
MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
if(block != NULL) {
return block->heat;
}
//errorstream << "No heat for " << p.X<<"," << p.Z << std::endl;
return 0;
}
s16 Map::getHumidity(v3s16 p)
{
MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
if(block != NULL) {
return block->humidity;
}
//errorstream << "No humidity for " << p.X<<"," << p.Z << std::endl;
return 0;
}
/*
ServerMap
*/
@ -3863,7 +3886,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
<<" (SerializationError). "
<<"what()="<<e.what()
<<std::endl;
//" Ignoring. A new one will be generated.
// Ignoring. A new one will be generated.
assert(0);
// TODO: Backup file; name is in fullpath.
@ -4039,6 +4062,63 @@ void ServerMap::PrintInfo(std::ostream &out)
out<<"ServerMap: ";
}
s16 ServerMap::getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block)
{
if(block == NULL)
block = getBlockNoCreateNoEx(getNodeBlockPos(p));
if(block != NULL) {
if (env->getGameTime() - block->heat_time < 10)
return block->heat;
}
//variant 1: full random
//f32 heat = NoisePerlin3D(m_emerge->biomedef->np_heat, p.X, env->getGameTime()/100, p.Z, m_emerge->params->seed);
//variant 2: season change based on default heat map
f32 heat = NoisePerlin2D(m_emerge->biomedef->np_heat, p.X, p.Z, m_emerge->params->seed);
heat += -30; // -30 - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50,
f32 base = (f32)env->getGameTime() * env->getTimeOfDaySpeed();
base /= ( 86400 * g_settings->getS16("year_days") );
base += (f32)p.X / 3000;
heat += 30 * sin(base * M_PI); // season
heat += p.Y / -333; // upper=colder, lower=hotter
// daily change, hotter at sun +4, colder at night -4
heat += 8 * (sin(cycle_shift(env->getTimeOfDayF(), -0.25) * M_PI) - 0.5);
if(block != NULL) {
block->heat = heat;
block->heat_time = env->getGameTime();
}
return heat;
}
s16 ServerMap::getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block)
{
if(block == NULL)
block = getBlockNoCreateNoEx(getNodeBlockPos(p));
if(block != NULL) {
if (env->getGameTime() - block->humidity_time < 10)
return block->humidity;
}
f32 humidity = NoisePerlin3D( m_emerge->biomedef->np_humidity,
p.X, env->getGameTime()/10, p.Z,
m_emerge->params->seed);
humidity += -12 * ( sin(cycle_shift(env->getTimeOfDayF(), -0.1) * M_PI) - 0.5);
//todo like heat//humidity += 20 * ( sin(((f32)p.Z / 300) * M_PI) - 0.5);
if (humidity > 100) humidity = 100;
if (humidity < 0) humidity = 0;
if(block != NULL) {
block->humidity = humidity;
block->humidity_time = env->getGameTime();
}
return humidity;
}
/*
MapVoxelManipulator
*/

View file

@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "modifiedstate.h"
#include "util/container.h"
#include "nodetimer.h"
#include "environment.h"
extern "C" {
#include "sqlite3.h"
@ -336,6 +337,9 @@ public:
void transforming_liquid_add(v3s16 p);
s32 transforming_liquid_size();
virtual s16 getHeat(v3s16 p);
virtual s16 getHumidity(v3s16 p);
protected:
friend class LuaVoxelManip;
@ -483,6 +487,10 @@ public:
// Parameters fed to the Mapgen
MapgenParams *m_mgparams;
virtual s16 getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL);
virtual s16 getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL);
private:
// Seed used for all kinds of randomness in generation
u64 m_seed;

View file

@ -58,7 +58,11 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
m_disk_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
m_usage_timer(0),
m_refcount(0)
m_refcount(0),
heat_time(0),
heat(0),
humidity_time(0),
humidity(0)
{
data = NULL;
if(dummy == false)
@ -632,6 +636,11 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
// Node timers
m_node_timers.serialize(os, version);
}
} else {
if(version >= 26){
writeF1000(os, heat);
writeF1000(os, humidity);
}
}
}
@ -734,6 +743,11 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
<<": Node timers (ver>=25)"<<std::endl);
m_node_timers.deSerialize(is, version);
}
} else {
if(version >= 26){
heat = readF1000(is);
humidity = readF1000(is);
}
}
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())

View file

@ -518,6 +518,11 @@ public:
NodeTimerList m_node_timers;
StaticObjectList m_static_objects;
s16 heat;
u32 heat_time;
s16 humidity;
u32 humidity_time;
private:
/*
Private member variables

View file

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapnode.h" // For mapnode_translate_*_internal
#include "serialization.h" // For ser_ver_supported
#include "util/serialize.h"
#include "log.h"
#include <string>
#include <sstream>
@ -359,9 +360,23 @@ std::vector<aabb3f> MapNode::getSelectionBoxes(INodeDefManager *nodemgr) const
return transformNodeBox(*this, f.selection_box, nodemgr);
}
u8 MapNode::getMaxLevel(INodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
// todo: after update in all games leave only if (f.param_type_2 ==
if( f.liquid_type == LIQUID_SOURCE
|| f.liquid_type == LIQUID_FLOWING
|| f.param_type_2 == CPT2_FLOWINGLIQUID)
return LIQUID_LEVEL_MAX;
if(f.leveled || f.param_type_2 == CPT2_LEVELED)
return LEVELED_MAX;
return 0;
}
u8 MapNode::getLevel(INodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
// todo: after update in all games leave only if (f.param_type_2 ==
if(f.liquid_type == LIQUID_SOURCE)
return LIQUID_LEVEL_SOURCE;
if (f.param_type_2 == CPT2_FLOWINGLIQUID)
@ -377,6 +392,37 @@ u8 MapNode::getLevel(INodeDefManager *nodemgr) const
return 0;
}
u8 MapNode::addLevel(INodeDefManager *nodemgr, s8 add)
{
s8 level = getLevel(nodemgr);
u8 rest = 0;
if (add == 0) level = 1;
level += add;
if (level < 1) {
setContent(CONTENT_AIR);
return 0;
}
const ContentFeatures &f = nodemgr->get(*this);
if ( f.param_type_2 == CPT2_FLOWINGLIQUID
|| f.liquid_type == LIQUID_FLOWING
|| f.liquid_type == LIQUID_SOURCE) {
if (level >= LIQUID_LEVEL_MAX) {
rest = level - LIQUID_LEVEL_MAX;
setContent(nodemgr->getId(f.liquid_alternative_source));
} else {
setContent(nodemgr->getId(f.liquid_alternative_flowing));
setParam2(level & LIQUID_LEVEL_MASK);
}
} else if (f.leveled || f.param_type_2 == CPT2_LEVELED) {
if (level > LEVELED_MAX) {
rest = level - LEVELED_MAX;
level = LEVELED_MAX;
}
setParam2(level & LEVELED_MASK);
}
return rest;
}
u32 MapNode::serializedLength(u8 version)
{
if(!ser_ver_supported(version))

View file

@ -227,7 +227,9 @@ struct MapNode
std::vector<aabb3f> getSelectionBoxes(INodeDefManager *nodemgr) const;
/* Liquid helpers */
u8 getMaxLevel(INodeDefManager *nodemgr) const;
u8 getLevel(INodeDefManager *nodemgr) const;
u8 addLevel(INodeDefManager *nodemgr, s8 add = 1);
/*
Serialization functions

View file

@ -213,6 +213,7 @@ void ContentFeatures::reset()
liquid_alternative_source = "";
liquid_viscosity = 0;
liquid_renewable = true;
freezemelt = "";
liquid_range = LIQUID_LEVEL_MAX+1;
drowning = true;
light_source = 0;

View file

@ -224,6 +224,8 @@ struct ContentFeatures
u8 liquid_viscosity;
// Is liquid renewable (new liquid source will be created between 2 existing)
bool liquid_renewable;
// Ice for water, water for ice
std::string freezemelt;
// Number of flowing liquids surrounding source
u8 liquid_range;
bool drowning;

View file

@ -397,6 +397,7 @@ ContentFeatures read_content_features(lua_State *L, int index)
f.leveled = getintfield_default(L, index, "leveled", f.leveled);
getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
getstringfield(L, index, "freezemelt", f.freezemelt);
getboolfield(L, index, "drowning", f.drowning);
// Amount of light the node emits
f.light_source = getintfield_default(L, index,

View file

@ -233,3 +233,20 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
scriptError("error: %s", lua_tostring(L, -1));
}
void ScriptApiNode::node_falling_update(v3s16 p)
{
SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L, "nodeupdate");
push_v3s16(L, p);
if(lua_pcall(L, 1, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
void ScriptApiNode::node_falling_update_single(v3s16 p)
{
SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L, "nodeupdate_single");
push_v3s16(L, p);
if(lua_pcall(L, 1, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}

View file

@ -49,6 +49,8 @@ public:
const std::string &formname,
const std::map<std::string, std::string> &fields,
ServerActiveObject *sender);
void node_falling_update(v3s16 p);
void node_falling_update_single(v3s16 p);
public:
static struct EnumString es_DrawType[];
static struct EnumString es_ContentParamType[];

View file

@ -263,6 +263,48 @@ int ModApiEnvMod::l_punch_node(lua_State *L)
return 1;
}
// minetest.get_node_max_level(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_max_level(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
MapNode n = env->getMap().getNodeNoEx(pos);
lua_pushnumber(L, n.getMaxLevel(env->getGameDef()->ndef()));
return 1;
}
// minetest.get_node_level(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_level(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
MapNode n = env->getMap().getNodeNoEx(pos);
lua_pushnumber(L, n.getLevel(env->getGameDef()->ndef()));
return 1;
}
// minetest.add_node_level(pos, level)
// pos = {x=num, y=num, z=num}
// level: 0..8
int ModApiEnvMod::l_add_node_level(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
u8 level = 1;
if(lua_isnumber(L, 2))
level = lua_tonumber(L, 2);
MapNode n = env->getMap().getNodeNoEx(pos);
lua_pushnumber(L, n.addLevel(env->getGameDef()->ndef(), level));
env->setNode(pos, n);
return 1;
}
// minetest.get_meta(pos)
int ModApiEnvMod::l_get_meta(lua_State *L)
{
@ -820,6 +862,40 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L)
return 1;
}
// minetest.transforming_liquid_add(pos)
int ModApiEnvMod::l_transforming_liquid_add(lua_State *L)
{
GET_ENV_PTR;
v3s16 p0 = read_v3s16(L, 1);
env->getMap().transforming_liquid_add(p0);
return 1;
}
// minetest.get_heat(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_heat(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
lua_pushnumber(L, env->getServerMap().getHeat(env, pos));
return 1;
}
// minetest.get_humidity(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_humidity(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
lua_pushnumber(L, env->getServerMap().getHumidity(env, pos));
return 1;
}
bool ModApiEnvMod::Initialize(lua_State *L,int top)
{
@ -835,6 +911,9 @@ bool ModApiEnvMod::Initialize(lua_State *L,int top)
retval &= API_FCT(place_node);
retval &= API_FCT(dig_node);
retval &= API_FCT(punch_node);
retval &= API_FCT(get_node_max_level);
retval &= API_FCT(get_node_level);
retval &= API_FCT(add_node_level);
retval &= API_FCT(add_entity);
retval &= API_FCT(get_meta);
retval &= API_FCT(get_node_timer);
@ -853,6 +932,9 @@ bool ModApiEnvMod::Initialize(lua_State *L,int top)
retval &= API_FCT(spawn_tree);
retval &= API_FCT(find_path);
retval &= API_FCT(line_of_sight);
retval &= API_FCT(transforming_liquid_add);
retval &= API_FCT(get_heat);
retval &= API_FCT(get_humidity);
return retval;
}

View file

@ -67,6 +67,19 @@ private:
// pos = {x=num, y=num, z=num}
static int l_punch_node(lua_State *L);
// minetest.get_node_max_level(pos)
// pos = {x=num, y=num, z=num}
static int l_get_node_max_level(lua_State *L);
// minetest.get_node_level(pos)
// pos = {x=num, y=num, z=num}
static int l_get_node_level(lua_State *L);
// minetest.add_node_level(pos)
// pos = {x=num, y=num, z=num}
static int l_add_node_level(lua_State *L);
// minetest.get_meta(pos)
static int l_get_meta(lua_State *L);
@ -135,6 +148,12 @@ private:
// minetest.find_path(pos1, pos2, searchdistance,
// max_jump, max_drop, algorithm) -> table containing path
static int l_find_path(lua_State *L);
// minetest.transforming_liquid_add(pos)
static int l_transforming_liquid_add(lua_State *L);
static int l_get_heat(lua_State *L);
static int l_get_humidity(lua_State *L);
static struct EnumString es_MapgenObject[];

View file

@ -61,11 +61,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
23: new node metadata format
24: 16-bit node ids and node timers (never released as stable)
25: Improved node timer format
26: MapBlocks contain heat and humidity
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
#define SER_FMT_VER_HIGHEST 25
#define SER_FMT_VER_HIGHEST 26
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0

View file

@ -349,5 +349,12 @@ inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxi
}
}
inline float cycle_shift(float value, float by = 0, float max = 1)
{
if (value + by < 0) return max + by + value;
if (value + by > max) return value + by - max;
return value + by;
}
#endif