diff options
Diffstat (limited to 'mcmap')
| -rw-r--r-- | mcmap/chunk.go | 24 | ||||
| -rw-r--r-- | mcmap/examples/addchunk/main.go | 45 | ||||
| -rw-r--r-- | mcmap/region.go | 89 | 
3 files changed, 144 insertions, 14 deletions
| diff --git a/mcmap/chunk.go b/mcmap/chunk.go index 6f6c4db..9196776 100644 --- a/mcmap/chunk.go +++ b/mcmap/chunk.go @@ -57,6 +57,28 @@ type Chunk struct {  	reg *Region  } +func newChunk(reg *Region, x, z int) *Chunk { +	biomes := make([]Biome, ChunkRectXZ) +	for i := range biomes { +		biomes[i] = BioUncalculated +	} + +	heightMap := make([]int32, ChunkRectXZ) +	for i := range heightMap { +		heightMap[i] = ChunkSizeY - 1 +	} + +	return &Chunk{ +		x:         int32(x), +		z:         int32(z), +		ts:        time.Now(), +		blocks:    make([]Block, ChunkSize), +		biomes:    biomes, +		heightMap: heightMap, +		reg:       reg, +	} +} +  // MarkModified needs to be called, if some data of the chunk was modified.  func (c *Chunk) MarkModified() { c.modified = true } @@ -118,7 +140,7 @@ func (c *Chunk) RecalcHeightMap() {  	i := 0  	for z := 0; z < ChunkSizeXZ; z++ {  		for x := 0; x < ChunkSizeXZ; x++ { -			for y := ChunkSizeY-1; y >= 0; y-- { +			for y := ChunkSizeY - 1; y >= 0; y-- {  				blkid := c.blocks[calcBlockOffset(x, y, z)].ID  				if (blkid != BlkAir) && (blkid != BlkGlass) && (blkid != BlkGlassPane) {  					c.heightMap[i] = int32(y) diff --git a/mcmap/examples/addchunk/main.go b/mcmap/examples/addchunk/main.go new file mode 100644 index 0000000..0ca763f --- /dev/null +++ b/mcmap/examples/addchunk/main.go @@ -0,0 +1,45 @@ +package main + +import ( +	"flag" +	"fmt" +	"github.com/kch42/gomcmap/mcmap" +	"os" +) + +func main() { +	path := flag.String("path", "", "Path to region directory") +	flag.Parse() + +	if *path == "" { +		flag.Usage() +		os.Exit(1) +	} + +	region, err := mcmap.OpenRegion(*path, false) +	if err != nil { +		fmt.Fprintf(os.Stderr, "Could not open region: %s\n", err) +		os.Exit(1) +	} + +	chunk, err := region.NewChunk(200, 200) +	if err != nil { +		fmt.Fprintf(os.Stderr, "Could not create a Chunk at 200,200: %s\n", err) +		os.Exit(1) +	} + +	chunk.Iter(func(x, y, z int, blk *mcmap.Block) { +		blk.ID = mcmap.BlkSandstone +	}) + +	chunk.RecalcHeightMap() +	if err := chunk.MarkUnused(); err != nil { +		fmt.Fprintf(os.Stderr, "Could not MarkUnused(): %s\n", err) +		os.Exit(1) +	} + +	if err := region.Save(); err != nil { +		fmt.Fprintf(os.Stderr, "Could not save region: %s\n", err) +		os.Exit(1) +	} +} diff --git a/mcmap/region.go b/mcmap/region.go index 8a5fd9f..34b3334 100644 --- a/mcmap/region.go +++ b/mcmap/region.go @@ -11,6 +11,7 @@ import (  var (  	NotAvailable = errors.New("Chunk or Superchunk not available") +	AlreadyThere = errors.New("Chunk is already there")  )  type superchunk struct { @@ -29,6 +30,8 @@ type Region struct {  var mcaRegex = regexp.MustCompile(`^r\.([0-9-]+)\.([0-9-]+)\.mca$`)  // OpenRegion opens a region directory. If autosave is true, mcmap will save modified and unloaded chunks automatically to reduce memory usage. You still have to call Save at the end. +// +// You can also use OpenRegion to create a new region. Yust make sure the path exists.  func OpenRegion(path string, autosave bool) (*Region, error) {  	rv := &Region{  		path:             path, @@ -176,11 +179,30 @@ func (reg *Region) cleanSuperchunks(forceSave bool) error {  	return nil  } +func (sc *superchunk) loadChunk(reg *Region, rx, rz int) (*Chunk, error) { +	cPos := XZPos{rx, rz} + +	if chunk, ok := sc.chunks[cPos]; ok { +		return chunk, nil +	} + +	pc, ok := sc.preChunks[cPos] +	if !ok { +		return nil, NotAvailable +	} + +	chunk, err := pc.toChunk(reg) +	if err != nil { +		return nil, err +	} +	sc.chunks[cPos] = chunk +	return chunk, nil +} +  // Chunk returns the chunk at x, z. If no chunk could be found, the error NotAvailable will be returned. Other errors indicate an internal error (I/O error, file format violated, ...)  func (reg *Region) Chunk(x, z int) (*Chunk, error) {  	scx, scz, cx, cz := chunkToSuperchunk(x, z)  	scPos := XZPos{scx, scz} -	cPos := XZPos{cx, cz}  	sc, ok := reg.superchunks[scPos]  	if !ok { @@ -190,18 +212,9 @@ func (reg *Region) Chunk(x, z int) (*Chunk, error) {  		sc = reg.superchunks[scPos]  	} -	chunk, ok := sc.chunks[cPos] -	if !ok { -		pc, ok := sc.preChunks[cPos] -		if !ok { -			return nil, NotAvailable -		} - -		var err error -		if chunk, err = pc.toChunk(reg); err != nil { -			return nil, err -		} -		sc.chunks[cPos] = chunk +	chunk, err := sc.loadChunk(reg, cx, cz) +	if err != nil { +		return nil, err  	}  	if err := reg.cleanSuperchunks(false); err != nil { @@ -263,6 +276,56 @@ func (reg *Region) AllChunks() <-chan XZPos {  	return ch  } +// NewChunk adds a new, blank chunk. If the Chunk is already there, error AlreadyThere will be returned. +// Other errors indicate internal errors. +func (reg *Region) NewChunk(cx, cz int) (*Chunk, error) { +	scx, scz, rx, rz := chunkToSuperchunk(cx, cz) + +	scPos := XZPos{scx, scz} + +	var sc *superchunk +	if reg.superchunksAvail[scPos] { +		var ok bool +		if sc, ok = reg.superchunks[scPos]; !ok { +			if err := reg.loadSuperchunk(scPos); err != nil { +				return nil, err +			} +			sc = reg.superchunks[scPos] +		} +	} else { +		sc = &superchunk{ +			chunks:    make(map[XZPos]*Chunk), +			preChunks: make(map[XZPos]*preChunk), +			modified:  true, +		} +		reg.superchunksAvail[scPos] = true +		reg.superchunks[scPos] = sc +	} + +	switch chunk, err := sc.loadChunk(reg, rx, rz); err { +	case nil: +		chunk.MarkUnused() +		return nil, AlreadyThere +	case NotAvailable: +	default: +		return nil, err +	} + +	cPos := XZPos{rx, rz} +	chunk := newChunk(reg, cx, cz) + +	pc, err := chunk.toPreChunk() +	if err != nil { +		return nil, err +	} + +	sc.preChunks[cPos] = pc +	sc.chunks[cPos] = chunk +	sc.modified = true + +	return chunk, nil +} +  // Save saves modified and unused chunks.  func (reg *Region) Save() error {  	return reg.cleanSuperchunks(true) | 
