syntax = "proto3";

package stormgate;

// protobuf schema for parsing lobby info from Stormgate replays
// Thanks to CascadeFury for most of this.

// Each chunk seems to be of the form 3: {1: {actual content}}
// Since I don't know the meaning of those outer structs yet, I'm just putting them as inline messages:
message ReplayChunk {
    int32 timestamp = 1; // Time since game start in units of 1/1024 seconds
    int32 client_id = 2;
    message Wrapper {
        message ReplayContent {
            oneof content_type {
                MapDetails map_details = 3;
                ClientConnected client_connected = 4;
                Player player = 12;
                LobbyChangeSlot change_slot = 13;
                LobbySetVariable set_variable = 15;
                StartGame start_game = 18;
                PlayerLeftGame player_left_game = 25;
                ClientDisconnected client_disconnected = 31;
                AssignPlayerSlot assign_player_slot = 37;
            }
        }
        ReplayContent content = 1;
    }
    Wrapper inner = 3;
}

// 3 - Map identifier + RNG seed
message MapDetails {
   string map_folder = 1;
   string map_name = 2;
   int32 map_seed = 3;   // Is different every lobby, so probably some kind of seed
   MatchType match_type = 7;
}

enum MatchType {
   UnknownMatchType = 0;
   Custom = 1;
   Ranked1v1 = 2;
   Coop3vE = 3;
}

// 4 - sent by server after each player connects?
// in new co-op replay it's the only way to link a player to their client_id.
message ClientConnected {
    int32 client_id = 1;
    UUID uuid = 2;
}

// 12 - Sent by a player when they join a game
message Player {
    UUID uuid = 2;
    message PlayerName {
        string nickname = 1;
        string discriminator = 2;
    }
    PlayerName name = 3;
}

// 13 - Sent when player changes slot (leave/enter), note that SlotChoice
// contains either a request for a specific slot, or what I assume is a "next
// slot available", slot 255 is observer
message LobbyChangeSlot {
    message SlotChoice {
        message SpecificSlot {
            int32 slot = 1;
        }
        oneof choice_type {
            SpecificSlot specific_slot = 2;
        }
    }

    SlotChoice choice = 1;
}

// 15 - Sent when a player slot has a variable changed
// Var 374945738: Type, 0 = Closed, 1 = Human, 2 = AI
// Var 2952722564: Faction, 0 = Vanguard, 1 = Infernals
// Var 655515685: AIType, 0 = Peaceful, 1 = Junior, 2 = Senior
message LobbySetVariable {
    int32 slot = 3;
    uint32 variable_id = 4;
    uint32 value = 5;
}

// 18 - "Start Game" Sent by players after second ReadyUp, that probably indicates player finished loading into the map
message StartGame {
}


enum LeaveReason {
   UnknownReason = 0;
   Surrender = 1;  // Player surrenders
   Leave = 2;      // Player leaves game normally (game ended earlier, if this is the first PlayerLeftGame message, the outcome should be considered unknown)
   Disconnect = 3; // Player lost connection
}

// 25 - When a player exits the game/disconnects
message PlayerLeftGame {
    UUID player_uuid = 1;
    LeaveReason reason = 2;
}

// 31 - sent by the server after a client disconnects
message ClientDisconnected {
    int32 client_id = 1;
    LeaveReason reason = 2;
    UUID player_uuid = 3;
}

// 37 - AssignPlayer (done by server as pl=64)
// Appears only in ladder games?
message AssignPlayerSlot {
    UUID uuid = 1;
    int64 slot = 2;
    string nickname = 3;
}

// UUIDs are encoded as 2 varints.
// To recover the original UUID, encode these as unsigned 64-bit big-endian
// integers and concatenate the resulting bitstrings; or in python:
//     uuid.UUID(bytes=struct.pack(">QQ", part1, part2))
// or equivalently
//     uuid.UUID(int=(part1 << 64) | part2)
message UUID {
    uint64 part1 = 1;
    uint64 part2 = 2;
}
