Skip to main content

Crate source2_demo_protobufs

Crate source2_demo_protobufs 

Source
Expand description

§source2-demo

Crates.io Documentation License

source2-demo is a Rust library for parsing Source 2 engine demo files.

§Supported Games

  • Dota 2
  • Deadlock
  • Counter-Strike 2

§Installation

Add the following to your Cargo.toml and enable the feature for the game you want to parse:

[dependencies]
# For Dota 2
source2-demo = { version = "0.5", features = ["dota"] }

# For Deadlock
# source2-demo = { version = "0.5", features = ["deadlock"] }

# For Counter-Strike 2
# source2-demo = { version = "0.5", features = ["cs2"] }

§Quick Start: Parsing Chat Messages

Here’s a simple program that prints chat messages from a Dota 2 replay. It handles the CDotaUserMsgChatMessage protobuf message and prints the player’s name and their message.

More examples can be found in the d2-examples and dl-examples directories.

use source2_demo::prelude::*;
use source2_demo::proto::*;

// Create a struct that implements the Default trait
#[derive(Default)]
struct Chat;

// Mark the impl block with the observer attribute
#[observer]
#[uses_all]
impl Chat {
    // Use the on_message attribute to mark the protobuf message handler
    #[on_message]
    fn handle_chat_msg(
        &mut self,
        ctx: &Context,
        chat_msg: CDotaUserMsgChatMessage, // Use any protobuf message as an argument
    ) -> ObserverResult {
        if let Ok(pr) = ctx.entities().get_by_class_name("CDOTA_PlayerResource") {
            let name: String = property!(
                pr,
                "m_vecPlayerData.{:04}.m_iszPlayerName",
                chat_msg.source_player_id()
            );
            println!("{}: {}", name, chat_msg.message_text());
        }
        Ok(())
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a parser
    let mut parser = Parser::from_reader(std::fs::File::open("replay.dem")?)?;

    // Register observers
    parser.register_observer::<Chat>();

    // Run the parser
    parser.run_to_end()?;

    Ok(())
}

§Quick Start: Rewriting Protobuf Messages

Use source2_demo::writer when you want to write a modified demo. The writer parses the input replay, applies registered rewriters, and writes a new replay stream to the output.

This example removes Dota 2 chat messages by rewriting a protobuf packet message:

use source2_demo::prelude::*;
use source2_demo::proto::CDotaUserMsgChatMessage;
use source2_demo::writer::*;
use std::fs::File;

#[derive(Default)]
struct RemoveChat;

#[rewriter]
impl RemoveChat {
    #[rewrite_packet_message]
    fn remove_chat(
        &mut self,
        _message: CDotaUserMsgChatMessage,
    ) -> Result<MessageRewrite, ParserError> {
        Ok(MessageRewrite::Drop)
    }
}

fn main() -> anyhow::Result<()> {
    let input = File::open("input.dem")?;
    let output = File::create("output.dem")?;

    let mut writer = DemoWriter::from_reader(input, output)?;
    writer.register_rewriter::<RemoveChat>();
    writer.run()?;

    Ok(())
}

§Quick Start: Rewriting Fields and String Tables

This Deadlock example anonymizes a replay by rewriting entity fields, a packet message, and userinfo entries in string tables. The full example is in dl-examples/anonymize-replay.

use source2_demo::prelude::*;
use source2_demo::proto::{
    CCitadelUserMsgPostMatchDetails, CMsgMatchMetaDataContents, CMsgPlayerInfo,
};
use source2_demo::writer::*;

#[derive(Default)]
struct ReplayAnonymizer;

#[rewriter]
impl ReplayAnonymizer {
    #[rewrite_field(class = "CCitadelPlayerController", field = "m_steamID")]
    fn remove_steam_id(&mut self, _value: u64) -> u64 {
        0
    }

    #[rewrite_packet_message]
    fn remove_post_match_details(
        &mut self,
        message: &mut CCitadelUserMsgPostMatchDetails,
    ) -> Result<MessageRewrite, ParserError> {
        if let Some(match_details) = message.match_details.as_mut() {
            let mut metadata = CMsgMatchMetaDataContents::decode(match_details.as_slice())?;
            if let Some(match_info) = metadata.match_info.as_mut() {
                match_info.match_id = Some(0);
                for player in &mut match_info.players {
                    player.account_id = Some(0);
                }
            }
            *match_details = metadata.encode_to_vec();
        }
        Ok(MessageRewrite::Rewrite)
    }

