summaryrefslogtreecommitdiff
path: root/tools.go
blob: 63972237f006b10fe66c1500e834d28974d0ab6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main

import (
	"github.com/kch42/gomcmap/mcmap"
)

type BiomeGetSetter interface {
	GetBiomeAt(x, z int) (mcmap.Biome, bool)
	SetBiomeAt(x, z int, bio mcmap.Biome)
}

type XZPos struct {
	X, Z int
}

type Tool interface {
	SingleClick() bool // Whether only one click should be performed (true) or the action should be repeated, if the mouse is dragged
	Do(bio mcmap.Biome, biogs BiomeGetSetter, x, z int)
}

type drawTool struct {
	radGetter func() int
}

func (d *drawTool) SingleClick() bool { return false }

func (d *drawTool) Do(bio mcmap.Biome, biogs BiomeGetSetter, x, z int) {
	rad := d.radGetter()
	if rad <= 0 {
		return
	}

	for xp := x - (rad - 1); xp < x+rad; xp++ {
		for zp := z - (rad - 1); zp < z+rad; zp++ {
			biogs.SetBiomeAt(xp, zp, bio)
		}
	}
}

func NewDrawTool(radGetter func() int) *drawTool {
	return &drawTool{radGetter}
}

type fillTool struct{}

func (f *fillTool) SingleClick() bool { return true }

func chkBounds(x, z, xStart, zStart, xEnd, zEnd int) bool {
	return (x >= xStart) && (z >= zStart) && (x < xEnd) && (z < zEnd)
}

func (f *fillTool) Do(bio mcmap.Biome, biogs BiomeGetSetter, x, z int) {
	oldbio, ok := biogs.GetBiomeAt(x, z)
	if !ok {
		return
	}

	inChunkQueue := []XZPos{}
	outOfChunkQueue := []XZPos{{x, z}}

	for {
		oocqL := len(outOfChunkQueue) - 1
		if oocqL < 0 {
			break
		}

		pos := outOfChunkQueue[oocqL]
		inChunkQueue = []XZPos{pos}
		outOfChunkQueue = outOfChunkQueue[:oocqL]

		cx, cz, _, _ := mcmap.BlockToChunk(pos.X, pos.Z)
		xStart := cx * mcmap.ChunkSizeXZ
		zStart := cz * mcmap.ChunkSizeXZ
		xEnd := xStart + mcmap.ChunkSizeXZ
		zEnd := zStart + mcmap.ChunkSizeXZ

		for {
			icqL := len(inChunkQueue) - 1
			if icqL < 0 {
				break
			}

			pos := inChunkQueue[icqL]
			inChunkQueue = inChunkQueue[:icqL]

			px, pz := pos.X, pos.Z

			if haveBio, ok := biogs.GetBiomeAt(px, pz); ok && (haveBio == oldbio) {
				biogs.SetBiomeAt(px, pz, bio)

				nx, nz := px+1, pz
				if chkBounds(nx, nz, xStart, zStart, xEnd, zEnd) {
					inChunkQueue = append(inChunkQueue, XZPos{nx, nz})
				} else {
					outOfChunkQueue = append(outOfChunkQueue, XZPos{nx, nz})
				}

				nx, nz = px-1, pz
				if chkBounds(nx, nz, xStart, zStart, xEnd, zEnd) {
					inChunkQueue = append(inChunkQueue, XZPos{nx, nz})
				} else {
					outOfChunkQueue = append(outOfChunkQueue, XZPos{nx, nz})
				}

				nx, nz = px, pz+1
				if chkBounds(nx, nz, xStart, zStart, xEnd, zEnd) {
					inChunkQueue = append(inChunkQueue, XZPos{nx, nz})
				} else {
					outOfChunkQueue = append(outOfChunkQueue, XZPos{nx, nz})
				}

				nx, nz = px, pz-1
				if chkBounds(nx, nz, xStart, zStart, xEnd, zEnd) {
					inChunkQueue = append(inChunkQueue, XZPos{nx, nz})
				} else {
					outOfChunkQueue = append(outOfChunkQueue, XZPos{nx, nz})
				}
			}
		}
	}
}

func NewFillTool() *fillTool {
	return new(fillTool)
}