-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathimage.go
138 lines (114 loc) · 3.5 KB
/
image.go
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
129
130
131
132
133
134
135
136
137
138
package commands
import (
// These imports are to allow support for PNG, JPEG, and WEBP decoding.
_ "golang.org/x/image/webp"
_ "image/jpeg"
_ "image/png"
"github.com/df-mc/dragonfly/server/session"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/cmd"
"github.com/df-mc/dragonfly/server/entity"
"github.com/df-mc/dragonfly/server/world"
"github.com/justtaldevelops/pixelart/colour"
"github.com/nfnt/resize"
"github.com/sandertv/gophertunnel/minecraft/text"
"image"
"io/ioutil"
"math"
"os"
"path/filepath"
"reflect"
)
// Image is a command which generates an image from a file in the working directory.
type Image struct {
// Name is the name of the image.
Name imageName `name:"name"`
// ImageCreationDistance is how far away the image should be created from the player. This is 50 by default.
ImageCreationDistance int `name:"distance" optional:""`
}
// Run is called when the command is ran from a source.
func (i Image) Run(source cmd.Source, output *cmd.Output) {
if c, ok := source.(session.Controllable); ok {
colours, err := colour.Defaults()
if err != nil {
output.Error(err)
return
}
img := string(i.Name)
reader, err := os.Open(img)
if err != nil {
output.Error(err)
return
}
defer reader.Close()
m, _, err := image.Decode(reader)
if err != nil {
output.Error(err)
return
}
width, height := m.Bounds().Max.X, m.Bounds().Max.Y
if height > cube.MaxY {
scaleFactor := int(math.Ceil(float64(height / cube.MaxY))) + 1
newWidth, newHeight := width/scaleFactor, height / scaleFactor
m = resize.Resize(uint(newWidth), uint(newHeight), m, resize.Bicubic)
width, height = newWidth, newHeight
}
facing := entity.Facing(c)
spawnPos := cube.PosFromVec3(c.Position())
if i.ImageCreationDistance == 0 {
i.ImageCreationDistance = 50
}
for j := 0; j < i.ImageCreationDistance; j++ {
spawnPos = spawnPos.Side(facing.Face())
}
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
r, g, b, a := m.At(x, y).RGBA()
if a > 0 {
var spawnX, spawnZ int
switch facing {
case cube.North:
spawnX = spawnPos.X() + x - width / 2
spawnZ = spawnPos.Z()
case cube.South:
spawnX = spawnPos.X() - x + width / 2
spawnZ = spawnPos.Z()
case cube.East:
spawnX = spawnPos.X()
spawnZ = spawnPos.Z() + x - width / 2
case cube.West:
spawnX = spawnPos.X()
spawnZ = spawnPos.Z() - x + width / 2
}
closest := colour.Closest(r / 257, g / 257, b / 257, colours)
pixel, _ := world.BlockByName(closest.Block.Name, closest.Block.Properties)
c.World().SetBlock(cube.Pos{spawnX, height - y, spawnZ}, pixel)
}
}
}
output.Print(text.Colourf("<green>Successfully generated %v with blocks!</green>", img))
} else {
output.Error("This command can only be ran by a controllable!")
}
}
// imageName is an enum which contains all images in the current working directory.
type imageName string
// Type is the type displayed client side.
func (imageName) Type() string {
return "ImageName"
}
// Options contains each file that may be used to generate an image.
func (imageName) Options(_ cmd.Source) (opts []string) {
files, _ := ioutil.ReadDir(".")
for _, file := range files {
ext := filepath.Ext(file.Name())
if ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".webp" {
opts = append(opts, file.Name())
}
}
return
}
// SetOption ...
func (imageName) SetOption(option string, r reflect.Value) {
r.SetString(option)
}