-void DecoSimple::resolveNodeNames(INodeDefManager *ndef) {
- Decoration::resolveNodeNames(ndef);
-
- if (c_deco == CONTENT_IGNORE && !decolist_names.size()) {
- c_deco = ndef->getId(deco_name);
- if (c_deco == CONTENT_IGNORE) {
- errorstream << "DecoSimple::resolveNodeNames: decoration node '"
- << deco_name << "' not defined" << std::endl;
- c_deco = CONTENT_AIR;
- }
- }
- if (c_spawnby == CONTENT_IGNORE) {
- c_spawnby = ndef->getId(spawnby_name);
- if (c_spawnby == CONTENT_IGNORE) {
- errorstream << "DecoSimple::resolveNodeNames: spawnby node '"
- << spawnby_name << "' not defined" << std::endl;
- nspawnby = -1;
- c_spawnby = CONTENT_AIR;
- }
- }
-
- if (c_decolist.size())
- return;
-
- for (size_t i = 0; i != decolist_names.size(); i++) {
- content_t c = ndef->getId(decolist_names[i]);
- if (c == CONTENT_IGNORE) {
- errorstream << "DecoSimple::resolveNodeNames: decolist node '"
- << decolist_names[i] << "' not defined" << std::endl;
- c = CONTENT_AIR;
- }
- c_decolist.push_back(c);
- }
-}
-
-
-void DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) {
- ManualMapVoxelManipulator *vm = mg->vm;
-
- u32 vi = vm->m_area.index(p);
- if (vm->m_data[vi].getContent() != c_place_on &&
- c_place_on != CONTENT_IGNORE)
- return;
-
- if (nspawnby != -1) {
- int nneighs = 0;
- v3s16 dirs[8] = { // a Moore neighborhood
- v3s16( 0, 0, 1),
- v3s16( 0, 0, -1),
- v3s16( 1, 0, 0),
- v3s16(-1, 0, 0),
- v3s16( 1, 0, 1),
- v3s16(-1, 0, 1),
- v3s16(-1, 0, -1),
- v3s16( 1, 0, -1)
- };
-
- for (int i = 0; i != 8; i++) {
- u32 index = vm->m_area.index(p + dirs[i]);
- if (vm->m_area.contains(index) &&
- vm->m_data[index].getContent() == c_spawnby)
- nneighs++;
- }
-
- if (nneighs < nspawnby)
- return;
- }
-
- size_t ndecos = c_decolist.size();
- content_t c_place = ndecos ? c_decolist[pr->range(0, ndecos - 1)] : c_deco;
-
- s16 height = (deco_height_max > 0) ?
- pr->range(deco_height, deco_height_max) : deco_height;
-
- height = MYMIN(height, max_y - p.Y);
-
- v3s16 em = vm->m_area.getExtent();
- for (int i = 0; i < height; i++) {
- vm->m_area.add_y(em, vi, 1);
-
- content_t c = vm->m_data[vi].getContent();
- if (c != CONTENT_AIR && c != CONTENT_IGNORE)
- break;
-
- vm->m_data[vi] = MapNode(c_place);
- }
-}
-
-
-int DecoSimple::getHeight() {
- return (deco_height_max > 0) ? deco_height_max : deco_height;
-}
-
-
-std::string DecoSimple::getName() {
- return deco_name;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-
-
-DecoSchematic::DecoSchematic() {
- node_names = NULL;
- schematic = NULL;
- slice_probs = NULL;
- flags = 0;
- size = v3s16(0, 0, 0);
-}
-
-
-DecoSchematic::~DecoSchematic() {
- delete node_names;
- delete []schematic;
- delete []slice_probs;
-}
-
-
-void DecoSchematic::resolveNodeNames(INodeDefManager *ndef) {
- Decoration::resolveNodeNames(ndef);
-
- if (filename.empty())
- return;
-
- if (!node_names) {
- errorstream << "DecoSchematic::resolveNodeNames: node name list was "
- "not created" << std::endl;
- return;
- }
-
- 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 '"
- << name << "' not defined" << std::endl;
- c = CONTENT_AIR;
- }
-
- c_nodes.push_back(c);
- }
-
- for (int i = 0; i != size.X * size.Y * size.Z; i++)
- schematic[i].setContent(c_nodes[schematic[i].getContent()]);
-
- delete node_names;
- node_names = NULL;
-}
-
-
-void DecoSchematic::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) {
- ManualMapVoxelManipulator *vm = mg->vm;
-
- if (flags & DECO_PLACE_CENTER_X)
- p.X -= (size.X + 1) / 2;
- if (flags & DECO_PLACE_CENTER_Y)
- p.Y -= (size.Y + 1) / 2;
- if (flags & DECO_PLACE_CENTER_Z)
- p.Z -= (size.Z + 1) / 2;
-
- u32 vi = vm->m_area.index(p);
- if (vm->m_data[vi].getContent() != c_place_on &&
- c_place_on != CONTENT_IGNORE)
- return;
-
- Rotation rot = (rotation == ROTATE_RAND) ?
- (Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
-
- blitToVManip(p, vm, rot, false);
-}
-
-
-int DecoSchematic::getHeight() {
- return size.Y;
-}
-
-
-std::string DecoSchematic::getName() {
- return filename;
-}
-
-
-void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
- Rotation rot, bool force_placement) {
- int xstride = 1;
- int ystride = size.X;
- int zstride = size.X * size.Y;
-
- s16 sx = size.X;
- s16 sy = size.Y;
- s16 sz = size.Z;
-
- int i_start, i_step_x, i_step_z;
- switch (rot) {
- case ROTATE_90:
- i_start = sx - 1;
- i_step_x = zstride;
- i_step_z = -xstride;
- SWAP(s16, sx, sz);
- break;
- case ROTATE_180:
- i_start = zstride * (sz - 1) + sx - 1;
- i_step_x = -xstride;
- i_step_z = -zstride;
- break;
- case ROTATE_270:
- i_start = zstride * (sz - 1);
- i_step_x = -zstride;
- i_step_z = xstride;
- SWAP(s16, sx, sz);
- break;
- default:
- i_start = 0;
- i_step_x = xstride;
- i_step_z = zstride;
- }
-
- s16 y_map = p.Y;
- for (s16 y = 0; y != sy; y++) {
- if (slice_probs[y] != MTSCHEM_PROB_ALWAYS &&
- myrand_range(1, 255) > slice_probs[y])
- continue;
-
- for (s16 z = 0; z != sz; z++) {
- u32 i = z * i_step_z + y * ystride + i_start;
- for (s16 x = 0; x != sx; x++, i += i_step_x) {
- u32 vi = vm->m_area.index(p.X + x, y_map, p.Z + z);
- if (!vm->m_area.contains(vi))
- continue;
-
- 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();
- if (c != CONTENT_AIR && c != CONTENT_IGNORE)
- continue;
- }
-
- if (schematic[i].param1 != MTSCHEM_PROB_ALWAYS &&
- myrand_range(1, 255) > schematic[i].param1)
- continue;
-
- vm->m_data[vi] = schematic[i];
- vm->m_data[vi].param1 = 0;
-
- if (rot)
- vm->m_data[vi].rotateAlongYAxis(ndef, rot);
- }
- }
- y_map++;
- }
-}
-
-
-void DecoSchematic::placeStructure(Map *map, v3s16 p, bool force_placement) {
- assert(schematic != NULL);
- ManualMapVoxelManipulator *vm = new ManualMapVoxelManipulator(map);
-
- Rotation rot = (rotation == ROTATE_RAND) ?
- (Rotation)myrand_range(ROTATE_0, ROTATE_270) : rotation;
-
- v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
- v3s16(size.Z, size.Y, size.X) : size;
-
- if (flags & DECO_PLACE_CENTER_X)
- p.X -= (s.X + 1) / 2;
- if (flags & DECO_PLACE_CENTER_Y)
- p.Y -= (s.Y + 1) / 2;
- if (flags & DECO_PLACE_CENTER_Z)
- p.Z -= (s.Z + 1) / 2;
-
- v3s16 bp1 = getNodeBlockPos(p);
- v3s16 bp2 = getNodeBlockPos(p + s - v3s16(1,1,1));
- vm->initialEmerge(bp1, bp2);
-
- blitToVManip(p, vm, rot, force_placement);
-
- std::map<v3s16, MapBlock *> lighting_modified_blocks;
- std::map<v3s16, MapBlock *> modified_blocks;
- vm->blitBackAll(&modified_blocks);
-
- // TODO: Optimize this by using Mapgen::calcLighting() instead
- lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
- map->updateLighting(lighting_modified_blocks, modified_blocks);
-
- MapEditEvent event;
- event.type = MEET_OTHER;
- for (std::map<v3s16, MapBlock *>::iterator
- it = modified_blocks.begin();
- it != modified_blocks.end(); ++it)
- event.modified_blocks.insert(it->first);
-
- map->dispatchEvent(&event);
-}
-
-
-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);
- if (signature != MTSCHEM_FILE_SIGNATURE) {
- errorstream << "loadSchematicFile: invalid schematic "
- "file" << std::endl;
- return false;
- }
-
- u16 version = readU16(is);
- if (version > MTSCHEM_FILE_VER_HIGHEST_READ) {
- errorstream << "loadSchematicFile: unsupported schematic "
- "file version" << std::endl;
- return false;
- }
-
- size = readV3S16(is);
-
- delete []slice_probs;
- slice_probs = new u8[size.Y];
- if (version >= 3) {
- for (int y = 0; y != size.Y; y++)
- slice_probs[y] = readU8(is);
- } else {
- for (int y = 0; y != size.Y; y++)
- slice_probs[y] = MTSCHEM_PROB_ALWAYS;
- }
-
- int nodecount = size.X * size.Y * size.Z;
-
- u16 nidmapcount = readU16(is);
-
- 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);
- }
-
- delete []schematic;
- 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;
-}
-
-
-/*
- Minetest Schematic File Format
-
- All values are stored in big-endian byte order.
- [u32] signature: 'MTSM'
- [u16] version: 3
- [u16] size X
- [u16] size Y
- [u16] size Z
- For each Y:
- [u8] slice probability value
- [Name-ID table] Name ID Mapping Table
- [u16] name-id count
- For each name-id mapping:
- [u16] name length
- [u8[]] name
- ZLib deflated {
- For each node in schematic: (for z, y, x)
- [u16] content
- For each node in schematic:
- [u8] probability of occurance (param1)
- 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
- 3 - Added y-slice probabilities; this allows for variable height structures
-*/
-void DecoSchematic::saveSchematicFile(INodeDefManager *ndef) {
- std::ostringstream ss(std::ios_base::binary);
-
- writeU32(ss, MTSCHEM_FILE_SIGNATURE); // signature
- writeU16(ss, MTSCHEM_FILE_VER_HIGHEST_WRITE); // version
- writeV3S16(ss, size); // schematic size
-
- for (int y = 0; y != size.Y; y++) // Y slice probabilities
- writeU8(ss, slice_probs[y]);
-
- std::vector<content_t> usednodes;
- int nodecount = size.X * size.Y * size.Z;
- build_nnlist_and_update_ids(schematic, nodecount, &usednodes);
-
- u16 numids = usednodes.size();
- writeU16(ss, numids); // name count
- for (int i = 0; i != numids; i++)
- ss << serializeString(ndef->get(usednodes[i]).name); // node names
-
- // compressed bulk node data
- MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE, schematic,
- nodecount, 2, 2, true);
-
- fs::safeWriteToFile(filename, ss.str());
-}
-
-
-void build_nnlist_and_update_ids(MapNode *nodes, u32 nodecount,
- std::vector<content_t> *usednodes) {
- std::map<content_t, content_t> nodeidmap;
- content_t numids = 0;
-
- for (u32 i = 0; i != nodecount; i++) {
- content_t id;
- content_t c = nodes[i].getContent();
-
- std::map<content_t, content_t>::const_iterator it = nodeidmap.find(c);
- if (it == nodeidmap.end()) {
- id = numids;
- numids++;
-
- usednodes->push_back(c);
- nodeidmap.insert(std::make_pair(c, id));
- } else {
- id = it->second;
- }
- nodes[i].setContent(id);
- }