aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_swapid.go
blob: 6ee111854988184227c2a68dcc3f7dc380d96c04 (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
package game

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strconv"

	"thehouseoficarus/internal/net"
)

func (g *Game) executeSwapID(sess *net.Session, args []string, rawInput string) {
	if !g.checkAdmin(sess) {
		sess.WriteLine("Unknown command.")
		return
	}
	p := sess.Player
	if p == nil {
		return
	}

	var id1, id2 int
	switch len(args) {
	case 1:
		id1 = p.RoomID
		var err error
		id2, err = strconv.Atoi(args[0])
		if err != nil {
			sess.WriteLine("Invalid room ID.")
			return
		}
	case 2:
		var err error
		id1, err = strconv.Atoi(args[0])
		if err != nil {
			sess.WriteLine("Invalid room ID.")
			return
		}
		id2, err = strconv.Atoi(args[1])
		if err != nil {
			sess.WriteLine("Invalid room ID.")
			return
		}
	default:
		sess.WriteLine("Usage: swapid <id>  or  swapid <id1> <id2>")
		return
	}

	if id1 == id2 {
		sess.WriteLine("Cannot swap a room with itself.")
		return
	}

	path1, ok1 := g.World.GetRoomPath(id1)
	path2, ok2 := g.World.GetRoomPath(id2)
	if !ok1 {
		sess.WriteLine(fmt.Sprintf("Room %d not found.", id1))
		return
	}
	if !ok2 {
		sess.WriteLine(fmt.Sprintf("Room %d not found.", id2))
		return
	}

	roomsDir := filepath.Join(g.DataDir, "rooms")
	re1 := regexp.MustCompile(fmt.Sprintf(`\b%d\b`, id1))
	re2 := regexp.MustCompile(fmt.Sprintf(`\b%d\b`, id2))
	placeholder := fmt.Sprintf("__SWAPID_TEMP_%d__", id1^id2)

	var modified []string
	err := filepath.WalkDir(roomsDir, func(roomPath string, d os.DirEntry, err error) error {
		if err != nil || d.IsDir() || filepath.Ext(roomPath) != ".yaml" {
			return nil
		}
		data, rerr := os.ReadFile(roomPath)
		if rerr != nil {
			return nil
		}
		text := string(data)
		if !re1.MatchString(text) && !re2.MatchString(text) {
			return nil
		}
		text = re1.ReplaceAllString(text, placeholder)
		text = re2.ReplaceAllString(text, strconv.Itoa(id1))
		text = regexp.MustCompile(placeholder).ReplaceAllString(text, strconv.Itoa(id2))
		if werr := os.WriteFile(roomPath, []byte(text), 0644); werr != nil {
			return werr
		}
		modified = append(modified, roomPath)
		return nil
	})
	if err != nil {
		sess.WriteLine(fmt.Sprintf("Error updating room files: %v", err))
		return
	}

	tempPath := path1 + ".swapid-tmp"
	if rerr := os.Rename(path1, tempPath); rerr != nil {
		sess.WriteLine(fmt.Sprintf("Error renaming room %d: %v", id1, rerr))
		return
	}
	if rerr := os.Rename(path2, path1); rerr != nil {
		os.Rename(tempPath, path1)
		sess.WriteLine(fmt.Sprintf("Error renaming room %d: %v", id2, rerr))
		return
	}
	if rerr := os.Rename(tempPath, path2); rerr != nil {
		os.Rename(path2, path1)
		os.Rename(tempPath, path1)
		sess.WriteLine(fmt.Sprintf("Error finishing rename: %v", rerr))
		return
	}

	g.World.RebuildRoomIndex(g.DataDir)
	g.World.LoadRoom(id1)
	g.World.LoadRoom(id2)

	if p.RoomID == id1 {
		p.RoomID = id2
	} else if p.RoomID == id2 {
		p.RoomID = id1
	}

	sess.WriteLine(fmt.Sprintf("Swapped room IDs %d and %d (%d files updated).", id1, id2, len(modified)))
}