diff --git a/core/src/avm1/globals/external_interface.rs b/core/src/avm1/globals/external_interface.rs index 0318e0818..cf0a59f39 100644 --- a/core/src/avm1/globals/external_interface.rs +++ b/core/src/avm1/globals/external_interface.rs @@ -41,6 +41,21 @@ pub fn add_callback<'gc>( } } +pub fn call<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + _this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if args.is_empty() { + return Ok(Value::Null); + } + + let name = args.get(0).unwrap().coerce_to_string(activation)?; + activation.context.external_interface.call_external(&name); + + Ok(Value::Null) +} + pub fn create_external_interface_object<'gc>( gc_context: MutationContext<'gc, '_>, proto: Object<'gc>, @@ -69,6 +84,14 @@ pub fn create_external_interface_object<'gc>( Some(fn_proto), ); + object.force_set_function( + "call", + call, + gc_context, + Attribute::DontDelete | Attribute::DontEnum, + Some(fn_proto), + ); + object.into() } diff --git a/core/src/external.rs b/core/src/external.rs index fb8952ed3..5ce5a8600 100644 --- a/core/src/external.rs +++ b/core/src/external.rs @@ -36,7 +36,9 @@ impl<'gc> Callback<'gc> { } } -pub trait ExternalInterfaceProvider {} +pub trait ExternalInterfaceProvider { + fn call(&self, name: &str) -> Option<()>; +} #[derive(Default)] pub struct ExternalInterface<'gc> { @@ -68,6 +70,14 @@ impl<'gc> ExternalInterface<'gc> { self.callbacks.get(name).cloned() } + pub fn call_external(&self, name: &str) { + for provider in &self.providers { + if provider.call(name).is_some() { + return; + } + } + } + pub fn available(&self) -> bool { !self.providers.is_empty() } diff --git a/core/tests/regression_tests.rs b/core/tests/regression_tests.rs index 90abfe1b1..c9d133368 100644 --- a/core/tests/regression_tests.rs +++ b/core/tests/regression_tests.rs @@ -546,4 +546,14 @@ impl ExternalInterfaceTestProvider { } } -impl ExternalInterfaceProvider for ExternalInterfaceTestProvider {} +impl ExternalInterfaceProvider for ExternalInterfaceTestProvider { + fn call(&self, name: &str) -> Option<()> { + match name { + "ping" => { + log::info!(target: "avm_trace", "[ExternalInterface] ping"); + Some(()) + } + _ => None, + } + } +} diff --git a/core/tests/swfs/avm1/external_interface/output.txt b/core/tests/swfs/avm1/external_interface/output.txt index 37705eb17..795676f18 100644 --- a/core/tests/swfs/avm1/external_interface/output.txt +++ b/core/tests/swfs/avm1/external_interface/output.txt @@ -4,6 +4,16 @@ true // ExternalInterface.addCallback("dump", object, dump) true +// ExternalInterface.call() +null + +// ExternalInterface.call("ping") +[ExternalInterface] ping +null + +// ExternalInterface.call("non_existent") +null + /// dump() start // this [object Object] diff --git a/core/tests/swfs/avm1/external_interface/test.fla b/core/tests/swfs/avm1/external_interface/test.fla index 4d44834df..9f2d0726a 100644 Binary files a/core/tests/swfs/avm1/external_interface/test.fla and b/core/tests/swfs/avm1/external_interface/test.fla differ diff --git a/core/tests/swfs/avm1/external_interface/test.swf b/core/tests/swfs/avm1/external_interface/test.swf index 6a43174d9..2d03d6554 100644 Binary files a/core/tests/swfs/avm1/external_interface/test.swf and b/core/tests/swfs/avm1/external_interface/test.swf differ