    #[rewrite_string_table_entry]
    fn remove_userinfo(
        &mut self,
        table_name: &str,
        entry: &mut StringTableEntryUpdate,
    ) -> Result<(), ParserError> {
        if table_name == "userinfo" {
            if let Some(value) = entry.value_mut() {
                let mut player = CMsgPlayerInfo::decode(value.as_slice())?;
                player.name = Some("Anonymous".to_string());
                player.xuid = Some(0);
                player.steamid = Some(0);
                *value = player.encode_to_vec();
            }
        }
        Ok(())
    }
}

§Building Examples

To build the examples, clone the repository and use Cargo:

git clone https://github.com/Rupas1k/source2-demo
cd source2-demo

# Build examples for a specific game
cd dl-examples # d2-examples
cargo build --release

§Run a Specific Example

cargo run --release -p example input.dem
cargo run --release -p example input.dem output.dem

§Features

The crate supports the following cargo features:

  • dota - Enable Dota 2 replay parsing (includes Dota 2 protobufs)
  • deadlock - Enable Deadlock replay parsing (includes Citadel protobufs)
  • cs2 - Enable Counter-Strike 2 replay parsing (includes CS2 protobufs)
  • unsafe - Disable bounds checking in the reader for improved performance.
  • mimalloc (default) - Use mimalloc as the global allocator for improved performance

You can enable multiple game features if needed:

source2-demo = { version = "*", features = ["dota", "cs2"] }

You can disable mimalloc if it causes issues on your platform (e.g., WebAssembly):

source2-demo = { version = "*", default-features = false }

§Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

§Credits

This project was inspired by and builds upon the work of other Source 2 demo parsers:

