diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 0b29f08f5..6b2c8a1d3 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -141,6 +141,7 @@ pub struct SystemClasses<'gc> { pub morphshape: ClassObject<'gc>, pub shaderinput: ClassObject<'gc>, pub shaderparameter: ClassObject<'gc>, + pub netstatusevent: ClassObject<'gc>, } impl<'gc> SystemClasses<'gc> { @@ -256,6 +257,7 @@ impl<'gc> SystemClasses<'gc> { morphshape: object, shaderinput: object, shaderparameter: object, + netstatusevent: object, } } } @@ -711,6 +713,7 @@ fn load_playerglobal<'gc>( ("flash.events", "MouseEvent", mouseevent), ("flash.events", "FullScreenEvent", fullscreenevent), ("flash.events", "UncaughtErrorEvents", uncaughterrorevents), + ("flash.events", "NetStatusEvent", netstatusevent), ("flash.geom", "Matrix", matrix), ("flash.geom", "Point", point), ("flash.geom", "Rectangle", rectangle), diff --git a/core/src/avm2/object/event_object.rs b/core/src/avm2/object/event_object.rs index 6cccef849..0af887f19 100644 --- a/core/src/avm2/object/event_object.rs +++ b/core/src/avm2/object/event_object.rs @@ -2,6 +2,7 @@ use crate::avm2::activation::Activation; use crate::avm2::events::Event; +use crate::avm2::multiname::Multiname; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::value::Value; @@ -144,6 +145,48 @@ impl<'gc> EventObject<'gc> { ) .unwrap() // we don't expect to break here } + + pub fn net_status_event( + activation: &mut Activation<'_, 'gc>, + event_type: S, + info: &[(&'static str, &'static str)], + ) -> Object<'gc> + where + S: Into>, + { + let mut info_object = activation + .avm2() + .classes() + .object + .construct(activation, &[]) + .unwrap(); + for (key, value) in info { + info_object + .set_property( + &Multiname::new(activation.avm2().public_namespace, AvmString::from(*key)), + Value::String(AvmString::from(*value)), + activation, + ) + .unwrap(); + } + + let event_type: AvmString<'gc> = event_type.into(); + + let net_status_cls = activation.avm2().classes().netstatusevent; + net_status_cls + .construct( + activation, + &[ + event_type.into(), + //bubbles + false.into(), + //cancelable + false.into(), + info_object.into(), + ], + ) + .unwrap() // we don't expect to break here + } } impl<'gc> TObject<'gc> for EventObject<'gc> { diff --git a/core/src/streams.rs b/core/src/streams.rs index fa606a071..0863baf79 100644 --- a/core/src/streams.rs +++ b/core/src/streams.rs @@ -1,5 +1,6 @@ //! NetStream implementation +use crate::avm2::{Activation as Avm2Activation, Avm2, EventObject as Avm2EventObject}; use crate::backend::navigator::Request; use crate::context::UpdateContext; use crate::loader::Error; @@ -552,16 +553,20 @@ impl<'gc> NetStream<'gc> { /// Trigger a status event on the stream. pub fn trigger_status_event( self, - _context: &mut UpdateContext<'_, 'gc>, - _values: &[(&str, &str)], + context: &mut UpdateContext<'_, 'gc>, + values: &[(&'static str, &'static str)], ) { let object = self.0.read().avm_object; match object { Some(AvmObject::Avm1(_object)) => { tracing::warn!("Status event (AVM1) is a stub!"); } - Some(AvmObject::Avm2(_object)) => { - tracing::warn!("Status event (AVM2) is a stub!"); + Some(AvmObject::Avm2(object)) => { + let domain = context.avm2.stage_domain(); + let mut activation = Avm2Activation::from_domain(context.reborrow(), domain); + let net_status_event = + Avm2EventObject::net_status_event(&mut activation, "netStatus", values); + Avm2::dispatch_event(&mut activation.context, net_status_event, object); } None => {} }