Skip to content

🤖 avm2: Emit StrictArray for dense AS3 Arrays in AMF0 (close #16381)#23772

Open
MavenRain wants to merge 3 commits into
ruffle-rs:masterfrom
MavenRain:fix/amf-strict-array-for-as3-array
Open

🤖 avm2: Emit StrictArray for dense AS3 Arrays in AMF0 (close #16381)#23772
MavenRain wants to merge 3 commits into
ruffle-rs:masterfrom
MavenRain:fix/amf-strict-array-for-as3-array

Conversation

@MavenRain
Copy link
Copy Markdown

Description

Closes #16381.

Per Lord-McSweeney's 2025-07-14 diagnosis, Ruffle was serializing AS3 Array
arguments as AMF0 ECMAArray (marker 0x08, with all entries as named string
keys "0", "1", ...) instead of AMF0 StrictArray (marker 0x0A, indexed by
position). Flash decoders see the former as {0: "x", 1: "y"} (associative
object) and the latter as ["x", "y"] (indexed array), which broke real-world
Flash Remoting endpoints that round-trip AS3 arrays as call arguments (the G2C
Online site that motivated the issue).

The fix unifies the AMF0 and AMF3 dense/sparse split in serialize_value
(previously the AMF3 branch did this split, the AMF0 branch dumped everything
into the sparse list with a // TODO: is this right? comment). For AMF0,
dense-only arrays now emit StrictArray; mixed arrays keep ECMAArray semantics.
AMF3 path is unchanged.

Byte-level confirmation

For new Array("G2C Online") in AMF0:

Before: 08 00 00 00 01 00 01 30 02 00 0A G2C Online 00 00 09 (ECMAArray
with sparse "0" key)
After: 0A 00 00 00 01 02 00 0A G2C Online (StrictArray,
length 1)
Flash: StrictArray(ObjectId(-1), [String("G2C Online")]) (matches
After)

Test coverage

The existing netconnection_send_remote test exercises the AMF0 args-wrap path
(top-level StrictArray of arguments), which was already correct before this PR
and stays correct after. All 5 netconnection tests plus the broader
amf/array/bytearray suites (~120 tests) stay green.

What we don't yet exercise is an AS3 Array passed AS an argument to
NetConnection.call, which is the bug case. Adding a SWF fixture requires Flex
SDK to recompile Test.swf, which I don't have set up locally. Happy to
follow up with a Rust unit test in a separate PR if you'd like dedicated
coverage; the heaviest piece there is mocking an Activation for
serialize_value.

Verification

  - cargo fmt --all --check
  - cargo clippy -p ruffle_core --tests --lib
  - cargo test --package tests for netconnection_*, amf*, array, bytearray (all
  green)

@danielhjacobs
Copy link
Copy Markdown
Contributor

This does not fix that site in testing.

Left is Ruffle, right is Flash:

Screenshot From 2026-05-21 09-48-27

Further information for diagnosis and testing: If you open the Network tab on DevTools and refresh http://www.g2conline.org/, with a Flash-enabled browser or with Ruffle, you will see a POST request sent to http://www.g2conline.org/g2camf/

If you right-click the request and copy it as cURL, and paste it in a Notepad, you'll see a cURL command ending with --data-raw ...

As raw data in Flash, you'll see this:

\x00\x00\x00\x00\x00\x01\x00\x12AMFApp.getDataMaps\x00\x02/1\x00\x00\x00\x17\n\x00\x00\x00\x01\n\x00\x00\x00\x01\x02\x00\nG2C Online

As raw data in Ruffle, both with this PR and the current version, you'll see this:

\x00\x00\x00\x00\x00\x01\x00\x12AMFApp.getDataMaps\x00\x02/1\x00\x00\x00\x19\n\x00\x00\x00\x01\x03\x00\x010\x02\x00\nG2C Online\x00\x00\x09

@danielhjacobs
Copy link
Copy Markdown
Contributor

Oh, you only changed AVM2. That's an AVM1 animation.

@danielhjacobs danielhjacobs added A-avm2 Area: AVM2 (ActionScript 3) T-compat Type: Compatibility with Flash Player llm The PR contains mostly LLM-generated code amf Issues relating to AMF serialization/deserialization T-fix Type: Bug fix (in something that's supposed to work already) and removed T-compat Type: Compatibility with Flash Player labels May 21, 2026
@danielhjacobs
Copy link
Copy Markdown
Contributor

danielhjacobs commented May 21, 2026

I see you fixed the tests. The above comment still applies. I'm guessing you'll have to further change core/src/avm1/globals/shared_object.rs

@kjarosh
Copy link
Copy Markdown
Member

kjarosh commented May 21, 2026

This needs tests to be merged.

@MavenRain MavenRain force-pushed the fix/amf-strict-array-for-as3-array branch from 4bde3ca to 8b581c0 Compare May 21, 2026 18:32
@MavenRain
Copy link
Copy Markdown
Author

I just pushed a follow-up addressing @danielhjacobs's diagnosis that G2C Online is an AVM1 animation. My original commit only touched the AVM2 path; this commit mirrors the same fix on the AVM1 side.

AVM1's serialize previously routed every Value::Object (including AS1 Arrays) through new_lso → recursive_serialize, which wraps the result as AmfValue::Object with "0", "1", ... property keys. Top-level AS1 Array arguments to NetConnection.call therefore appeared as bare Object on the wire, not even ECMAArray, which is worse than the AVM2 symptom this PR's first commit fixed.

Changes:

  1. core/src/avm1/globals/shared_object.rs::serialize now detects
    NativeObject::Array and routes it through a new serialize_array helper that
    emits AmfValue::ECMAArray (matching what flash-lso's ObjWriter::array /
    ArrayWriter::commit emit for nested arrays in recursive_serialize).
  2. core/src/avm1/globals/netconnection.rs::call and
    core/src/avm1/globals/local_connection.rs::send now wrap each serialize(...)
    result with promote_dense_ecma_to_strict_array (the helper added in the
    prior commit on the AVM2 path), recursively converting dense ECMAArray nodes
    to StrictArray. Both top-level and arbitrarily-nested AS1 arrays are now
    correct on the wire.
  3. core/src/avm2.rs makes the amf submodule pub(crate) so AVM1 can import
    the helper. Sharing across AVMs reflects the fact that the promotion rule
    is a property of the NetConnection / LocalConnection wire format, not a
    property of either AVM version; willing to refactor into a neutral module if
    reviewers prefer.

Verified locally against the same byte pattern from the G2C cURL capture:
the args wrap now produces StrictArray([StrictArray([String("G2COnline")])])
instead of StrictArray([Object([{name:"0", value:String("G2COnline")}])]).
All net-related test suites (localconnection, encoding1,netconnection, sharedobject, amf, array, bytearray)
stay green.

@danielhjacobs danielhjacobs added A-core Area: Core player, where no other category fits and removed A-avm2 Area: AVM2 (ActionScript 3) labels May 21, 2026
MavenRain added 3 commits May 21, 2026 13:47
…16381)

Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
…sites

Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
…/LocalConnection (ruffle-rs#16381)

Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
@MavenRain MavenRain force-pushed the fix/amf-strict-array-for-as3-array branch from 8b581c0 to b8e7c4c Compare May 21, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-core Area: Core player, where no other category fits amf Issues relating to AMF serialization/deserialization llm The PR contains mostly LLM-generated code T-fix Type: Bug fix (in something that's supposed to work already)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Genes to Cognition Online - Remaining issues after Flash Remoting support

3 participants