diff options
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/handlers/record.go | 94 | ||||
| -rw-r--r-- | backend/parser/parser.go | 196 |
2 files changed, 244 insertions, 46 deletions
diff --git a/backend/handlers/record.go b/backend/handlers/record.go index fea6b5d..2338097 100644 --- a/backend/handlers/record.go +++ b/backend/handlers/record.go | |||
| @@ -24,10 +24,9 @@ import ( | |||
| 24 | ) | 24 | ) |
| 25 | 25 | ||
| 26 | type RecordRequest struct { | 26 | type RecordRequest struct { |
| 27 | HostDemo *multipart.FileHeader `json:"host_demo" form:"host_demo" binding:"required" swaggerignore:"true"` | 27 | HostDemo *multipart.FileHeader `json:"host_demo" form:"host_demo" binding:"required" swaggerignore:"true"` |
| 28 | PartnerDemo *multipart.FileHeader `json:"partner_demo" form:"partner_demo" swaggerignore:"true"` | 28 | PartnerDemo *multipart.FileHeader `json:"partner_demo" form:"partner_demo" swaggerignore:"true"` |
| 29 | IsPartnerOrange bool `json:"is_partner_orange" form:"is_partner_orange"` | 29 | PartnerID string `json:"partner_id" form:"partner_id"` |
| 30 | PartnerID string `json:"partner_id" form:"partner_id"` | ||
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | type RecordResponse struct { | 32 | type RecordResponse struct { |
| @@ -50,7 +49,12 @@ type RecordResponse struct { | |||
| 50 | // @Success 200 {object} models.Response{data=RecordResponse} | 49 | // @Success 200 {object} models.Response{data=RecordResponse} |
| 51 | // @Router /maps/{mapid}/record [post] | 50 | // @Router /maps/{mapid}/record [post] |
| 52 | func CreateRecordWithDemo(c *gin.Context) { | 51 | func CreateRecordWithDemo(c *gin.Context) { |
| 53 | mapId := c.Param("mapid") | 52 | id := c.Param("mapid") |
| 53 | mapID, err := strconv.Atoi(id) | ||
| 54 | if err != nil { | ||
| 55 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | ||
| 56 | return | ||
| 57 | } | ||
| 54 | // Check if user exists | 58 | // Check if user exists |
| 55 | user, exists := c.Get("user") | 59 | user, exists := c.Get("user") |
| 56 | if !exists { | 60 | if !exists { |
| @@ -62,7 +66,7 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 62 | var isCoop bool | 66 | var isCoop bool |
| 63 | var isDisabled bool | 67 | var isDisabled bool |
| 64 | sql := `SELECT g.name, m.is_disabled FROM maps m INNER JOIN games g ON m.game_id=g.id WHERE m.id = $1` | 68 | sql := `SELECT g.name, m.is_disabled FROM maps m INNER JOIN games g ON m.game_id=g.id WHERE m.id = $1` |
| 65 | err := database.DB.QueryRow(sql, mapId).Scan(&gameName, &isDisabled) | 69 | err = database.DB.QueryRow(sql, mapID).Scan(&gameName, &isDisabled) |
| 66 | if err != nil { | 70 | if err != nil { |
| 67 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 71 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 68 | return | 72 | return |
| @@ -94,8 +98,8 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 94 | var hostDemoUUID, hostDemoFileID, partnerDemoUUID, partnerDemoFileID string | 98 | var hostDemoUUID, hostDemoFileID, partnerDemoUUID, partnerDemoFileID string |
| 95 | var hostDemoScoreCount, hostDemoScoreTime int | 99 | var hostDemoScoreCount, hostDemoScoreTime int |
| 96 | var hostSteamID, partnerSteamID string | 100 | var hostSteamID, partnerSteamID string |
| 97 | client := serviceAccount() | 101 | var hostDemoServerNumber, partnerDemoServerNumber int |
| 98 | srv, err := drive.New(client) | 102 | srv, err := drive.New(serviceAccount()) |
| 99 | if err != nil { | 103 | if err != nil { |
| 100 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 104 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 101 | return | 105 | return |
| @@ -131,13 +135,22 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 131 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 135 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 132 | return | 136 | return |
| 133 | } | 137 | } |
| 134 | hostDemoScoreCount, hostDemoScoreTime, hostSteamID, partnerSteamID, err = parser.ProcessDemo("backend/parser/" + uuid + ".dem") | 138 | parserResult, err := parser.ProcessDemo("backend/parser/" + uuid + ".dem") |
| 135 | if err != nil { | 139 | if err != nil { |
| 136 | deleteFile(srv, file.Id) | 140 | deleteFile(srv, file.Id) |
| 137 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordProcessDemoFail, err.Error()) | 141 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordProcessDemoFail, err.Error()) |
| 138 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 142 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 139 | return | 143 | return |
| 140 | } | 144 | } |
| 145 | if mapID != parserResult.MapID { | ||
| 146 | deleteFile(srv, file.Id) | ||
| 147 | c.JSON(http.StatusOK, models.ErrorResponse("demo map does not match uploaded map id")) | ||
| 148 | return | ||
| 149 | } | ||
| 150 | hostDemoScoreCount = parserResult.PortalCount | ||
| 151 | hostDemoScoreTime = parserResult.TickCount | ||
| 152 | hostSteamID = parserResult.HostSteamID | ||
| 153 | partnerSteamID = parserResult.PartnerSteamID | ||
| 141 | if hostDemoScoreCount == 0 && hostDemoScoreTime == 0 { | 154 | if hostDemoScoreCount == 0 && hostDemoScoreTime == 0 { |
| 142 | deleteFile(srv, file.Id) | 155 | deleteFile(srv, file.Id) |
| 143 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordProcessDemoFail, err.Error()) | 156 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordProcessDemoFail, err.Error()) |
| @@ -145,30 +158,32 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 145 | return | 158 | return |
| 146 | } | 159 | } |
| 147 | if !isCoop { | 160 | if !isCoop { |
| 148 | hostSplit := strings.Split(hostSteamID, ":") | 161 | convertedSteamID := strconv.FormatInt(convertSteamID64(hostSteamID), 10) |
| 149 | if hostSplit[len(hostSplit)-1] != user.(models.User).SteamID { | 162 | if convertedSteamID != user.(models.User).SteamID { |
| 150 | c.JSON(http.StatusOK, models.ErrorResponse(fmt.Sprintf("Host SteamID from demo and request does not match! Check your submission and try again.\nDemo Host SteamID: %s\nRequest Host SteamID: %s", hostSplit[len(hostSplit)-1], user.(models.User).SteamID))) | 163 | deleteFile(srv, file.Id) |
| 164 | c.JSON(http.StatusOK, models.ErrorResponse(fmt.Sprintf("Host SteamID from demo and request does not match! Check your submission and try again.\nDemo Host SteamID: %s\nRequest Host SteamID: %s", convertedSteamID, user.(models.User).SteamID))) | ||
| 151 | return | 165 | return |
| 152 | } | 166 | } |
| 153 | } else { | 167 | } else { |
| 154 | partnerSplit := strings.Split(partnerSteamID, ":") | 168 | if parserResult.IsHost && i != 0 { |
| 155 | if partnerSplit[len(partnerSplit)-1] != record.PartnerID { | 169 | deleteFile(srv, file.Id) |
| 156 | c.JSON(http.StatusOK, models.ErrorResponse(fmt.Sprintf("Partner SteamID from demo and request does not match! Check your submission and try again.\nDemo Partner SteamID: %s\nRequest Partner SteamID: %s", partnerSplit[len(partnerSplit)-1], record.PartnerID))) | 170 | c.JSON(http.StatusOK, models.ErrorResponse("Given partner demo is a host demo.")) |
| 157 | return | 171 | return |
| 158 | } | 172 | } |
| 159 | var verifyCoopSteamID string | 173 | if !parserResult.IsHost && i == 0 { |
| 160 | database.DB.QueryRow("SELECT steam_id FROM users WHERE steam_id = $1", record.PartnerID).Scan(&verifyCoopSteamID) | 174 | deleteFile(srv, file.Id) |
| 161 | if verifyCoopSteamID != record.PartnerID { | 175 | c.JSON(http.StatusOK, models.ErrorResponse("Given host demo is a partner demo.")) |
| 162 | c.JSON(http.StatusOK, models.ErrorResponse("Given partner SteamID does not match an account on LPHUB.")) | ||
| 163 | return | 176 | return |
| 164 | } | 177 | } |
| 165 | } | 178 | } |
| 166 | if i == 0 { | 179 | if i == 0 { |
| 167 | hostDemoFileID = file.Id | 180 | hostDemoFileID = file.Id |
| 168 | hostDemoUUID = uuid | 181 | hostDemoUUID = uuid |
| 182 | hostDemoServerNumber = parserResult.ServerNumber | ||
| 169 | } else if i == 1 { | 183 | } else if i == 1 { |
| 170 | partnerDemoFileID = file.Id | 184 | partnerDemoFileID = file.Id |
| 171 | partnerDemoUUID = uuid | 185 | partnerDemoUUID = uuid |
| 186 | partnerDemoServerNumber = parserResult.ServerNumber | ||
| 172 | } | 187 | } |
| 173 | _, err = tx.Exec(`INSERT INTO demos (id,location_id) VALUES ($1,$2)`, uuid, file.Id) | 188 | _, err = tx.Exec(`INSERT INTO demos (id,location_id) VALUES ($1,$2)`, uuid, file.Id) |
| 174 | if err != nil { | 189 | if err != nil { |
| @@ -180,18 +195,37 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 180 | } | 195 | } |
| 181 | // Insert into records | 196 | // Insert into records |
| 182 | if isCoop { | 197 | if isCoop { |
| 198 | if hostDemoServerNumber != partnerDemoServerNumber { | ||
| 199 | deleteFile(srv, hostDemoFileID) | ||
| 200 | deleteFile(srv, partnerDemoFileID) | ||
| 201 | c.JSON(http.StatusOK, models.ErrorResponse(fmt.Sprintf("Host and partner demo server numbers (%d & %d) does not match!", hostDemoServerNumber, partnerDemoServerNumber))) | ||
| 202 | return | ||
| 203 | } | ||
| 204 | convertedHostSteamID := strconv.FormatInt(convertSteamID64(hostSteamID), 10) | ||
| 205 | if convertedHostSteamID != user.(models.User).SteamID && convertedHostSteamID != record.PartnerID { | ||
| 206 | deleteFile(srv, hostDemoFileID) | ||
| 207 | deleteFile(srv, partnerDemoFileID) | ||
| 208 | c.JSON(http.StatusOK, models.ErrorResponse(fmt.Sprintf("Host SteamID from demo and request does not match! Check your submission and try again.\nDemo Host SteamID: %s\nRequest Host SteamID: %s", convertedHostSteamID, user.(models.User).SteamID))) | ||
| 209 | return | ||
| 210 | } | ||
| 211 | convertedPartnerSteamID := strconv.FormatInt(convertSteamID64(partnerSteamID), 10) | ||
| 212 | if convertedPartnerSteamID != record.PartnerID && convertedPartnerSteamID != user.(models.User).SteamID { | ||
| 213 | deleteFile(srv, hostDemoFileID) | ||
| 214 | deleteFile(srv, partnerDemoFileID) | ||
| 215 | c.JSON(http.StatusOK, models.ErrorResponse(fmt.Sprintf("Partner SteamID from demo and request does not match! Check your submission and try again.\nDemo Partner SteamID: %s\nRequest Partner SteamID: %s", convertedPartnerSteamID, record.PartnerID))) | ||
| 216 | return | ||
| 217 | } | ||
| 218 | var verifyPartnerSteamID string | ||
| 219 | database.DB.QueryRow("SELECT steam_id FROM users WHERE steam_id = $1", record.PartnerID).Scan(&verifyPartnerSteamID) | ||
| 220 | if verifyPartnerSteamID != record.PartnerID { | ||
| 221 | deleteFile(srv, hostDemoFileID) | ||
| 222 | deleteFile(srv, partnerDemoFileID) | ||
| 223 | c.JSON(http.StatusOK, models.ErrorResponse("Given partner SteamID does not match an account on LPHUB.")) | ||
| 224 | return | ||
| 225 | } | ||
| 183 | sql := `INSERT INTO records_mp(map_id,score_count,score_time,host_id,partner_id,host_demo_id,partner_demo_id) | 226 | sql := `INSERT INTO records_mp(map_id,score_count,score_time,host_id,partner_id,host_demo_id,partner_demo_id) |
| 184 | VALUES($1, $2, $3, $4, $5, $6, $7)` | 227 | VALUES($1, $2, $3, $4, $5, $6, $7)` |
| 185 | var hostID string | 228 | _, err := tx.Exec(sql, mapID, hostDemoScoreCount, hostDemoScoreTime, strconv.FormatInt(convertSteamID64(hostSteamID), 10), strconv.FormatInt(convertSteamID64(partnerSteamID), 10), hostDemoUUID, partnerDemoUUID) |
| 186 | var partnerID string | ||
| 187 | if record.IsPartnerOrange { | ||
| 188 | hostID = user.(models.User).SteamID | ||
| 189 | partnerID = record.PartnerID | ||
| 190 | } else { | ||
| 191 | partnerID = user.(models.User).SteamID | ||
| 192 | hostID = record.PartnerID | ||
| 193 | } | ||
| 194 | _, err := tx.Exec(sql, mapId, hostDemoScoreCount, hostDemoScoreTime, hostID, partnerID, hostDemoUUID, partnerDemoUUID) | ||
| 195 | if err != nil { | 229 | if err != nil { |
| 196 | deleteFile(srv, hostDemoFileID) | 230 | deleteFile(srv, hostDemoFileID) |
| 197 | deleteFile(srv, partnerDemoFileID) | 231 | deleteFile(srv, partnerDemoFileID) |
| @@ -202,7 +236,7 @@ func CreateRecordWithDemo(c *gin.Context) { | |||
| 202 | } else { | 236 | } else { |
| 203 | sql := `INSERT INTO records_sp(map_id,score_count,score_time,user_id,demo_id) | 237 | sql := `INSERT INTO records_sp(map_id,score_count,score_time,user_id,demo_id) |
| 204 | VALUES($1, $2, $3, $4, $5)` | 238 | VALUES($1, $2, $3, $4, $5)` |
| 205 | _, err := tx.Exec(sql, mapId, hostDemoScoreCount, hostDemoScoreTime, user.(models.User).SteamID, hostDemoUUID) | 239 | _, err := tx.Exec(sql, mapID, hostDemoScoreCount, hostDemoScoreTime, user.(models.User).SteamID, hostDemoUUID) |
| 206 | if err != nil { | 240 | if err != nil { |
| 207 | deleteFile(srv, hostDemoFileID) | 241 | deleteFile(srv, hostDemoFileID) |
| 208 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordInsertRecordFail, err.Error()) | 242 | CreateLog(user.(models.User).SteamID, LogTypeRecord, LogDescriptionCreateRecordInsertRecordFail, err.Error()) |
diff --git a/backend/parser/parser.go b/backend/parser/parser.go index 1a80d4a..4605600 100644 --- a/backend/parser/parser.go +++ b/backend/parser/parser.go | |||
| @@ -4,30 +4,52 @@ import ( | |||
| 4 | "errors" | 4 | "errors" |
| 5 | "math" | 5 | "math" |
| 6 | "os" | 6 | "os" |
| 7 | "regexp" | ||
| 8 | "strconv" | ||
| 9 | "strings" | ||
| 7 | 10 | ||
| 8 | "github.com/pektezol/bitreader" | 11 | "github.com/pektezol/bitreader" |
| 9 | ) | 12 | ) |
| 10 | 13 | ||
| 14 | type Result struct { | ||
| 15 | MapID int | ||
| 16 | ServerNumber int | ||
| 17 | PortalCount int | ||
| 18 | TickCount int | ||
| 19 | HostSteamID string | ||
| 20 | PartnerSteamID string | ||
| 21 | IsHost bool | ||
| 22 | } | ||
| 23 | |||
| 11 | // Don't try to understand it, feel it. | 24 | // Don't try to understand it, feel it. |
| 12 | func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID string, partnerSteamID string, err error) { | 25 | func ProcessDemo(filePath string) (Result, error) { |
| 26 | var result Result | ||
| 13 | file, err := os.Open(filePath) | 27 | file, err := os.Open(filePath) |
| 14 | if err != nil { | 28 | if err != nil { |
| 15 | return 0, 0, "", "", err | 29 | return Result{}, err |
| 16 | } | 30 | } |
| 17 | reader := bitreader.NewReader(file, true) | 31 | reader := bitreader.NewReader(file, true) |
| 18 | demoFileStamp := reader.TryReadString() | 32 | demoFileStamp := reader.TryReadString() |
| 19 | demoProtocol := reader.TryReadSInt32() | 33 | demoProtocol := reader.TryReadSInt32() |
| 20 | networkProtocol := reader.TryReadSInt32() | 34 | networkProtocol := reader.TryReadSInt32() |
| 21 | reader.SkipBytes(1056) | 35 | serverName := reader.TryReadStringLength(260) |
| 36 | // clientName := reader.TryReadStringLength(260) | ||
| 37 | reader.SkipBytes(260) | ||
| 38 | mapName := reader.TryReadStringLength(260) | ||
| 39 | reader.SkipBytes(276) | ||
| 22 | if demoFileStamp != "HL2DEMO" { | 40 | if demoFileStamp != "HL2DEMO" { |
| 23 | return 0, 0, "", "", errors.New("invalid demo file stamp") | 41 | return Result{}, errors.New("invalid demo file stamp") |
| 24 | } | 42 | } |
| 25 | if demoProtocol != 4 { | 43 | if demoProtocol != 4 { |
| 26 | return 0, 0, "", "", errors.New("this parser only supports demos from new engine") | 44 | return Result{}, errors.New("this parser only supports demos from new engine") |
| 27 | } | 45 | } |
| 28 | if networkProtocol != 2001 { | 46 | if networkProtocol != 2001 { |
| 29 | return 0, 0, "", "", errors.New("this parser only supports demos from portal 2") | 47 | return Result{}, errors.New("this parser only supports demos from portal 2") |
| 48 | } | ||
| 49 | if mapDict[mapName] == 0 { | ||
| 50 | return Result{}, errors.New("demo recorded on an invalid map") | ||
| 30 | } | 51 | } |
| 52 | result.MapID = mapDict[mapName] | ||
| 31 | for { | 53 | for { |
| 32 | packetType := reader.TryReadUInt8() | 54 | packetType := reader.TryReadUInt8() |
| 33 | reader.SkipBits(40) | 55 | reader.SkipBits(40) |
| @@ -119,7 +141,17 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 119 | packetReader.SkipBytes(2) | 141 | packetReader.SkipBytes(2) |
| 120 | packetReader.SkipBits(uint64(packetReader.TryReadUInt16())) | 142 | packetReader.SkipBits(uint64(packetReader.TryReadUInt16())) |
| 121 | case 16: | 143 | case 16: |
| 122 | packetReader.TryReadString() | 144 | print := packetReader.TryReadString() |
| 145 | re := regexp.MustCompile(`Server Number: (\d+)`) | ||
| 146 | match := re.FindStringSubmatch(print) | ||
| 147 | if len(match) >= 1 { | ||
| 148 | serverNumber := match[1] | ||
| 149 | n, err := strconv.Atoi(serverNumber) | ||
| 150 | if err != nil { | ||
| 151 | return Result{}, err | ||
| 152 | } | ||
| 153 | result.ServerNumber = n | ||
| 154 | } | ||
| 123 | case 17: | 155 | case 17: |
| 124 | var length uint16 | 156 | var length uint16 |
| 125 | if packetReader.TryReadBool() { | 157 | if packetReader.TryReadBool() { |
| @@ -180,8 +212,8 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 180 | NumPortals: userMessageReader.TryReadSInt32(), | 212 | NumPortals: userMessageReader.TryReadSInt32(), |
| 181 | TimeTaken: userMessageReader.TryReadSInt32(), | 213 | TimeTaken: userMessageReader.TryReadSInt32(), |
| 182 | } | 214 | } |
| 183 | portalCount = int(scoreboardTempUpdate.NumPortals) | 215 | result.PortalCount = int(scoreboardTempUpdate.NumPortals) |
| 184 | tickCount = int(math.Round(float64((float32(scoreboardTempUpdate.TimeTaken) / 100.0) / float32(1.0/60.0)))) | 216 | result.TickCount = int(math.Round(float64((float32(scoreboardTempUpdate.TimeTaken) / 100.0) / float32(1.0/60.0)))) |
| 185 | } | 217 | } |
| 186 | case 24: | 218 | case 24: |
| 187 | packetReader.SkipBits(20) | 219 | packetReader.SkipBits(20) |
| @@ -216,8 +248,8 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 216 | packetReader.SkipBytes(packetReader.TryReadBits(32)) | 248 | packetReader.SkipBytes(packetReader.TryReadBits(32)) |
| 217 | case 33: | 249 | case 33: |
| 218 | packetReader.SkipBits(packetReader.TryReadBits(32)) | 250 | packetReader.SkipBits(packetReader.TryReadBits(32)) |
| 219 | default: | 251 | // default: |
| 220 | return 0, 0, "", "", errors.New("unknown msg type") | 252 | // return Result{}, errors.New(fmt.Sprintf("unknown msg type %d", messageType)) |
| 221 | } | 253 | } |
| 222 | } | 254 | } |
| 223 | case 3, 7: | 255 | case 3, 7: |
| @@ -252,7 +284,7 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 252 | if stringTableReader.TryReadBool() { | 284 | if stringTableReader.TryReadBool() { |
| 253 | byteLen, err := stringTableReader.ReadBits(16) | 285 | byteLen, err := stringTableReader.ReadBits(16) |
| 254 | if err != nil { | 286 | if err != nil { |
| 255 | return 0, 0, "", "", errors.New("error on reading entry length") | 287 | return Result{}, errors.New("error on reading entry length") |
| 256 | } | 288 | } |
| 257 | stringTableEntryReader := bitreader.NewReaderFromBytes(stringTableReader.TryReadBytesToSlice(byteLen), true) | 289 | stringTableEntryReader := bitreader.NewReaderFromBytes(stringTableReader.TryReadBytesToSlice(byteLen), true) |
| 258 | if tableName == "userinfo" { | 290 | if tableName == "userinfo" { |
| @@ -285,10 +317,14 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 285 | userInfo.FilesDownloaded = stringTableEntryReader.TryReadUInt8() | 317 | userInfo.FilesDownloaded = stringTableEntryReader.TryReadUInt8() |
| 286 | stringTableEntryReader.SkipBytes(3) | 318 | stringTableEntryReader.SkipBytes(3) |
| 287 | if guidCount == 0 { | 319 | if guidCount == 0 { |
| 288 | hostSteamID = userInfo.GUID | 320 | result.HostSteamID = userInfo.GUID |
| 321 | if strings.Contains(serverName, "localhost") { | ||
| 322 | result.IsHost = true | ||
| 323 | } | ||
| 289 | } else if guidCount == 1 { | 324 | } else if guidCount == 1 { |
| 290 | partnerSteamID = userInfo.GUID | 325 | result.PartnerSteamID = userInfo.GUID |
| 291 | } | 326 | } |
| 327 | guidCount++ | ||
| 292 | } | 328 | } |
| 293 | } | 329 | } |
| 294 | } | 330 | } |
| @@ -303,11 +339,139 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 303 | } | 339 | } |
| 304 | } | 340 | } |
| 305 | default: | 341 | default: |
| 306 | return 0, 0, "", "", errors.New("invalid packet type") | 342 | return Result{}, errors.New("invalid packet type") |
| 307 | } | 343 | } |
| 308 | if packetType == 7 { | 344 | if packetType == 7 { |
| 309 | break | 345 | break |
| 310 | } | 346 | } |
| 311 | } | 347 | } |
| 312 | return portalCount, tickCount, hostSteamID, partnerSteamID, nil | 348 | return result, nil |
| 349 | } | ||
| 350 | |||
| 351 | var mapDict = map[string]int{ | ||
| 352 | "sp_a1_intro1": 1, | ||
| 353 | "sp_a1_intro2": 2, | ||
| 354 | "sp_a1_intro3": 3, | ||
| 355 | "sp_a1_intro4": 4, | ||
| 356 | "sp_a1_intro5": 5, | ||
| 357 | "sp_a1_intro6": 6, | ||
| 358 | "sp_a1_intro7": 7, | ||
| 359 | "sp_a1_wakeup": 8, | ||
| 360 | "sp_a2_intro": 9, | ||
| 361 | |||
| 362 | "sp_a2_laser_intro": 10, | ||
| 363 | "sp_a2_laser_stairs": 11, | ||
| 364 | "sp_a2_dual_lasers": 12, | ||
| 365 | "sp_a2_laser_over_goo": 13, | ||
| 366 | "sp_a2_catapult_intro": 14, | ||
| 367 | "sp_a2_trust_fling": 15, | ||
| 368 | "sp_a2_pit_flings": 16, | ||
| 369 | "sp_a2_fizzler_intro": 17, | ||
| 370 | |||
| 371 | "sp_a2_sphere_peek": 18, | ||
| 372 | "sp_a2_ricochet": 19, | ||
| 373 | "sp_a2_bridge_intro": 20, | ||
| 374 | "sp_a2_bridge_the_gap": 21, | ||
| 375 | "sp_a2_turret_intro": 22, | ||
| 376 | "sp_a2_laser_relays": 23, | ||
| 377 | "sp_a2_turret_blocker": 24, | ||
| 378 | "sp_a2_laser_vs_turret": 25, | ||
| 379 | "sp_a2_pull_the_rug": 26, | ||
| 380 | |||
| 381 | "sp_a2_column_blocker": 27, | ||
| 382 | "sp_a2_laser_chaining": 28, | ||
| 383 | "sp_a2_triple_laser": 29, | ||
| 384 | "sp_a2_bts1": 30, | ||
| 385 | "sp_a2_bts2": 31, | ||
| 386 | |||
| 387 | "sp_a2_bts3": 32, | ||
| 388 | "sp_a2_bts4": 33, | ||
| 389 | "sp_a2_bts5": 34, | ||
| 390 | "sp_a2_core": 35, | ||
| 391 | |||
| 392 | "sp_a3_01": 36, | ||
| 393 | "sp_a3_03": 37, | ||
| 394 | "sp_a3_jump_intro": 38, | ||
| 395 | "sp_a3_bomb_flings": 39, | ||
| 396 | "sp_a3_crazy_box": 40, | ||
| 397 | "sp_a3_transition01": 41, | ||
| 398 | |||
| 399 | "sp_a3_speed_ramp": 42, | ||
| 400 | "sp_a3_speed_flings": 43, | ||
| 401 | "sp_a3_portal_intro": 44, | ||
| 402 | "sp_a3_end": 45, | ||
| 403 | |||
| 404 | "sp_a4_intro": 46, | ||
| 405 | "sp_a4_tb_intro": 47, | ||
| 406 | "sp_a4_tb_trust_drop": 48, | ||
| 407 | "sp_a4_tb_wall_button": 49, | ||
| 408 | "sp_a4_tb_polarity": 50, | ||
| 409 | "sp_a4_tb_catch": 51, | ||
| 410 | "sp_a4_stop_the_box": 52, | ||
| 411 | "sp_a4_laser_catapult": 53, | ||
| 412 | "sp_a4_laser_platform": 54, | ||
| 413 | "sp_a4_speed_catch": 55, | ||
| 414 | "sp_a4_jump_polarity": 56, | ||
| 415 | |||
| 416 | "sp_a4_finale1": 57, | ||
| 417 | "sp_a4_finale2": 58, | ||
| 418 | "sp_a4_finale3": 59, | ||
| 419 | "sp_a4_finale4": 60, | ||
| 420 | |||
| 421 | "mp_coop_start": 61, | ||
| 422 | "mp_coop_lobby_2": 62, | ||
| 423 | |||
| 424 | "mp_coop_doors": 63, | ||
| 425 | "mp_coop_race_2": 64, | ||
| 426 | "mp_coop_laser_2": 65, | ||
| 427 | "mp_coop_rat_maze": 66, | ||
| 428 | "mp_coop_laser_crusher": 67, | ||
| 429 | "mp_coop_teambts": 68, | ||
| 430 | |||
| 431 | "mp_coop_fling_3": 69, | ||
| 432 | "mp_coop_infinifling_train": 70, | ||
| 433 | "mp_coop_come_along": 71, | ||
| 434 | "mp_coop_fling_1": 72, | ||
| 435 | "mp_coop_catapult_1": 73, | ||
| 436 | "mp_coop_multifling_1": 74, | ||
| 437 | "mp_coop_fling_crushers": 75, | ||
| 438 | "mp_coop_fan": 76, | ||
| 439 | |||
| 440 | "mp_coop_wall_intro": 77, | ||
| 441 | "mp_coop_wall_2": 78, | ||
| 442 | "mp_coop_catapult_wall_intro": 79, | ||
| 443 | "mp_coop_wall_block": 80, | ||
| 444 | "mp_coop_catapult_2": 81, | ||
| 445 | "mp_coop_turret_walls": 82, | ||
| 446 | "mp_coop_turret_ball": 83, | ||
| 447 | "mp_coop_wall_5": 84, | ||
| 448 | |||
| 449 | "mp_coop_tbeam_redirect": 85, | ||
| 450 | "mp_coop_tbeam_drill": 86, | ||
| 451 | "mp_coop_tbeam_catch_grind_1": 87, | ||
| 452 | "mp_coop_tbeam_laser_1": 88, | ||
| 453 | "mp_coop_tbeam_polarity": 89, | ||
| 454 | "mp_coop_tbeam_polarity2": 90, | ||
| 455 | "mp_coop_tbeam_polarity3": 91, | ||
| 456 | "mp_coop_tbeam_maze": 92, | ||
| 457 | "mp_coop_tbeam_end": 93, | ||
| 458 | |||
| 459 | "mp_coop_paint_come_along": 94, | ||
| 460 | "mp_coop_paint_redirect": 95, | ||
| 461 | "mp_coop_paint_bridge": 96, | ||
| 462 | "mp_coop_paint_walljumps": 97, | ||
| 463 | "mp_coop_paint_speed_flings": 98, | ||
| 464 | "mp_coop_paint_red_racer": 99, | ||
| 465 | "mp_coop_paint_speed_catch": 100, | ||
| 466 | "mp_coop_paint_longjump_intro": 101, | ||
| 467 | |||
| 468 | "mp_coop_seperation_1": 102, | ||
| 469 | "mp_coop_tripleaxis": 103, | ||
| 470 | "mp_coop_catapult_catch": 104, | ||
| 471 | "mp_coop_2paints_1bridge": 105, | ||
| 472 | "mp_coop_paint_conversion": 106, | ||
| 473 | "mp_coop_bridge_catch": 107, | ||
| 474 | "mp_coop_laser_tbeam": 108, | ||
| 475 | "mp_coop_paint_rat_maze": 109, | ||
| 476 | "mp_coop_paint_crazy_box": 110, | ||
| 313 | } | 477 | } |