Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions core/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,22 @@ impl<'gc> MovieLoader<'gc> {

mc.replace_with_movie(uc, Some(movie.clone()), true, loader_info);

// Update the MovieClip's script object prototype to match the new movie's version.
// This is needed because the level clip may have been created by a loader with
// a different SWF version, and its script object was set up with the wrong prototype.
if !movie.is_action_script_3() {
if let Some(object) = mc.object1() {
let new_proto = uc.avm1.prototypes(mc.swf_version()).movie_clip;

object.define_value(
uc.gc(),
istr!(uc, "__proto__"),
new_proto.into(),
Attribute::DONT_ENUM | Attribute::DONT_DELETE,
);
}
}

// Loaded movies are considered to be timeline-instantiated
mc.set_instantiated_by_timeline(true);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Compile with:
// mtasc -main -header 200:150:30 -version 8 Target.as -swf target.swf

class Target {
static function main(current) {
current.runProtoTest = function() {
MovieClip.prototype.customProp = "FROM_SWF8";
trace("Target (SWF8): _level2.customProp = " + _level2.customProp);
trace("Target (SWF8): _level2.__proto__ === MovieClip.prototype: " + (_level2.__proto__ === MovieClip.prototype));
};
}
}
49 changes: 49 additions & 0 deletions tests/tests/swfs/avm1/loadmovienum_cross_version_prototype/Test.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Compile with:
// mtasc -main -header 200:150:30 -version 6 Test.as -swf test.swf

class Test {
static var checkCount = 0;
static var phase = 0;

static function main(current) {
trace("Test (SWF6): Loading target.swf into _level2");
getURL("target.swf", "_level2");

current.onEnterFrame = function() {
Test.checkCount++;

if (Test.phase == 0) {
// Phase 0: Wait for load and test prototype
if (_level2 != undefined && _level2._url != undefined && _level2._url.indexOf("target.swf") >= 0) {
trace("Test (SWF6): _level2.getSWFVersion() = " + _level2.getSWFVersion());

MovieClip.prototype.testProp = "FROM_SWF6";
trace("Test (SWF6): _level2.testProp = " + _level2.testProp);
trace("Test (SWF6): _level2.__proto__ === MovieClip.prototype: " + (_level2.__proto__ === MovieClip.prototype));

if (_level2.runProtoTest != undefined) {
_level2.runProtoTest();
}

// Now test unload behavior
trace("Test (SWF6): Unloading _level2");
getURL("", "_level2");
Test.phase = 1;
Test.checkCount = 0;
} else if (Test.checkCount > 60) {
trace("Test (SWF6): Timeout");
delete current.onEnterFrame;
}
} else if (Test.phase == 1) {
// Phase 1: Check state after unload (wait a couple frames)
if (Test.checkCount >= 2) {
trace("Test (SWF6): After unload - _level2.__proto__ === MovieClip.prototype: " + (_level2.__proto__ === MovieClip.prototype));
// The prototype should still be SWF8's, not SWF6's, because the unloaded
// stub keeps the loaded movie's version
trace("Test (SWF6): After unload - _level2.testProp = " + _level2.testProp);
delete current.onEnterFrame;
}
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Test (SWF6): Loading target.swf into _level2
Test (SWF6): _level2.getSWFVersion() = 8
Test (SWF6): _level2.testProp =
Test (SWF6): _level2.__proto__ === MovieClip.prototype: false
Target (SWF8): _level2.customProp = FROM_SWF8
Target (SWF8): _level2.__proto__ === MovieClip.prototype: true
Test (SWF6): Unloading _level2
Test (SWF6): After unload - _level2.__proto__ === MovieClip.prototype: false
Test (SWF6): After unload - _level2.testProp =
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
num_frames = 6
Loading