Decoration: Fix schematic probability mess with new MTS file version

This commit is contained in:
kwolekr 2013-08-04 22:59:22 -04:00
parent 56b9377c1c
commit c06caa14c3
8 changed files with 75 additions and 37 deletions

@ -436,18 +436,16 @@ Schematic specifier
or through raw data supplied through Lua, in the form of a table. This table must specify two fields: or through raw data supplied through Lua, in the form of a table. This table must specify two fields:
- The 'size' field is a 3d vector containing the dimensions of the provided schematic. - The 'size' field is a 3d vector containing the dimensions of the provided schematic.
- The 'data' field is a flat table of MapNodes making up the schematic, in the order of [z [y [x]]]. - The 'data' field is a flat table of MapNodes making up the schematic, in the order of [z [y [x]]].
Important: The default value for param1 in MapNodes here is 255, which represents "always place".
In the bulk MapNode data, param1, instead of the typical light values, instead represents the In the bulk MapNode data, param1, instead of the typical light values, instead represents the
probability of that node appearing in the structure. probability of that node appearing in the structure.
When passed to minetest.create_schematic, probability is an integer value ranging from -1 to 255: When passed to minetest.create_schematic, probability is an integer value ranging from 0 to 255:
- A probability value of 0 means that node will always appear. - A probability value of 0 means that node will never appear (0% chance).
- A probability value of -1 means the node will never appear. - A probability value of 255 means the node will always appear (100% chance).
- If the probability value p is greater than 0, then there is a (p / 256 * 100)% chance that node - If the probability value p is greater than 0, then there is a (p / 256 * 100)% chance that node
will appear when the schematic is placed on the map. will appear when the schematic is placed on the map.
If registering a structure in the raw format, however, -1 is not a valid probability value; in order to
have a node that is not placed, it must be CONTENT_IGNORE (the name for which is "ignore").
Important note: Node aliases cannot be used for a raw schematic provided when registering as a decoration. Important note: Node aliases cannot be used for a raw schematic provided when registering as a decoration.
Schematic attributes Schematic attributes
@ -1436,7 +1434,7 @@ minetest.create_schematic(p1, p2, probability_list, filename)
^ Apply the specified probability values to the specified nodes in probability_list. ^ Apply the specified probability values to the specified nodes in probability_list.
^ probability_list is an array of tables containing two fields, pos and prob. ^ probability_list is an array of tables containing two fields, pos and prob.
^ pos is the 3d vector specifying the absolute coordinates of the node being modified, ^ pos is the 3d vector specifying the absolute coordinates of the node being modified,
^ and prob is the integer value from -1 to 255 of the probability (see: Schematic specifier). ^ and prob is the integer value from 0 to 255 of the probability (see: Schematic specifier).
^ If there are two or more entries with the same pos value, the last occuring in the array is used. ^ If there are two or more entries with the same pos value, the last occuring in the array is used.
^ If pos is not inside the box formed by p1 and p2, it is ignored. ^ If pos is not inside the box formed by p1 and p2, it is ignored.
^ If probability_list is nil, no probabilities are applied. ^ If probability_list is nil, no probabilities are applied.
@ -2195,8 +2193,8 @@ Decoration definition (register_decoration)
schematic = { schematic = {
size = {x=4, y=6, z=4}, size = {x=4, y=6, z=4},
data = { data = {
{name="cobble", param1=0, param2=0}, {name="cobble", param1=255, param2=0},
{name="dirt_with_grass", param1=0, param2=0}, {name="dirt_with_grass", param1=255, param2=0},
... ...
} }
}, },

@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapblock.h" #include "mapblock.h"
#include "serverobject.h" #include "serverobject.h"
#include "content_sao.h" #include "content_sao.h"
#include "mapgen.h"
#include "settings.h" #include "settings.h"
#include "log.h" #include "log.h"
#include "profiler.h" #include "profiler.h"

@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h" #include "filesys.h"
#include "voxel.h" #include "voxel.h"
#include "porting.h" #include "porting.h"
#include "mapgen.h"
#include "nodemetadata.h" #include "nodemetadata.h"
#include "settings.h" #include "settings.h"
#include "log.h" #include "log.h"

@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapnode.h" #include "mapnode.h"
#include "constants.h" #include "constants.h"
#include "voxel.h" #include "voxel.h"
#include "mapgen.h" //for BlockMakeData and EmergeManager #include "mapgen.h" //for MapgenParams
#include "modifiedstate.h" #include "modifiedstate.h"
#include "util/container.h" #include "util/container.h"
#include "nodetimer.h" #include "nodetimer.h"

