1 package store
2
3 import (
4 "encoding/hex"
5 "fmt"
6
7 _ "github.com/go-sql-driver/mysql"
8
9 "go.formulabun.club/srb2kart/lump/replay"
10 )
11
12 type columnScanner interface {
13 Scan(dest ...any) error
14 }
15
16 func ConvertToStoreData(replay replay.ReplayRaw) (r Replay, files []ReplayFile, err error) {
17 if len(replay.PlayerEntries) != 1 {
18 err = fmt.Errorf("Replay file doesn't contain exactly 1 player, it contains %v", len(replay.PlayerEntries))
19 return
20 }
21 player := replay.PlayerEntries[0]
22 r = Replay{
23 GameMap: replay.GameMap,
24 Time: replay.Time,
25 BestLap: replay.Lap,
26 Speed: player.Speed,
27 Weight: player.Weight,
28 }
29 copy(r.PlayerName[:], player.Name[:16])
30 copy(r.PlayerSkin[:], player.Skin[:16])
31 copy(r.PlayerColor[:], player.Color[:16])
32
33 files = make([]ReplayFile, len(replay.WadEntries))
34 for i, file := range replay.WadEntries {
35 files[i].FileName = file.FileName
36 copy(files[i].FileCheckSum[:16], file.WadMd5[:])
37 }
38
39 return r, files, nil
40 }
41
42 func (db *Client) InsertReplayRaw(replay replay.ReplayRaw) (id int64, err error) {
43 r, files, err := ConvertToStoreData(replay)
44 if err != nil {
45 return 0, err
46 }
47 return db.InsertReplayInfo(r, files)
48 }
49
50 func (db *Client) InsertReplayInfo(replay Replay, files []ReplayFile) (id int64, err error) {
51 t, err := db.Begin()
52 defer t.Commit()
53 if err != nil {
54 return
55 }
56
57 res, err := t.Exec(
58 `
59 INSERT INTO replays
60 (GameMap, Time, BestLap, PlayerName, PlayerSkin, PlayerColor, Speed, Weight)
61 VALUE
62 (?, ?, ?, ?, ?, ?, ?, ?)
63 `,
64 replay.GameMap, replay.Time, replay.BestLap, fmt.Sprintf("%s", replay.PlayerName), fmt.Sprintf("%s", replay.PlayerSkin), fmt.Sprintf("%s", replay.PlayerColor), replay.Speed, replay.Weight)
65 if err != nil {
66 t.Rollback()
67 return
68 }
69
70 id, err = res.LastInsertId()
71
72 for _, file := range files {
73 checksum := hex.EncodeToString(file.FileCheckSum[:])
74 _, err = t.Exec(
75 `
76 INSERT INTO replayfiles
77 (ReplayID, FileName, FileCheckSum)
78 VALUE
79 (?, ?, ?)
80 `,
81 id, file.FileName, checksum)
82 if err != nil {
83 t.Rollback()
84 return
85 }
86
87 }
88
89 return
90 }
91
92 func scanRow(row columnScanner) (Replay, error) {
93 var result Replay
94 var name, skin, color string
95 err := row.Scan(&result.ReplayID, &result.GameMap, &result.Time, &result.BestLap, &name, &skin, &color, &result.Speed, &result.Weight)
96
97 copy(result.PlayerName[:], name)
98 copy(result.PlayerSkin[:], skin)
99 copy(result.PlayerColor[:], color)
100
101 return result, err
102 }
103
104 func (db *Client) GetReplayById(id int64) (result Replay, err error) {
105 row := db.QueryRow(
106 `
107 SELECT ReplayID, GameMap, Time, BestLap, PlayerName, PlayerSkin, PlayerColor, Speed, Weight from replays
108 WHERE ReplayId = ?
109 `, id)
110 return scanRow(row)
111 }
112
113 func (db *Client) FindReplay(r Replay) ([]Replay, error) {
114 var where = "WHERE GameMap %s ? AND Time %s ? AND BestLap %s ? AND Speed %s ? AND Weight %s ?"
115 var cMap, cTime, cLap, cSpeed, cWeight string
116 if r.GameMap == 0 {
117 cMap = ">"
118 } else {
119 cMap = "="
120 }
121 if r.Time == 0 {
122 cTime = ">"
123 } else {
124 cTime = "<="
125 }
126 if r.BestLap == 0 {
127 cLap = ">"
128 } else {
129 cLap = "<="
130 }
131 if r.Speed == 0 {
132 cSpeed = ">"
133 } else {
134 cSpeed = "="
135 }
136 if r.Weight == 0 {
137 cWeight = ">"
138 } else {
139 cWeight = "="
140 }
141
142 where = fmt.Sprintf(where, cMap, cTime, cLap, cSpeed, cWeight)
143 rows, err := db.Query(
144 fmt.Sprintf(`SELECT ReplayID, GameMap, min(Time), BestLap, PlayerName, PlayerSkin, Playercolor, Speed, weight FROM replays
145 %s
146 GROUP BY PlayerName
147 ORDER BY Time ASC`, where),
148 r.GameMap, r.Time, r.BestLap, r.Speed, r.Weight)
149
150 var result = []Replay{}
151 if err != nil {
152 return result, err
153 }
154
155 for rows.Next() {
156 item, err := scanRow(rows)
157 if err != nil {
158 return result, err
159 }
160 result = append(result, item)
161 }
162 return result, err
163
164 }
165
View as plain text