1 package main 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "io" 8 "math/rand" 9 "os" 10 "path" 11 "strconv" 12 13 "vimagination.zapto.org/minecraft" 14 "vimagination.zapto.org/minewebgen/internal/data" 15 ) 16 17 type RPC struct { 18 *Controller 19 } 20 21 func (r RPC) Settings(_ struct{}, settings *data.ServerSettings) error { 22 *settings = r.c.Settings() 23 return nil 24 } 25 26 func (r RPC) SetSettings(settings data.ServerSettings, _ *struct{}) error { 27 settings.DirMaps = path.Clean(settings.DirMaps) 28 settings.DirServers = path.Clean(settings.DirServers) 29 if settings.DirMaps == settings.DirServers { 30 return errors.New("map and server paths cannot be the same") 31 } 32 r.c.SetSettings(settings) 33 go r.c.Save() 34 return nil 35 } 36 37 func (r RPC) ServerName(_ struct{}, serverName *string) error { 38 *serverName = r.c.Settings().ServerName 39 return nil 40 } 41 42 func (r RPC) ServerList(_ struct{}, list *[]data.Server) error { 43 r.c.Servers.mu.RLock() 44 defer r.c.Servers.mu.RUnlock() 45 *list = make([]data.Server, len(r.c.Servers.List)) 46 for n, s := range r.c.Servers.List { 47 s.RLock() 48 (*list)[n] = *s 49 s.RUnlock() 50 } 51 return nil 52 } 53 54 func (r RPC) MapList(_ struct{}, list *[]data.Map) error { 55 r.c.Maps.mu.RLock() 56 defer r.c.Maps.mu.RUnlock() 57 *list = make([]data.Map, len(r.c.Maps.List)) 58 for n, m := range r.c.Maps.List { 59 m.RLock() 60 (*list)[n] = *m 61 m.RUnlock() 62 } 63 return nil 64 } 65 66 func (r RPC) Server(id int, s *data.Server) error { 67 ser := r.c.Server(id) 68 ser.RLock() 69 defer ser.RUnlock() 70 *s = *ser 71 return nil 72 } 73 74 func (r RPC) Map(id int, m *data.Map) error { 75 mp := r.c.Map(id) 76 mp.RLock() 77 defer mp.RUnlock() 78 *m = *mp 79 return nil 80 } 81 82 func (r RPC) SetServer(s data.Server, _ *struct{}) error { 83 ser := r.c.Server(s.ID) 84 if ser == nil { 85 return ErrUnknownServer 86 } 87 if ser.State != data.StateStopped { 88 return ErrServerRunning 89 } 90 ser.Lock() 91 defer ser.Unlock() 92 ser.Name = s.Name 93 ser.Args = s.Args 94 go r.c.Save() 95 return nil 96 } 97 98 func (r RPC) SetMap(m data.Map, _ *struct{}) error { 99 mp := r.c.Map(m.ID) 100 if mp == nil { 101 return ErrUnknownMap 102 } 103 mp.RLock() 104 sID := mp.Server 105 mp.RUnlock() 106 if sID != -1 { 107 ser := r.c.Server(sID) 108 if ser != nil { 109 ser.RLock() 110 s := ser.State 111 ser.RUnlock() 112 if s != data.StateStopped { 113 return ErrServerRunning 114 } 115 } 116 } 117 mp.Lock() 118 defer mp.Unlock() 119 mp.Name = m.Name 120 go r.c.Save() 121 return nil 122 } 123 124 func (r RPC) SetServerMap(ids [2]int, _ *struct{}) error { 125 if ids[0] != -1 { 126 serv := r.c.Server(ids[0]) 127 if serv == nil { 128 return ErrUnknownServer 129 } 130 serv.RLock() 131 mID := serv.Map 132 s := serv.State 133 serv.RUnlock() 134 if s != data.StateStopped { 135 return ErrServerRunning 136 } 137 if mID != -1 { 138 if mID == ids[1] { 139 return nil 140 } 141 mp := r.c.Map(mID) 142 if mp != nil { 143 mp.Lock() 144 mp.Server = -1 145 mp.Unlock() 146 } 147 } 148 serv.Lock() 149 serv.Map = ids[1] 150 serv.Unlock() 151 } 152 if ids[1] != -1 { 153 mp := r.c.Map(ids[1]) 154 if mp == nil { 155 return ErrUnknownMap 156 } 157 mp.RLock() 158 sID := mp.Server 159 mp.RUnlock() 160 if sID == -2 { 161 return errors.New("map busy") 162 } else if sID != -1 { 163 serv := r.c.Server(sID) 164 if serv != nil { 165 serv.RLock() 166 s := serv.State 167 serv.RUnlock() 168 if s != data.StateStopped { 169 return ErrServerRunning 170 } 171 serv.Lock() 172 serv.Map = -1 173 serv.Unlock() 174 } 175 } 176 mp.Lock() 177 mp.Server = ids[0] 178 mp.Unlock() 179 } 180 go r.c.Save() 181 return nil 182 } 183 184 func (r RPC) ServerProperties(id int, sp *ServerProperties) error { 185 s := r.c.Server(id) 186 if s == nil { 187 return ErrUnknownServer 188 } 189 s.RLock() 190 defer s.RUnlock() 191 p := s.Path 192 f, err := os.Open(path.Join(p, "properties.server")) 193 if err != nil { 194 return err 195 } 196 defer f.Close() 197 *sp = make(ServerProperties) 198 return sp.ReadFrom(f) 199 } 200 201 func (r RPC) SetServerProperties(sp data.ServerProperties, _ *struct{}) error { 202 s := r.c.Server(sp.ID) 203 if s == nil { 204 return ErrUnknownServer 205 } 206 s.Lock() 207 defer s.Unlock() 208 p := s.Path 209 f, err := os.Create(path.Join(p, "properties.server")) 210 if err != nil { 211 return err 212 } 213 defer f.Close() 214 return ServerProperties(sp.Properties).WriteTo(f) 215 } 216 217 func (r RPC) MapProperties(id int, mp *ServerProperties) error { 218 m := r.c.Map(id) 219 if m == nil { 220 return ErrUnknownMap 221 } 222 m.RLock() 223 defer m.RUnlock() 224 p := m.Path 225 f, err := os.Open(path.Join(p, "properties.map")) 226 if err != nil { 227 return err 228 } 229 defer f.Close() 230 *mp = make(ServerProperties) 231 return mp.ReadFrom(f) 232 } 233 234 func (r RPC) SetMapProperties(sp data.ServerProperties, _ *struct{}) error { 235 m := r.c.Map(sp.ID) 236 if m == nil { 237 return ErrUnknownMap 238 } 239 m.Lock() 240 defer m.Unlock() 241 p := m.Path 242 f, err := os.Create(path.Join(p, "properties.map")) 243 if err != nil { 244 return err 245 } 246 defer f.Close() 247 return ServerProperties(sp.Properties).WriteTo(f) 248 } 249 250 func (r RPC) RemoveServer(id int, _ *struct{}) error { 251 s := r.c.Server(id) 252 if s == nil { 253 return ErrUnknownServer 254 } 255 s.Lock() 256 defer s.Unlock() 257 if s.State != data.StateStopped { 258 return ErrServerRunning 259 } 260 if s.Map >= 0 { 261 m := r.c.Map(s.Map) 262 m.Lock() 263 m.Server = -1 264 m.Unlock() 265 } 266 r.c.RemoveServer(id) 267 s.ID = -1 268 go r.c.Save() 269 return nil 270 } 271 272 func (r RPC) RemoveMap(id int, _ *struct{}) error { 273 m := r.c.Map(id) 274 if m == nil { 275 return ErrUnknownMap 276 } 277 m.Lock() 278 defer m.Unlock() 279 if m.Server >= 0 { 280 s := r.c.Server(m.Server) 281 m.Lock() 282 defer m.Unlock() 283 if s.State != data.StateStopped { 284 return ErrServerRunning 285 } 286 m.Server = -1 287 } 288 r.c.RemoveMap(id) 289 m.ID = -1 290 go r.c.Save() 291 return nil 292 } 293 294 func (r RPC) CreateDefaultMap(data data.DefaultMap, _ *struct{}) error { 295 return r.createMap(data, "") 296 } 297 298 func (r RPC) createMap(data data.DefaultMap, generatorSettings string) error { 299 if data.Seed == 0 { 300 data.Seed = rand.Int63() 301 } 302 m := r.c.NewMap() 303 if m == nil { 304 return errors.New("failed to create map") 305 } 306 m.Lock() 307 defer m.Unlock() 308 p, err := minecraft.NewFilePath(m.Path) 309 if err != nil { 310 r.c.RemoveMap(m.ID) 311 return err 312 } 313 l, err := minecraft.NewLevel(p) 314 if err != nil { 315 r.c.RemoveMap(m.ID) 316 return err 317 } 318 l.GameMode(data.GameMode) 319 l.LevelName(data.Name) 320 m.Name = data.Name 321 switch data.Mode { 322 case 0: 323 l.Generator(minecraft.DefaultGenerator) 324 case 1: 325 l.Generator(minecraft.FlatGenerator) 326 case 2: 327 l.Generator(minecraft.LargeBiomeGenerator) 328 case 3: 329 l.Generator(minecraft.AmplifiedGenerator) 330 case 4: 331 l.Generator(minecraft.CustomGenerator) 332 } 333 l.Seed(data.Seed) 334 l.AllowCommands(data.Cheats) 335 l.MapFeatures(data.Structures) 336 if generatorSettings != "" { 337 l.GeneratorOptions(generatorSettings) 338 } 339 l.Save() 340 f, err := os.Create(path.Join(m.Path, "properties.map")) 341 if err != nil { 342 r.c.RemoveMap(m.ID) 343 return err 344 } 345 defer f.Close() 346 ms := DefaultMapSettings() 347 ms["gamemode"] = strconv.Itoa(int(data.GameMode)) 348 if !data.Structures { 349 ms["generate-structures"] = "false" 350 } 351 if data.GameMode == 3 { 352 ms["hardcore"] = "true" 353 } 354 if generatorSettings != "" { 355 ms["generator-settings"] = generatorSettings 356 } 357 ms["level-seed"] = strconv.FormatInt(data.Seed, 10) 358 ms["motd"] = data.Name 359 switch data.Mode { 360 case 0: 361 ms["level-type"] = minecraft.DefaultGenerator 362 case 1: 363 ms["level-type"] = minecraft.FlatGenerator 364 case 2: 365 ms["level-type"] = minecraft.LargeBiomeGenerator 366 case 3: 367 ms["level-type"] = minecraft.AmplifiedGenerator 368 case 4: 369 ms["level-type"] = minecraft.CustomGenerator 370 case 5: 371 ms["level-type"] = minecraft.DebugGenerator 372 } 373 if err := ms.WriteTo(f); err != nil { 374 return err 375 } 376 go r.c.Save() 377 return nil 378 } 379 380 func (r RPC) CreateSuperflatMap(data data.SuperFlatMap, _ *struct{}) error { 381 return r.createMap(data.DefaultMap, data.GeneratorSettings) 382 } 383 384 func (r RPC) CreateCustomMap(data data.CustomMap, _ *struct{}) error { 385 // check settings for validity 386 var buf bytes.Buffer 387 err := json.NewEncoder(&buf).Encode(data.GeneratorSettings) 388 if err != nil { 389 return err 390 } 391 return r.createMap(data.DefaultMap, buf.String()) 392 } 393 394 func (r RPC) ServerEULA(id int, d *string) error { 395 s := r.c.Server(id) 396 if s == nil { 397 return ErrUnknownServer 398 } 399 s.RLock() 400 p := s.Path 401 s.RUnlock() 402 f, err := os.Open(path.Join(p, "eula.txt")) 403 if err != nil { 404 if !os.IsNotExist(err) { 405 return err 406 } else { 407 return nil 408 } 409 } 410 b, err := io.ReadAll(f) 411 if err != nil { 412 return err 413 } 414 *d = string(b) 415 return nil 416 } 417 418 func (r RPC) SetServerEULA(d data.ServerEULA, _ *struct{}) error { 419 s := r.c.Server(d.ID) 420 if s == nil { 421 return ErrUnknownServer 422 } 423 s.RLock() 424 p := s.Path 425 s.RUnlock() 426 f, err := os.Create(path.Join(p, "eula.txt")) 427 if err != nil { 428 return err 429 } 430 _, err = f.WriteString(d.EULA) 431 return err 432 } 433 434 func (r RPC) Generators(_ struct{}, list *[]data.Generator) error { 435 r.c.Generators.mu.RLock() 436 defer r.c.Generators.mu.RUnlock() 437 *list = make([]data.Generator, len(r.c.Generators.List)) 438 for n, g := range r.c.Generators.List { 439 (*list)[n] = *g 440 } 441 return nil 442 } 443 444 func (r RPC) Generator(id int, gd *data.GeneratorData) error { 445 g := r.c.Generator(id) 446 if g == nil { 447 return ErrUnknownGenerator 448 } 449 f, err := os.Open(path.Join(g.Path, "data.gen")) 450 if err != nil { 451 return err 452 } 453 defer f.Close() 454 return json.NewDecoder(f).Decode(gd) 455 } 456 457 func (r RPC) RemoveGenerator(id int, _ *struct{}) error { 458 r.c.RemoveGenerator(id) 459 go r.c.Save() 460 return nil 461 } 462 463 // Errors 464 465 var ( 466 ErrUnknownServer = errors.New("unknown server") 467 ErrUnknownMap = errors.New("unknown map") 468 ErrServerRunning = errors.New("server running") 469 ErrUnknownGenerator = errors.New("unknown generator") 470 ) 471