avm2: Convert SharedObject to AS3

This commit is contained in:
Adrian Wielgosik 2022-12-19 11:38:07 +01:00 committed by Adrian Wielgosik
parent f3ebb0c297
commit e90d595cb3
6 changed files with 43 additions and 97 deletions

View File

@ -86,7 +86,6 @@ pub struct SystemClasses<'gc> {
pub bitmapdata: ClassObject<'gc>, pub bitmapdata: ClassObject<'gc>,
pub date: ClassObject<'gc>, pub date: ClassObject<'gc>,
pub qname: ClassObject<'gc>, pub qname: ClassObject<'gc>,
pub sharedobject: ClassObject<'gc>,
pub mouseevent: ClassObject<'gc>, pub mouseevent: ClassObject<'gc>,
pub progressevent: ClassObject<'gc>, pub progressevent: ClassObject<'gc>,
pub textevent: ClassObject<'gc>, pub textevent: ClassObject<'gc>,
@ -172,7 +171,6 @@ impl<'gc> SystemClasses<'gc> {
bitmapdata: object, bitmapdata: object,
date: object, date: object,
qname: object, qname: object,
sharedobject: object,
mouseevent: object, mouseevent: object,
progressevent: object, progressevent: object,
textevent: object, textevent: object,
@ -572,14 +570,6 @@ pub fn load_player_globals<'gc>(
script script
); );
// package `flash.net`
avm2_system_class!(
sharedobject,
activation,
flash::net::sharedobject::create_class(mc),
script
);
// package `flash.text` // package `flash.text`
avm2_system_class!( avm2_system_class!(
textfield, textfield,

View File

@ -4,7 +4,7 @@ use crate::avm2::object::TObject;
use crate::avm2::{Activation, Error, Multiname, Object, Value}; use crate::avm2::{Activation, Error, Multiname, Object, Value};
pub mod object_encoding; pub mod object_encoding;
pub mod sharedobject; pub mod shared_object;
pub mod url_loader; pub mod url_loader;
/// Implements `flash.net.navigateToURL` /// Implements `flash.net.navigateToURL`

View File

@ -0,0 +1,34 @@
package flash.net
{
import flash.events.EventDispatcher;
namespace ruffle = "__ruffle__";
public class SharedObject extends EventDispatcher
{
public function SharedObject()
{
this.data = {};
}
// NOTE: We currently always use AMF3 serialization.
// If you implement the `defaultObjectEncoding` or `objectEncoding`,
// you will need to adjust the serialization and deserialization code
// to work with AMF0.
native public static function getLocal(name:String, localPath:String = null, secure:Boolean = false): SharedObject;
native public function flush(minDiskSpace:int = 0) : String;
native public function close() : void;
native public function clear() : void;
// note: this is supposed to be a read-only property
public var data: Object;
// note: this is supposed to be a read-only property
public var size: uint;
ruffle var _ruffleName: String;
}
}

View File

@ -1,49 +1,17 @@
//! `flash.net.SharedObject` builtin/prototype //! `flash.net.SharedObject` builtin/prototype
use crate::avm2::class::{Class, ClassAttributes};
use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::TObject; use crate::avm2::object::TObject;
use crate::avm2::traits::Trait;
use crate::avm2::Multiname; use crate::avm2::Multiname;
use crate::avm2::{Activation, Error, Namespace, Object, QName, Value}; use crate::avm2::{Activation, Error, Namespace, Object, Value};
use crate::display_object::DisplayObject; use crate::display_object::DisplayObject;
use crate::display_object::TDisplayObject; use crate::display_object::TDisplayObject;
use crate::string::AvmString; use crate::string::AvmString;
use flash_lso::types::{AMFVersion, Lso}; use flash_lso::types::{AMFVersion, Lso};
use gc_arena::{GcCell, MutationContext};
use std::borrow::Cow; use std::borrow::Cow;
fn instance_init<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(mut this) = this {
activation.super_init(this, &[])?;
let data = activation
.context
.avm2
.classes()
.object
.construct(activation, &[])?;
this.set_property(&Multiname::public("data"), data.into(), activation)?;
}
Ok(Value::Undefined)
}
fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(Value::Undefined)
}
pub fn get_local<'gc>( pub fn get_local<'gc>(
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>, this: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> { ) -> Result<Value<'gc>, Error<'gc>> {
// TODO: It appears that Flash does some kind of escaping here: // TODO: It appears that Flash does some kind of escaping here:
@ -169,11 +137,11 @@ pub fn get_local<'gc>(
} }
// Data property only should exist when created with getLocal/Remote // Data property only should exist when created with getLocal/Remote
let constructor = activation.avm2().classes().sharedobject; let sharedobject_cls = this.unwrap(); // `this` of a static method is the class
let mut this = constructor.construct(activation, &[])?; let mut this = sharedobject_cls.construct(activation, &[])?;
// Set the internal name // Set the internal name
let ruffle_name = Multiname::new(Namespace::Private("".into()), "_ruffleName"); let ruffle_name = Multiname::new(Namespace::Namespace("__ruffle__".into()), "_ruffleName");
this.set_property( this.set_property(
&ruffle_name, &ruffle_name,
AvmString::new_utf8(activation.context.gc_context, &full_name).into(), AvmString::new_utf8(activation.context.gc_context, &full_name).into(),
@ -218,7 +186,7 @@ pub fn flush<'gc>(
.get_property(&Multiname::public("data"), activation)? .get_property(&Multiname::public("data"), activation)?
.coerce_to_object(activation)?; .coerce_to_object(activation)?;
let ruffle_name = Multiname::new(Namespace::Private("".into()), "_ruffleName"); let ruffle_name = Multiname::new(Namespace::Namespace("__ruffle__".into()), "_ruffleName");
let name = this let name = this
.get_property(&ruffle_name, activation)? .get_property(&ruffle_name, activation)?
.coerce_to_string(activation)?; .coerce_to_string(activation)?;
@ -260,50 +228,3 @@ pub fn clear<'gc>(
log::warn!("SharedObject.clear - not yet implemented"); log::warn!("SharedObject.clear - not yet implemented");
Ok(Value::Undefined) Ok(Value::Undefined)
} }
/// Construct `SharedObject`'s class.
/// NOTE: We currently always use AMF3 serialization.
/// If you implement the `defaultObjectEncoding` or `objectEncoding`,
/// you will need to adjust the serialization and deserialization code
/// to work with AMF0.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
let class = Class::new(
QName::new(Namespace::package("flash.net"), "SharedObject"),
Some(Multiname::new(
Namespace::package("flash.events"),
"EventDispatcher",
)),
Method::from_builtin(instance_init, "<SharedObject instance initializer>", mc),
Method::from_builtin(class_init, "<SharedObject class initializer>", mc),
mc,
);
let mut write = class.write(mc);
write.set_attributes(ClassAttributes::SEALED);
write.define_instance_trait(Trait::from_slot(
QName::new(Namespace::public(), "data"),
Multiname::public("Object"),
None,
));
write.define_instance_trait(Trait::from_slot(
QName::new(Namespace::public(), "size"),
Multiname::public("uint"),
None,
));
write.define_instance_trait(Trait::from_slot(
QName::new(Namespace::private(""), "_ruffleName"),
Multiname::public("String"),
None,
));
const PUBLIC_CLASS_METHODS: &[(&str, NativeMethodImpl)] = &[("getLocal", get_local)];
write.define_public_builtin_class_methods(mc, PUBLIC_CLASS_METHODS);
const PUBLIC_INSTANCE_METHODS: &[(&str, NativeMethodImpl)] =
&[("flush", flush), ("close", close), ("clear", clear)];
write.define_public_builtin_instance_methods(mc, PUBLIC_INSTANCE_METHODS);
class
}

