summaryrefslogtreecommitdiff
path: root/tools.go
blob: a24d69685da45eb620cf4d6ec441a0db1c4f56f0 (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
126
127
128
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
	IsSlow() bool
	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) IsSlow() 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 (f *fillTool) IsSlow() 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) || (oldbio == bio) {
		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)
}