core: Add SharedObject object type
This commit is contained in:
parent
752ffc5cca
commit
0c6a7b3b4c
|
@ -26,6 +26,7 @@ pub(crate) mod number;
|
||||||
mod object;
|
mod object;
|
||||||
mod point;
|
mod point;
|
||||||
mod rectangle;
|
mod rectangle;
|
||||||
|
pub(crate) mod shared_object;
|
||||||
mod sound;
|
mod sound;
|
||||||
mod stage;
|
mod stage;
|
||||||
pub(crate) mod string;
|
pub(crate) mod string;
|
||||||
|
@ -33,7 +34,6 @@ pub(crate) mod system;
|
||||||
pub(crate) mod system_capabilities;
|
pub(crate) mod system_capabilities;
|
||||||
pub(crate) mod system_ime;
|
pub(crate) mod system_ime;
|
||||||
pub(crate) mod system_security;
|
pub(crate) mod system_security;
|
||||||
pub(crate) mod shared_object;
|
|
||||||
pub(crate) mod text_field;
|
pub(crate) mod text_field;
|
||||||
mod text_format;
|
mod text_format;
|
||||||
mod xml;
|
mod xml;
|
||||||
|
@ -326,8 +326,17 @@ pub fn create_globals<'gc>(
|
||||||
|
|
||||||
let shared_object_proto = shared_object::create_proto(gc_context, object_proto, function_proto);
|
let shared_object_proto = shared_object::create_proto(gc_context, object_proto, function_proto);
|
||||||
|
|
||||||
let shared_obj = shared_object::create_shared_object_object(gc_context, Some(shared_object_proto), Some(function_proto));
|
let shared_obj = shared_object::create_shared_object_object(
|
||||||
globals.define_value(gc_context, "SharedObject", shared_obj.into(), EnumSet::empty());
|
gc_context,
|
||||||
|
Some(shared_object_proto),
|
||||||
|
Some(function_proto),
|
||||||
|
);
|
||||||
|
globals.define_value(
|
||||||
|
gc_context,
|
||||||
|
"SharedObject",
|
||||||
|
shared_obj.into(),
|
||||||
|
EnumSet::empty(),
|
||||||
|
);
|
||||||
|
|
||||||
let system_security =
|
let system_security =
|
||||||
system_security::create(gc_context, Some(object_proto), Some(function_proto));
|
system_security::create(gc_context, Some(object_proto), Some(function_proto));
|
||||||
|
|
|
@ -1,12 +1,300 @@
|
||||||
use crate::avm1::{ScriptObject, Avm1, Value, Error, TObject};
|
|
||||||
use gc_arena::MutationContext;
|
|
||||||
use crate::avm1::function::{Executable, FunctionObject};
|
use crate::avm1::function::{Executable, FunctionObject};
|
||||||
use enumset::EnumSet;
|
|
||||||
use crate::context::UpdateContext;
|
|
||||||
use crate::avm1::return_value::ReturnValue;
|
use crate::avm1::return_value::ReturnValue;
|
||||||
use crate::avm1::object::Object;
|
use crate::avm1::{Avm1, Error, Object, ObjectPtr, ScriptObject, TObject, Value};
|
||||||
use json::JsonValue;
|
use crate::context::UpdateContext;
|
||||||
|
use enumset::EnumSet;
|
||||||
|
use gc_arena::{GcCell, MutationContext, Collect};
|
||||||
|
use crate::avm1::property::Attribute;
|
||||||
|
use crate::display_object::DisplayObject;
|
||||||
|
use crate::avm1::sound_object::SoundObject;
|
||||||
|
|
||||||
|
use json::JsonValue;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// A SharedObject
|
||||||
|
#[derive(Clone, Copy, Collect)]
|
||||||
|
#[collect(no_drop)]
|
||||||
|
pub struct SharedObject<'gc>(GcCell<'gc, SharedObjectData<'gc>>);
|
||||||
|
|
||||||
|
#[derive(Clone, Collect)]
|
||||||
|
#[collect(no_drop)]
|
||||||
|
pub struct SharedObjectData<'gc> {
|
||||||
|
/// The underlying script object.
|
||||||
|
base: ScriptObject<'gc>,
|
||||||
|
|
||||||
|
/// The local name of this shared object
|
||||||
|
name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SharedObject<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let this = self.0.read();
|
||||||
|
f.debug_struct("SharedObject")
|
||||||
|
.field("name", &this.name)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'gc> SharedObject<'gc> {
|
||||||
|
fn empty_shared_obj(
|
||||||
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
proto: Option<Object<'gc>>,
|
||||||
|
) -> Self {
|
||||||
|
SharedObject(GcCell::allocate(
|
||||||
|
gc_context,
|
||||||
|
SharedObjectData {
|
||||||
|
base: ScriptObject::object(gc_context, proto),
|
||||||
|
name: None,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
//TODO: any need for these
|
||||||
|
|
||||||
|
//TODO: use enum Remote(url), Local(name)
|
||||||
|
|
||||||
|
fn set_name(&self, gc_context: MutationContext<'gc, '_>, name: String) {
|
||||||
|
self.0.write(gc_context).name = Some(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self) -> String {
|
||||||
|
self.0.read().name.as_ref().cloned().unwrap_or("".to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn base(self) -> ScriptObject<'gc> {
|
||||||
|
self.0.read().base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'gc> TObject<'gc> for SharedObject<'gc> {
|
||||||
|
fn get_local(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
this: Object<'gc>,
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
|
self.base().get_local(name, avm, context, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
value: Value<'gc>,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.base().set(name, value, avm, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(
|
||||||
|
&self,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
this: Object<'gc>,
|
||||||
|
base_proto: Option<Object<'gc>>,
|
||||||
|
args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
|
self.base().call(avm, context, this, base_proto, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_setter(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
value: Value<'gc>,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
this: Object<'gc>,
|
||||||
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
|
self.base().call_setter(name, value, avm, context, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::new_ret_no_self)]
|
||||||
|
fn new(
|
||||||
|
&self,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
_this: Object<'gc>,
|
||||||
|
_args: &[Value<'gc>],
|
||||||
|
) -> Result<Object<'gc>, Error> {
|
||||||
|
Ok(SharedObject::empty_shared_obj(context.gc_context, Some(avm.prototypes.shared_object)).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete(
|
||||||
|
&self,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
name: &str,
|
||||||
|
) -> bool {
|
||||||
|
self.base().delete(avm, gc_context, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proto(&self) -> Option<Object<'gc>> {
|
||||||
|
self.base().proto()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_proto(&self, gc_context: MutationContext<'gc, '_>, prototype: Option<Object<'gc>>) {
|
||||||
|
self.base().set_proto(gc_context, prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn define_value(
|
||||||
|
&self,
|
||||||
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
name: &str,
|
||||||
|
value: Value<'gc>,
|
||||||
|
attributes: EnumSet<Attribute>,
|
||||||
|
) {
|
||||||
|
self.base()
|
||||||
|
.define_value(gc_context, name, value, attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_attributes(
|
||||||
|
&mut self,
|
||||||
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
name: Option<&str>,
|
||||||
|
set_attributes: EnumSet<Attribute>,
|
||||||
|
clear_attributes: EnumSet<Attribute>,
|
||||||
|
) {
|
||||||
|
self.base()
|
||||||
|
.set_attributes(gc_context, name, set_attributes, clear_attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_property(
|
||||||
|
&self,
|
||||||
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
name: &str,
|
||||||
|
get: Executable<'gc>,
|
||||||
|
set: Option<Executable<'gc>>,
|
||||||
|
attributes: EnumSet<Attribute>,
|
||||||
|
) {
|
||||||
|
self.base()
|
||||||
|
.add_property(gc_context, name, get, set, attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_property_with_case(
|
||||||
|
&self,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
name: &str,
|
||||||
|
get: Executable<'gc>,
|
||||||
|
set: Option<Executable<'gc>>,
|
||||||
|
attributes: EnumSet<Attribute>,
|
||||||
|
) {
|
||||||
|
self.base()
|
||||||
|
.add_property_with_case(avm, gc_context, name, get, set, attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_property(
|
||||||
|
&self,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
name: &str,
|
||||||
|
) -> bool {
|
||||||
|
self.base().has_property(avm, context, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_own_property(
|
||||||
|
&self,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
name: &str,
|
||||||
|
) -> bool {
|
||||||
|
self.base().has_own_property(avm, context, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_own_virtual(
|
||||||
|
&self,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
name: &str,
|
||||||
|
) -> bool {
|
||||||
|
self.base().has_own_virtual(avm, context, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_property_overwritable(&self, avm: &mut Avm1<'gc>, name: &str) -> bool {
|
||||||
|
self.base().is_property_overwritable(avm, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_property_enumerable(&self, avm: &mut Avm1<'gc>, name: &str) -> bool {
|
||||||
|
self.base().is_property_enumerable(avm, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_keys(&self, avm: &mut Avm1<'gc>) -> Vec<String> {
|
||||||
|
self.base().get_keys(avm)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_string(&self) -> String {
|
||||||
|
self.base().as_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_of(&self) -> &'static str {
|
||||||
|
self.base().type_of()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interfaces(&self) -> Vec<Object<'gc>> {
|
||||||
|
self.base().interfaces()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_interfaces(
|
||||||
|
&mut self,
|
||||||
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
iface_list: Vec<Object<'gc>>,
|
||||||
|
) {
|
||||||
|
self.base().set_interfaces(gc_context, iface_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_script_object(&self) -> Option<ScriptObject<'gc>> {
|
||||||
|
Some(self.base())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_display_object(&self) -> Option<DisplayObject<'gc>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_executable(&self) -> Option<Executable<'gc>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_sound_object(&self) -> Option<SoundObject<'gc>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_shared_object(&self) -> Option<SharedObject<'gc>> {
|
||||||
|
Some(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_ptr(&self) -> *const ObjectPtr {
|
||||||
|
self.0.as_ptr() as *const ObjectPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn length(&self) -> usize {
|
||||||
|
self.base().length()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array(&self) -> Vec<Value<'gc>> {
|
||||||
|
self.base().array()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_length(&self, gc_context: MutationContext<'gc, '_>, length: usize) {
|
||||||
|
self.base().set_length(gc_context, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_element(&self, index: usize) -> Value<'gc> {
|
||||||
|
self.base().array_element(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_array_element(
|
||||||
|
&self,
|
||||||
|
index: usize,
|
||||||
|
value: Value<'gc>,
|
||||||
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
) -> usize {
|
||||||
|
self.base().set_array_element(index, value, gc_context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_array_element(&self, index: usize, gc_context: MutationContext<'gc, '_>) {
|
||||||
|
self.base().delete_array_element(index, gc_context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn delete_all<'gc>(
|
pub fn delete_all<'gc>(
|
||||||
_avm: &mut Avm1<'gc>,
|
_avm: &mut Avm1<'gc>,
|
||||||
|
@ -28,65 +316,65 @@ pub fn get_disk_usage<'gc>(
|
||||||
Ok(Value::Undefined.into())
|
Ok(Value::Undefined.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_json<'gc>(json_obj: JsonValue, avm: &mut Avm1<'gc>, object: Object<'gc>, context: &mut UpdateContext<'_, 'gc, '_>) {
|
fn parse_json<'gc>(
|
||||||
|
json_obj: JsonValue,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
object: Object<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
) {
|
||||||
for entry in json_obj.entries() {
|
for entry in json_obj.entries() {
|
||||||
match entry.1 {
|
match entry.1 {
|
||||||
JsonValue::Null => {
|
JsonValue::Null => {
|
||||||
object.define_value(
|
object.define_value(context.gc_context, entry.0, Value::Null, EnumSet::empty());
|
||||||
context.gc_context,
|
}
|
||||||
entry.0,
|
|
||||||
Value::Null,
|
|
||||||
EnumSet::empty()
|
|
||||||
);
|
|
||||||
},
|
|
||||||
JsonValue::Short(s) => {
|
JsonValue::Short(s) => {
|
||||||
let val: String = s.as_str().to_string();
|
let val: String = s.as_str().to_string();
|
||||||
object.define_value(
|
object.define_value(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
entry.0,
|
entry.0,
|
||||||
Value::String(val),
|
Value::String(val),
|
||||||
EnumSet::empty()
|
EnumSet::empty(),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
JsonValue::String(s) => {
|
JsonValue::String(s) => {
|
||||||
object.define_value(
|
object.define_value(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
entry.0,
|
entry.0,
|
||||||
Value::String(s.clone()),
|
Value::String(s.clone()),
|
||||||
EnumSet::empty()
|
EnumSet::empty(),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
JsonValue::Number(f) => {
|
JsonValue::Number(f) => {
|
||||||
let val: f64 = f.clone().into();
|
let val: f64 = f.clone().into();
|
||||||
object.define_value(
|
object.define_value(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
entry.0,
|
entry.0,
|
||||||
Value::Number(val),
|
Value::Number(val),
|
||||||
EnumSet::empty()
|
EnumSet::empty(),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
JsonValue::Boolean(b) => {
|
JsonValue::Boolean(b) => {
|
||||||
object.define_value(
|
object.define_value(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
entry.0,
|
entry.0,
|
||||||
Value::Bool(*b),
|
Value::Bool(*b),
|
||||||
EnumSet::empty()
|
EnumSet::empty(),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
JsonValue::Object(o) => {
|
JsonValue::Object(o) => {
|
||||||
let so = avm.prototypes().object;
|
let so = avm.prototypes().object;
|
||||||
let obj = so.new(avm, context, so, &[]).unwrap();
|
let obj = so.new(avm, context, so, &[]).unwrap();
|
||||||
let _ = crate::avm1::globals::object::constructor(avm, context, obj, &[]).unwrap();
|
let _ = crate::avm1::globals::object::constructor(avm, context, obj, &[]).unwrap();
|
||||||
parse_json(JsonValue::Object(o.clone()), avm,obj, context);
|
parse_json(JsonValue::Object(o.clone()), avm, obj, context);
|
||||||
|
|
||||||
object.define_value(
|
object.define_value(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
entry.0,
|
entry.0,
|
||||||
Value::Object(obj),
|
Value::Object(obj),
|
||||||
EnumSet::empty()
|
EnumSet::empty(),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
JsonValue::Array(_) => {},
|
JsonValue::Array(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,9 +386,12 @@ pub fn get_local<'gc>(
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<ReturnValue<'gc>, Error> {
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
// Data property only should exist when created with getLocal/Remote
|
// Data property only should exist when created with getLocal/Remote
|
||||||
|
//TODO: use args
|
||||||
|
let name = "tmp".to_string();
|
||||||
|
|
||||||
let so = avm.prototypes().shared_object;
|
let so = avm.prototypes().shared_object;
|
||||||
let obj = so.new(avm, context, so, &[])?;
|
let obj = so.new(avm, action_context, so, &[])?;
|
||||||
let _ = crate::avm1::globals::object::constructor(avm, context, obj, &[])?;
|
let _ = constructor(avm, action_context, obj, &[])?;
|
||||||
|
|
||||||
obj.define_value(
|
obj.define_value(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
|
@ -108,12 +399,18 @@ pub fn get_local<'gc>(
|
||||||
obj.into(),
|
obj.into(),
|
||||||
EnumSet::empty(),
|
EnumSet::empty(),
|
||||||
);
|
);
|
||||||
//TODO: use args
|
|
||||||
|
|
||||||
|
let obj_so = obj.as_shared_object().unwrap();
|
||||||
|
obj_so.set_name(action_context.gc_context, name.clone());
|
||||||
|
|
||||||
let saved = action_context.storage.get_string("tmp".to_string());
|
//TODO: this should take &String
|
||||||
|
let saved = action_context.storage.get_string(name.clone());
|
||||||
if let Some(saved_data) = saved {
|
if let Some(saved_data) = saved {
|
||||||
let data = obj.get("data", avm, action_context).unwrap().as_object().unwrap();
|
let data = obj
|
||||||
|
.get("data", avm, action_context)
|
||||||
|
.unwrap()
|
||||||
|
.as_object()
|
||||||
|
.unwrap();
|
||||||
//TODO: error handle
|
//TODO: error handle
|
||||||
let js = json::parse(&saved_data).unwrap();
|
let js = json::parse(&saved_data).unwrap();
|
||||||
parse_json(js, avm, data, action_context);
|
parse_json(js, avm, data, action_context);
|
||||||
|
@ -142,7 +439,6 @@ pub fn get_max_size<'gc>(
|
||||||
Ok(Value::Undefined.into())
|
Ok(Value::Undefined.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn add_listener<'gc>(
|
pub fn add_listener<'gc>(
|
||||||
_avm: &mut Avm1<'gc>,
|
_avm: &mut Avm1<'gc>,
|
||||||
_action_context: &mut UpdateContext<'_, 'gc, '_>,
|
_action_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
@ -153,7 +449,6 @@ pub fn add_listener<'gc>(
|
||||||
Ok(Value::Undefined.into())
|
Ok(Value::Undefined.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn remove_listener<'gc>(
|
pub fn remove_listener<'gc>(
|
||||||
_avm: &mut Avm1<'gc>,
|
_avm: &mut Avm1<'gc>,
|
||||||
_action_context: &mut UpdateContext<'_, 'gc, '_>,
|
_action_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
@ -182,7 +477,7 @@ pub fn create_shared_object_object<'gc>(
|
||||||
delete_all,
|
delete_all,
|
||||||
gc_context,
|
gc_context,
|
||||||
EnumSet::empty(),
|
EnumSet::empty(),
|
||||||
fn_proto
|
fn_proto,
|
||||||
);
|
);
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
|
@ -190,7 +485,7 @@ pub fn create_shared_object_object<'gc>(
|
||||||
get_disk_usage,
|
get_disk_usage,
|
||||||
gc_context,
|
gc_context,
|
||||||
EnumSet::empty(),
|
EnumSet::empty(),
|
||||||
fn_proto
|
fn_proto,
|
||||||
);
|
);
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
|
@ -198,7 +493,7 @@ pub fn create_shared_object_object<'gc>(
|
||||||
get_local,
|
get_local,
|
||||||
gc_context,
|
gc_context,
|
||||||
EnumSet::empty(),
|
EnumSet::empty(),
|
||||||
fn_proto
|
fn_proto,
|
||||||
);
|
);
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
|
@ -206,7 +501,7 @@ pub fn create_shared_object_object<'gc>(
|
||||||
get_remote,
|
get_remote,
|
||||||
gc_context,
|
gc_context,
|
||||||
EnumSet::empty(),
|
EnumSet::empty(),
|
||||||
fn_proto
|
fn_proto,
|
||||||
);
|
);
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
|
@ -214,7 +509,7 @@ pub fn create_shared_object_object<'gc>(
|
||||||
get_max_size,
|
get_max_size,
|
||||||
gc_context,
|
gc_context,
|
||||||
EnumSet::empty(),
|
EnumSet::empty(),
|
||||||
fn_proto
|
fn_proto,
|
||||||
);
|
);
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
|
@ -222,7 +517,7 @@ pub fn create_shared_object_object<'gc>(
|
||||||
add_listener,
|
add_listener,
|
||||||
gc_context,
|
gc_context,
|
||||||
EnumSet::empty(),
|
EnumSet::empty(),
|
||||||
fn_proto
|
fn_proto,
|
||||||
);
|
);
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
|
@ -230,7 +525,7 @@ pub fn create_shared_object_object<'gc>(
|
||||||
remove_listener,
|
remove_listener,
|
||||||
gc_context,
|
gc_context,
|
||||||
EnumSet::empty(),
|
EnumSet::empty(),
|
||||||
fn_proto
|
fn_proto,
|
||||||
);
|
);
|
||||||
|
|
||||||
shared_obj
|
shared_obj
|
||||||
|
@ -243,7 +538,11 @@ pub fn clear<'gc>(
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<ReturnValue<'gc>, Error> {
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
|
|
||||||
let data = this.get("data", avm, action_context).unwrap().as_object().unwrap();
|
let data = this
|
||||||
|
.get("data", avm, action_context)
|
||||||
|
.unwrap()
|
||||||
|
.as_object()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
for k in &data.get_keys(avm) {
|
for k in &data.get_keys(avm) {
|
||||||
data.delete(avm, action_context.gc_context, k);
|
data.delete(avm, action_context.gc_context, k);
|
||||||
|
@ -275,7 +574,12 @@ pub fn connect<'gc>(
|
||||||
Ok(Value::Undefined.into())
|
Ok(Value::Undefined.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recursive_serialize<'gc>(avm: &mut Avm1<'gc>, action_context: &mut UpdateContext<'_, 'gc, '_>, obj: Object<'gc>, json_obj: &mut JsonValue) {
|
fn recursive_serialize<'gc>(
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
action_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
obj: Object<'gc>,
|
||||||
|
json_obj: &mut JsonValue,
|
||||||
|
) {
|
||||||
for k in &obj.get_keys(avm) {
|
for k in &obj.get_keys(avm) {
|
||||||
let elem = obj.get(k, avm, action_context).unwrap();
|
let elem = obj.get(k, avm, action_context).unwrap();
|
||||||
|
|
||||||
|
@ -288,13 +592,15 @@ fn recursive_serialize<'gc>(avm: &mut Avm1<'gc>, action_context: &mut UpdateCont
|
||||||
Value::String(s) => json_obj[k] = s.into(),
|
Value::String(s) => json_obj[k] = s.into(),
|
||||||
Value::Object(o) => {
|
Value::Object(o) => {
|
||||||
// Don't attempt to serialize functions, etc
|
// Don't attempt to serialize functions, etc
|
||||||
if !o.is_instance_of(avm, action_context, o, avm.prototypes().function).unwrap() {
|
if !o
|
||||||
|
.is_instance_of(avm, action_context, o, avm.prototypes().function)
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
let mut sub_data_json = JsonValue::new_object();
|
let mut sub_data_json = JsonValue::new_object();
|
||||||
recursive_serialize(avm, action_context, o, &mut sub_data_json);
|
recursive_serialize(avm, action_context, o, &mut sub_data_json);
|
||||||
json_obj[k] = sub_data_json;
|
json_obj[k] = sub_data_json;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,12 +612,22 @@ pub fn flush<'gc>(
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<ReturnValue<'gc>, Error> {
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
//TODO: consider args
|
//TODO: consider args
|
||||||
let data = _this.get("data", avm, action_context).unwrap().as_object().unwrap();
|
let data = _this
|
||||||
|
.get("data", _avm, _action_context)
|
||||||
|
.unwrap()
|
||||||
|
.as_object()
|
||||||
|
.unwrap();
|
||||||
let mut data_json = JsonValue::new_object();
|
let mut data_json = JsonValue::new_object();
|
||||||
|
|
||||||
recursive_serialize(avm, action_context, data, &mut data_json);
|
recursive_serialize(avm, action_context, data, &mut data_json);
|
||||||
|
|
||||||
//TODO: somehow need to know the name of where to save it to (hidden property?)
|
let this_obj = this.as_shared_object().unwrap();
|
||||||
|
let name = this_obj.get_name();
|
||||||
|
|
||||||
|
//TODO: take &STring
|
||||||
|
_action_context
|
||||||
|
.storage
|
||||||
|
.put_string(name.clone(), data_json.dump());
|
||||||
Ok(action_context.storage.put_string("tmp".into(), data_json.dump()).into())
|
Ok(action_context.storage.put_string("tmp".into(), data_json.dump()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,8 +637,8 @@ pub fn get_size<'gc>(
|
||||||
_this: Object<'gc>,
|
_this: Object<'gc>,
|
||||||
args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
) -> Result<ReturnValue<'gc>, Error> {
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
|
let name = args
|
||||||
let name = args.get(0)
|
.get(0)
|
||||||
.unwrap_or(&Value::Undefined)
|
.unwrap_or(&Value::Undefined)
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.coerce_to_string(avm, action_context)?;
|
.coerce_to_string(avm, action_context)?;
|
||||||
|
@ -378,24 +694,12 @@ pub fn create_proto<'gc>(
|
||||||
proto: Object<'gc>,
|
proto: Object<'gc>,
|
||||||
fn_proto: Object<'gc>,
|
fn_proto: Object<'gc>,
|
||||||
) -> Object<'gc> {
|
) -> Object<'gc> {
|
||||||
let shared_obj = ScriptObject::object(gc_context, Some(proto));
|
let shared_obj = SharedObject::empty_shared_obj(gc_context, Some(proto));
|
||||||
let mut object = shared_obj.as_script_object().unwrap();
|
let mut object = shared_obj.as_script_object().unwrap();
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function("clear", clear, gc_context, EnumSet::empty(), Some(fn_proto));
|
||||||
"clear",
|
|
||||||
clear,
|
|
||||||
gc_context,
|
|
||||||
EnumSet::empty(),
|
|
||||||
Some(fn_proto),
|
|
||||||
);
|
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function("close", close, gc_context, EnumSet::empty(), Some(fn_proto));
|
||||||
"close",
|
|
||||||
close,
|
|
||||||
gc_context,
|
|
||||||
EnumSet::empty(),
|
|
||||||
Some(fn_proto),
|
|
||||||
);
|
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
"connect",
|
"connect",
|
||||||
|
@ -405,13 +709,7 @@ pub fn create_proto<'gc>(
|
||||||
Some(fn_proto),
|
Some(fn_proto),
|
||||||
);
|
);
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function("flush", flush, gc_context, EnumSet::empty(), Some(fn_proto));
|
||||||
"flush",
|
|
||||||
flush,
|
|
||||||
gc_context,
|
|
||||||
EnumSet::empty(),
|
|
||||||
Some(fn_proto),
|
|
||||||
);
|
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
"getSize",
|
"getSize",
|
||||||
|
@ -421,13 +719,7 @@ pub fn create_proto<'gc>(
|
||||||
Some(fn_proto),
|
Some(fn_proto),
|
||||||
);
|
);
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function("send", send, gc_context, EnumSet::empty(), Some(fn_proto));
|
||||||
"send",
|
|
||||||
send,
|
|
||||||
gc_context,
|
|
||||||
EnumSet::empty(),
|
|
||||||
Some(fn_proto),
|
|
||||||
);
|
|
||||||
|
|
||||||
object.force_set_function(
|
object.force_set_function(
|
||||||
"setFps",
|
"setFps",
|
||||||
|
|
|
@ -6,6 +6,8 @@ use crate::avm1::property::Attribute;
|
||||||
use crate::avm1::return_value::ReturnValue;
|
use crate::avm1::return_value::ReturnValue;
|
||||||
use crate::avm1::super_object::SuperObject;
|
use crate::avm1::super_object::SuperObject;
|
||||||
use crate::avm1::value_object::ValueObject;
|
use crate::avm1::value_object::ValueObject;
|
||||||
|
use crate::avm1::globals::shared_object::SharedObject;
|
||||||
|
|
||||||
use crate::avm1::xml_attributes_object::XMLAttributesObject;
|
use crate::avm1::xml_attributes_object::XMLAttributesObject;
|
||||||
use crate::avm1::xml_idmap_object::XMLIDMapObject;
|
use crate::avm1::xml_idmap_object::XMLIDMapObject;
|
||||||
use crate::avm1::xml_object::XMLObject;
|
use crate::avm1::xml_object::XMLObject;
|
||||||
|
@ -13,7 +15,7 @@ use crate::avm1::{Avm1, ScriptObject, SoundObject, StageObject, UpdateContext, V
|
||||||
use crate::display_object::DisplayObject;
|
use crate::display_object::DisplayObject;
|
||||||
use crate::xml::XMLNode;
|
use crate::xml::XMLNode;
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
use gc_arena::{Collect, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
use ruffle_macros::enum_trait_object;
|
use ruffle_macros::enum_trait_object;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -33,6 +35,7 @@ use std::fmt::Debug;
|
||||||
XMLIDMapObject(XMLIDMapObject<'gc>),
|
XMLIDMapObject(XMLIDMapObject<'gc>),
|
||||||
ValueObject(ValueObject<'gc>),
|
ValueObject(ValueObject<'gc>),
|
||||||
FunctionObject(FunctionObject<'gc>),
|
FunctionObject(FunctionObject<'gc>),
|
||||||
|
SharedObject(SharedObject<'gc>)
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy {
|
pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy {
|
||||||
|
@ -379,6 +382,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the underlying `SharedObject`, if it exists
|
||||||
|
fn as_shared_object(&self) -> Option<SharedObject<'gc>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn as_ptr(&self) -> *const ObjectPtr;
|
fn as_ptr(&self) -> *const ObjectPtr;
|
||||||
|
|
||||||
/// Check if this object is in the prototype chain of the specified test object.
|
/// Check if this object is in the prototype chain of the specified test object.
|
||||||
|
|
|
@ -712,6 +712,7 @@ mod tests {
|
||||||
use crate::backend::input::NullInputBackend;
|
use crate::backend::input::NullInputBackend;
|
||||||
use crate::backend::navigator::NullNavigatorBackend;
|
use crate::backend::navigator::NullNavigatorBackend;
|
||||||
use crate::backend::render::NullRenderer;
|
use crate::backend::render::NullRenderer;
|
||||||
|
use crate::backend::storage::MemoryStorageBackend;
|
||||||
use crate::display_object::MovieClip;
|
use crate::display_object::MovieClip;
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
use crate::loader::LoadManager;
|
use crate::loader::LoadManager;
|
||||||
|
@ -721,7 +722,6 @@ mod tests {
|
||||||
use rand::{rngs::SmallRng, SeedableRng};
|
use rand::{rngs::SmallRng, SeedableRng};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::backend::storage::MemoryStorageBackend;
|
|
||||||
|
|
||||||
fn with_object<F, R>(swf_version: u8, test: F) -> R
|
fn with_object<F, R>(swf_version: u8, test: F) -> R
|
||||||
where
|
where
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::backend::audio::NullAudioBackend;
|
||||||
use crate::backend::input::NullInputBackend;
|
use crate::backend::input::NullInputBackend;
|
||||||
use crate::backend::navigator::NullNavigatorBackend;
|
use crate::backend::navigator::NullNavigatorBackend;
|
||||||
use crate::backend::render::NullRenderer;
|
use crate::backend::render::NullRenderer;
|
||||||
|
use crate::backend::storage::MemoryStorageBackend;
|
||||||
use crate::context::ActionQueue;
|
use crate::context::ActionQueue;
|
||||||
use crate::display_object::{MovieClip, TDisplayObject};
|
use crate::display_object::{MovieClip, TDisplayObject};
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
|
@ -15,7 +16,6 @@ use gc_arena::{rootless_arena, GcCell, MutationContext};
|
||||||
use rand::{rngs::SmallRng, SeedableRng};
|
use rand::{rngs::SmallRng, SeedableRng};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::backend::storage::MemoryStorageBackend;
|
|
||||||
|
|
||||||
pub fn with_avm<F, R>(swf_version: u8, test: F) -> R
|
pub fn with_avm<F, R>(swf_version: u8, test: F) -> R
|
||||||
where
|
where
|
||||||
|
|
|
@ -15,13 +15,13 @@ pub trait StorageBackend: Downcast {
|
||||||
impl_downcast!(StorageBackend);
|
impl_downcast!(StorageBackend);
|
||||||
|
|
||||||
pub struct MemoryStorageBackend {
|
pub struct MemoryStorageBackend {
|
||||||
pub map: HashMap<String, String>
|
pub map: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MemoryStorageBackend {
|
impl Default for MemoryStorageBackend {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
MemoryStorageBackend {
|
MemoryStorageBackend {
|
||||||
map: HashMap::new()
|
map: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,5 +65,3 @@ impl StorageBackend for MemoryStorageBackend {
|
||||||
// struct LocalStorageBackend {}
|
// struct LocalStorageBackend {}
|
||||||
//
|
//
|
||||||
// //TODO: check the issue about this, need to prefix with url of site somehow to avoid collisions
|
// //TODO: check the issue about this, need to prefix with url of site somehow to avoid collisions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::avm1::globals::system::SystemProperties;
|
||||||
use crate::avm1::listeners::SystemListener;
|
use crate::avm1::listeners::SystemListener;
|
||||||
use crate::avm1::{Object, Value};
|
use crate::avm1::{Object, Value};
|
||||||
use crate::backend::input::InputBackend;
|
use crate::backend::input::InputBackend;
|
||||||
|
use crate::backend::storage::StorageBackend;
|
||||||
use crate::backend::{audio::AudioBackend, navigator::NavigatorBackend, render::RenderBackend};
|
use crate::backend::{audio::AudioBackend, navigator::NavigatorBackend, render::RenderBackend};
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
use crate::loader::LoadManager;
|
use crate::loader::LoadManager;
|
||||||
|
@ -18,7 +19,6 @@ use rand::rngs::SmallRng;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
use crate::backend::storage::StorageBackend;
|
|
||||||
|
|
||||||
/// `UpdateContext` holds shared data that is used by the various subsystems of Ruffle.
|
/// `UpdateContext` holds shared data that is used by the various subsystems of Ruffle.
|
||||||
/// `Player` crates this when it begins a tick and passes it through the call stack to
|
/// `Player` crates this when it begins a tick and passes it through the call stack to
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::avm1::globals::system::SystemProperties;
|
||||||
use crate::avm1::listeners::SystemListener;
|
use crate::avm1::listeners::SystemListener;
|
||||||
use crate::avm1::{Activation, Avm1, TObject, Value};
|
use crate::avm1::{Activation, Avm1, TObject, Value};
|
||||||
use crate::backend::input::{InputBackend, MouseCursor};
|
use crate::backend::input::{InputBackend, MouseCursor};
|
||||||
|
use crate::backend::storage::StorageBackend;
|
||||||
use crate::backend::{
|
use crate::backend::{
|
||||||
audio::AudioBackend, navigator::NavigatorBackend, render::Letterbox, render::RenderBackend,
|
audio::AudioBackend, navigator::NavigatorBackend, render::Letterbox, render::RenderBackend,
|
||||||
};
|
};
|
||||||
|
@ -22,7 +23,6 @@ use std::collections::BTreeMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
use crate::backend::storage::StorageBackend;
|
|
||||||
|
|
||||||
static DEVICE_FONT_TAG: &[u8] = include_bytes!("../assets/noto-sans-definefont3.bin");
|
static DEVICE_FONT_TAG: &[u8] = include_bytes!("../assets/noto-sans-definefont3.bin");
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ impl Player {
|
||||||
navigator: Navigator,
|
navigator: Navigator,
|
||||||
input: Input,
|
input: Input,
|
||||||
movie: SwfMovie,
|
movie: SwfMovie,
|
||||||
storage: Storage
|
storage: Storage,
|
||||||
) -> Result<Arc<Mutex<Self>>, Error> {
|
) -> Result<Arc<Mutex<Self>>, Error> {
|
||||||
let movie = Arc::new(movie);
|
let movie = Arc::new(movie);
|
||||||
|
|
||||||
|
@ -193,7 +193,6 @@ impl Player {
|
||||||
view_matrix: Default::default(),
|
view_matrix: Default::default(),
|
||||||
inverse_view_matrix: Default::default(),
|
inverse_view_matrix: Default::default(),
|
||||||
|
|
||||||
|
|
||||||
rng: SmallRng::from_seed([0u8; 16]), // TODO(Herschel): Get a proper seed on all platforms.
|
rng: SmallRng::from_seed([0u8; 16]), // TODO(Herschel): Get a proper seed on all platforms.
|
||||||
|
|
||||||
gc_arena: GcArena::new(ArenaParameters::default(), |gc_context| {
|
gc_arena: GcArena::new(ArenaParameters::default(), |gc_context| {
|
||||||
|
@ -248,7 +247,7 @@ impl Player {
|
||||||
self_reference: None,
|
self_reference: None,
|
||||||
system: SystemProperties::default(),
|
system: SystemProperties::default(),
|
||||||
instance_counter: 0,
|
instance_counter: 0,
|
||||||
storage
|
storage,
|
||||||
};
|
};
|
||||||
|
|
||||||
player.mutate_with_update_context(|avm, context| {
|
player.mutate_with_update_context(|avm, context| {
|
||||||
|
@ -856,11 +855,8 @@ impl Player {
|
||||||
stage_height,
|
stage_height,
|
||||||
player,
|
player,
|
||||||
system_properties,
|
system_properties,
|
||||||
<<<<<<< HEAD
|
|
||||||
instance_counter,
|
instance_counter,
|
||||||
=======
|
|
||||||
storage,
|
storage,
|
||||||
>>>>>>> 0ca1eb0... core: Add inital storage backend implementation
|
|
||||||
) = (
|
) = (
|
||||||
self.player_version,
|
self.player_version,
|
||||||
self.global_time,
|
self.global_time,
|
||||||
|
@ -876,11 +872,8 @@ impl Player {
|
||||||
Twips::from_pixels(self.movie_height.into()),
|
Twips::from_pixels(self.movie_height.into()),
|
||||||
self.self_reference.clone(),
|
self.self_reference.clone(),
|
||||||
&mut self.system,
|
&mut self.system,
|
||||||
<<<<<<< HEAD
|
|
||||||
&mut self.instance_counter,
|
&mut self.instance_counter,
|
||||||
=======
|
|
||||||
self.storage.deref_mut(),
|
self.storage.deref_mut(),
|
||||||
>>>>>>> 0ca1eb0... core: Add inital storage backend implementation
|
|
||||||
);
|
);
|
||||||
|
|
||||||
self.gc_arena.mutate(|gc_context, gc_root| {
|
self.gc_arena.mutate(|gc_context, gc_root| {
|
||||||
|
@ -911,11 +904,8 @@ impl Player {
|
||||||
player,
|
player,
|
||||||
load_manager,
|
load_manager,
|
||||||
system: system_properties,
|
system: system_properties,
|
||||||
<<<<<<< HEAD
|
|
||||||
instance_counter,
|
instance_counter,
|
||||||
=======
|
storage,
|
||||||
storage
|
|
||||||
>>>>>>> 0ca1eb0... core: Add inital storage backend implementation
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret = f(avm, &mut update_context);
|
let ret = f(avm, &mut update_context);
|
||||||
|
|
Loading…
Reference in New Issue