Coder Social home page Coder Social logo

r6-dissect's Introduction

r6-dissect

Go Reference

Match Replay API/CLI for Rainbow Six: Siege's Dissect (.rec) format.

This is a work in progress. The data format is subject to change until a stable version is released.

Current Features

  • Match Info (Game version, map, gamemode, match type, teams, players)
  • Match Feedback (Kills, headshots, objective locates, defuser plants/disables, BattlEye bans, DCs)
  • JSON or Excel output

Planned Features

  • UI alternative
  • Track bullet hits/misses
  • Track movement packets
  • Track other player statistics

CLI Usage

Print a match overview by specifying a match folder or .rec file:

r6-dissect --info Match-2023-03-13_23-23-58-199
# or
r6-dissect --info Match-2023-03-13_23-23-58-199-R01.rec
5:20PM INF Version:          Y8S1/7422506
5:20PM INF Recording Player: redraskal [1f63af29-7ebe-48e7-b570-e820632d9565]
5:20PM INF Match ID:         d74d2685-193f-4fee-831f-41f8c7792250
5:20PM INF Timestamp:        2023-03-13 13:00:08 -0500 CDT
5:20PM INF Match Type:       QuickMatch
5:20PM INF Game Mode:        Bomb
5:20PM INF Map:              House

You can export round stats to a JSON file:

r6-dissect Match-2023-03-13_23-23-58-199-R01.rec -o round.json

Example:

