core: Introduce a NetConnection struct, backing AVM1/AVM2 NetConnection objects

This commit is contained in:
Nathan Adams 2023-11-01 16:35:05 +01:00
parent 514611451f
commit c691b32886
8 changed files with 227 additions and 10 deletions

View File

@ -3,6 +3,7 @@ package flash.net {
import flash.errors.IOError;
import __ruffle__.stub_method;
[Ruffle(InstanceAllocator)]
public class NetConnection extends EventDispatcher {
public static var defaultObjectEncoding:uint = 3;

View File

@ -1,5 +1,8 @@
pub use crate::avm2::object::net_connection_allocator;
use crate::avm2::object::TObject;
use crate::net_connection::NetConnections;
use crate::{
avm2::{Activation, Avm2, Error, EventObject, Object, Value},
avm2::{Activation, Error, Object, Value},
avm2_stub_method,
};
@ -8,16 +11,12 @@ pub fn connect<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let connection = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Value::Null = args[0] {
let event = EventObject::net_status_event(
activation,
"netStatus",
vec![
("code", "NetConnection.Connect.Success"),
("level", "status"),
],
);
Avm2::dispatch_event(&mut activation.context, event, this);
NetConnections::connect_to_local(&mut activation.context, connection);
return Ok(Value::Undefined);
}
avm2_stub_method!(

View File

@ -45,6 +45,7 @@ mod function_object;
mod index_buffer_3d_object;
mod loaderinfo_object;
mod namespace_object;
mod net_connection_object;
mod netstream_object;
mod primitive_object;
mod program_3d_object;
@ -97,6 +98,9 @@ pub use crate::avm2::object::loaderinfo_object::{
pub use crate::avm2::object::namespace_object::{
namespace_allocator, NamespaceObject, NamespaceObjectWeak,
};
pub use crate::avm2::object::net_connection_object::{
net_connection_allocator, NetConnectionObject, NetConnectionObjectWeak,
};
pub use crate::avm2::object::netstream_object::{
netstream_allocator, NetStreamObject, NetStreamObjectWeak,
};
@ -175,6 +179,7 @@ use crate::font::Font;
TextureObject(TextureObject<'gc>),
Program3DObject(Program3DObject<'gc>),
NetStreamObject(NetStreamObject<'gc>),
NetConnectionObject(NetConnectionObject<'gc>),
ShaderDataObject(ShaderDataObject<'gc>),
SocketObject(SocketObject<'gc>),
FontObject(FontObject<'gc>)
@ -1385,6 +1390,10 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
None
}
fn as_net_connection(self) -> Option<NetConnectionObject<'gc>> {
None
}
fn as_socket(&self) -> Option<SocketObject<'gc>> {
None
}
@ -1432,6 +1441,7 @@ impl<'gc> Object<'gc> {
Self::TextureObject(o) => WeakObject::TextureObject(TextureObjectWeak(Gc::downgrade(o.0))),
Self::Program3DObject(o) => WeakObject::Program3DObject(Program3DObjectWeak(Gc::downgrade(o.0))),
Self::NetStreamObject(o) => WeakObject::NetStreamObject(NetStreamObjectWeak(GcCell::downgrade(o.0))),
Self::NetConnectionObject(o) => WeakObject::NetConnectionObject(NetConnectionObjectWeak(Gc::downgrade(o.0))),
Self::ShaderDataObject(o) => WeakObject::ShaderDataObject(ShaderDataObjectWeak(Gc::downgrade(o.0))),
Self::SocketObject(o) => WeakObject::SocketObject(SocketObjectWeak(Gc::downgrade(o.0))),
Self::FontObject(o) => WeakObject::FontObject(FontObjectWeak(GcCell::downgrade(o.0))),
@ -1489,6 +1499,7 @@ pub enum WeakObject<'gc> {
TextureObject(TextureObjectWeak<'gc>),
Program3DObject(Program3DObjectWeak<'gc>),
NetStreamObject(NetStreamObjectWeak<'gc>),
NetConnectionObject(NetConnectionObjectWeak<'gc>),
ShaderDataObject(ShaderDataObjectWeak<'gc>),
SocketObject(SocketObjectWeak<'gc>),
FontObject(FontObjectWeak<'gc>),
@ -1529,6 +1540,7 @@ impl<'gc> WeakObject<'gc> {
Self::TextureObject(o) => TextureObject(o.0.upgrade(mc)?).into(),
Self::Program3DObject(o) => Program3DObject(o.0.upgrade(mc)?).into(),
Self::NetStreamObject(o) => NetStreamObject(o.0.upgrade(mc)?).into(),
Self::NetConnectionObject(o) => NetConnectionObject(o.0.upgrade(mc)?).into(),
Self::ShaderDataObject(o) => ShaderDataObject(o.0.upgrade(mc)?).into(),
Self::SocketObject(o) => SocketObject(o.0.upgrade(mc)?).into(),
Self::FontObject(o) => FontObject(o.0.upgrade(mc)?).into(),

View File

@ -0,0 +1,85 @@
//! Object representation for NetConnection
use crate::avm2::activation::Activation;
use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::net_connection::NetConnectionHandle;
use gc_arena::barrier::unlock;
use gc_arena::lock::RefLock;
use gc_arena::{Collect, Gc, GcWeak, Mutation};
use std::cell::{Cell, Ref, RefMut};
use std::fmt;
use std::fmt::Debug;
pub fn net_connection_allocator<'gc>(
class: ClassObject<'gc>,
activation: &mut Activation<'_, 'gc>,
) -> Result<Object<'gc>, Error<'gc>> {
let base = ScriptObjectData::new(class).into();
let this: Object<'gc> = NetConnectionObject(Gc::new(
activation.context.gc_context,
NetConnectionObjectData {
base,
handle: Cell::new(None),
},
))
.into();
Ok(this)
}
#[derive(Clone, Collect, Copy)]
#[collect(no_drop)]
pub struct NetConnectionObject<'gc>(pub Gc<'gc, NetConnectionObjectData<'gc>>);
#[derive(Collect, Clone, Copy, Debug)]
#[collect(no_drop)]
pub struct NetConnectionObjectWeak<'gc>(pub GcWeak<'gc, NetConnectionObjectData<'gc>>);
#[derive(Collect)]
#[collect(no_drop)]
pub struct NetConnectionObjectData<'gc> {
base: RefLock<ScriptObjectData<'gc>>,
#[collect(require_static)]
handle: Cell<Option<NetConnectionHandle>>,
}
impl<'gc> TObject<'gc> for NetConnectionObject<'gc> {
fn base(&self) -> Ref<ScriptObjectData<'gc>> {
self.0.base.borrow()
}
fn base_mut(&self, mc: &Mutation<'gc>) -> RefMut<ScriptObjectData<'gc>> {
unlock!(Gc::write(mc, self.0), NetConnectionObjectData, base).borrow_mut()
}
fn as_ptr(&self) -> *const ObjectPtr {
Gc::as_ptr(self.0) as *const ObjectPtr
}
fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
Ok(Value::Object(Object::from(*self)))
}
fn as_net_connection(self) -> Option<NetConnectionObject<'gc>> {
Some(self)
}
}
impl<'gc> NetConnectionObject<'gc> {
pub fn handle(&self) -> Option<NetConnectionHandle> {
self.0.handle.get()
}
pub fn set_handle(&self, handle: Option<NetConnectionHandle>) -> Option<NetConnectionHandle> {
self.0.handle.replace(handle)
}
}
impl<'gc> Debug for NetConnectionObject<'gc> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NetConnectionObject")
}
}

View File

@ -18,6 +18,7 @@ use crate::focus_tracker::FocusTracker;
use crate::frame_lifecycle::FramePhase;
use crate::library::Library;
use crate::loader::LoadManager;
use crate::net_connection::NetConnections;
use crate::player::Player;
use crate::prelude::*;
use crate::socket::Sockets;
@ -227,6 +228,9 @@ pub struct UpdateContext<'a, 'gc> {
pub sockets: &'a mut Sockets<'gc>,
/// List of active NetConnection instances.
pub net_connections: &'a mut NetConnections<'gc>,
/// Dynamic root for allowing handles to GC objects to exist outside of the GC.
pub dynamic_root: gc_arena::DynamicRootSet<'gc>,
}
@ -394,6 +398,7 @@ impl<'a, 'gc> UpdateContext<'a, 'gc> {
frame_phase: self.frame_phase,
stream_manager: self.stream_manager,
sockets: self.sockets,
net_connections: self.net_connections,
dynamic_root: self.dynamic_root,
}
}

View File

@ -38,6 +38,7 @@ mod library;
pub mod limits;
pub mod loader;
mod locale;
mod net_connection;
pub mod pixel_bender;
mod player;
mod prelude;

105
core/src/net_connection.rs Normal file
View File

@ -0,0 +1,105 @@
use crate::avm2::object::NetConnectionObject as Avm2NetConnectionObject;
use crate::avm2::{Activation as Avm2Activation, Avm2, EventObject as Avm2EventObject};
use crate::context::UpdateContext;
use gc_arena::Collect;
use generational_arena::{Arena, Index};
pub type NetConnectionHandle = Index;
#[derive(Copy, Clone, Collect)]
#[collect(no_drop)]
pub enum NetConnectionObject<'gc> {
Avm2(Avm2NetConnectionObject<'gc>),
}
impl<'gc> NetConnectionObject<'gc> {
pub fn set_handle(&self, handle: Option<NetConnectionHandle>) -> Option<NetConnectionHandle> {
match self {
NetConnectionObject::Avm2(object) => object.set_handle(handle),
}
}
}
impl<'gc> From<Avm2NetConnectionObject<'gc>> for NetConnectionObject<'gc> {
fn from(value: Avm2NetConnectionObject<'gc>) -> Self {
NetConnectionObject::Avm2(value)
}
}
/// Manages the collection of NetConnections.
pub struct NetConnections<'gc> {
connections: Arena<NetConnection<'gc>>,
}
unsafe impl<'gc> Collect for NetConnections<'gc> {
fn trace(&self, cc: &gc_arena::Collection) {
for (_, connection) in self.connections.iter() {
connection.trace(cc)
}
}
}
impl<'gc> Default for NetConnections<'gc> {
fn default() -> Self {
Self {
connections: Arena::new(),
}
}
}
impl<'gc> NetConnections<'gc> {
pub fn connect_to_local<O: Into<NetConnectionObject<'gc>>>(
context: &mut UpdateContext<'_, 'gc>,
target: O,
) {
let target = target.into();
let connection = NetConnection { object: target };
let handle = context.net_connections.connections.insert(connection);
if let Some(existing_handle) = target.set_handle(Some(handle)) {
NetConnections::close(context, existing_handle)
}
match target {
NetConnectionObject::Avm2(object) => {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let event = Avm2EventObject::net_status_event(
&mut activation,
"netStatus",
vec![
("code", "NetConnection.Connect.Success"),
("level", "status"),
],
);
Avm2::dispatch_event(&mut activation.context, event, object.into());
}
}
}
pub fn close(context: &mut UpdateContext<'_, 'gc>, handle: NetConnectionHandle) {
let Some(connection) = context.net_connections.connections.remove(handle) else {
return;
};
match connection.object {
NetConnectionObject::Avm2(object) => {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let event = Avm2EventObject::net_status_event(
&mut activation,
"netStatus",
vec![
("code", "NetConnection.Connect.Closed"),
("level", "status"),
],
);
Avm2::dispatch_event(&mut activation.context, event, object.into());
}
}
}
}
#[derive(Collect)]
#[collect(no_drop)]
pub struct NetConnection<'gc> {
object: NetConnectionObject<'gc>,
}

View File

@ -39,6 +39,7 @@ use crate::library::Library;
use crate::limits::ExecutionLimit;
use crate::loader::{LoadBehavior, LoadManager};
use crate::locale::get_current_date_time;
use crate::net_connection::NetConnections;
use crate::prelude::*;
use crate::socket::Sockets;
use crate::streams::StreamManager;
@ -167,6 +168,9 @@ struct GcRootData<'gc> {
sockets: Sockets<'gc>,
/// List of active NetConnection objects.
net_connections: NetConnections<'gc>,
/// Dynamic root for allowing handles to GC objects to exist outside of the GC.
dynamic_root: DynamicRootSet<'gc>,
}
@ -195,6 +199,7 @@ impl<'gc> GcRootData<'gc> {
&mut AudioManager<'gc>,
&mut StreamManager<'gc>,
&mut Sockets<'gc>,
&mut NetConnections<'gc>,
DynamicRootSet<'gc>,
) {
(
@ -215,6 +220,7 @@ impl<'gc> GcRootData<'gc> {
&mut self.audio_manager,
&mut self.stream_manager,
&mut self.sockets,
&mut self.net_connections,
self.dynamic_root,
)
}
@ -1889,6 +1895,7 @@ impl Player {
audio_manager,
stream_manager,
sockets,
net_connections,
dynamic_root,
) = root_data.update_context_params();
@ -1940,6 +1947,7 @@ impl Player {
stub_tracker: &mut self.stub_tracker,
stream_manager,
sockets,
net_connections,
dynamic_root,
};
@ -2423,6 +2431,7 @@ impl PlayerBuilder {
unbound_text_fields: Vec::new(),
stream_manager: StreamManager::new(),
sockets: Sockets::empty(),
net_connections: NetConnections::default(),
dynamic_root,
},
),