avm2: Implement `MovieClip.currentLabels`
This commit is contained in:
parent
77a86aef9b
commit
de186ed5f3
|
@ -54,6 +54,7 @@ pub struct SystemPrototypes<'gc> {
|
|||
pub uint: Object<'gc>,
|
||||
pub namespace: Object<'gc>,
|
||||
pub array: Object<'gc>,
|
||||
pub framelabel: Object<'gc>,
|
||||
}
|
||||
|
||||
impl<'gc> SystemPrototypes<'gc> {
|
||||
|
@ -81,6 +82,7 @@ impl<'gc> SystemPrototypes<'gc> {
|
|||
uint: empty,
|
||||
namespace: empty,
|
||||
array: empty,
|
||||
framelabel: empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -377,7 +379,13 @@ pub fn load_player_globals<'gc>(activation: &mut Activation<'_, 'gc, '_>) -> Res
|
|||
flash::display::movieclip::create_class(activation.context.gc_context),
|
||||
implicit_deriver,
|
||||
)?;
|
||||
class(
|
||||
activation
|
||||
.context
|
||||
.avm2
|
||||
.system_prototypes
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.framelabel = class(
|
||||
activation,
|
||||
gs,
|
||||
flash::display::framelabel::create_class(activation.context.gc_context),
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
//! `flash.display.MovieClip` builtin/prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::array::ArrayStorage;
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::globals::flash::display::framelabel;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::{Object, TObject};
|
||||
use crate::avm2::object::{ArrayObject, Object, TObject};
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::traits::Trait;
|
||||
use crate::avm2::value::Value;
|
||||
|
@ -120,6 +122,45 @@ pub fn current_label<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Implements `currentLabels`.
|
||||
pub fn current_labels<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
if let Some(mc) = this
|
||||
.and_then(|o| o.as_display_object())
|
||||
.and_then(|dobj| dobj.as_movie_clip())
|
||||
{
|
||||
let mut frame_labels = Vec::new();
|
||||
let frame_label_proto = activation.context.avm2.prototypes().framelabel;
|
||||
let current_scene_start = mc
|
||||
.current_scene()
|
||||
.map(|(_, frame)| frame.saturating_sub(1))
|
||||
.unwrap_or(0);
|
||||
|
||||
for (name, frame) in mc.current_labels() {
|
||||
let name: Value<'gc> = AvmString::new(activation.context.gc_context, name).into();
|
||||
let local_frame = frame - current_scene_start;
|
||||
let frame_label =
|
||||
frame_label_proto.construct(activation, &[name.clone(), local_frame.into()])?;
|
||||
|
||||
framelabel::instance_init(activation, Some(frame_label), &[name, local_frame.into()])?;
|
||||
|
||||
frame_labels.push(Some(frame_label.into()));
|
||||
}
|
||||
|
||||
return Ok(ArrayObject::from_array(
|
||||
ArrayStorage::from_storage(frame_labels),
|
||||
activation.context.avm2.prototypes().array,
|
||||
activation.context.gc_context,
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Implements `framesLoaded`.
|
||||
pub fn frames_loaded<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
|
@ -379,6 +420,11 @@ pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>
|
|||
Method::from_builtin(current_label),
|
||||
));
|
||||
|
||||
write.define_instance_trait(Trait::from_getter(
|
||||
QName::new(Namespace::package(""), "currentLabels"),
|
||||
Method::from_builtin(current_labels),
|
||||
));
|
||||
|
||||
write.define_instance_trait(Trait::from_getter(
|
||||
QName::new(Namespace::package(""), "framesLoaded"),
|
||||
Method::from_builtin(frames_loaded),
|
||||
|
|
|
@ -681,6 +681,36 @@ impl<'gc> MovieClip<'gc> {
|
|||
best.map(|(s, fnum)| (s.to_string(), fnum))
|
||||
}
|
||||
|
||||
/// Yield a list of labels and frame-nubmers in the current scene.
|
||||
///
|
||||
/// Labels are returned sorted by frame number.
|
||||
pub fn current_labels(self) -> Vec<(String, FrameNumber)> {
|
||||
let read = self.0.read();
|
||||
let current_scene = self.current_scene();
|
||||
let next_scene = self.next_scene();
|
||||
|
||||
let mut values: Vec<(String, FrameNumber)> = read
|
||||
.static_data
|
||||
.frame_labels
|
||||
.iter()
|
||||
.filter(|(_label, frame)| {
|
||||
current_scene
|
||||
.as_ref()
|
||||
.map(|(_, scene_start)| **frame >= *scene_start)
|
||||
.unwrap_or(false)
|
||||
&& next_scene
|
||||
.as_ref()
|
||||
.map(|(_, scene_start)| **frame < *scene_start)
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map(|(label, frame)| (label.clone(), *frame))
|
||||
.collect();
|
||||
|
||||
values.sort_unstable_by(|(_, framea), (_, frameb)| framea.cmp(frameb));
|
||||
|
||||
values
|
||||
}
|
||||
|
||||
pub fn total_frames(self) -> FrameNumber {
|
||||
self.0.read().static_data.total_frames
|
||||
}
|
||||
|
|
|
@ -394,6 +394,7 @@ swf_tests! {
|
|||
(as3_movieclip_prev_scene, "avm2/movieclip_prev_scene", 5),
|
||||
(as3_movieclip_next_scene, "avm2/movieclip_next_scene", 5),
|
||||
(as3_framelabel_constr, "avm2/framelabel_constr", 5),
|
||||
(as3_movieclip_currentlabels, "avm2/movieclip_currentlabels", 5),
|
||||
}
|
||||
|
||||
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
//(contents of this.currentLabels)
|
||||
1
|
||||
frame1
|
||||
3
|
||||
frame3
|
||||
//(contents of this.currentLabels in scene 2)
|
||||
1
|
||||
frame4
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue