1 package battlemap 2 3 import ( 4 "encoding/json" 5 "math" 6 "strconv" 7 8 "vimagination.zapto.org/keystore" 9 "vimagination.zapto.org/memio" 10 ) 11 12 func (m *mapsDir) RPCData(cd ConnData, method string, data json.RawMessage) (interface{}, error) { 13 switch method { 14 case "list": 15 m.mu.RLock() 16 j := m.json 17 m.mu.RUnlock() 18 return json.RawMessage(j), nil 19 case "setUserMap": 20 var userMap keystore.Uint64 21 if err := json.Unmarshal(data, &userMap); err != nil { 22 return nil, err 23 } 24 m.mu.RLock() 25 defer m.mu.RUnlock() 26 mp, ok := m.maps[uint64(userMap)] 27 if !ok { 28 return nil, ErrUnknownMap 29 } 30 m.Battlemap.config.Set("currentUserMap", &userMap) 31 m.Battlemap.socket.SetCurrentUserMap(uint64(userMap), data, json.RawMessage(mp.JSON), cd.ID) 32 return nil, nil 33 case "getMapData": 34 var mapID uint64 35 if err := json.Unmarshal(data, &mapID); err != nil { 36 return nil, err 37 } 38 m.mu.RLock() 39 defer m.mu.RUnlock() 40 mp, ok := m.maps[mapID] 41 if !ok { 42 return nil, ErrUnknownMap 43 } 44 return json.RawMessage(mp.JSON), nil 45 case "new": 46 var nm mapDetails 47 if err := json.Unmarshal(data, &nm); err != nil { 48 return nil, err 49 } 50 return m.newMap(nm, cd.ID) 51 case "setMapDetails": 52 var md struct { 53 mapDimensions 54 mapGrid 55 } 56 if err := json.Unmarshal(data, &md); err != nil { 57 return nil, err 58 } 59 if md.Width == 0 || md.Height == 0 { 60 return nil, ErrInvalidData 61 } 62 return nil, m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 63 if mp.Width == md.Width && mp.Height == md.Height && mp.GridType == md.GridType && mp.GridSize == md.GridSize && mp.GridColour == md.GridColour && mp.GridStroke == md.GridStroke { 64 return false 65 } 66 if md.Width < mp.StartX { 67 mp.StartX = md.Width 68 } 69 if md.Height < mp.StartY { 70 mp.StartY = md.Height 71 } 72 mp.Width = md.Width 73 mp.Height = md.Height 74 mp.GridType = md.GridType 75 mp.GridSize = md.GridSize 76 mp.GridColour = md.GridColour 77 mp.GridStroke = md.GridStroke 78 m.socket.broadcastMapChange(cd, broadcastMapItemChange, data, userAny) 79 return true 80 }) 81 case "setMapStart": 82 var ms [2]uint64 83 err := json.Unmarshal(data, &ms) 84 if err != nil { 85 return nil, err 86 } 87 if errr := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 88 if ms[0] > mp.Width || ms[1] > mp.Height { 89 err = ErrInvalidStart 90 return false 91 } 92 if ms[0] == mp.StartX && ms[1] == mp.StartY { 93 return false 94 } 95 mp.StartX = ms[0] 96 mp.StartY = ms[1] 97 m.socket.broadcastMapChange(cd, broadcastMapStartChange, data, userAny) 98 return true 99 }); errr != nil { 100 return nil, errr 101 } 102 return nil, err 103 case "setData": 104 var sd struct { 105 Key string `json:"key"` 106 Data json.RawMessage `json:"data"` 107 } 108 if err := json.Unmarshal(data, &sd); err != nil { 109 return nil, err 110 } 111 return nil, m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 112 mp.Data[sd.Key] = sd.Data 113 m.socket.broadcastMapChange(cd, broadcastMapDataSet, data, userAny) 114 return true 115 }) 116 case "removeData": 117 var rd string 118 if err := json.Unmarshal(data, &rd); err != nil { 119 return nil, err 120 } 121 return nil, m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 122 delete(mp.Data, rd) 123 m.socket.broadcastMapChange(cd, broadcastMapDataRemove, data, userAny) 124 return true 125 }) 126 case "setGridDistance": 127 var md uint64 128 if err := json.Unmarshal(data, &md); err != nil { 129 return nil, err 130 } 131 return nil, m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 132 if mp.GridDistance == md { 133 return false 134 } 135 mp.GridDistance = md 136 m.socket.broadcastMapChange(cd, broadcastGridDistanceChange, data, userAny) 137 return true 138 }) 139 case "setGridDiagonal": 140 var md bool 141 if err := json.Unmarshal(data, &md); err != nil { 142 return nil, err 143 } 144 return nil, m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 145 if mp.GridDiagonal == md { 146 return false 147 } 148 mp.GridDiagonal = md 149 m.socket.broadcastMapChange(cd, broadcastGridDiagonalChange, data, userAny) 150 return true 151 }) 152 case "setLightColour": 153 var c colour 154 if err := json.Unmarshal(data, &c); err != nil { 155 return nil, err 156 } 157 if err := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 158 mp.Light = c 159 m.socket.broadcastMapChange(cd, broadcastMapLightChange, data, userAny) 160 return true 161 }); err != nil { 162 return nil, err 163 } 164 return nil, nil 165 case "addToMask": 166 var mask []uint64 167 if err := json.Unmarshal(data, &mask); err != nil { 168 return nil, err 169 } 170 if len(mask) == 0 { 171 return nil, ErrInvalidMaskData 172 } 173 switch mask[0] { 174 case 0, 1: // rect 175 if len(mask) != 5 { 176 return nil, ErrInvalidMaskData 177 } 178 case 2, 3: // ellipse 179 if len(mask) != 5 { 180 return nil, ErrInvalidMaskData 181 } 182 case 4, 5: // poly 183 if l := len(mask); l < 7 || l&1 == 0 { 184 return nil, ErrInvalidMaskData 185 } 186 default: 187 return nil, ErrInvalidMaskData 188 } 189 if err := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 190 mp.Mask = append(mp.Mask, mask) 191 m.socket.broadcastMapChange(cd, broadcastMaskAdd, data, userAny) 192 return true 193 }); err != nil { 194 return nil, err 195 } 196 return nil, nil 197 case "removeFromMask": 198 var ( 199 toRemove int 200 errr error 201 ) 202 if err := json.Unmarshal(data, &toRemove); err != nil { 203 return nil, err 204 } 205 if err := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 206 if toRemove < 0 || toRemove >= len(mp.Mask) { 207 errr = ErrInvalidMaskIndex 208 return false 209 } 210 mp.Mask = append(mp.Mask[:toRemove], mp.Mask[toRemove+1:]...) 211 m.socket.broadcastMapChange(cd, broadcastMaskRemove, data, userAny) 212 return true 213 }); err != nil { 214 return nil, err 215 } 216 return nil, errr 217 case "setMask": 218 var set struct { 219 BaseOpaque bool `json:"baseOpaque"` 220 Masks [][]uint64 `json:"masks"` 221 } 222 if err := json.Unmarshal(data, &set); err != nil { 223 return nil, err 224 } 225 for _, mask := range set.Masks { 226 if len(mask) == 0 { 227 return nil, ErrInvalidMaskData 228 } 229 switch mask[0] { 230 case 0, 1: // rect 231 if len(mask) != 5 { 232 return nil, ErrInvalidMaskData 233 } 234 case 2, 3: // ellipse 235 if len(mask) != 4 { 236 return nil, ErrInvalidMaskData 237 } 238 case 4, 5: // poly 239 if l := len(mask); l < 7 || l&1 == 0 { 240 return nil, ErrInvalidMaskData 241 } 242 default: 243 return nil, ErrInvalidMaskData 244 } 245 } 246 if err := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 247 mp.MaskOpaque = set.BaseOpaque 248 mp.Mask = set.Masks 249 m.socket.broadcastMapChange(cd, broadcastMaskSet, data, userAny) 250 return true 251 }); err != nil { 252 return nil, err 253 } 254 return nil, nil 255 case "addWall": 256 var wallAdd struct { 257 Path string `json:"path"` 258 Wall *wall `json:"wall"` 259 } 260 wallAdd.Wall = new(wall) 261 if err := json.Unmarshal(data, &wallAdd); err != nil { 262 return nil, err 263 } 264 if err := m.updateMapLayer(cd.CurrentMap, wallAdd.Path, tokenLayer, func(mp *levelMap, l *layer) bool { 265 if _, ok := mp.walls[wallAdd.Wall.ID]; ok || wallAdd.Wall.ID == 0 || wallAdd.Wall.ID > mp.lastWallID { 266 mp.lastWallID++ 267 wallAdd.Wall.ID = mp.lastWallID 268 data, _ := json.Marshal(wallAdd) 269 m.socket.broadcastMapChange(cd, broadcastWallAdd, json.RawMessage(data), userAny) 270 } else { 271 m.socket.broadcastMapChange(cd, broadcastWallAdd, data, userAny) 272 } 273 l.Walls = append(l.Walls, wallAdd.Wall) 274 mp.walls[mp.lastWallID] = layerWall{l, wallAdd.Wall} 275 return true 276 }); err != nil { 277 return nil, err 278 } 279 return wallAdd.Wall.ID, nil 280 case "removeWall": 281 var wall uint64 282 if err := json.Unmarshal(data, &wall); err != nil { 283 return nil, err 284 } 285 var errr error 286 if err := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 287 w, ok := mp.walls[wall] 288 if !ok { 289 errr = ErrInvalidWall 290 return false 291 } 292 for pos := range w.Walls { 293 if w.Walls[pos].ID == wall { 294 l := w.layer 295 l.Walls = append(l.Walls[:pos], l.Walls[pos+1:]...) 296 m.socket.broadcastMapChange(cd, broadcastWallRemove, data, userAny) 297 return true 298 } 299 } 300 return false 301 }); err != nil { 302 return nil, err 303 } 304 if errr != nil { 305 return nil, errr 306 } 307 return nil, nil 308 case "modifyWall": 309 var w *wall 310 if err := json.Unmarshal(data, &w); err != nil { 311 return nil, err 312 } 313 var errr error 314 if err := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 315 wall, ok := mp.walls[w.ID] 316 if !ok { 317 errr = ErrInvalidWall 318 return false 319 } 320 wall.wall.X1 = w.X1 321 wall.wall.Y1 = w.Y1 322 wall.wall.X2 = w.X2 323 wall.wall.Y2 = w.Y2 324 wall.wall.Colour = w.Colour 325 wall.wall.Scattering = w.Scattering 326 m.socket.broadcastMapChange(cd, broadcastWallModify, data, userAny) 327 return true 328 }); err != nil { 329 return nil, err 330 } 331 if errr != nil { 332 return nil, errr 333 } 334 return nil, nil 335 case "moveWall": 336 var ip struct { 337 ID uint64 `json:"id"` 338 Path string `json:"path"` 339 } 340 if err := json.Unmarshal(data, &ip); err != nil { 341 return nil, err 342 } 343 var errr error 344 if err := m.updateMapLayer(cd.CurrentMap, ip.Path+"/", tokenLayer, func(mp *levelMap, l *layer) bool { 345 lw, ok := mp.walls[ip.ID] 346 if !ok { 347 errr = ErrInvalidWall 348 return false 349 } 350 for pos := range lw.Walls { 351 if lw.Walls[pos] == lw.wall { 352 lw.Walls = append(lw.Walls[:pos], lw.Walls[pos+1:]...) 353 break 354 } 355 } 356 l.Walls = append(l.Walls, lw.wall) 357 mp.walls[ip.ID] = layerWall{l, lw.wall} 358 m.socket.broadcastMapChange(cd, broadcastWallMoveLayer, data, userAny) 359 return true 360 }); err != nil { 361 return nil, err 362 } 363 if errr != nil { 364 return nil, errr 365 } 366 return nil, nil 367 case "addLayer": 368 var name string 369 if err := json.Unmarshal(data, &name); err != nil { 370 return nil, err 371 } 372 err := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 373 newName := uniqueLayer(mp.layers, name) 374 if newName != name { 375 name = newName 376 data = appendString(data[:0], name) 377 } 378 mp.Layers = append(mp.Layers, &layer{Name: name}) 379 mp.layers[name] = struct{}{} 380 m.socket.broadcastMapChange(cd, broadcastLayerAdd, data, userAny) 381 return true 382 }) 383 return data, err 384 case "addLayerFolder": 385 var path string 386 if err := json.Unmarshal(data, &path); err != nil { 387 return nil, err 388 } 389 parent, name := splitAfterLastSlash(path) 390 err := m.updateMapLayer(cd.CurrentMap, parent, folderLayer, func(lm *levelMap, l *layer) bool { 391 newName := uniqueLayer(lm.layers, name) 392 if newName != name { 393 name = newName 394 path = parent + "/" + name 395 data = appendString(data[:0], path) 396 } 397 l.Layers = append(l.Layers, &layer{ 398 Name: name, 399 Layers: []*layer{}, 400 }) 401 m.socket.broadcastMapChange(cd, broadcastLayerFolderAdd, data, userAny) 402 return true 403 }) 404 return data, err 405 case "renameLayer": 406 var rename struct { 407 Path string `json:"path"` 408 Name string `json:"name"` 409 } 410 if err := json.Unmarshal(data, &rename); err != nil { 411 return nil, err 412 } 413 err := m.updateMapLayer(cd.CurrentMap, rename.Path, anyLayer, func(lm *levelMap, l *layer) bool { 414 if l.Name == rename.Name { 415 return false 416 } 417 delete(lm.layers, l.Name) 418 l.Name = uniqueLayer(lm.layers, rename.Name) 419 if l.Name != rename.Name { 420 rename.Name = l.Name 421 data = append(appendString(append(appendString(append(data[:0], "{\"path\":"...), rename.Path), ",\"name\":"...), rename.Name), '}') 422 } 423 m.socket.broadcastMapChange(cd, broadcastLayerRename, data, userAny) 424 return true 425 }) 426 return data, err 427 case "moveLayer": 428 var moveLayer struct { 429 From string `json:"from"` 430 To string `json:"to"` 431 Position uint `json:"position"` 432 } 433 err := json.Unmarshal(data, &moveLayer) 434 if err != nil { 435 return nil, err 436 } 437 if (moveLayer.From == "/Light" || moveLayer.From == "/Grid") && !isRoot(moveLayer.To) { 438 return nil, ErrInvalidLayerPath 439 } 440 if e := m.updateMapData(cd.CurrentMap, func(mp *levelMap) bool { 441 op, l := getParentLayer(&mp.layer, moveLayer.From, true) 442 if l == nil { 443 err = ErrUnknownLayer 444 return false 445 } 446 np := getLayer(&mp.layer, moveLayer.To, false) 447 if np == nil || np.Layers == nil { 448 err = ErrUnknownLayer 449 return false 450 } 451 op.removeLayer(l.Name) 452 np.addLayer(l, moveLayer.Position) 453 m.socket.broadcastMapChange(cd, broadcastLayerMove, data, userAny) 454 return true 455 }); e != nil { 456 return nil, e 457 } 458 return nil, err 459 case "showLayer": 460 var path string 461 if err := json.Unmarshal(data, &path); err != nil { 462 return nil, err 463 } 464 if len(path) == 0 { 465 return nil, ErrInvalidLayerPath 466 } 467 return nil, m.updateMapLayer(cd.CurrentMap, path, anyLayerAll, func(_ *levelMap, l *layer) bool { 468 if !l.Hidden { 469 return false 470 } 471 l.Hidden = false 472 m.socket.broadcastMapChange(cd, broadcastLayerShow, data, userAny) 473 return true 474 }) 475 case "hideLayer": 476 var path string 477 if err := json.Unmarshal(data, &path); err != nil { 478 return nil, err 479 } 480 if len(path) == 0 { 481 return nil, ErrInvalidLayerPath 482 } 483 return nil, m.updateMapLayer(cd.CurrentMap, path, anyLayerAll, func(_ *levelMap, l *layer) bool { 484 if l.Hidden { 485 return false 486 } 487 l.Hidden = true 488 m.socket.broadcastMapChange(cd, broadcastLayerHide, data, userAny) 489 return true 490 }) 491 case "lockLayer": 492 var path string 493 if err := json.Unmarshal(data, &path); err != nil { 494 return nil, err 495 } 496 if len(path) == 0 { 497 return nil, ErrInvalidLayerPath 498 } 499 return nil, m.updateMapLayer(cd.CurrentMap, path, anyLayerAll, func(_ *levelMap, l *layer) bool { 500 if l.Locked { 501 return false 502 } 503 l.Locked = true 504 m.socket.broadcastMapChange(cd, broadcastLayerLock, data, userAny) 505 return true 506 }) 507 case "unlockLayer": 508 var path string 509 if err := json.Unmarshal(data, &path); err != nil { 510 return nil, err 511 } 512 if len(path) == 0 { 513 return nil, ErrInvalidLayerPath 514 } 515 return nil, m.updateMapLayer(cd.CurrentMap, path, anyLayerAll, func(_ *levelMap, l *layer) bool { 516 if !l.Locked { 517 return false 518 } 519 l.Locked = false 520 m.socket.broadcastMapChange(cd, broadcastLayerUnlock, data, userAny) 521 return true 522 }) 523 case "removeLayer": 524 var path string 525 err := json.Unmarshal(data, &path) 526 if err != nil { 527 return nil, err 528 } 529 parent, name := splitAfterLastSlash(path) 530 if name == "Light" || name == "Grid" { 531 return nil, ErrInvalidLayerPath 532 } 533 err = m.updateMapLayer(cd.CurrentMap, parent, anyLayer, func(mp *levelMap, l *layer) bool { 534 l.removeLayer(name) 535 delete(mp.layers, name) 536 m.socket.broadcastMapChange(cd, broadcastLayerRemove, data, userAny) 537 return true 538 }) 539 return nil, err 540 case "addToken": 541 var newToken struct { 542 Token *token `json:"token"` 543 Path string `json:"path"` 544 Pos uint `json:"pos"` 545 } 546 newToken.Token = new(token) 547 newToken.Pos = math.MaxUint 548 if err := json.Unmarshal(data, &newToken); err != nil { 549 return nil, err 550 } 551 if err := newToken.Token.validate(false); err != nil { 552 return nil, err 553 } 554 if err := m.updateMapLayer(cd.CurrentMap, newToken.Path, tokenLayer, func(mp *levelMap, l *layer) bool { 555 newToken.Pos = l.addToken(newToken.Token, newToken.Pos) 556 if _, ok := mp.tokens[newToken.Token.ID]; ok || newToken.Token.ID == 0 { 557 mp.lastTokenID++ 558 newToken.Token.ID = mp.lastTokenID 559 data = append(strconv.AppendUint(append(newToken.Token.appendTo(append(appendString(append(data[:0], "{\"path\":"...), newToken.Path), ",\"token\":"...), false), ",\"pos\":"...), uint64(newToken.Pos), 10), '}') 560 } 561 mp.tokens[newToken.Token.ID] = layerToken{l, newToken.Token} 562 m.socket.broadcastMapChange(cd, broadcastTokenAdd, data, userAdmin) 563 m.socket.broadcastMapChange(cd, broadcastTokenAdd, append(strconv.AppendUint(append(newToken.Token.appendTo(append(appendString(append(data[:0], "{\"path\":"...), newToken.Path), ",\"token\":"...), true), ",\"pos\":"...), uint64(newToken.Pos), 10), '}'), userNotAdmin) 564 return true 565 }); err != nil { 566 return nil, err 567 } 568 return newToken.Token.ID, nil 569 case "removeToken": 570 var tokenID uint64 571 if err := json.Unmarshal(data, &tokenID); err != nil { 572 return nil, err 573 } 574 return nil, m.updateMapsLayerToken(cd.CurrentMap, tokenID, func(mp *levelMap, l *layer, tk *token) bool { 575 delete(mp.tokens, tokenID) 576 l.removeToken(tokenID) 577 m.socket.broadcastMapChange(cd, broadcastTokenRemove, data, userAny) 578 return true 579 }) 580 case "setToken": 581 var setToken setToken 582 if err := json.Unmarshal(data, &setToken); err != nil { 583 return nil, err 584 } 585 var err error 586 if errr := m.updateMapsLayerToken(cd.CurrentMap, setToken.ID, func(_ *levelMap, _ *layer, tk *token) bool { 587 if !checkTokenLighting(setToken, tk) { 588 err = ErrInvalidLighting 589 return false 590 } 591 m.socket.broadcastMapChange(cd, broadcastTokenSet, data, userAdmin) 592 m.socket.broadcastMapChange(cd, broadcastTokenSet, updateToken(setToken, tk, data[:0]), userNotAdmin) 593 return true 594 }); errr != nil { 595 return nil, errr 596 } 597 return nil, err 598 case "setTokenMulti": 599 var setTokens []setToken 600 if err := json.Unmarshal(data, &setTokens); err != nil { 601 return nil, err 602 } 603 var err error 604 if errr := m.updateMapData(cd.CurrentMap, func(l *levelMap) bool { 605 for _, st := range setTokens { 606 if tk, ok := l.tokens[st.ID]; ok { 607 if !checkTokenLighting(st, tk.token) { 608 err = ErrInvalidLighting 609 return false 610 } 611 } else { 612 err = ErrInvalidToken 613 return false 614 } 615 } 616 m.socket.broadcastMapChange(cd, broadcastTokenSetMulti, data, userAdmin) 617 data = append(data[:0], '[') 618 for n, st := range setTokens { 619 if n > 0 { 620 data = append(data, ',') 621 } 622 data = updateToken(st, l.tokens[st.ID].token, data) 623 } 624 data = append(data, ']') 625 m.socket.broadcastMapChange(cd, broadcastTokenSetMulti, data, userNotAdmin) 626 return true 627 }); errr != nil { 628 return nil, errr 629 } 630 return nil, err 631 case "setTokenLayerPos": 632 var tokenLayerPos struct { 633 ID uint64 `jons:"id"` 634 To string `json:"to"` 635 NewPos uint `json:"newPos"` 636 } 637 if err := json.Unmarshal(data, &tokenLayerPos); err != nil { 638 return nil, err 639 } 640 var err error 641 if errr := m.updateMapsLayerToken(cd.CurrentMap, tokenLayerPos.ID, func(mp *levelMap, l *layer, tk *token) bool { 642 ml := getLayer(&mp.layer, tokenLayerPos.To, false) 643 if ml == nil || ml.Layers != nil { 644 err = ErrInvalidLayerPath 645 return false 646 } 647 l.removeToken(tokenLayerPos.ID) 648 ml.addToken(tk, tokenLayerPos.NewPos) 649 if ml != l { 650 mp.tokens[tk.ID] = layerToken{ml, tk} 651 } 652 m.socket.broadcastMapChange(cd, broadcastTokenMoveLayerPos, data, userAny) 653 return true 654 }); errr != nil { 655 return nil, errr 656 } 657 return nil, err 658 case "shiftLayer": 659 var layerShift struct { 660 Path string `json:"path"` 661 DX int64 `json:"dx"` 662 DY int64 `json:"dy"` 663 } 664 if err := json.Unmarshal(data, &layerShift); err != nil { 665 return nil, err 666 } 667 if layerShift.DX == 0 && layerShift.DY == 0 { 668 return nil, nil 669 } 670 return nil, m.updateMapLayer(cd.CurrentMap, layerShift.Path, tokenLayer, func(mp *levelMap, l *layer) bool { 671 for _, t := range l.Tokens { 672 t.X += layerShift.DX 673 t.Y += layerShift.DY 674 } 675 for _, w := range l.Walls { 676 w.X1 += layerShift.DX 677 w.Y1 += layerShift.DY 678 w.X2 += layerShift.DX 679 w.Y2 += layerShift.DY 680 } 681 m.socket.broadcastMapChange(cd, broadcastLayerShift, data, userAny) 682 return true 683 }) 684 case "remove": 685 var ( 686 mapPath string 687 cu keystore.Uint64 688 ) 689 if err := json.Unmarshal(data, &mapPath); err != nil { 690 return nil, err 691 } 692 m.config.Get("currentUserMap", &cu) 693 _, _, id := m.getFolderItem(mapPath) 694 if id == uint64(cu) { 695 return nil, ErrCurrentlySelected 696 } 697 inUse := false 698 m.socket.mu.RLock() 699 for c := range m.socket.conns { 700 if c.CurrentMap == id { 701 inUse = true 702 break 703 } 704 } 705 m.socket.mu.RUnlock() 706 if inUse { 707 return nil, ErrCurrentlyInUse 708 } 709 case "rename": 710 var ( 711 mapPath struct { 712 From string `json:"from"` 713 } 714 cu keystore.Uint64 715 ) 716 if err := json.Unmarshal(data, &mapPath); err != nil { 717 return nil, err 718 } 719 m.config.Get("currentUserMap", &cu) 720 if _, _, id := m.getFolderItem(mapPath.From); id == uint64(cu) || id == cd.CurrentMap { 721 return nil, ErrCurrentlySelected 722 } 723 case "removeFolder": 724 var ( 725 mapPath string 726 cu keystore.Uint64 727 ) 728 if err := json.Unmarshal(data, &mapPath); err != nil { 729 return nil, err 730 } 731 m.config.Get("currentUserMap", &cu) 732 if f := m.getFolder(mapPath); f != nil { 733 if walkFolders(f, func(items map[string]uint64) bool { 734 for _, id := range items { 735 if id == uint64(cu) || id == cd.CurrentMap { 736 return true 737 } 738 } 739 return false 740 }) { 741 return nil, ErrContainsCurrentlySelected 742 } 743 } 744 case "renameFolder": 745 var ( 746 mapPath struct { 747 From string `json:"from"` 748 } 749 cu keystore.Uint64 750 ) 751 if err := json.Unmarshal(data, &mapPath); err != nil { 752 return nil, err 753 } 754 m.config.Get("currentUserMap", &cu) 755 if f := m.getFolder(mapPath.From); f != nil { 756 if walkFolders(f, func(items map[string]uint64) bool { 757 for _, id := range items { 758 if id == uint64(cu) || id == cd.CurrentMap { 759 return true 760 } 761 } 762 return false 763 }) { 764 return nil, ErrContainsCurrentlySelected 765 } 766 } 767 case "copy": 768 var ( 769 ip struct { 770 ID uint64 `json:"id"` 771 Path string `json:"path"` 772 } 773 errr error 774 ) 775 if err := json.Unmarshal(data, &ip); err != nil { 776 return nil, err 777 } 778 if err := m.updateMapData(ip.ID, func(mp *levelMap) bool { 779 p, name, _ := m.getFolderItem(ip.Path) 780 if p == nil { 781 errr = ErrFolderNotFound 782 return false 783 } 784 m.lastID++ 785 mid := m.lastID 786 j := mp.JSON 787 m.Set(strconv.FormatUint(mid, 10), &j) 788 j = mp.JSON 789 l := new(levelMap) 790 l.JSON = make(memio.Buffer, 0, len(j)) 791 l.ReadFrom(&j) 792 newName := addItemTo(p.Items, name, mid) 793 m.maps[mid] = l 794 m.saveFolders() 795 ip.Path = ip.Path[:len(ip.Path)-len(name)] + newName 796 data = append(appendString(append(strconv.AppendUint(append(strconv.AppendUint(append(data[:0], "{\"oldID\":"...), ip.ID, 10), ",\"newID\":"...), mid, 10), ",\"path\":"...), ip.Path), '}') 797 m.socket.broadcastAdminChange(broadcastMapItemCopy, data, cd.ID) 798 data = append(appendString(append(strconv.AppendUint(append(data[:0], "{\"id\":"...), mid, 10), ",\"path\":"...), ip.Path), '}') 799 return false 800 }); err != nil { 801 return nil, err 802 } 803 if errr != nil { 804 return nil, errr 805 } 806 return data, nil 807 } 808 return m.folders.RPCData(cd, method, data) 809 } 810 811 type setToken struct { 812 ID uint64 `json:"id"` 813 X *int64 `json:"x"` 814 Y *int64 `json:"y"` 815 Width *uint64 `json:"width"` 816 Height *uint64 `json:"height"` 817 Rotation *uint8 `json:"rotation"` 818 Snap *bool `json:"snap"` 819 LightColours *[][]colour `json:"lightColours"` 820 LightStages *[]uint64 `json:"lightStages"` 821 LightTimings *[]uint64 `json:"lightTimings"` 822 Source *uint64 `json:"src"` 823 PatternWidth *uint64 `json:"patternWidth"` 824 PatternHeight *uint64 `json:"patternHeight"` 825 TokenData map[string]keystoreData `json:"tokenData"` 826 RemoveTokenData []string `json:"removeTokenData"` 827 Flip *bool `json:"flip"` 828 Flop *bool `json:"flop"` 829 830 IsEllipse *bool `json:"isEllipse"` 831 Fill *colour `json:"fill"` 832 Stroke *colour `json:"stroke"` 833 StrokeWidth *uint8 `json:"strokeWidth"` 834 835 Points []coords `json:"points"` 836 } 837 838 func checkTokenLighting(setToken setToken, tk *token) bool { 839 if setToken.LightStages != nil { 840 if setToken.LightColours != nil { 841 if len(*setToken.LightColours) != len(*setToken.LightStages) { 842 return false 843 } 844 } else if len(tk.LightColours) != len(*setToken.LightStages) { 845 return false 846 } 847 } 848 if setToken.LightTimings != nil { 849 if setToken.LightColours != nil { 850 for _, cs := range *setToken.LightColours { 851 if len(cs) != len(*setToken.LightTimings) { 852 return false 853 } 854 } 855 } else { 856 for _, cs := range tk.LightColours { 857 if len(cs) != len(*setToken.LightTimings) { 858 return false 859 } 860 } 861 } 862 } else if setToken.LightColours != nil && setToken.LightStages == nil { 863 if len(*setToken.LightColours) != len(tk.LightStages) { 864 return false 865 } 866 for _, cs := range *setToken.LightColours { 867 if len(cs) != len(tk.LightTimings) { 868 return false 869 } 870 } 871 } 872 return true 873 } 874 875 func updateToken(setToken setToken, tk *token, data json.RawMessage) json.RawMessage { 876 data = strconv.AppendUint(append(data[:0], "{\"id\":"...), setToken.ID, 10) 877 if setToken.X != nil && *setToken.X != tk.X { 878 tk.X = *setToken.X 879 data = strconv.AppendInt(append(data, ",\"x\":"...), tk.X, 10) 880 } 881 if setToken.Y != nil && *setToken.Y != tk.Y { 882 tk.Y = *setToken.Y 883 data = strconv.AppendInt(append(data, ",\"y\":"...), tk.Y, 10) 884 } 885 if setToken.Width != nil && *setToken.Width != tk.Width && *setToken.Width > 0 { 886 tk.Width = *setToken.Width 887 data = strconv.AppendUint(append(data, ",\"width\":"...), tk.Width, 10) 888 } 889 if setToken.Height != nil && *setToken.Height != tk.Height && *setToken.Height > 0 { 890 tk.Height = *setToken.Height 891 data = strconv.AppendUint(append(data, ",\"height\":"...), tk.Height, 10) 892 } 893 if setToken.Rotation != nil && *setToken.Rotation != tk.Rotation { 894 tk.Rotation = *setToken.Rotation 895 data = appendNum(append(data, ",\"rotation\":"...), tk.Rotation) 896 } 897 if setToken.Snap != nil && *setToken.Snap != tk.Snap { 898 tk.Snap = *setToken.Snap 899 data = strconv.AppendBool(append(data, ",\"snap\":"...), tk.Snap) 900 } 901 if setToken.LightColours != nil { 902 tk.LightColours = *setToken.LightColours 903 data = tk.LightColours.appendTo(append(data, ",\"lightColours\":"...)) 904 } 905 if setToken.LightStages != nil { 906 tk.LightStages = *setToken.LightStages 907 data = tk.LightStages.appendTo(append(data, ",\"lightStages\":"...)) 908 } 909 if setToken.LightTimings != nil { 910 tk.LightTimings = *setToken.LightTimings 911 data = tk.LightTimings.appendTo(append(data, ",\"lightTimings\":"...)) 912 } 913 switch tk.TokenType { 914 case tokenImage: 915 if setToken.Source != nil && *setToken.Source != tk.Source { 916 tk.Source = *setToken.Source 917 data = strconv.AppendUint(append(data, ",\"src\":"...), tk.Source, 10) 918 } 919 if setToken.PatternWidth != nil && *setToken.PatternWidth != tk.PatternWidth { 920 tk.PatternWidth = *setToken.PatternWidth 921 data = strconv.AppendUint(append(data, ",\"patternWidth\":"...), tk.PatternWidth, 10) 922 } 923 if setToken.PatternHeight != nil && *setToken.PatternHeight != tk.PatternHeight { 924 tk.PatternHeight = *setToken.PatternHeight 925 data = strconv.AppendUint(append(data, ",\"patternHeight\":"...), tk.PatternHeight, 10) 926 } 927 if setToken.Flip != nil && *setToken.Flip != tk.Flip { 928 tk.Flip = *setToken.Flip 929 data = strconv.AppendBool(append(data, ",\"flip\":"...), tk.Flip) 930 } 931 if setToken.Flop != nil && *setToken.Flop != tk.Flop { 932 tk.Flop = *setToken.Flop 933 data = strconv.AppendBool(append(data, ",\"flip\":"...), tk.Flop) 934 } 935 case tokenDrawing: 936 if setToken.Points != nil { 937 tk.Points = setToken.Points 938 data = append(data, ",\"points\":["...) 939 for n, p := range tk.Points { 940 if n > 0 { 941 data = append(data, ',') 942 } 943 data = strconv.AppendInt(append(data, "{\"x\":"...), p.X, 10) 944 data = strconv.AppendInt(append(data, ",\"y\":"...), p.Y, 10) 945 data = append(data, '}') 946 } 947 data = append(data, ']') 948 } 949 fallthrough 950 case tokenShape: 951 if setToken.IsEllipse != nil && *setToken.IsEllipse != tk.IsEllipse { 952 tk.IsEllipse = *setToken.IsEllipse 953 data = strconv.AppendBool(append(data, ",\"isEllipse\":"...), tk.IsEllipse) 954 } 955 if setToken.Fill != nil && *setToken.Fill != tk.Fill { 956 tk.Fill = *setToken.Fill 957 data = tk.Fill.appendTo(append(data, ",\"fill\":"...)) 958 } 959 if setToken.Stroke != nil && *setToken.Stroke != tk.Stroke { 960 tk.Stroke = *setToken.Stroke 961 data = tk.Stroke.appendTo(append(data, ",\"stroke\":"...)) 962 } 963 if setToken.StrokeWidth != nil && *setToken.StrokeWidth != tk.StrokeWidth { 964 tk.StrokeWidth = *setToken.StrokeWidth 965 data = appendNum(append(data, ",\"strokeWidth\":"...), tk.StrokeWidth) 966 } 967 } 968 var userRemoves []string 969 if len(setToken.TokenData) > 0 { 970 if len(setToken.RemoveTokenData) > 0 { 971 for _, r := range setToken.RemoveTokenData { 972 delete(setToken.TokenData, r) 973 } 974 } 975 data = append(data, ",\"tokenData\":{"...) 976 first := true 977 for key, kd := range setToken.TokenData { 978 if kd.User { 979 if first { 980 first = false 981 } else { 982 data = append(data, ',') 983 } 984 data = append(append(append(appendString(data, key), ":{\"user\":true,\"data\":"...), kd.Data...), '}') 985 } else if td, ok := tk.TokenData[key]; ok && td.User { 986 userRemoves = append(userRemoves, key) 987 } 988 tk.TokenData[key] = kd 989 } 990 data = append(data, '}') 991 } 992 if len(setToken.RemoveTokenData) > 0 { 993 for _, r := range setToken.RemoveTokenData { 994 delete(setToken.TokenData, r) 995 if d, ok := tk.TokenData[r]; ok { 996 if d.User { 997 userRemoves = append(userRemoves, r) 998 } 999 delete(tk.TokenData, r) 1000 } 1001 } 1002 } 1003 if len(userRemoves) > 0 { 1004 data = append(data, ",\"removeTokenData\":["...) 1005 first := true 1006 for _, r := range userRemoves { 1007 if first { 1008 first = false 1009 } else { 1010 data = append(data, ',') 1011 } 1012 data = appendString(data, r) 1013 } 1014 data = append(data, ']') 1015 } 1016 return append(data, '}') 1017 } 1018