{
  "gameVersion": "Y8S1",
  "codeVersion": 7422506,
  "timestamp": "2023-03-13T23:25:46Z",
  "matchType": {
    "name": "Ranked",
    "id": 2
  },
  "map": {
    "name": "Villa",
    "id": 88107330328
  },
  "site": "2F Aviator Room, 2F Games Room",
  "recordingPlayerID": 15451868541914624436,
  "recordingProfileID": "1f63af29-7ebe-48e7-b570-e820632d9565",
  "additionalTags": "423855620",
  "gamemode": {
    "name": "Bomb",
    "id": 327933806
  },
...
  "teams": [
    {
      "name": "YOUR TEAM",
      "score": 1,
      "won": true,
      "winCondition": "KilledOpponents",
      "role": "Attack"
    },
    {
      "name": "OPPONENTS",
      "score": 0,
      "won": false,
      "role": "Defense"
    }
  ],
  "players": [
    {
      "id": 1830934665040226621,
      "profileID": "f33396d4-714b-442d-b110-9237e291cc71",
      "username": "IanFiftyForty",
      "teamIndex": 1,
      "operator": {
        "name": "Oryx",
        "id": 104189664155
      },
      "heroName": 243632506966,
      "alliance": 0,
      "roleImage": 104189664090,
      "roleName": "ORYX",
      "rolePortrait": 258649622576
    },
...
  "matchFeedback": [
    {
      "type": "Other",
      "time": "2:59",
      "timeInSeconds": 179,
      "message": "Friendly Fire is now active"
    },
    {
      "type": "Kill",
      "username": "ReithYT",
      "target": "Ambatakum.",
      "headshot": false,
      "time": "1:51",
      "timeInSeconds": 111
    },
...

Or the entire match:

r6-dissect Match-2023-03-13_23-23-58-199 -o match.json

Export an Excel spreadsheet by swapping .json with .xlsx.

r6-dissect Match-2023-03-13_23-23-58-199-R01 -o match.xlsx

Output JSON to the console (stdout) with the following syntax:

# entire match
r6-dissect Match-2023-03-13_23-23-58-199-R01
# or single round
r6-dissect Match-2023-03-13_23-23-58-199-R01/Match-2023-03-13_23-23-58-199-R01.rec

See example outputs in /examples.

Importing a .rec file

package main

import (
	"log"
	"os"

	"github.com/redraskal/r6-dissect/dissect"
)

func main() {
	f, err := os.Open("Match-2023-03-13_23-23-58-199-R01.rec")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	r, err := dissect.NewReader(f)
	if err != nil {
		log.Fatal(err)
	}
	// Use r.ReadPartial() for faster reads with less data (designed to fill in data gaps in the header)
	// dissect.Ok(err) returns true if the error only pertains to EOF (read was successful)
	if err := r.Read(); !dissect.Ok(err) {
		log.Fatal(err)
	}
	print(r.Header.GameVersion) // Y8S1
}

I would like to thank stnokott for their work on r6-dissect, along with draguve & other contributors at draguve/R6-Replays for their additional reverse engineering work.

r6-dissect's People

Contributors

f870103 avatar redraskal avatar stnokott avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

r6-dissect's Issues

1F Open Area name shows up in json as Lockers/CCTV

Describe the bug
1st floor Open Area site name on Bank is detected as Lockers/CCTV (only played once, so I don't know if it is a one off)
It seems like just the name is but I am not sure. All other sites are fine
To Reproduce
Steps to reproduce the behavior:
Play a round on Open area

Expected behavior
A clear and concise description of what you expected to happen.
Open area would be detected as 1F Staff Room, 1F Open Area

Additional context
This was in a custom game if that makes any difference

Can't analyze any match replay after `v0.21.1` release

Describe the bug
v0.21.1 is not able to analyze any match replay.

To Reproduce
Steps to reproduce the behavior:

  1. Try to analyze any Y9S2.2 match.
  2. Received the following error message:
    PS E:\Uplay\games\Tom Clancy's Rainbow Six Siege\MatchReplay> .\r6-dissect.exe -f json -o 1.json .\Match-2024-07-21_03-08-51-27\
    panic: role unknown for operator ID 0
    
    goroutine 1 [running]:
    github.com/redraskal/r6-dissect/dissect.Operator.Role(...)
        /github/workspace/dissect/operator_roles.go:86
    github.com/redraskal/r6-dissect/dissect.readSpawn(0xc006e62248)
        /github/workspace/dissect/site.go:32 +0x505
    github.com/redraskal/r6-dissect/dissect.(*Reader).Read(0xc006e62248)
        /github/workspace/dissect/reader.go:221 +0x543
    github.com/redraskal/r6-dissect/dissect.(*MatchReader).read(0xc0002f4460, 0x3)
        /github/workspace/dissect/match.go:73 +0x210
    github.com/redraskal/r6-dissect/dissect.(*MatchReader).Read(...)
        /github/workspace/dissect/match.go:78
    main.writeMatch(0x50e015?, {0xc00009e090, 0x4}, {0x59a780, 0xc0000901f8})
        /github/workspace/main.go:155 +0x72
    main.main()
        /github/workspace/main.go:64 +0x547
    

Expected behavior
The commands should function as they did prior to the latest release, providing match info and exporting files correctly.

Defense Site sometimes missing

Describe the bug
In some rounds, the defense site is not recorded.

Expected behavior
The defense site should always be present in the Header.

1v1 custom game rounds fail to index 1 team

Describe the bug
In 1v1s on custom games, one team is missing from player data. This causes r6-dissect to panic when calculating the winning team.

image

To Reproduce
Steps to reproduce the behavior:

  1. Create custom game
  2. Play a 1v1 round
  3. Run r6-dissect on the round file

Expected behavior
All players should be indexed by r6-dissect

Incorrect player spawns for Y7S4 replays

Describe the bug
Hey there, sorry to keep bothering.

All my replays from Y7S4 currently produce incorrect spawns / roles for some rounds.
I am running on your most recent commit on main (d934da6).

For the affected rounds, the spawn is filled for all players. For the attackers, it's their actual spawn, for the defenders though, it's the same spawn for all:

  "teams": [
    {
      "name": "YOUR TEAM",
      "score": 1,
      "won": true,
      "winCondition": "DISABLED_DEFUSER",
      "role": "ATTACK"
    },
    {
      "name": "OPPONENTS",
      "score": 2,
      "won": false,
      "role": "ATTACK"
    }
  ],
  "players": [
    {
      "id": 6074306815492722120,
      "profileID": "fa94e165-6328-4a9b-8581-81735ffaba27",
      "username": "Knoblauch.SOOS",
      "teamIndex": 0,
      "heroName": 189095391481,
      "alliance": 0,
      "roleImage": 104189662842,
      "roleName": "WARDEN",
      "rolePortrait": 104189662868,
      "spawn": "Christmas Market"
    },
    {
      "id": 11698620738034145238,
      "profileID": "b65a0d8d-b676-4d02-9eee-e9c3756d942b",
      "username": "Oliver124",
      "teamIndex": 0,
      "heroName": 153816116120,
      "alliance": 0,
      "roleImage": 161289666176,
      "roleName": "KAID",
      "rolePortrait": 161289666206,
      "spawn": "Christmas Market"
    },
    {
      "id": 8602592387850206533,
      "profileID": "2198c78f-fdb5-4494-93a3-2da39b5f1dc0",
      "username": "KTKrueger",
      "teamIndex": 0,
      "heroName": 423855893,
      "alliance": 0,
      "roleImage": 1326495635,
      "roleName": "KAPKAN",
      "rolePortrait": 27880706822,
      "spawn": "Christmas Market"
    },
    {
      "id": 6250949426960069847,
      "profileID": "bf597fa6-ca43-4ceb-9fd3-644aacf6fb99",
      "username": "Vanille.SOOS",
      "teamIndex": 0,
      "heroName": 350237839,
      "alliance": 0,
      "roleImage": 1494825836,
      "roleName": "ROOK",
      "rolePortrait": 27880706877,
      "spawn": "Christmas Market"
    },
    {
      "id": 17944097535649856136,
      "profileID": "f1080efc-58a1-4c15-aaad-f2ca8fad21a7",
      "username": "Chili.SOOS",
      "teamIndex": 0,
      "heroName": 423855917,
      "alliance": 0,
      "roleImage": 1494825824,
      "roleName": "CASTLE",
      "rolePortrait": 27880706756,
      "spawn": "Christmas Market"
    },
    {
      "id": 4087786036330991033,
      "profileID": "e3b1a612-81c3-4b80-9c3d-2e7c9fbbde2c",
      "username": "natalieczka",
      "teamIndex": 1,
      "alliance": 0,
      "spawn": "River Docks"
    },
    {
      "id": 16756575710445550787,
      "profileID": "0023824a-ea2b-483b-a5dd-e8fa8e4e09b2",
      "username": "GOATMysterion",
      "teamIndex": 1,
      "alliance": 0,
      "spawn": "River Docks"
    },
    {
      "id": 6705769074279472193,
      "profileID": "b96de89b-8624-405d-af5c-22a5bb4a9ea2",
      "username": "LuluTwentyFaces",
      "teamIndex": 1,
      "alliance": 0,
      "spawn": "Park"
    },
    {
      "id": 17715213864621837973,
      "profileID": "cbf919f7-0ef8-4435-b5df-cbc8f4b0ded1",
      "username": "You296",
      "teamIndex": 1,
      "alliance": 0,
      "spawn": "Christmas Market"
    },
    {
      "id": 14086110198522065878,
      "profileID": "dc16e35d-fd9b-41ca-aa2e-5c1d5e9a4840",
      "username": "Sniper07Paul",
      "teamIndex": 1,
      "alliance": 0,
      "spawn": "RANDOM"
    }
  ],

As a byproduct, this also results in wrong team roles since you are deriving them from the spawn:

if spawn == "" {
p.Alliance = 4
r.Header.Teams[teamIndex].Role = DEFENSE
} else {
r.Header.Teams[teamIndex].Role = ATTACK
}

To Reproduce
Steps to reproduce the behavior:

  1. Use the replay files I already sent you via email
  2. Parse rounds 3 or 4 of those files
  3. See how you get ATTACK role for both teams and inconsistent spawns

Expected behavior
Empty spawns for defenders and no duplicate team roles.

Additional context
I don't have any Y8S1 replays yet, so can't check with those.
For Y7S4, I can confirm though that all replays I have produce this issue. I also tested with some replays of SI '23.

Also, it seems like the issue only pops up after the first role swap, i.e. the first few rounds of a match are usually fine.

Incorrect `matchFeedback` message in JSON output

I'm encountering an issue with the matchFeedback field in the JSON output file generated by version v0.19.0 when using a Y9S1 replay file.
The message property within matchFeedback objects contains unreadable characters like \ufffd\ufffd\ufffd\ufffd and \ufffd\ufffd\u0005\u0000.

"matchFeedback": [{
                    "type": {
                        "name": "Other",
                        "id": 10
                    },
                    "time": "0:00",
                    "timeInSeconds": 0,
                    "message": "\ufffd\ufffd\ufffd\ufffd"
                }, {
                    "type": {
                        "name": "Other",
                        "id": 10
                    },
                    "time": "0:00",
                    "timeInSeconds": 0,
                    "message": "\ufffd\ufffd\u0005\u0000"
                }, {
                    "type": {
                        "name": "Other",
                        "id": 10
                    },
                    "time": "2:59",
                    "timeInSeconds": 179,
                    "message": "\ufffd\ufffd\u0005\u0000"
                },

This issue has been observed on all my standard matches so far. I'm not sure if other match types are affected.

Match-2024-03-13_22-26-58-200-R01.zip
Match-2024-03-13_22-26-58-200.json

1vX stat broken when plant is down

The 1vX stat does not appear for a player that won a 1vX then defused. The score for the teams increased properly, but the win boolean is set to false for their team. I believe this is what makes the 1vx not appear. The 1vx does appear for a player on the team that planted - although this person lost the 1v1.

Snippets of json
{
"name": "YOUR TEAM",
"score": 4,
"won": true,
"winCondition": "DefusedBomb",
"role": "Attack"
},
{
"name": "OPPONENTS",
"score": 1,
"won": false,
"role": "Defense"
}

"Opponents" won here, but won is set to false.

{
"type": {
"name": "DefuserPlantStart",
"id": 2
},
"username": "UNiTY_Imp3r1um",
"time": "0:54",
"timeInSeconds": 54
},
{
"type": {
"name": "DefuserPlantComplete",
"id": 3
},
"username": "UNiTY_Imp3r1um",
"time": "0:47",
"timeInSeconds": 47
},
{
"type": {
"name": "Kill",
"id": 0
},
"username": "DugBolt_MCC",
"target": "Yeti_.AWP",
"headshot": true,
"time": "0:29",
"timeInSeconds": 29
},
{
"type": {
"name": "Kill",
"id": 0
},
"username": "DugBolt_MCC",
"target": "UNiTY_Imp3r1um",
"headshot": true,
"time": "0:16",
"timeInSeconds": 16
},
{
"type": {
"name": "DefuserDisableStart",
"id": 4
},
"username": "DugBolt_MCC",
"time": "0:11",
"timeInSeconds": 11
}
}

Unity planted and was left in a 2 (atk) v 1 (def). DugBolt killed Unity and Yeti, then defused.

{
"username": "DugBolt_MCC",
"score": 1528,
"kills": 5,
"died": false,
"assists": 0,
"headshots": 3,
"headshotPercentage": 60
},
{
"username": "UNiTY_Imp3r1um",
"score": 0,
"kills": 0,
"died": true,
"assists": 0,
"headshots": 0,
"headshotPercentage": 0,
"1vX": 1
},

DugBolt does not have a 1vx, and Unity does.

Json from the round, .rec is in discord server
Round5.json

"won" attribute set inconsistently with "score" attribute for defuser planted in last second edge case

Describe the bug
Team can be marked as having won a round even though the lost it. Score is updated correctly.

To Reproduce
I believe this issue is caused when the defuser is finished being planted after the action phase ends. In the case I found, there was a 1v1 in the last seconds of the round. The attacker planted the defuser, starting before the round ended, and finishing after the round would have ended. This, of course, adds 45s to the timer for the defender to stop the defuser. In this case, that happened. The defender killed the attacker and stopped the defuser. The following was output to the JSON after running r6-dissect

"teams": [
    {
        "name": "Kenough Uni",
        "score": 6,
        "won": false,
        "role": "Defense"
    },
    {
        "name": "UC Acad",
        "score": 0,
        "won": true,
        "winCondition": "DefusedBomb",
        "role": "Attack"
    }

Expected behavior
The "won" value should be flipped for each team. "Kenough Uni" should have true for "won" and "UC Acad" false.

Player ID's are all the same

Describe the bug
Within the players object all the ids associated for each individual player appear to be the same. Additionally some replays have the same ID as the previous, however others don't

Replays of the new season Deep Freeze all cause the same error

I've tried multiple match replay folders as well as match replay files and all of them cause 'FTL error="dissect: received an invalid length of bytes"'.

The match replays I am talking about were generated by the game with the new Deep Freeze patch installed.
I am using the r6-dissect.exe from the most recent Windows release.

All players have same team indexes.

All 10 players have the same team index. They should be seperated into 2 teams.

One example:

{
    "header":{
        "gameVersion":"Y7S4",
        "codeVersion":7338571,
        "timestamp":"2023-01-20T21:14:32Z",
        "matchType":{
            "name":"UNRANKED",
            "id":12
        },
        "map":{
            "name":"KANAL",
            "id":1460220617
        },
        "recordingPlayerID":"16470266420671064662",
        "recordingProfileID":"5305afe0-0522-4c97-8d99-3f49911fac78",
        "additionalTags":"423855620",
        "gamemode":{
            "name":"BOMB",
            "id":327933806
        },
        "roundsPerMatch":6,
        "roundsPerMatchOvertime":3,
        "roundNumber":0,
        "overtimeRoundNumber":0,
        "teams":[
            {
                "name":"你方队伍",
                "score":0
            },
            {
                "name":"敌人",
                "score":1
            }
        ],
        "players":[
            {
                "id":"14364323565883972756",
                "profileID":"56aed88e-4377-47d1-a7e1-eb22ff11f803",
                "username":"h--hoo",
                "teamIndex":1,
                "heroName":38576460310,
                "alliance":4,
                "roleImage":39149215589,
                "roleName":"ELA",
                "rolePortrait":39149215613
            },
            {
                "id":"330586818339081656",
                "profileID":"e938e123-8f85-4037-8cbe-4c7a1b5356e6",
                "username":"WF030829",
                "teamIndex":1,
                "heroName":9147168387,
                "alliance":4,
                "roleImage":32822532301,
                "roleName":"FROST",
                "rolePortrait":27880782933
            },
            {
                "id":"14226176432092997577",
                "profileID":"5c6a0c73-af67-4aaa-bc65-262fbaef7bd4",
                "username":"EggZong",
                "teamIndex":1,
                "heroName":423855857,
                "alliance":4,
                "roleImage":1494825830,
                "roleName":"MUTE",
                "rolePortrait":27880706844
            },
            {
                "id":"10087852244609720090",
                "profileID":"2fccd99a-7e6d-4c85-b4bc-a4aef4aac10c",
                "username":"momnkke",
                "teamIndex":1,
                "heroName":350237839,
                "alliance":4,
                "roleImage":1494825836,
                "roleName":"ROOK",
                "rolePortrait":27880706877
            },
            {
                "id":"7319414423521281910",
                "profileID":"4017bf4e-8304-49f8-8eda-a9ec432dbe0a",
                "username":"tony_122203",
                "teamIndex":1,
                "heroName":350237879,
                "alliance":4,
                "roleImage":1326495671,
                "roleName":"BANDIT",
                "rolePortrait":27880706734
            },
            {
                "id":"",
                "profileID":"5305afe0-0522-4c97-8d99-3f49911fac78",
                "username":"dev_ken",
                "teamIndex":1,
                "heroName":0,
                "alliance":0,
                "roleImage":0,
                "roleName":"",
                "rolePortrait":0
            },
            {
                "id":"",
                "profileID":"30c2b6dd-bd40-47c3-9421-e2e26a2c08b5",
                "username":"twists.",
                "teamIndex":1,
                "heroName":0,
                "alliance":0,
                "roleImage":0,
                "roleName":"",
                "rolePortrait":0
            },
            {
                "id":"",
                "profileID":"6bc5e638-a3b1-4bfc-8378-52a6daddab21",
                "username":"Lry10Justin",
                "teamIndex":1,
                "heroName":0,
                "alliance":0,
                "roleImage":0,
                "roleName":"",
                "rolePortrait":0
            },
            {
                "id":"",
                "profileID":"488b3fdd-0e85-460a-b17a-031c73edc612",
                "username":"linijn",
                "teamIndex":1,
                "heroName":0,
                "alliance":0,
                "roleImage":0,
                "roleName":"",
                "rolePortrait":0
            },
            {
                "id":"",
                "profileID":"8397931b-139a-4f65-89e0-527955b8f126",
                "username":"xjy630",
                "teamIndex":1,
                "heroName":0,
                "alliance":0,
                "roleImage":0,
                "roleName":"",
                "rolePortrait":0
            }
        ],
        "gmSettings":[
            245225394808,
            245225394853,
            245225394902
        ],
        "playlistCategory":245225348548,
        "matchID":"28b72e2e-cb91-4565-a4c8-fdba2b6171a0"
    },
    "activityFeed":[
        {
            "type":"KILL",
            "username":"twists.",
            "target":"WF030829",
            "headshot":true
        },
        {
            "type":"KILL",
            "username":"dev_ken",
            "target":"h--hoo",
            "headshot":false
        },
        {
            "type":"KILL",
            "username":"dev_ken",
            "target":"EggZong",
            "headshot":true
        },
        {
            "type":"KILL",
            "username":"momnkke",
            "target":"Lry10Justin",
            "headshot":false
        },
        {
            "type":"KILL",
            "username":"momnkke",
            "target":"dev_ken",
            "headshot":false
        },
        {
            "type":"KILL",
            "username":"tony_122203",
            "target":"linijn",
            "headshot":false
        },
        {
            "type":"KILL",
            "username":"twists.",
            "target":"tony_122203",
            "headshot":false
        },
        {
            "type":"KILL",
            "username":"momnkke",
            "target":"twists.",
            "headshot":false
        },
        {
            "type":"KILL",
            "username":"WF030829",
            "target":"xjy630",
            "headshot":false
        }
    ]
}

`ReadPartial` and `Read` yield conflicting operator data

Using r6-dissect as a Go package and reading the same replay file once with Read and once with ReadPartial yields different operator IDs in some cases.

Minimum reproducible example can be found here: https://github.com/stnokott/r6-dissect-test

The above program prints the following output (for the same replay file):

2023/03/21 14:14:30 full players:
2023/03/21 14:14:30 0: Solis (391752120891)
2023/03/21 14:14:30 1: Capitao (92270644215)
2023/03/21 14:14:30 2: Amaru (104189663607)
2023/03/21 14:14:30 3: Caveira (92270644241)
2023/03/21 14:14:30 4: Rook (92270644059)
2023/03/21 14:14:30 5: Glaz (92270642084)
2023/03/21 14:14:30 6: Lion (104189661861)
2023/03/21 14:14:30 7: Smoke (92270642396)
2023/03/21 14:14:30 8: Mozzie (174977508820)
2023/03/21 14:14:30 9: Blitz (92270642539)

2023/03/21 14:14:30 partial players:
2023/03/21 14:14:30 0: Solis (391752120891)
2023/03/21 14:14:30 1: Capitao (92270644215)
2023/03/21 14:14:30 2: Ash (92270642656)
2023/03/21 14:14:30 3: Caveira (92270644241)
2023/03/21 14:14:30 4: Rook (92270644059)
2023/03/21 14:14:30 5: Glaz (92270642084)
2023/03/21 14:14:30 6: Lion (104189661861)
2023/03/21 14:14:30 7: Smoke (92270642396)
2023/03/21 14:14:30 8: Mozzie (174977508820)
2023/03/21 14:14:30 9: Twitch (92270644111)

As mentioned above, indices 2 and 9 have different operator IDs for the two reads.

Opponents team player is not in the player list.

Is your feature request related to a problem? Please describe.
I am working on a project that depend on reading R6 replays. I tried this repo and find it amazing.
I noticed players in the opponents team is not in that player list in the output json file.
Will it be possible to have that?

Describe alternatives you've considered
For now, I can just use information in activity feed, record any player mentioned not in the player list to obtain extra info.

Test if every operator has a role

As discussed in #29 , a test to check whether our map[operator]role is missing any operators.
One approach could be:

  1. use reflect or golang.org/x/tools/go/packages to go through header.go, finding all constants of type Operator
  2. for each const we find, check if Operator.Role() returns an error
  3. if we have no errors, we know that each of our operators has a role assigned

@redraskal do you think we should also add a test that queries the Ubisoft page to check if we are missing any operators in header.go that are present in the game?

New Operator

Describe the bug
Needs to be updated to include the new operator Fenrir. Crashes: "role unknown for operator ID 288200867339"
I tried adding it myself in operator_roles.go and operator_string.go but now getting "role unknown for operator ID 0"

To Reproduce
Steps to reproduce the behavior:

  1. Play a match and make sure the new operator Fenrir is in match.
  2. Try to run the dessector on the match replay files
  3. Crashes...

Live Match Information

Hello, @redraskal, @stnokott, and any other developers reading this.
A group of developers, along with myself are working to find the source for live match information on all platforms––some way to pass a profileId into the request, and get back a list of all opponents of that player in the match they are currently in.

There is currently a $1000 bounty for whoever solves this. All are welcome to participate in the research and investigation.

Please check out Seems2Legit/Rainbow-Six-Siege-Player-Stats-API#11

Increase Time Precision

Discussed in #64

Originally posted by f870103 August 12, 2023
The output precision is second, is it possible to set it to millisecond?

This will help a lot when tracking defuser-related events (e.g. defender team successfully counter-defused with less than one second to round end).

Also, is it possible to add events like DefuserPlantStop and DefuserDisableStop?

New Season Compatibility (r6-dissect-0.11.0)

Describe the bug
Executing the r6-dissect on replay files from Y8S2 with a json output will cause an error stopping the program from working

To Reproduce
Steps to reproduce the behavior:

  1. Open a cmd line in r6-dissect directory
  2. Type in the cmd line enter "r6-dissect | path of your replay file | -x | output file name.json |" (without quotations)

Expected behavior
A json file with the specified output name containing all the match details.

Additional context
InkedCapture

No additional context.

Support Y8S1

Dissect seems to no longer supply usernames except from a player packet (we already use this as a fallback). Hopefully, r6-dissect will have a compatible branch before the season launch

Attacker round victory by defusing counts as victory for the defenders

Match-2023-10-07_22-43-33-242-R06

The round I attached (file renamed to .png because of Github limitations) is the 6th round in a match. Defenders are leading 3:2. The attackers win this round by planting the defuser. The round ends after the 40 seconds defuser time-out (not by the attackers killing the defenders). Yet r6-dissect counts the round as a win for the defenders (by win condition 'Time').

Additionally, r6-dissect prints these two warnings:

  • 'WRN tracked players greater than 10'
  • 'WRN operator id was 0, removing from list username=Bucky-_-'

However, it prints these warnings for all 8 rounds of the match, not only for round 6 mentioned earlier, so I am not sure if those warnings are even related to original problem.

Recruit Operator not supported

Dissect will panic on rounds with Recruit.

Recruit does not have a defined team role. How should we handle this?

Operator ID: 359656345734

Missing operator IDs in header.go

Hey there,

while working on #31 , I discovered that header.go is missing a few operator IDs.
I guess that's also why I sometimes did not have an operator in my replay JSONs.

The operators in question are:

  • Blitz
  • Buck
  • Clash
  • Flores
  • Frost
  • Glaz
  • Gridlock
  • Grim
  • Hibana
  • IQ
  • Jackal
  • Maestro
  • Maverick
  • Oryx
  • Sens
  • Tachanka
  • Thatcher
  • Twitch

Create friendly UI for non-coding applications

Some ideas of mine:

  • Replay organization
  • Replay archiver
  • More convenient replay sharing
  • Spreadsheet/JSON exporting
  • Player heatmaps, animated or timestamped screenshots (down the line)

Example: friend shares replay. you had 12 saved beforehand. tool could automatically back them up and copy the replays you want to watch into the game files. the program could name them, while siege simply goes off of timestamps and maps. then, you have no clutter in the replay menu and know which replays belong to who. your previous replays are saved and can be loaded back into the game.

Feel free to suggest ideas below :)

Win condition "TIME" possibly assigned to wrong team

Describe the bug
When the win condition is TIME, sometimes, the wrong team gets the the won=true boolean set.
See this simple example of an exported JSON (exported with r6-dissect commit b593acf):

  [...]
  "teams": [
    {
      "name": "YOUR TEAM",
      "score": 0,
      "won": true,
      "winCondition": "TIME"
    },
    {
      "name": "OPPONENTS",
      "score": 1,
      "won": false
    }
  ],
  [...]

This is the first round of the match.
Since the score after this round is 0:1, won=true should be on the team with score=1, not score=0.

To Reproduce
Steps to reproduce the behavior:

  1. Export a round replay that ended on win condition "TIME" (I can't attach match replay files due to GitHub file type restrictions, if you need a file, I will PM it to you)
  2. See how the won=true value is sometimes* wrong

*note on "sometimes":
I don't have enough match replay files to find out under what conditions it is wrong, I suspect it does not always happen.
It might be related to whether the observing player starts as defender or attacker.

Expected behavior
won=true should be set on the winning team.

Additional context
All other win conditions seem correct, thus, I assume that the issue is related to this section:

r6-dissect/dissect/time.go

Lines 102 to 107 in b593acf

i := 0
if alliances[1] == 4 { // defender
i = 1
}
r.Header.Teams[i].Won = true
r.Header.Teams[i].WinCondition = TIME

This in turn relies on alliances which is set here:
alliances := make([]int, 2)
for _, p := range r.Header.Players {
sizes[p.TeamIndex] = sizes[p.TeamIndex] + 1
alliances[p.TeamIndex] = p.Alliance
}

I think this all boils down to the TeamIndex field being wrong as already partly discussed in #20, but I wanted to put this out there just to be sure in case it's actually related to a different issue.

Let me know if I can help with anything. I'm confident in Go, but not with the match replay file format, but I'll try my best.

Track Defense player spawns

Is your feature request related to a problem? Please describe.
Player spawn locations on defense are missing. This data is elsewhere in the file format since defense chooses a site instead of a spawn location.

Describe the solution you'd like
The spawn room names should be tracked on defense.

Track site

Discussed in #22

Originally posted by Sleepy-Git-User March 6, 2023
Hello, I was wondering if your able to see which site was played. As when reviewing the json example I couldnt seem to find it. Thanks.

Attack operators are sometimes incorrect

Describe the bug
Attack operator swaps during prep phase are not always present in replay files if an attacker swaps 2+ times.

Likely, we will need to find a new way to identify attack operators. I'm looking into reverse engineering the player spawning (hoping there will be some sort of identifier)

To Reproduce
Steps to reproduce the behavior:

  1. Create a custom game
  2. Swap attack operators 2+ times before prep phase ends
  3. Run r6-dissect
  4. Notice the operator may be incorrectly marked

Expected behavior
The operator in the player object should always be the operator the player runs when spawned into the round.

Inaccurate Repeating Site Names

Describe the bug
After running a few rec files from LATAM and Brazil BLAST on the new version of R6 Dissect I noticed Defender site names arent being reportedly properly and are repeating the same site name over and over again after getting a few correct.

To Reproduce
Steps to reproduce the behavior:

  1. Run R6 Dissect on a LATAM Blast match.
  2. Check a few of the sites being played in the JSON and youll see repeating sites.
  3. After checking the vod you can see the sites being reported are wrong.

Expected behavior
The JSONs should reflect the correct site being picked.

Additional context
Here is a vod link to one of the effect matches: https://www.youtube.com/live/sJ96LEBygNk?feature=share&t=2907,https://www.youtube.com/live/sJ96LEBygNk?feature=share&t=6783

Nether team wins a round.

In this case as shown below both teams won flag is set to false, with no win condition. Where in the case of this round team 0 won by KilledOpponents is the expected output.
"teams": [ { "name": "BLUE TEAM", "score": 3, "won": false, "role": "Attack" }, { "name": "ORANGE TEAM", "score": 3, "won": false, "role": "Defense" }

To Reproduce
Steps to reproduce the behaviour:

  1. Get the rec files for EUL2023 stage 1 play day 6 Chalet VP vs secret round 6.
  2. The JSON output for this round shows the above.

Expected behaviour
According to seige GG this round should be a win for secret by elimination:
https://siege.gg/matches/9109-eul-eu-team-secret-vs-virtuspro

for new replay files json key 'site' is missing

The json string returned by r6-dissect.exe doesn't contain the key 'site' (bomb site) anymore.

That is the case for all match replays since the latest balancing patch a few days ago. I tried some older replay files and those worked fine.

I am assuming they changed up the format of the replay files a bit.

Issues with bun

Describe the bug
When using dissectMatch from "r6-dissect" (from npm) you get the following error:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x188 pc=0x7ff117dd1a97]

goroutine 17 [running, locked to thread]:
github.com/redraskal/r6-dissect/dissect.(*Reader).PlayerStats(0x0)
        /github/workspace/dissect/stats.go:82 +0xb7
github.com/redraskal/r6-dissect/dissect.(*MatchReader).Data(0xc0001df280)
        /github/workspace/dissect/match.go:236 +0xbc
main.dissect_read(0x0?)
        /github/workspace/exports/exports.go:57 +0xd4
Aborted

When using dissect from "r6-dissect" you get the following error:
invalid input: magic number mismatch

To Reproduce
Steps to reproduce the behavior:

  1. Import the latest "r6-dissect" from NPM, using bun i r6-dissect
  2. Import the dissect/dissectMatch from "r6-dissect" (as one would normally with bun)
  3. Try to read the data of a Match directory / round .rec file; example const { data, error } = await dissectMatch("Match-2023-12-27_20-41-51-74/");
  4. Observe the error in console.

Expected behavior
I feel like the expected behavior is quite apparent but, I would expect it to console.log(data.matchID)

Additional context
This is running on Ubuntu 22.04 LTS via WSL
This is using the Latest Release of r6-dissect via NPM
This is also a fresh install of Ubuntu.

Add replay file tests

We should create some tests to read a few replay files and validate the data.

This would help test compatibility between multiple versions of Siege

Invalid Windows .dll

Describe the bug
Something is wrong with Windows .dll. I'm trying to port r6-dissect-bun to Node.js with node-ffi-napi.
It gives a V8 failure:

#
# Fatal error in , line 0
# Check failed: result.second.
#
#
#
#FailureMessage Object: 00000043CB2FBBD0
 1: 00007FF7DAA5815F v8::internal::CodeObjectRegistry::~CodeObjectRegistry+114079
 2: 00007FF7DA97343F std::basic_ostream<char,std::char_traits<char> >::operator<<+65023
 3: 00007FF7DB652D52 V8_Fatal+162
 4: 00007FF7DB0BE0CD v8::internal::BackingStore::Reallocate+637
 5: 00007FF7DB307849 v8::ArrayBuffer::GetBackingStore+137
 6: 00007FF7DAA2A3B9 napi_get_typedarray_info+393
 7: 00007FFFB5EC8828
 8: 00007FFFB5EC7C19 
 9: 00007FFFB5ECD003
10: 00007FFFB5ECED79
11: 00007FFFB5ECEF18
12: 00007FFFD6B326E6 FFI::WrapPointerImpl+134 [...\node_modules\ffi-napi\src\ffi.cc]:L28
13: 00007FFFD6B33943 FFI::FFI::InitializeBindings+3571 [...\node_modules\ffi-napi\src\ffi.cc]:L138
14: 00007FFFD6B376E7 FFI::InitializeBindings+471 [...\node_modules\ffi-napi\src\ffi.cc]:L339
15: 00007FFFD6B389C0 Napi::details::WrapCallback<<lambda_4b130013be4a466940e6fe08d32cda83> >+64 [...\node_modules\node-addon-api\napi-inl.h]:L74
16: 00007FFFD6B38918 Napi::details::CallbackData<Napi::Value (__cdecl*)(Napi::CallbackInfo const &),Napi::Value>::Wrapper+40 [...\node_modules\node-addon-api\napi-inl.h]:L115
17: 00007FF7DAA24B9B node::Stop+36395
18: 00007FF7DB2D6256 v8::internal::Builtins::code_handle+172790
19: 00007FF7DB2D5E49 v8::internal::Builtins::code_handle+171753
20: 00007FF7DB2D610C v8::internal::Builtins::code_handle+172460
21: 00007FF7DB2D5F70 v8::internal::Builtins::code_handle+172048
22: 00007FF7DB3A9671 v8::internal::SetupIsolateDelegate::SetupHeap+494673
23: 00007FF7DB33BB1E v8::internal::SetupIsolateDelegate::SetupHeap+45310
24: 00007FF7DB33BB1E v8::internal::SetupIsolateDelegate::SetupHeap+45310
25: 00007FF7DB33BB1E v8::internal::SetupIsolateDelegate::SetupHeap+45310
26: 00000182808B4A3B

node: 16.14.1
ffi-napi: 4.0.3

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://speedtesting.herokuapp.com/peviewer/
  2. Import libr6dissect.dll
  3. See error

Expected behavior
It should work the same as libr6dissect.so

Spawn Location IDs?

siteID and spawnID to be next to site names and attacker spawn locations
(obviously this doesnt apply to random spawn)

Describe alternatives you've considered
Translating site names, too much heavy lifting with inaccurate results

Additional context
REC files from game clients with different languages have different names, this can be difficult to work with. A site ID (whether its unique to the game or map) if possible would make life much easier.

Plant and Defused types are mixed up

Describe the bug
Defuser event types sometimes to not line up

To Reproduce
Team Secret .vs KOI Villa @ 2023-04-12 Blast/EU 2023 Stage 1 LCQ
9th round, Team Secret plants, KOI defuses

Current behavior

{
            "type": {
                "name": "DefuserPlantStart",
                "id": 2
            },
            "username": "yzn.SECRET",
            "time": "0:27",
            "timeInSeconds": 27
        },
{
            "type": {
                "name": "DefuserPlantStart",
                "id": 2
            },
            "username": "cryn.KOI",
            "time": "0:40",
            "timeInSeconds": 40
        },
        {
            "type": {
                "name": "DefuserPlantComplete",
                "id": 3
            },
            "username": "cryn.KOI",
            "time": "0:33",
            "timeInSeconds": 33
        }

Expected behavior

{
            "type": {
                "name": "DefuserPlantStart",
                "id": 2
            },
            "username": "yzn.SECRET",
            "time": "0:27",
            "timeInSeconds": 27
},
{
            "type": {
                "name": "DefuserPlantComplete",
                "id": 'idk whats meant to be here instead'
            },
            "username": "yzn.SECRET",
            "time": "0:27",
            "timeInSeconds": 27
},
{
            "type": {
                "name": "DefuserDisableStart",
                "id": 'idk whats meant to be here instead'
            },
            "username": "cryn.KOI",
            "time": "0:40",
            "timeInSeconds": 40
        },
        {
            "type": {
                "name": "DefuserDisableComplete",
                "id": 'idk whats meant to be here instead'
            },
            "username": "cryn.KOI",
            "time": "0:33",
            "timeInSeconds": 33
        }

Additional context
Seems to be getting confused on whether a player is planting or disabling the defuser.
Defenders, obviously should never be able to plant a defuser and visa versa.

Banned By BattleEye Activity

Hey, just reading through your code right now, I've found lines 35 – 43 in activity.go.

log.Debug().Hex("indicator", indicator).Send()
if !bytes.Equal(indicator, someOtherActivityIndicator) {
	continue
}
// No idea what the first 18 bytes mean
_, err = readBytes(18, c.compressed)
if err != nil {
	return activities, err
}

You're stating “No idea what the first 18 bytes mean” here. While going through some replays on my own in a hex editor, I've found an interesting pattern.

After someOtherActivityIndicator (these are old demos with version 6619085, the identifier in here is 0x03, 0xf0) there are 4 empty bytes following 6 bytes indicating what I presume an Activity Type. On the Left you see the regular Bomb Location Found-Activity and on the Right you'll see a BattleEye-Ban-Activity. Well in these sequences only the last byte changes as for these both types. But I'm still not sure what the 8 bytes after that mean.

var battleEyeBanType = []byte{0x59, 0x34, 0xe5, 0x8b, 0x04, 0x00}
var bombFoundType = []byte{0x59, 0x34, 0xe5, 0x8b, 0x04, 0x02}

This might be a trace for finding Defuse etc. and be worth a shot for adding that in.

Screenshot 2022-12-06 231917

panic: role unknown for operator ID 0

The attached replay file causes the r6-dissect.exe file to output this error message:
"panic: role unknown for operator ID 0

goroutine 1 [running]:
github.com/redraskal/r6-dissect/dissect.Operator.Role(...)
/github/workspace/dissect/operator_roles.go:82
github.com/redraskal/r6-dissect/dissect.(*Reader).deriveTeamRoles(0xc0002c66c0)
/github/workspace/dissect/header.go:508 +0x5db
github.com/redraskal/r6-dissect/dissect.(*Reader).readPlayer.func1()
/github/workspace/dissect/player.go:21 +0x27
github.com/redraskal/r6-dissect/dissect.(*Reader).readPlayer(0xc0002c66c0)
/github/workspace/dissect/player.go:158 +0x1271
github.com/redraskal/r6-dissect/dissect.(*Reader).Read(0xc0002c66c0)
/github/workspace/dissect/reader.go:138 +0x5cf
main.exportRound({0xc00006e100?, 0xf8822a?}, {0xc00000e0e8, 0x6})
/github/workspace/main.go:155 +0xf0
main.main()
/github/workspace/main.go:52 +0x2f2"

The command line is:
"[...]\Tom Clancy's Rainbow Six Siege\MatchReplay\Match-2023-09-21_21-34-28-63\Match-2023-09-21_21-34-28-63-R02.rec" -x stdout

I attached the replay file in question to this post but renamed it to end with .png as Github only allows specific file endings.

Match-2023-09-21_21-34-28-63-R02

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.