Decoration: Fix schematic probability mess with new MTS file version
authorkwolekr <kwolekr@minetest.net>
Mon, 5 Aug 2013 02:59:22 +0000 (22:59 -0400)
committerkwolekr <kwolekr@minetest.net>
Sun, 11 Aug 2013 19:34:49 +0000 (15:34 -0400)
doc/lua_api.txt
src/environment.cpp
src/map.cpp
src/map.h
src/mapgen.cpp
src/mapgen.h
src/script/common/c_content.cpp
src/script/lua_api/luaapi.cpp

index 5247b248d8c189642c9f822b24ab00743b8733fc..3dfb67157db909cd2456dd6220d404152ed4ee93 100644 (file)
@@ -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:
  - 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]]].
+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 
 probability of that node appearing in the structure.
-When passed to minetest.create_schematic, probability is an integer value ranging from -1 to 255:
- - A probability value of 0 means that node will always appear.
- - A probability value of -1 means the node will never appear.
+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 never appear (0% chance).
+ - 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
    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.
 
 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.
    ^ 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,
-   ^ 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 pos is not inside the box formed by p1 and p2, it is ignored.
    ^ If probability_list is nil, no probabilities are applied.
@@ -2195,8 +2193,8 @@ Decoration definition (register_decoration)
     schematic = {
         size = {x=4, y=6, z=4},
         data = {
-            {name="cobble", param1=0, param2=0},
-            {name="dirt_with_grass", param1=0, param2=0},
+            {name="cobble", param1=255, param2=0},
+            {name="dirt_with_grass", param1=255, param2=0},
              ...
         }
     },
index 76a8aab5130dbb54ef6243f9dd0ffd7ce9b9edf7..35983aaaf30b8e216fa5cc4383d6ff40b28b4be0 100644 (file)
@@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapblock.h"
 #include "serverobject.h"
 #include "content_sao.h"
-#include "mapgen.h"
 #include "settings.h"
 #include "log.h"
 #include "profiler.h"
index 90cd498b7e931551c62212db3980491b939fef05..da20b5b0e1e9993d85ca6002b0a4b4dc3e7f3aa4 100644 (file)
@@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "voxel.h"
 #include "porting.h"
-#include "mapgen.h"
 #include "nodemetadata.h"
 #include "settings.h"
 #include "log.h"
index c1fd361a77dc9886119df1c4c523cc9a3016f6bc..c90106ed1a689041676e9b011b887fead2a3dcdc 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapnode.h"
 #include "constants.h"
 #include "voxel.h"
-#include "mapgen.h" //for BlockMakeData and EmergeManager
+#include "mapgen.h" //for MapgenParams
 #include "modifiedstate.h"
 #include "util/container.h"
 #include "nodetimer.h"
