subtr_actor/
error.rs

1use crate::*;
2use boxcars::Attribute;
3use std::backtrace::Backtrace;
4use thiserror::Error;
5
6/// [`SubtrActorErrorVariant`] is an enumeration of all the specific error
7/// variants that can occur while processing game replays in the subtr-actor
8/// domain. These include errors related to network frames, frame indexing,
9/// player sets, actor states, object ids, team identities, and data types
10/// amongst others.
11#[derive(Error, Debug, Clone)]
12pub enum SubtrActorErrorVariant {
13    #[error("Replay has no network frames")]
14    NoNetworkFrames,
15
16    #[error("Frame index out of bounds")]
17    FrameIndexOutOfBounds,
18
19    #[error("Players found in frames that were not part of original set. Found: {found:?}, Original: {original:?}")]
20    InconsistentPlayerSet {
21        found: std::collections::HashSet<PlayerId>,
22        original: std::collections::HashSet<PlayerId>,
23    },
24
25    #[error(
26        "No update for ActorId {actor_id:?} of ObjectId {object_id:?} after frame {frame_index}"
27    )]
28    NoUpdateAfterFrame {
29        actor_id: boxcars::ActorId,
30        object_id: boxcars::ObjectId,
31        frame_index: usize,
32    },
33
34    #[error("No boost amount value.")]
35    NoBoostAmountValue,
36
37    #[error("The attribute value that was found was not of the expected type {expected_type:?} {actual_type:?}")]
38    UnexpectedAttributeType {
39        expected_type: String,
40        actual_type: String,
41    },
42
43    #[error("ActorId {actor_id:?} has no matching player id")]
44    NoMatchingPlayerId { actor_id: boxcars::ActorId },
45
46    #[error("No game actor")]
47    NoGameActor,
48
49    #[error("ActorId {actor_id:} already exists with object_id {object_id:}")]
50    ActorIdAlreadyExists {
51        actor_id: boxcars::ActorId,
52        object_id: boxcars::ObjectId,
53    },
54
55    #[error("{name:?} actor for player {player_id:?} not found")]
56    ActorNotFound {
57        name: &'static str,
58        player_id: PlayerId,
59    },
60
61    #[error("There was no actor state for actor_id: {actor_id:?}")]
62    NoStateForActorId { actor_id: boxcars::ActorId },
63
64    #[error("Couldn't find object id for {name}")]
65    ObjectIdNotFound { name: &'static str },
66
67    #[error("No value found for derived key {name:?}")]
68    DerivedKeyValueNotFound { name: String },
69
70    #[error("Ball actor not found")]
71    BallActorNotFound,
72
73    #[error("Player team unknown, {player_id:?}")]
74    UnknownPlayerTeam { player_id: PlayerId },
75
76    #[error("Team object id not known {object_id:?}, for player {player_id:?}")]
77    UnknownTeamObjectId {
78        object_id: boxcars::ObjectId,
79        player_id: PlayerId,
80    },
81
82    #[error("Team name was empty for {player_id:?}")]
83    EmptyTeamName { player_id: PlayerId },
84
85    #[error("Error returned to deliberately end processing early")]
86    FinishProcessingEarly,
87
88    #[error("Player stats header not found")]
89    PlayerStatsHeaderNotFound,
90
91    #[error("Interpolation time order was incorrect start_time {start_time:} {time:} {end_time:}")]
92    InterpolationTimeOrderError {
93        start_time: f32,
94        time: f32,
95        end_time: f32,
96    },
97
98    #[error("The updated actor id does not exist {update:?}")]
99    UpdatedActorIdDoesNotExist { update: boxcars::UpdatedAttribute },
100
101    #[error("Could not find {property:} in state")]
102    PropertyNotFoundInState { property: &'static str },
103
104    #[error("Could not build replay meta")]
105    CouldNotBuildReplayMeta,
106
107    #[error("Error converting float")]
108    FloatConversionError,
109
110    #[error(transparent)]
111    NDArrayShapeError(#[from] ::ndarray::ShapeError),
112
113    #[error("{0:?} was not a recognized feature adder")]
114    UnknownFeatureAdderName(String),
115}
116
117/// [`SubtrActorError`] struct provides an error variant
118/// [`SubtrActorErrorVariant`] along with its backtrace.
119#[derive(Debug)]
120pub struct SubtrActorError {
121    pub backtrace: Backtrace,
122    pub variant: SubtrActorErrorVariant,
123}
124
125impl SubtrActorError {
126    pub fn new(variant: SubtrActorErrorVariant) -> Self {
127        Self {
128            backtrace: Backtrace::capture(),
129            variant,
130        }
131    }
132
133    pub fn new_result<T>(variant: SubtrActorErrorVariant) -> Result<T, Self> {
134        Err(Self::new(variant))
135    }
136}
137
138#[allow(clippy::result_large_err)]
139pub type SubtrActorResult<T> = Result<T, SubtrActorError>;
140
141pub fn attribute_to_tag(attribute: &Attribute) -> &str {
142    match attribute {
143        Attribute::Boolean(_) => "AttributeTag::Boolean",
144        Attribute::Byte(_) => "AttributeTag::Byte",
145        Attribute::AppliedDamage(_) => "AttributeTag::AppliedDamage",
146        Attribute::DamageState(_) => "AttributeTag::DamageState",
147        Attribute::CamSettings(_) => "AttributeTag::CamSettings",
148        Attribute::ClubColors(_) => "AttributeTag::ClubColors",
149        Attribute::Demolish(_) => "AttributeTag::Demolish",
150        Attribute::DemolishFx(_) => "AttributeTag::DemolishFx",
151        Attribute::Enum(_) => "AttributeTag::Enum",
152        Attribute::Explosion(_) => "AttributeTag::Explosion",
153        Attribute::ExtendedExplosion(_) => "AttributeTag::ExtendedExplosion",
154        Attribute::FlaggedByte(_, _) => "AttributeTag::FlaggedByte",
155        Attribute::ActiveActor(_) => "AttributeTag::ActiveActor",
156        Attribute::Float(_) => "AttributeTag::Float",
157        Attribute::GameMode(_, _) => "AttributeTag::GameMode",
158        Attribute::Int(_) => "AttributeTag::Int",
159        Attribute::Int64(_) => "AttributeTag::Int64",
160        Attribute::Loadout(_) => "AttributeTag::Loadout",
161        Attribute::TeamLoadout(_) => "AttributeTag::TeamLoadout",
162        Attribute::Location(_) => "AttributeTag::Location",
163        Attribute::MusicStinger(_) => "AttributeTag::MusicStinger",
164        Attribute::Pickup(_) => "AttributeTag::Pickup",
165        Attribute::PickupNew(_) => "AttributeTag::PickupNew",
166        Attribute::PlayerHistoryKey(_) => "AttributeTag::PlayerHistoryKey",
167        Attribute::Welded(_) => "AttributeTag::Welded",
168        Attribute::RigidBody(_) => "AttributeTag::RigidBody",
169        Attribute::Title(_, _, _, _, _, _, _, _) => "AttributeTag::Title",
170        Attribute::TeamPaint(_) => "AttributeTag::TeamPaint",
171        Attribute::String(_) => "AttributeTag::String",
172        Attribute::UniqueId(_) => "AttributeTag::UniqueId",
173        Attribute::Reservation(_) => "AttributeTag::Reservation",
174        Attribute::PartyLeader(_) => "AttributeTag::PartyLeader",
175        Attribute::LoadoutOnline(_) => "AttributeTag::LoadoutOnline",
176        Attribute::LoadoutsOnline(_) => "AttributeTag::LoadoutsOnline",
177        Attribute::StatEvent(_) => "AttributeTag::StatEvent",
178        Attribute::RepStatTitle(_) => "AttributeTag::RepStatTitle",
179        Attribute::PickupInfo(_) => "AttributeTag::PickupInfo",
180        Attribute::Impulse(_) => "AttributeTag::Impulse",
181        Attribute::QWord(_) => "AttributeTag::QWordString",
182        Attribute::PrivateMatch(_) => "AttributeTag::PrivateMatchSettings",
183        Attribute::Rotation(_) => "AttributeTag::RotationTag",
184        Attribute::DemolishExtended(_) => "AttributeTag::DemolishExtended",
185        Attribute::ReplicatedBoost(_) => "AttributeTag::ReplicatedBoost",
186        Attribute::LogoData(_) => "AttributeTag::LogoData",
187    }
188}