Ejemplo n.º 1
0
        public static List <IGameEvent> Parse(Replay replay, byte[] buffer)
        {
            // The GameEvent file changes significantly after 16561.
            // This is sometime around the first patch after release. Since
            // parsing replays this old should be extremely rare, I don't believe
            // its worth the effort to try to support both. If it is, it should be
            // done in another method.
            //
            // Still a bitstream, but stuff's moved around and event codes are different.
            if (replay.ReplayBuild < 16561)
            {
                throw new NotSupportedException(
                          "Replay builds under 16561 are not supported for parsing GameEvent log.");
            }

            // Initialize Ability and Unit data.
            var effectiveBuild = BuildData.GetInstance().GetEffectiveBuild(replay.ReplayBuild);

            if (effectiveBuild == 0)
            {
                throw new NotSupportedException(
                          String.Format("Replay build {0} is not supported by the current event database", replay.ReplayBuild));
            }
            var abilityData = new AbilityData(effectiveBuild);
            var unitData    = new UnitData(effectiveBuild);

            var events = new List <IGameEvent>();

            // Keep a reference to know the game length.
            var ticksElapsed = 0;

            using (var stream = new MemoryStream(buffer))
            {
                var bitReader = new BitReader(stream);

                var playersGone = new bool[0x10];

                while (!bitReader.EndOfStream)
                {
                    var intervalLength = 6 + (bitReader.Read(2) << 3);
                    var interval       = bitReader.Read(intervalLength);
                    ticksElapsed += (int)interval;
                    var    playerIndex = (int)bitReader.Read(5);
                    Player player;
                    if (playerIndex < 0x10)
                    {
                        player = replay.GetPlayerById(playerIndex);
                    }
                    else
                    {
                        player = Player.Global;
                    }

                    var        eventType = bitReader.Read(7);
                    IGameEvent gameEvent;
                    switch (eventType)
                    {
                    case 0x05:     // Game start
                        gameEvent = new GameStartEvent();
                        break;

                    case 0x0b:
                    case 0x0c:     // Join game
                        gameEvent = new PlayerJoinEvent(bitReader, replay, playerIndex);
                        break;

                    case 0x19:     // Leave game
                        gameEvent = new PlayerLeftEvent(player);
                        playersGone[playerIndex] = true;
                        DetectWinners(playersGone, replay);
                        break;

                    case 0x1b:     // Ability
                        gameEvent = new AbilityEvent(bitReader, replay, player, abilityData, unitData);
                        break;

                    case 0x1c:     // Selection
                        gameEvent = new SelectionEvent(bitReader, replay, player, unitData);
                        break;

                    case 0x1d:     // Control groups
                        gameEvent = new HotkeyEvent(bitReader, replay, player);
                        break;

                    case 0x1f:     // Send resources
                        gameEvent = new SendResourcesEvent(bitReader, replay);
                        break;

                    case 0x23:     // ??
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Inactive;
                        bitReader.Read(8);
                        break;

                    case 0x26:     // ??
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Inactive;
                        bitReader.Read(32);
                        bitReader.Read(32);
                        break;

                    case 0x27:     // Target critter - special
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Selection;
                        var unitId = bitReader.Read(32);
                        break;

                    case 0x31:     // Camera
                        gameEvent = new CameraEvent(bitReader, replay);
                        break;

                    case 0x37:     // UI Event
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Other;
                        bitReader.Read(32);
                        bitReader.Read(32);
                        break;

                    case 0x38:     // weird sync event
                    {
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Other;
                        for (var j = 0; j < 2; j++)
                        {
                            var length = bitReader.Read(8);
                            for (var i = 0; i < length; i++)
                            {
                                bitReader.Read(32);
                            }
                        }
                        break;
                    }

                    case 0x3c:     // ???
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Inactive;
                        bitReader.Read(16);
                        break;

                    case 0x46:     // Request resources
                        gameEvent = new RequestResourcesEvent(bitReader, replay);
                        break;

                    case 0x47:     // ?? -- associated with send minerals
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Inactive;
                        bitReader.Read(32);
                        break;

                    case 0x48:     // ?? -- sync event
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Inactive;
                        bitReader.Read(32);
                        break;

                    case 0x4C:     // ?? -- seen with spectator
                        bitReader.Read(4);
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Inactive;
                        break;

                    case 0x59:     // ?? -- sync flags maybe?
                        bitReader.Read(32);
                        gameEvent           = new GameEventBase();
                        gameEvent.EventType = GameEventType.Inactive;
                        break;

                    default:     // debug
                        throw new InvalidOperationException(String.Format(
                                                                "Unknown event type {0:x} at {1:x} in replay.game.events",
                                                                eventType, bitReader.Cursor));
                    }

                    gameEvent.Player = player;
                    gameEvent.Time   = Timestamp.Create(ticksElapsed);
                    events.Add(gameEvent);

                    bitReader.AlignToByte();
                }
            }

            replay.GameLength = Timestamp.Create(ticksElapsed).TimeSpan;

            return(events);
        }