  • clarity - Java-based Source 2 replay parser
  • manta - Go-based Dota 2 replay parser

§License

This project is dual-licensed under either:

at your option.

§Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Re-exports§

pub use prost;

Modules§

c_bidir_msg_prediction_event
c_demo_class_info
c_demo_recovery
c_demo_string_tables
c_game_info
c_msg_add_item_to_socket_response
c_msg_add_socket_response
c_msg_apply_remote_con_vars
c_msg_c_vars
c_msg_client_to_gc_aggregate_metrics
c_msg_client_to_gc_integrity_status
c_msg_client_welcome
c_msg_extract_gems_response
c_msg_gc_to_gcso_cache_subscribe
c_msg_gc_update_sub_gc_session_info
c_msg_inference_iterate_beam_search
c_msg_reset_strange_gem_count_response
c_msg_sdo_assert
c_msg_serialized_so_cache
c_msg_server_network_stats
c_msg_set_item_positions
c_msg_so_cache_subscribed
c_msg_so_multiple_objects
c_msg_source1_legacy_game_event
c_msg_source1_legacy_game_event_list
c_msg_source2_perf_interval_sample
c_msg_source2_play_stats_packed_record_list
c_msg_steam_learn_access_tokens
c_msg_steam_learn_inference_backend_response
c_msg_steam_learn_inference_metadata_response
c_msg_steam_learn_server_info
c_source2_metrics_fetch_map_data_response
c_source2_metrics_match_perf_summary_notification
c_user_message_camera_transition
c_user_message_diagnostic_response
c_user_message_dll_status
c_user_message_inventory_response
c_user_message_notify_response_found
c_user_message_request_diagnostic
c_user_message_util_msg_response
c_user_msg_particle_manager
c_workshop_populate_item_descriptions_request
c_workshop_set_item_payment_rules_request
cgc_to_gc_msg_master_ack
cgc_to_gc_msg_master_startup_complete
csvc_msg_class_info
csvc_msg_game_event
csvc_msg_game_event_list
csvc_msg_list_game_events
csvc_msg_packet_entities
csvc_msg_send_table
csvc_msg_sounds
proto_flattened_serializer_field_t

Structs§

CBidirMsgPredictionEvent
CBidirMsgRebroadcastGameEvent
CBidirMsgRebroadcastSource
CBroadcastPostGameDataFrameRequest
CCommunityClanAnnouncementInfo
CCommunityGetClanAnnouncementsRequest
CCommunityGetClanAnnouncementsResponse
CDemoAnimationData
CDemoAnimationHeader
CDemoClassInfo
CDemoConsoleCmd
CDemoCustomData
CDemoCustomDataCallbacks
CDemoFileHeader
CDemoFileInfo
CDemoFullPacket
CDemoPacket
CDemoRecovery
CDemoSaveGame
CDemoSendTables
CDemoSpawnGroups
CDemoSpawnGroupsHltvBroadcast
CDemoStop
CDemoStringTables
CDemoSyncTick
CDemoUserCmd
CEntityMessageDoSpark
CEntityMessageFixAngle
CEntityMessagePlayJingle
CEntityMessagePropagateForce
CEntityMessageRemoveAllDecals
CEntityMessageScreenOverlay
CEntityMsg
CExtraMsgBlock
CGameInfo
CGcMsgCompressedMsgToClient
CGcMsgGetIpLocationResponse
CGcStorePurchaseInitLineItem
CGcSystemMsgGetAccountDetails
CGcSystemMsgGetAccountDetailsResponse
CGcToGcMsgMasterAck
CGcToGcMsgMasterAckResponse
CGcToGcMsgMasterStartupComplete
CGcToGcMsgRouted
CGcToGcMsgRoutedReply
CIpLocationInfo
CMsgAddItemToSocket
CMsgAddItemToSocketData
CMsgAddItemToSocketResponse
CMsgAddSocket
CMsgAddSocketResponse
CMsgApplyEggEssence
CMsgApplyPennantUpgrade
CMsgApplyRemoteConVars
CMsgApplyStrangePart
CMsgCVars
CMsgClearDecalsForEntityEvent
CMsgClearEntityDecalsEvent
CMsgClearWorldDecalsEvent
CMsgClientHello
CMsgClientPingData
CMsgClientToGcAggregateMetrics
CMsgClientToGcIntegrityStatus
CMsgClientWelcome
CMsgClothEffectAnimEvent
CMsgClothStiffenAnimEvent
CMsgConnectionStatus
CMsgCustomGameInstallStatus
CMsgExtractGems
CMsgExtractGemsResponse
CMsgGcAdditionalWelcomeMsgList
CMsgGcAssertJobData
CMsgGcClientPing
CMsgGcClientVersionUpdated
CMsgGcConCommand
CMsgGcMultiplexMessage
CMsgGcRequestSubGcSessionInfo
CMsgGcRequestSubGcSessionInfoResponse
CMsgGcServerVersionUpdated
CMsgGcStorePurchaseCancel
CMsgGcStorePurchaseCancelResponse
CMsgGcStorePurchaseFinalize
CMsgGcStorePurchaseFinalizeResponse
CMsgGcStorePurchaseInit
CMsgGcStorePurchaseInitResponse
CMsgGcToClientAggregateMetricsBackoff
CMsgGcToClientApplyRemoteConVars
CMsgGcToClientPollConvarRequest
CMsgGcToClientPollConvarResponse
CMsgGcToClientPollFileRequest
CMsgGcToClientPollFileResponse
CMsgGcToClientRequestDropped
CMsgGcToGcBannedWordListUpdated
CMsgGcToGcDirtySdoCache
CMsgGcToGcForwardAccountDetails
CMsgGcToGcLoadSessionSoCache
CMsgGcToGcLoadSessionSoCacheResponse
CMsgGcToGcMasterBroadcastMessage
CMsgGcToGcMasterDestroyCache
CMsgGcToGcMasterSubscribeToCache
CMsgGcToGcMasterSubscribeToCacheAsync
CMsgGcToGcMasterSubscribeToCacheResponse
CMsgGcToGcMasterUnsubscribeFromCache
CMsgGcToGcPerformManualOp
CMsgGcToGcPerformManualOpCompleted
CMsgGcToGcReloadServerRegionSettings
CMsgGcToGcSubGcStarting
CMsgGcToGcUniverseStartup
CMsgGcToGcUniverseStartupResponse
CMsgGcToGcUpdateSessionStats
CMsgGcToGcUpdateSqlKeyValue
CMsgGcToGcWebApiAccountChanged
CMsgGcToGcsoCacheSubscribe
CMsgGcToGcsoCacheUnsubscribe
CMsgGcToServerApplyRemoteConVars
CMsgGcToServerSteamLearnAccessTokensChanged
CMsgGcToServerSteamLearnUseHttp
CMsgGcUpdateSubGcSessionInfo
CMsgInferenceIterateBeamSearch
CMsgInvitationCreated
CMsgInviteToLobby
CMsgInviteToParty
CMsgIpcAddress
CMsgItemAcknowledged
CMsgKickFromParty
CMsgLanServerAvailable
CMsgLeaveParty
CMsgLobbyInviteResponse
CMsgPartyInviteResponse
CMsgPlaceDecalEvent
CMsgPlayerInfo
CMsgProtoBufHeader
CMsgQAngle
CMsgQuaternion
CMsgResetStrangeGemCount
CMsgResetStrangeGemCountResponse
CMsgRgba
CMsgSdoAssert
CMsgSdoNoMemcached
CMsgSerializedSoCache
CMsgServerAvailable
CMsgServerNetworkStats
CMsgServerPeer
CMsgServerUserCmd
CMsgSetItemPositions
CMsgSoCacheHaveVersion
CMsgSoCacheSubscribed
CMsgSoCacheSubscribedUpToDate
CMsgSoCacheSubscriptionCheck
CMsgSoCacheSubscriptionRefresh
CMsgSoCacheUnsubscribed
CMsgSoCacheVersion
CMsgSoMultipleObjects
CMsgSoSingleObject
CMsgSoidOwner
CMsgSortItems
CMsgSosSetLibraryStackFields
CMsgSosSetSoundEventParams
CMsgSosStartSoundEvent
CMsgSosStopSoundEvent
CMsgSosStopSoundEventHash
CMsgSource1LegacyGameEvent
CMsgSource1LegacyGameEventList
CMsgSource1LegacyListenEvents
CMsgSource2NetworkFlowQuality
CMsgSource2PerfIntervalSample
CMsgSource2PlayStatsPackedRecordList
CMsgSource2SystemSpecs
CMsgSource2VProfLiteReport
CMsgSource2VProfLiteReportItem
CMsgSteamLearnAccessTokens
CMsgSteamLearnBatchOperationRequest
CMsgSteamLearnBatchOperationResponse
CMsgSteamLearnCacheDataRequest
CMsgSteamLearnCacheDataResponse
CMsgSteamLearnData
CMsgSteamLearnDataElement
CMsgSteamLearnDataList
CMsgSteamLearnDataObject
CMsgSteamLearnDataSource
CMsgSteamLearnDataSourceDescElement
CMsgSteamLearnDataSourceDescObject
CMsgSteamLearnGetAccessTokensRequest
CMsgSteamLearnGetAccessTokensResponse
CMsgSteamLearnInferenceBackendResponse
CMsgSteamLearnInferenceMetadataBackendRequest
CMsgSteamLearnInferenceMetadataRequest
CMsgSteamLearnInferenceMetadataResponse
CMsgSteamLearnInferenceRequest
CMsgSteamLearnInferenceResponse
CMsgSteamLearnRegisterDataSourceRequest
CMsgSteamLearnRegisterDataSourceResponse
CMsgSteamLearnServerInfo
CMsgSteamLearnSnapshotProjectRequest
CMsgSteamLearnSnapshotProjectResponse
CMsgTransform
CMsgVDebugGameSessionIdEvent
CMsgVector
CMsgVector2D
CMsgVoiceAudio
CNetMsgDebugOverlay
CNetMsgNop
CNetMsgSetConVar
CNetMsgSignonState
CNetMsgSpawnGroupLoad
CNetMsgSpawnGroupLoadCompleted
CNetMsgSpawnGroupManifestUpdate
CNetMsgSpawnGroupSetCreationTick
CNetMsgSpawnGroupUnload
CNetMsgSplitScreenUser
CNetMsgStringCmd
CNetMsgTick
CSoEconGameAccountClient
CSoEconItem
CSoEconItemAttribute
CSoEconItemEquipped
CSource2MetricsFetchMapDataRequest
CSource2MetricsFetchMapDataResponse
CSource2MetricsMatchPerfSummaryNotification
CSource2MetricsRecordPlayStatsNotification
CSvcMsgBroadcastCommand
CSvcMsgBspDecal
CSvcMsgClassInfo
CSvcMsgClearAllStringTables
CSvcMsgCmdKeyValues
CSvcMsgCreateStringTable
CSvcMsgCrosshairAngle
CSvcMsgFixAngle
CSvcMsgFlattenedSerializer
CSvcMsgFullFrameSplit
CSvcMsgGameEvent
CSvcMsgGameEventList
CSvcMsgGameSessionConfiguration
CSvcMsgGetCvarValue
CSvcMsgHltvFixupOperatorStatus
CSvcMsgHltvReplay
CSvcMsgHltvStatus
CSvcMsgListGameEvents
CSvcMsgMenu
CSvcMsgNextMsgPredicted
CSvcMsgPacketEntities
CSvcMsgPacketReliable
CSvcMsgPeerList
CSvcMsgPrefetch
CSvcMsgPrint
CSvcMsgRconServerDetails
CSvcMsgSendTable
CSvcMsgServerInfo
CSvcMsgServerSteamId
CSvcMsgSetPause
CSvcMsgSetView
CSvcMsgSounds
CSvcMsgSplitScreen
CSvcMsgStopSound
CSvcMsgTempEntities
CSvcMsgUpdateStringTable
CSvcMsgUserCommands
CSvcMsgUserMessage
CSvcMsgVoiceData
CSvcMsgVoiceInit
CUserMessageAchievementEvent
CUserMessageAmmoDenied
CUserMessageAnimStateGraphState
CUserMessageAudioParameter
CUserMessageCameraTransition
CUserMessageCloseCaption
CUserMessageCloseCaptionDirect
CUserMessageCloseCaptionPlaceholder
CUserMessageColoredText
CUserMessageCreditsMsg
CUserMessageCurrentTimescale
CUserMessageDesiredTimescale
CUserMessageDiagnosticResponse
CUserMessageDllStatus
CUserMessageExtraUserData
CUserMessageFade
CUserMessageGameTitle
CUserMessageHapticsManagerEffect
CUserMessageHapticsManagerPulse
CUserMessageHudMsg
CUserMessageHudText
CUserMessageInventoryResponse
CUserMessageItemPickup
CUserMessageLagCompensationError
CUserMessageNotifyResponseFound
CUserMessagePlayResponseConditional
CUserMessageRequestDiagnostic
CUserMessageRequestDllStatus
CUserMessageRequestInventory
CUserMessageRequestState
CUserMessageRequestUtilAction
CUserMessageResetHud
CUserMessageRumble
CUserMessageSayText
CUserMessageSayText2
CUserMessageSayTextChannel
CUserMessageScreenTilt
CUserMessageSendAudio
CUserMessageServerFrameTime
CUserMessageShake
CUserMessageShakeDir
CUserMessageShowMenu
CUserMessageTextMsg
CUserMessageUpdateCssClasses
CUserMessageUtilMsgResponse
CUserMessageVoiceMask
CUserMessageWaterShake
CUserMsgCustomGameEvent
CUserMsgHudError
CUserMsgParticleManager
CWorkshopGetContributorsRequest
CWorkshopGetContributorsResponse
CWorkshopPopulateItemDescriptionsRequest
CWorkshopSetItemPaymentRulesRequest
CWorkshopSetItemPaymentRulesResponse
CclcMsgBaselineAck
CclcMsgClientInfo
CclcMsgCmdKeyValues
CclcMsgDiagnostic
CclcMsgHltvFixupOperatorTick
CclcMsgHltvReplay
CclcMsgListenEvents
CclcMsgLoadingProgress
CclcMsgMove
CclcMsgRconServerDetails
CclcMsgRequestPause
CclcMsgRespondCvarValue
CclcMsgServerStatus
CclcMsgSplitPlayerConnect
CclcMsgSplitPlayerDisconnect
CclcMsgVoiceData
ProtoFlattenedSerializerFieldT
ProtoFlattenedSerializerT

Enums§

BidirectionalMessages
ClcMessages
DialogType
EBaseEntityMessages
EBaseGameEvents
EBaseUserMessages
ECustomGameInstallStatus
EDemoCommands
EHapticPulseType
ENetworkDisconnectionReason
EProtoDebugVisiblity
EProtoExecutionSite
EQueryCvarValueStatus
ERollType
ESource2PlayStatsFieldType
ESourceEngine
ESplitScreenMessageType
ESteamLearnCacheDataResult
ESteamLearnDataType
ESteamLearnGetAccessTokensResult
ESteamLearnInferenceMetadataResult
ESteamLearnInferenceResult
ESteamLearnSnapshotProjectResult
ESteammLearnRegisterDataSourceResult
EgcBaseMsg
EgcPlatform
GcConnectionStatus
GcProtoBufMsgSrc
NetMessages
ParticleMessage
PartnerAccountType
PrefetchType
ReplayEventTypeT
RequestPauseT
SignonStateT
SpawnGroupFlagsT
SvcMessages
SvcMessagesLowFrequency
VoiceDataFormatT