@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
35
35
#include " treegen.h"
36
36
#include " mapgen_v6.h"
37
37
#include " mapgen_v7.h"
38
+ #include " util/serialize.h"
38
39
39
40
FlagDesc flagdesc_mapgen[] = {
40
41
{" trees" , MG_TREES},
@@ -53,6 +54,12 @@ FlagDesc flagdesc_ore[] = {
53
54
{NULL , 0 }
54
55
};
55
56
57
+ FlagDesc flagdesc_deco_schematic[] = {
58
+ {" place_center_x" , DECO_PLACE_CENTER_X},
59
+ {" place_center_y" , DECO_PLACE_CENTER_Y},
60
+ {" place_center_z" , DECO_PLACE_CENTER_Z},
61
+ {NULL , 0 }
62
+ };
56
63
57
64
// /////////////////////////////////////////////////////////////////////////////
58
65
@@ -198,12 +205,15 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed,
198
205
}
199
206
200
207
208
+ // /////////////////////////////////////////////////////////////////////////////
209
+
210
+
201
211
Decoration *createDecoration (DecorationType type) {
202
212
switch (type) {
203
213
case DECO_SIMPLE:
204
214
return new DecoSimple;
205
- // case DECO_SCHEMATIC:
206
- // return new DecoSchematic;
215
+ case DECO_SCHEMATIC:
216
+ return new DecoSchematic;
207
217
// case DECO_LSYSTEM:
208
218
// return new DecoLSystem;
209
219
default :
@@ -212,6 +222,14 @@ Decoration *createDecoration(DecorationType type) {
212
222
}
213
223
214
224
225
+ Decoration::Decoration () {
226
+ mapseed = 0 ;
227
+ np = NULL ;
228
+ fill_ratio = 0 ;
229
+ sidelen = 1 ;
230
+ }
231
+
232
+
215
233
Decoration::~Decoration () {
216
234
delete np;
217
235
}
@@ -352,22 +370,25 @@ void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
352
370
#endif
353
371
354
372
373
+ // /////////////////////////////////////////////////////////////////////////////
374
+
375
+
355
376
void DecoSimple::resolveNodeNames (INodeDefManager *ndef) {
356
377
Decoration::resolveNodeNames (ndef);
357
378
358
379
if (c_deco == CONTENT_IGNORE) {
359
380
c_deco = ndef->getId (deco_name);
360
381
if (c_deco == CONTENT_IGNORE) {
361
382
errorstream << " DecoSimple::resolveNodeNames: decoration node '"
362
- << deco_name << " ' not defined" ;
383
+ << deco_name << " ' not defined" << std::endl ;
363
384
c_deco = CONTENT_AIR;
364
385
}
365
386
}
366
387
if (c_spawnby == CONTENT_IGNORE) {
367
388
c_spawnby = ndef->getId (spawnby_name);
368
389
if (c_spawnby == CONTENT_IGNORE) {
369
390
errorstream << " DecoSimple::resolveNodeNames: spawnby node '"
370
- << deco_name << " ' not defined" ;
391
+ << deco_name << " ' not defined" << std::endl ;
371
392
nspawnby = -1 ;
372
393
c_spawnby = CONTENT_AIR;
373
394
}
@@ -380,15 +401,16 @@ void DecoSimple::resolveNodeNames(INodeDefManager *ndef) {
380
401
content_t c = ndef->getId (decolist_names[i]);
381
402
if (c == CONTENT_IGNORE) {
382
403
errorstream << " DecoSimple::resolveNodeNames: decolist node '"
383
- << decolist_names[i] << " ' not defined" ;
404
+ << decolist_names[i] << " ' not defined" << std::endl ;
384
405
c = CONTENT_AIR;
385
406
}
386
407
c_decolist.push_back (c);
387
408
}
388
409
}
389
410
390
411
391
- void DecoSimple::generate (Mapgen *mg, PseudoRandom *pr, s16 max_y, s16 start_y, v3s16 p) {
412
+ void DecoSimple::generate (Mapgen *mg, PseudoRandom *pr, s16 max_y,
413
+ s16 start_y, v3s16 p) {
392
414
ManualMapVoxelManipulator *vm = mg->vm ;
393
415
394
416
u32 vi = vm->m_area .index (p);
@@ -454,6 +476,291 @@ std::string DecoSimple::getName() {
454
476
// /////////////////////////////////////////////////////////////////////////////
455
477
456
478
479
+ DecoSchematic::DecoSchematic () {
480
+ node_names = NULL ;
481
+ schematic = NULL ;
482
+ flags = 0 ;
483
+ size = v3s16 (0 , 0 , 0 );
484
+ }
485
+
486
+
487
+ DecoSchematic::~DecoSchematic () {
488
+ delete node_names;
489
+ delete [] schematic;
490
+ }
491
+
492
+
493
+ void DecoSchematic::resolveNodeNames (INodeDefManager *ndef) {
494
+ Decoration::resolveNodeNames (ndef);
495
+
496
+ if (filename.empty ())
497
+ return ;
498
+
499
+ if (!node_names) {
500
+ errorstream << " DecoSchematic::resolveNodeNames: node name list was "
501
+ " not created" << std::endl;
502
+ return ;
503
+ }
504
+
505
+ for (size_t i = 0 ; i != node_names->size (); i++) {
506
+ content_t c = ndef->getId (node_names->at (i));
507
+ if (c == CONTENT_IGNORE) {
508
+ errorstream << " DecoSchematic::resolveNodeNames: node '"
509
+ << node_names->at (i) << " ' not defined" << std::endl;
510
+ c = CONTENT_AIR;
511
+ }
512
+ c_nodes.push_back (c);
513
+ }
514
+
515
+ for (int i = 0 ; i != size.X * size.Y * size.Z ; i++)
516
+ schematic[i].setContent (c_nodes[schematic[i].getContent ()]);
517
+
518
+ delete node_names;
519
+ node_names = NULL ;
520
+ }
521
+
522
+
523
+ void DecoSchematic::generate (Mapgen *mg, PseudoRandom *pr, s16 max_y,
524
+ s16 start_y, v3s16 p) {
525
+ ManualMapVoxelManipulator *vm = mg->vm ;
526
+
527
+ if (flags & DECO_PLACE_CENTER_X)
528
+ p.X -= (size.X + 1 ) / 2 ;
529
+ if (flags & DECO_PLACE_CENTER_Y)
530
+ p.Y -= (size.Y + 1 ) / 2 ;
531
+ if (flags & DECO_PLACE_CENTER_Z)
532
+ p.Z -= (size.Z + 1 ) / 2 ;
533
+
534
+ u32 vi = vm->m_area .index (p);
535
+ if (vm->m_data [vi].getContent () != c_place_on &&
536
+ c_place_on != CONTENT_IGNORE)
537
+ return ;
538
+
539
+ u32 i = 0 ;
540
+ for (s16 z = 0 ; z != size.Z ; z++)
541
+ for (s16 y = 0 ; y != size.Y ; y++) {
542
+ vi = vm->m_area .index (p.X , p.Y + y, p.Z + z);
543
+ for (s16 x = 0 ; x != size.X ; x++, i++, vi++) {
544
+ if (!vm->m_area .contains (vi))
545
+ continue ;
546
+
547
+ content_t c = vm->m_data [vi].getContent ();
548
+ if (c != CONTENT_AIR && c != CONTENT_IGNORE)
549
+ continue ;
550
+
551
+ if (schematic[i].param1 && myrand_range (1 , 256 ) > schematic[i].param1 )
552
+ continue ;
553
+
554
+ vm->m_data [vi] = schematic[i];
555
+ vm->m_data [vi].param1 = 0 ;
556
+ }
557
+ }
558
+ }
559
+
560
+
561
+ int DecoSchematic::getHeight () {
562
+ return size.Y ;
563
+ }
564
+
565
+
566
+ std::string DecoSchematic::getName () {
567
+ return filename;
568
+ }
569
+
570
+
571
+ void DecoSchematic::placeStructure (Map *map, v3s16 p) {
572
+ assert (schematic != NULL );
573
+ ManualMapVoxelManipulator *vm = new ManualMapVoxelManipulator (map);
574
+
575
+ if (flags & DECO_PLACE_CENTER_X)
576
+ p.X -= (size.X + 1 ) / 2 ;
577
+ if (flags & DECO_PLACE_CENTER_Y)
578
+ p.Y -= (size.Y + 1 ) / 2 ;
579
+ if (flags & DECO_PLACE_CENTER_Z)
580
+ p.Z -= (size.Z + 1 ) / 2 ;
581
+
582
+ v3s16 bp1 = getNodeBlockPos (p);
583
+ v3s16 bp2 = getNodeBlockPos (p + size - v3s16 (1 ,1 ,1 ));
584
+ vm->initialEmerge (bp1, bp2);
585
+
586
+ u32 i = 0 ;
587
+ for (s16 z = 0 ; z != size.Z ; z++)
588
+ for (s16 y = 0 ; y != size.Y ; y++) {
589
+ u32 vi = vm->m_area .index (p.X , p.Y + y, p.Z + z);
590
+ for (s16 x = 0 ; x != size.X ; x++, i++, vi++) {
591
+ if (!vm->m_area .contains (vi))
592
+ continue ;
593
+ if (schematic[i].param1 && myrand_range (1 , 256 ) > schematic[i].param1 )
594
+ continue ;
595
+
596
+ vm->m_data [vi] = schematic[i];
597
+ vm->m_data [vi].param1 = 0 ;
598
+ }
599
+ }
600
+
601
+ std::map<v3s16, MapBlock *> lighting_modified_blocks;
602
+ std::map<v3s16, MapBlock *> modified_blocks;
603
+ vm->blitBackAll (&modified_blocks);
604
+
605
+ // TODO: Optimize this by using Mapgen::calcLighting() instead
606
+ lighting_modified_blocks.insert (modified_blocks.begin (), modified_blocks.end ());
607
+ map->updateLighting (lighting_modified_blocks, modified_blocks);
608
+
609
+ MapEditEvent event;
610
+ event.type = MEET_OTHER;
611
+ for (std::map<v3s16, MapBlock *>::iterator
612
+ it = modified_blocks.begin ();
613
+ it != modified_blocks.end (); ++it)
614
+ event.modified_blocks .insert (it->first );
615
+
616
+ map->dispatchEvent (&event);
617
+ }
618
+
619
+
620
+ bool DecoSchematic::loadSchematicFile () {
621
+ std::ifstream is (filename.c_str (), std::ios_base::binary);
622
+
623
+ u32 signature = readU32 (is);
624
+ if (signature != ' MTSM' ) {
625
+ errorstream << " loadSchematicFile: invalid schematic "
626
+ " file" << std::endl;
627
+ return false ;
628
+ }
629
+
630
+ u16 version = readU16 (is);
631
+ if (version != 1 ) {
632
+ errorstream << " loadSchematicFile: unsupported schematic "
633
+ " file version" << std::endl;
634
+ return false ;
635
+ }
636
+
637
+ size = readV3S16 (is);
638
+ int nodecount = size.X * size.Y * size.Z ;
639
+
640
+ u16 nidmapcount = readU16 (is);
641
+
642
+ node_names = new std::vector<std::string>;
643
+ for (int i = 0 ; i != nidmapcount; i++) {
644
+ std::string name = deSerializeString (is);
645
+ node_names->push_back (name);
646
+ }
647
+
648
+ delete schematic;
649
+ schematic = new MapNode[nodecount];
650
+ MapNode::deSerializeBulk (is, SER_FMT_VER_HIGHEST, schematic,
651
+ nodecount, 2 , 2 , true );
652
+
653
+ return true ;
654
+ }
655
+
656
+
657
+ /*
658
+ Minetest Schematic File Format
659
+
660
+ All values are stored in big-endian byte order.
661
+ [u32] signature: 'MTSM'
662
+ [u16] version: 1
663
+ [u16] size X
664
+ [u16] size Y
665
+ [u16] size Z
666
+ [Name-ID table] Name ID Mapping Table
667
+ [u16] name-id count
668
+ For each name-id mapping:
669
+ [u16] name length
670
+ [u8[]] name
671
+ ZLib deflated {
672
+ For each node in schematic: (for z, y, x)
673
+ [u16] content
674
+ For each node in schematic:
675
+ [u8] probability of occurance (param1)
676
+ For each node in schematic:
677
+ [u8] param2
678
+ }
679
+ */
680
+ void DecoSchematic::saveSchematicFile (INodeDefManager *ndef) {
681
+ std::ofstream os (filename.c_str (), std::ios_base::binary);
682
+
683
+ writeU32 (os, ' MTSM' ); // signature
684
+ writeU16 (os, 1 ); // version
685
+ writeV3S16 (os, size); // schematic size
686
+
687
+ std::vector<content_t > usednodes;
688
+ int nodecount = size.X * size.Y * size.Z ;
689
+ build_nnlist_and_update_ids (schematic, nodecount, &usednodes);
690
+
691
+ u16 numids = usednodes.size ();
692
+ writeU16 (os, numids); // name count
693
+ for (int i = 0 ; i != numids; i++)
694
+ os << serializeString (ndef->get (usednodes[i]).name ); // node names
695
+
696
+ // compressed bulk node data
697
+ MapNode::serializeBulk (os, SER_FMT_VER_HIGHEST, schematic,
698
+ nodecount, 2 , 2 , true );
699
+ }
700
+
701
+
702
+ void build_nnlist_and_update_ids (MapNode *nodes, u32 nodecount,
703
+ std::vector<content_t > *usednodes) {
704
+ std::map<content_t , content_t > nodeidmap;
705
+ content_t numids = 0 ;
706
+
707
+ for (u32 i = 0 ; i != nodecount; i++) {
708
+ content_t id;
709
+ content_t c = nodes[i].getContent ();
710
+
711
+ std::map<content_t , content_t >::const_iterator it = nodeidmap.find (c);
712
+ if (it == nodeidmap.end ()) {
713
+ id = numids;
714
+ numids++;
715
+
716
+ usednodes->push_back (c);
717
+ nodeidmap.insert (std::make_pair (c, id));
718
+ } else {
719
+ id = it->second ;
720
+ }
721
+ nodes[i].setContent (id);
722
+ }
723
+ }
724
+
725
+
726
+ bool DecoSchematic::getSchematicFromMap (Map *map, v3s16 p1, v3s16 p2) {
727
+ ManualMapVoxelManipulator *vm = new ManualMapVoxelManipulator (map);
728
+
729
+ v3s16 bp1 = getNodeBlockPos (p1);
730
+ v3s16 bp2 = getNodeBlockPos (p2);
731
+ vm->initialEmerge (bp1, bp2);
732
+
733
+ size = p2 - p1 + 1 ;
734
+ schematic = new MapNode[size.X * size.Y * size.Z ];
735
+
736
+ u32 i = 0 ;
737
+ for (s16 z = p1.Z ; z <= p2.Z ; z++)
738
+ for (s16 y = p1.Y ; y <= p2.Y ; y++) {
739
+ u32 vi = vm->m_area .index (p1.X , y, z);
740
+ for (s16 x = p1.X ; x <= p2.X ; x++, i++, vi++) {
741
+ schematic[i] = vm->m_data [vi];
742
+ schematic[i].param1 = 0 ;
743
+ }
744
+ }
745
+
746
+ delete vm;
747
+ return true ;
748
+ }
749
+
750
+
751
+ void DecoSchematic::applyProbabilities (std::vector<std::pair<v3s16, u8> > *plist, v3s16 p0) {
752
+ for (size_t i = 0 ; i != plist->size (); i++) {
753
+ v3s16 p = (*plist)[i].first - p0;
754
+ int index = p.Z * (size.Y * size.X ) + p.Y * size.X + p.X ;
755
+ if (index < size.Z * size.Y * size.X )
756
+ schematic[index ].param1 = (*plist)[i].second ;
757
+ }
758
+ }
759
+
760
+
761
+ // /////////////////////////////////////////////////////////////////////////////
762
+
763
+
457
764
Mapgen::Mapgen () {
458
765
seed = 0 ;
459
766
water_level = 0 ;