ruffle icon indicating copy to clipboard operation
ruffle copied to clipboard

Meaty B - Worked via Ruffle in the past but currently a white screen.

Open TomFulp opened this issue 1 month ago • 5 comments

Describe the bug

At some point in the past, Meaty B worked in Ruffle but currently (not sure since when) it's a white screen.

Expected behavior

The game is expected to proceed to the loading / title screen.

Content Location

https://www.newgrounds.com/portal/view/562927/format/flash?emulate=flash

Affected platform

Desktop app

Operating system

Windows 11

Browser

Google Chrome Version 141.0.7390.67

Additional information

No response

TomFulp avatar Nov 09 '25 21:11 TomFulp

I tried to find a working build, but until 2025.7.13, I am getting BorrowMutError and after that only white screen.

MartySVK avatar Nov 09 '25 22:11 MartySVK

I tried to find a working build, but until 2025.7.13, I am getting BorrowMutError and after that only white screen.

I did some digging, last build I could find where the game got to the preloader was 2023-11-10, all builds after that go straight to the white screen. Guess one of the commits here broke it.

https://github.com/ruffle-rs/ruffle/releases/tag/nightly-2023-11-11

waspennator avatar Nov 09 '25 23:11 waspennator

I bisected and the offending commit seems to be this one: https://github.com/ruffle-rs/ruffle/commit/2cb1efca8c799e8e40a0bc31c77baa9b25c8ab94

SuchAFuriousDeath avatar Nov 10 '25 18:11 SuchAFuriousDeath

The reason why this doesn't work is that Preloader is not being instantiated (and an event listener is not being registered in its constructor). Preloader is supposed to be a symbol class for character 0.

kjarosh avatar Nov 10 '25 20:11 kjarosh

When attempting to access the Preloader class, the symbolclass runs Preloader's class initializer code, which initializes a bunch of DisplayObjects:

    public class Preloader extends MovieClip {
        
        private static const PRELOADER_CLASS:Class = Preloader_PRELOADER_CLASS;
        
        private static const SMOKE_CLASS:Class = Preloader_SMOKE_CLASS;
        
        public static var background:Sprite = new BACKGOUND_CLASS() as Sprite;
        
        public static var smoke:Sprite = new SMOKE_CLASS() as Sprite;
        
        private static const BACKGOUND_CLASS:Class = Preloader_BACKGOUND_CLASS;
        
        private static var preloader:Sprite = new PRELOADER_CLASS() as Sprite;
         

This results in an Avm2Button being constructed down the line. In its construction code is this:

            if needs_avm2_construction {
                // ...

                if has_movie_clip_state && self.movie().version() > 9 {
                    // ...

                    let stage = context.stage;
                    stage.construct_frame(context);
                    stage.frame_constructed(context);
                    self.set_state(context, ButtonState::Up);
                    stage.run_frame_scripts(context);
                    stage.exit_frame(context);
                }

                // ...
            }

When construct_frame is called on the stage, all children of the stage, including the root MovieClip, get construct_frame called on them. When the root MovieClip is constructed, its class isn't set properly yet, so it gets constructed but with the class of MovieClip rather than Preloader.

Finally, the class initializer is completed, and the Preloader class is resolved, but at this point the root MovieClip has already been constructed with the class of MovieClip, so it isn't constructed a second time.

Lord-McSweeney avatar Dec 03 '25 22:12 Lord-McSweeney