View File

@ -178,6 +178,7 @@ include "flash/net/NetGroupReplicationStrategy.as"
include "flash/net/NetGroupSendMode.as" include "flash/net/NetGroupSendMode.as"
include "flash/net/NetGroupSendResult.as" include "flash/net/NetGroupSendResult.as"
include "flash/net/ObjectEncoding.as" include "flash/net/ObjectEncoding.as"
include "flash/net/SharedObject.as"
include "flash/net/SharedObjectFlushStatus.as" include "flash/net/SharedObjectFlushStatus.as"
include "flash/net/URLLoader.as" include "flash/net/URLLoader.as"
include "flash/net/URLLoaderDataFormat.as" include "flash/net/URLLoaderDataFormat.as"

View File

@ -1805,7 +1805,7 @@ impl Player {
let mut avm2_activation = let mut avm2_activation =
Avm2Activation::from_nothing(avm1_activation.context.reborrow()); Avm2Activation::from_nothing(avm1_activation.context.reborrow());
for so in avm2_activation.context.avm2_shared_objects.clone().values() { for so in avm2_activation.context.avm2_shared_objects.clone().values() {
if let Err(e) = crate::avm2::globals::flash::net::sharedobject::flush( if let Err(e) = crate::avm2::globals::flash::net::shared_object::flush(
&mut avm2_activation, &mut avm2_activation,
Some(*so), Some(*so),
&[], &[],