Skip to content

Commit

Permalink
Update error model
Browse files Browse the repository at this point in the history
  • Loading branch information
nickbabcock committed Dec 20, 2024
1 parent 97cb430 commit 7d66246
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 125 deletions.
181 changes: 85 additions & 96 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::data::ATTRIBUTES;
use crate::network::{ActorId, Frame, NewActor, ObjectId, StreamId, UpdatedAttribute};
use crate::{AttributeTag, CacheInfo};
use fnv::FnvHashMap;
use std::error::Error;
use std::fmt;
Expand Down Expand Up @@ -105,12 +106,12 @@ impl Display for AttributeError {

#[derive(PartialEq, Debug, Clone)]
pub struct FrameContext {
pub objects: Vec<String>,
pub object_attributes: FnvHashMap<ObjectId, FnvHashMap<StreamId, ObjectId>>,
pub frames: Vec<Frame>,
pub actors: FnvHashMap<ActorId, ObjectId>,
pub new_actors: Vec<NewActor>,
pub updated_actors: Vec<UpdatedAttribute>,
pub(crate) objects: Vec<String>,
pub(crate) object_attributes: Vec<Option<CacheInfo>>,
pub(crate) frames: Vec<Frame>,
pub(crate) actors: FnvHashMap<ActorId, ObjectId>,
pub(crate) new_actors: Vec<NewActor>,
pub(crate) updated_actors: Vec<UpdatedAttribute>,
}

impl FrameContext {
Expand All @@ -124,55 +125,56 @@ impl FrameContext {
}

fn display_new_actor(&self, f: &mut fmt::Formatter<'_>, actor: &NewActor) -> fmt::Result {
write!(
writeln!(f)?;
writeln!(f, "Last new actor:")?;
writeln!(
f,
"(id: {}, nameId: {}, objId: {}, objName: {}, initial trajectory: {:?})",
actor.actor_id,
"{}",
std::iter::repeat_n('-', "Last new actor:".len()).collect::<String>()
)?;
writeln!(f, "actor id: {}", actor.actor_id)?;
writeln!(
f,
"name id: {}",
actor
.name_id
.map(|x| x.to_string())
.unwrap_or_else(|| String::from("<none>")),
actor.object_id,
self.object_ind_to_string(actor.object_id),
actor.initial_trajectory
)
.unwrap_or_else(|| String::from("<none>"))
)?;
writeln!(f, "object id: {}", actor.object_id)?;
writeln!(
f,
"object name: {}",
self.object_ind_to_string(actor.object_id)
)?;
writeln!(f, "location: {:?}", actor.initial_trajectory.location)?;
writeln!(f, "rotation: {:?}", actor.initial_trajectory.rotation)
}

fn display_update(&self, f: &mut fmt::Formatter<'_>, attr: &UpdatedAttribute) -> fmt::Result {
let actor_entry = self.actors.get(&attr.actor_id);
let actor_obj_name = actor_entry.and_then(|x| self.objects.get(usize::from(*x)));
let stream_obj_name = self.objects.get(usize::from(attr.object_id));

write!(
writeln!(f)?;
writeln!(f, "Last actor update:")?;
writeln!(
f,
"(actor stream id / object id / name: {} / ",
attr.actor_id
"{}",
std::iter::repeat_n('-', "Last actor update:".len()).collect::<String>()
)?;
if let Some(actor_id) = actor_entry {
write!(f, "{} / ", actor_id)
} else {
write!(f, "<none> / ")
}?;

if let Some(name) = actor_obj_name {
write!(f, "{}, ", name)
writeln!(f, "actor id: {}", attr.actor_id)?;
if let Some(object_id) = self.actors.get(&attr.actor_id) {
writeln!(f, "object id: {}", object_id)?;
writeln!(f, "object name: {}", self.object_ind_to_string(*object_id))?;
} else {
write!(f, "<none>, ")
}?;

write!(
writeln!(f, "object id: <none>")?;
};
writeln!(f, "attribute stream id: {}", attr.stream_id)?;
writeln!(f, "attribute object id: {}", attr.object_id)?;
writeln!(
f,
"attribute stream id / object id / name: {} / {} / ",
attr.stream_id, attr.object_id
"attribute object name: {}",
self.object_ind_to_string(attr.object_id)
)?;

if let Some(name) = stream_obj_name {
write!(f, "{}", name)
} else {
write!(f, "<none>")
}?;

write!(f, ", attribute: {:?})", attr.attribute)
writeln!(f, "attribute: {:?}", attr.attribute)
}

fn most_recent_frame_with_data(&self) -> Option<(usize, &Frame)> {
Expand All @@ -187,32 +189,37 @@ impl FrameContext {
impl fmt::Display for FrameContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let last_frame = self.frames.last();
write!(
writeln!(
f,
"on frame: {} (time: {} delta: {}), ",
"Current frame: {} (time: {} delta: {})",
self.frames.len(),
last_frame.map(|x| x.time).unwrap_or_default(),
last_frame.map(|x| x.delta).unwrap_or_default()
)?;
if let Some(updated) = self.updated_actors.last() {
write!(f, "last updated actor: ")?;
self.display_update(f, updated)
return self.display_update(f, updated);
} else if let Some(new) = self.new_actors.last() {
write!(f, "last new actor: ")?;
return self.display_new_actor(f, new);
}

writeln!(f, "- No actor information decoded")?;

let Some((frame_idx, frame)) = self.most_recent_frame_with_data() else {
return Ok(());
};

writeln!(
f,
"Retrace frame: {} (time: {}, delta: {})",
frame_idx, frame.time, frame.delta
)?;

if let Some(updated) = frame.updated_actors.last() {
self.display_update(f, updated)
} else if let Some(new) = frame.new_actors.last() {
self.display_new_actor(f, new)
} else if let Some((frame_idx, frame)) = self.most_recent_frame_with_data() {
write!(f, "backtracking to frame {}, ", frame_idx)?;
if let Some(updated) = frame.updated_actors.last() {
write!(f, "last updated actor: ")?;
self.display_update(f, updated)
} else if let Some(new) = frame.new_actors.last() {
write!(f, "last new actor: ")?;
self.display_new_actor(f, new)
} else {
write!(f, "it didn't decode anything")
}
} else {
write!(f, "it didn't decode anything")
writeln!(f, "- No actor information decoded")
}
}
}
Expand Down Expand Up @@ -278,35 +285,28 @@ impl FrameError {
let objs_with_attr = context
.object_attributes
.iter()
.flat_map(|(obj_id, attrs)| {
attrs
.iter()
.map(move |(attr_id, attr_obj_id)| (obj_id, attr_obj_id, attr_id))
})
.filter(|&(_, _, stream_id)| stream_id == attribute_stream)
.filter_map(|x| x.as_ref())
.filter_map(|c| c.attributes.get(*attribute_stream))
.collect::<Vec<_>>();

let obj = context
.object_attributes
.get(actor_object)
.and_then(|x| x.get(attribute_stream));

if let Some(attr_obj_id) = obj {
if let Some(name) = context.objects.get(usize::from(*attr_obj_id)) {
if let Some(attr) = ATTRIBUTES.get(name.as_str()) {
write!(
f,
"found attribute {} ({:?}) on {} in network cache data. ",
name, attr, actor_obj_name
)?;
} else {
write!(f, "found attribute {} (unknown to boxcars) on {} in network cache data. This is likely due to a rocket league update or an atypical replay. File a bug report!", name, actor_obj_name)?;

// No need for further context so we return early.
return Ok(());
}
.get(usize::from(*actor_object))
.and_then(|x| x.as_ref())
.and_then(|x| x.attributes.get(*attribute_stream));

if let Some(attr_obj) = obj {
if attr_obj.attribute != AttributeTag::NotImplemented {
write!(
f,
"found attribute ({:?}) on {} in network cache data. ",
attr_obj.attribute, actor_obj_name
)?;
} else {
write!(f, "found attribute on {} in network cache data, but not in replay object data, ", actor_obj_name)?;
write!(f, "found attribute {} (unknown to boxcars). This is likely due to a rocket league update or an atypical replay. File a bug report!", context.objects.get(usize::from(attr_obj.object_id)).map_or("<unknown>", |v| v))?;

// No need for further context so we return early.
return Ok(());
}
} else {
write!(
Expand All @@ -318,25 +318,14 @@ impl FrameError {

let mut obj_attr_names = objs_with_attr
.iter()
.filter_map(|&(obj_id, attr_obj_id, _)| {
context
.objects
.get(usize::from(*obj_id))
.and_then(|obj_name| {
context
.objects
.get(usize::from(*attr_obj_id))
.map(|attr_name| (obj_name, attr_name))
})
})
.filter_map(|attr| context.objects.get(usize::from(attr.object_id)))
.collect::<Vec<_>>();

obj_attr_names.sort();
obj_attr_names.dedup();

let mut unknown_attributes = obj_attr_names
.iter()
.map(|(_obj_name, attr_name)| attr_name)
.filter(|x| !ATTRIBUTES.contains_key(x.as_str()))
.cloned()
.cloned()
Expand All @@ -347,7 +336,7 @@ impl FrameError {

let stringify_names = obj_attr_names
.iter()
.map(|(obj_name, attr_name)| format!("({}: {})", obj_name, attr_name))
.map(|attr_name| format!("({})", attr_name))
.collect::<Vec<_>>();

write!(f, "searching all attributes with the same stream id, ")?;
Expand Down
67 changes: 44 additions & 23 deletions src/network/frame_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,42 @@ impl<T> RawSegmentedArray<T> {
}
}

impl<T: Clone> Clone for RawSegmentedArray<T> {
fn clone(&self) -> Self {
Self {
array: self.array.clone(),
map: self.map.clone(),
}
}
}

impl<T: PartialEq> PartialEq for RawSegmentedArray<T> {
fn eq(&self, other: &Self) -> bool {
self.array == other.array && self.map == other.map
}
}

#[derive(Debug)]
pub(crate) struct SegmentedArray<K, V> {
raw: RawSegmentedArray<V>,
marker: std::marker::PhantomData<K>,
}

impl<K, V: Clone> Clone for SegmentedArray<K, V> {
fn clone(&self) -> Self {
Self {
raw: self.raw.clone(),
marker: std::marker::PhantomData,
}
}
}

impl<K, V: PartialEq> PartialEq for SegmentedArray<K, V> {
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}

impl<K, V> SegmentedArray<K, V>
where
K: Into<usize>,
Expand Down Expand Up @@ -316,33 +346,24 @@ impl<'a, 'b> FrameDecoder<'a, 'b> {
e,
Box::new(FrameContext {
objects: self.body.objects.clone(),
object_attributes: self
.object_ind_attributes
.iter()
.enumerate()
.flat_map(|(i, x)| Some((i, x.as_ref()?)))
.map(|(key, value)| {
(
ObjectId(key as i32),
value
.attributes
.raw
.map
.iter()
.enumerate()
.map(|(key2, value)| {
(StreamId(key2 as i32), value.1.object_id)
})
.collect(),
)
})
.collect(),
object_attributes: self.object_ind_attributes.clone(),
frames: frames.clone(),
actors: actors
.raw
.map
.array
.iter()
.map(|(k, (o, _))| (ActorId(*k as i32), *o))
.enumerate()
.filter_map(|(i, x)| {
let (obj_id, _) = x.as_ref()?;
Some((ActorId(i as i32), *obj_id))
})
.chain(
actors
.raw
.map
.iter()
.map(|(k, (o, _))| (ActorId(*k as i32), *o)),
)
.collect(),
new_actors: new_actors.clone(),
updated_actors: updated_actors.clone(),
Expand Down
12 changes: 6 additions & 6 deletions src/network/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ use fnv::FnvHashMap;
use frame_decoder::SegmentedArray;
use std::cmp;

#[derive(Debug)]
#[derive(PartialEq, Debug, Clone)]
pub(crate) struct CacheInfo {
max_prop_id: u32,
prop_id_bits: u32,
attributes: SegmentedArray<StreamId, ObjectAttribute>,
pub(crate) max_prop_id: u32,
pub(crate) prop_id_bits: u32,
pub(crate) attributes: SegmentedArray<StreamId, ObjectAttribute>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ObjectAttribute {
attribute: AttributeTag,
object_id: ObjectId,
pub(crate) attribute: AttributeTag,
pub(crate) object_id: ObjectId,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
Expand Down

0 comments on commit 7d66246

Please sign in to comment.