@ -507,16 +507,19 @@ void DecoSchematic::resolveNodeNames(INodeDefManager *ndef) {
for (size_t i = 0; i != node_names->size(); i++) { for (size_t i = 0; i != node_names->size(); i++) {
std::string name = node_names->at(i); std::string name = node_names->at(i);
std::map<std::string, std::string>::iterator it; std::map<std::string, std::string>::iterator it;
it = replacements.find(name); it = replacements.find(name);
if (it != replacements.end()) if (it != replacements.end())
name = it->second; name = it->second;
content_t c = ndef->getId(name); content_t c = ndef->getId(name);
if (c == CONTENT_IGNORE) { if (c == CONTENT_IGNORE) {
errorstream << "DecoSchematic::resolveNodeNames: node '" errorstream << "DecoSchematic::resolveNodeNames: node '"
<< node_names->at(i) << "' not defined" << std::endl; << name << "' not defined" << std::endl;
c = CONTENT_AIR; c = CONTENT_AIR;
} }
c_nodes.push_back(c); c_nodes.push_back(c);
} }
@ -605,6 +608,9 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
if (schematic[i].getContent() == CONTENT_IGNORE) if (schematic[i].getContent() == CONTENT_IGNORE)
continue; continue;
if (schematic[i].param1 == MTSCHEM_PROB_NEVER)
continue;
if (!force_placement) { if (!force_placement) {
content_t c = vm->m_data[vi].getContent(); content_t c = vm->m_data[vi].getContent();
@ -612,7 +618,8 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
continue; continue;
} }
if (schematic[i].param1 && myrand_range(1, 256) > schematic[i].param1) if (schematic[i].param1 != MTSCHEM_PROB_ALWAYS &&
myrand_range(1, 255) > schematic[i].param1)
continue; continue;
vm->m_data[vi] = schematic[i]; vm->m_data[vi] = schematic[i];
@ -668,6 +675,9 @@ void DecoSchematic::placeStructure(Map *map, v3s16 p) {
bool DecoSchematic::loadSchematicFile() { bool DecoSchematic::loadSchematicFile() {
content_t cignore = CONTENT_IGNORE;
bool have_cignore = false;
std::ifstream is(filename.c_str(), std::ios_base::binary); std::ifstream is(filename.c_str(), std::ios_base::binary);
u32 signature = readU32(is); u32 signature = readU32(is);
@ -678,7 +688,7 @@ bool DecoSchematic::loadSchematicFile() {
} }
u16 version = readU16(is); u16 version = readU16(is);
if (version != 1) { if (version > 2) {
errorstream << "loadSchematicFile: unsupported schematic " errorstream << "loadSchematicFile: unsupported schematic "
"file version" << std::endl; "file version" << std::endl;
return false; return false;
@ -692,6 +702,11 @@ bool DecoSchematic::loadSchematicFile() {
node_names = new std::vector<std::string>; node_names = new std::vector<std::string>;
for (int i = 0; i != nidmapcount; i++) { for (int i = 0; i != nidmapcount; i++) {
std::string name = deSerializeString(is); std::string name = deSerializeString(is);
if (name == "ignore") {
name = "air";
cignore = i;
have_cignore = true;
}
node_names->push_back(name); node_names->push_back(name);
} }
@ -699,7 +714,16 @@ bool DecoSchematic::loadSchematicFile() {
schematic = new MapNode[nodecount]; schematic = new MapNode[nodecount];
MapNode::deSerializeBulk(is, SER_FMT_VER_HIGHEST_READ, schematic, MapNode::deSerializeBulk(is, SER_FMT_VER_HIGHEST_READ, schematic,
nodecount, 2, 2, true); nodecount, 2, 2, true);
if (version == 1) { // fix up the probability values
for (int i = 0; i != nodecount; i++) {
if (schematic[i].param1 == 0)
schematic[i].param1 = MTSCHEM_PROB_ALWAYS;
if (have_cignore && schematic[i].getContent() == cignore)
schematic[i].param1 = MTSCHEM_PROB_NEVER;
}
}
return true; return true;
} }
@ -709,7 +733,7 @@ bool DecoSchematic::loadSchematicFile() {
All values are stored in big-endian byte order. All values are stored in big-endian byte order.
[u32] signature: 'MTSM' [u32] signature: 'MTSM'
[u16] version: 1 [u16] version: 2
[u16] size X [u16] size X
[u16] size Y [u16] size Y
[u16] size Z [u16] size Z
@ -726,12 +750,16 @@ bool DecoSchematic::loadSchematicFile() {
For each node in schematic: For each node in schematic:
[u8] param2 [u8] param2
} }
Version changes:
1 - Initial version
2 - Fixed messy never/always place; 0 probability is now never, 0xFF is always
*/ */
void DecoSchematic::saveSchematicFile(INodeDefManager *ndef) { void DecoSchematic::saveSchematicFile(INodeDefManager *ndef) {
std::ofstream os(filename.c_str(), std::ios_base::binary); std::ofstream os(filename.c_str(), std::ios_base::binary);
writeU32(os, MTSCHEM_FILE_SIGNATURE); // signature writeU32(os, MTSCHEM_FILE_SIGNATURE); // signature
writeU16(os, 1); // version writeU16(os, 2); // version
writeV3S16(os, size); // schematic size writeV3S16(os, size); // schematic size
std::vector<content_t> usednodes; std::vector<content_t> usednodes;
@ -789,7 +817,7 @@ bool DecoSchematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2) {
u32 vi = vm->m_area.index(p1.X, y, z); u32 vi = vm->m_area.index(p1.X, y, z);
for (s16 x = p1.X; x <= p2.X; x++, i++, vi++) { for (s16 x = p1.X; x <= p2.X; x++, i++, vi++) {
schematic[i] = vm->m_data[vi]; schematic[i] = vm->m_data[vi];
schematic[i].param1 = 0; schematic[i].param1 = MTSCHEM_PROB_ALWAYS;
} }
} }
@ -798,16 +826,18 @@ bool DecoSchematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2) {
} }
void DecoSchematic::applyProbabilities(std::vector<std::pair<v3s16, s16> > *plist, v3s16 p0) { void DecoSchematic::applyProbabilities(std::vector<std::pair<v3s16, u8> > *plist,
v3s16 p0) {
for (size_t i = 0; i != plist->size(); i++) { for (size_t i = 0; i != plist->size(); i++) {
v3s16 p = (*plist)[i].first - p0; v3s16 p = (*plist)[i].first - p0;
int index = p.Z * (size.Y * size.X) + p.Y * size.X + p.X; int index = p.Z * (size.Y * size.X) + p.Y * size.X + p.X;
if (index < size.Z * size.Y * size.X) { if (index < size.Z * size.Y * size.X) {
s16 prob = (*plist)[i].second; u8 prob = (*plist)[i].second;
if (prob != -1) schematic[index].param1 = prob;
schematic[index].param1 = prob;
else // trim unnecessary node names from schematic
schematic[index].setContent(CONTENT_IGNORE); if (prob == MTSCHEM_PROB_NEVER)
schematic[index].setContent(CONTENT_AIR);
} }
} }
} }

@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapnode.h" #include "mapnode.h"
#include "noise.h" #include "noise.h"
#include "settings.h" #include "settings.h"
#include <map>
/////////////////// Mapgen flags /////////////////// Mapgen flags
#define MG_TREES 0x01 #define MG_TREES 0x01
@ -262,6 +261,8 @@ public:
}; };
#define MTSCHEM_FILE_SIGNATURE 0x4d54534d // 'MTSM' #define MTSCHEM_FILE_SIGNATURE 0x4d54534d // 'MTSM'
#define MTSCHEM_PROB_NEVER 0x00
#define MTSCHEM_PROB_ALWAYS 0xFF
class DecoSchematic : public Decoration { class DecoSchematic : public Decoration {
public: public:
@ -292,7 +293,7 @@ public:
bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2); bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2);
void placeStructure(Map *map, v3s16 p); void placeStructure(Map *map, v3s16 p);
void applyProbabilities(std::vector<std::pair<v3s16, s16> > *plist, v3s16 p0); void applyProbabilities(std::vector<std::pair<v3s16, u8> > *plist, v3s16 p0);
}; };
void build_nnlist_and_update_ids(MapNode *nodes, u32 nodecount, void build_nnlist_and_update_ids(MapNode *nodes, u32 nodecount,

@ -956,8 +956,24 @@ bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *serv
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, -2)) { while (lua_next(L, -2)) {
if (i < numnodes) if (i < numnodes) {
schemdata[i] = readnode(L, -1, ndef); // same as readnode, except param1 default is MTSCHEM_PROB_CONST
lua_getfield(L, -1, "name");
const char *name = luaL_checkstring(L, -1);
lua_pop(L, 1);
u8 param1;
lua_getfield(L, -1, "param1");
param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
lua_pop(L, 1);
u8 param2;
lua_getfield(L, -1, "param2");
param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
lua_pop(L, 1);
schemdata[i] = MapNode(ndef, name, param1, param2);
}
i++; i++;
lua_pop(L, 1); lua_pop(L, 1);

@ -867,7 +867,7 @@ int ModApiBasic::l_create_schematic(lua_State *L)
v3s16 p2 = read_v3s16(L, 2); v3s16 p2 = read_v3s16(L, 2);
sortBoxVerticies(p1, p2); sortBoxVerticies(p1, p2);
std::vector<std::pair<v3s16, s16> > probability_list; std::vector<std::pair<v3s16, u8> > probability_list;
if (lua_istable(L, 3)) { if (lua_istable(L, 3)) {
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, 3)) { while (lua_next(L, 3)) {
@ -876,13 +876,8 @@ int ModApiBasic::l_create_schematic(lua_State *L)
v3s16 pos = read_v3s16(L, -1); v3s16 pos = read_v3s16(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
s16 prob = getintfield_default(L, -1, "prob", 0); u8 prob = getintfield_default(L, -1, "prob", 0xFF);
if (prob < -1 || prob >= UCHAR_MAX) { probability_list.push_back(std::make_pair(pos, prob));
errorstream << "create_schematic: probability value of "
<< prob << " at " << PP(pos) << " out of range" << std::endl;
} else {
probability_list.push_back(std::make_pair(pos, prob));
}
} }
lua_pop(L, 1); lua_pop(L, 1);