index 397e52f74b998d8a082e5b774d5f6c548ba9ae8c..d3996de5f974f1b397971d34d4883663b9e831b4 100644 (file)
@@ -507,16 +507,19 @@ void DecoSchematic::resolveNodeNames(INodeDefManager *ndef) {
        
        for (size_t i = 0; i != node_names->size(); i++) {
                std::string name = node_names->at(i);
+               
                std::map<std::string, std::string>::iterator it;
                it = replacements.find(name);
                if (it != replacements.end())
                        name = it->second;
+               
                content_t c = ndef->getId(name);
                if (c == CONTENT_IGNORE) {
                        errorstream << "DecoSchematic::resolveNodeNames: node '"
-                               << node_names->at(i) << "' not defined" << std::endl;
+                               << name << "' not defined" << std::endl;
                        c = CONTENT_AIR;
                }
+               
                c_nodes.push_back(c);
        }
                
@@ -605,6 +608,9 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
                        
                        if (schematic[i].getContent() == CONTENT_IGNORE)
                                continue;
+                               
+                       if (schematic[i].param1 == MTSCHEM_PROB_NEVER)
+                               continue;
 
                        if (!force_placement) {
                                content_t c = vm->m_data[vi].getContent();
@@ -612,7 +618,8 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
                                        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;
                        
                        vm->m_data[vi] = schematic[i];
@@ -668,6 +675,9 @@ void DecoSchematic::placeStructure(Map *map, v3s16 p) {
 
 
 bool DecoSchematic::loadSchematicFile() {
+       content_t cignore = CONTENT_IGNORE;
+       bool have_cignore = false;
+       
        std::ifstream is(filename.c_str(), std::ios_base::binary);
 
        u32 signature = readU32(is);
@@ -678,7 +688,7 @@ bool DecoSchematic::loadSchematicFile() {
        }
        
        u16 version = readU16(is);
-       if (version != 1) {
+       if (version > 2) {
                errorstream << "loadSchematicFile: unsupported schematic "
                        "file version" << std::endl;
                return false;
@@ -692,6 +702,11 @@ bool DecoSchematic::loadSchematicFile() {
        node_names = new std::vector<std::string>;
        for (int i = 0; i != nidmapcount; i++) {
                std::string name = deSerializeString(is);
+               if (name == "ignore") {
+                       name = "air";
+                       cignore = i;
+                       have_cignore = true;
+               }
                node_names->push_back(name);
        }
 
@@ -699,7 +714,16 @@ bool DecoSchematic::loadSchematicFile() {
        schematic = new MapNode[nodecount];
        MapNode::deSerializeBulk(is, SER_FMT_VER_HIGHEST_READ, schematic,
                                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;
 }
 
@@ -709,7 +733,7 @@ bool DecoSchematic::loadSchematicFile() {
 
        All values are stored in big-endian byte order.
        [u32] signature: 'MTSM'
-       [u16] version: 1
+       [u16] version: 2
        [u16] size X
        [u16] size Y
        [u16] size Z
@@ -726,12 +750,16 @@ bool DecoSchematic::loadSchematicFile() {
        For each node in schematic:
                [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) {
        std::ofstream os(filename.c_str(), std::ios_base::binary);
 
        writeU32(os, MTSCHEM_FILE_SIGNATURE); // signature
-       writeU16(os, 1);      // version
+       writeU16(os, 2);      // version
        writeV3S16(os, size); // schematic size
        
        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);
                for (s16 x = p1.X; x <= p2.X; x++, i++, 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++) {
                v3s16 p = (*plist)[i].first - p0;
                int index = p.Z * (size.Y * size.X) + p.Y * size.X + p.X;
                if (index < size.Z * size.Y * size.X) {
-                       s16 prob = (*plist)[i].second;
-                       if (prob != -1)
-                               schematic[index].param1 = prob;
-                       else
-                               schematic[index].setContent(CONTENT_IGNORE);
+                       u8 prob = (*plist)[i].second;
+                       schematic[index].param1 = prob;
+                       
+                       // trim unnecessary node names from schematic
+                       if (prob == MTSCHEM_PROB_NEVER)
+                               schematic[index].setContent(CONTENT_AIR);
                }
        }
 }
index 7b8ff57ca42ee0bfe03043a7f8c623777b890d4d..6ed2c09943d71f87cb0cc865f40df6c71d20ccda 100644 (file)
@@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapnode.h"
 #include "noise.h"
 #include "settings.h"
-#include <map>
 
 /////////////////// Mapgen flags
 #define MG_TREES         0x01
@@ -262,6 +261,8 @@ public:
 };
 
 #define MTSCHEM_FILE_SIGNATURE 0x4d54534d // 'MTSM'
+#define MTSCHEM_PROB_NEVER  0x00
+#define MTSCHEM_PROB_ALWAYS 0xFF
 
 class DecoSchematic : public Decoration {
 public:
@@ -292,7 +293,7 @@ public:
        
        bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2);
        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,
index f9765b6553b8e9e77f063447ea81771d92a46b76..ca7c7fde934bccf4d43e5d592fb4aed5f24729db 100644 (file)
@@ -956,8 +956,24 @@ bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *serv
                
                lua_pushnil(L);
                while (lua_next(L, -2)) {
-                       if (i < numnodes)
-                               schemdata[i] = readnode(L, -1, ndef);
+                       if (i < numnodes) {
+                               // 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++;
                        lua_pop(L, 1);
index 929aa40d09c9094ebab3bd42a1bcf2c5efe1fcbf..26fb0c318ddf5e0a877c8dcf70d9a1219312bb3e 100644 (file)
@@ -867,7 +867,7 @@ int ModApiBasic::l_create_schematic(lua_State *L)
        v3s16 p2 = read_v3s16(L, 2);
        sortBoxVerticies(p1, p2);
        
-       std::vector<std::pair<v3s16, s16> > probability_list;
+       std::vector<std::pair<v3s16, u8> > probability_list;
        if (lua_istable(L, 3)) {
                lua_pushnil(L);
                while (lua_next(L, 3)) {
@@ -876,13 +876,8 @@ int ModApiBasic::l_create_schematic(lua_State *L)
                                v3s16 pos = read_v3s16(L, -1);
                                lua_pop(L, 1);
                                
-                               s16 prob = getintfield_default(L, -1, "prob", 0);
-                               if (prob < -1 || prob >= UCHAR_MAX) {
-                                       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));
-                               }
+                               u8 prob = getintfield_default(L, -1, "prob", 0xFF);
+                               probability_list.push_back(std::make_pair(pos, prob));
                        }
 
                        lua_pop(L, 1);