mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
- Implement comprehensive C++ serializer generator (tests/generate-cpp-serializer.ts) - Direct transformation of Java SkeletonSerializer to C++ header-only implementation - Handle all C++-specific API differences: * Field access patterns (obj.field → obj->field, private fields → obj->_field) * Null check removal for reference-returning methods (getBones, getEdges) * Nested array null check elimination (getVertices, getDrawOrders) * Enum serialization via switch statements replacing .name() calls * Custom function replacement system for C++-specific implementations - Add specialized C++ implementations: * writeColor: handle public Color fields (r,g,b,a without underscore) * writeSkin: iterate AttachmentMap::Entries and call writeSkinEntry * writeSkinEntry: handle AttachmentMap::Entry instead of Java SkinEntry - Auto-generate both pointer and reference versions of all write methods - Create JsonWriter.h as header-only port of Java JsonWriter - Update HeadlessTest.cpp to use generated SkeletonSerializer - Add comprehensive type analysis and enum mapping from analysis-result.json - Implement exclusion system for filtering unwanted types/methods - Fix Java generator nested array null checks that were incorrectly hardcoded Generated C++ serializer produces identical JSON output to Java reference implementation.
Spine Runtimes Test Suite
This test suite is designed to ensure consistency across all Spine runtime implementations by comparing their outputs against the reference implementation (spine-libgdx).
Purpose
Unlike traditional unit tests, this test suite:
- Loads skeleton data and animations in each runtime
- Outputs all internal state in a consistent, diffable text format
- Compares outputs between runtimes to detect discrepancies
- Helps maintain consistency when porting changes from the reference implementation
HeadlessTest Locations
Each runtime has a HeadlessTest program that outputs skeleton data in a standardized format:
- Java (Reference):
spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/HeadlessTest.java - C++:
spine-cpp/tests/HeadlessTest.cpp - C:
spine-c/tests/headless-test.c - TypeScript:
spine-ts/spine-core/tests/HeadlessTest.ts
Running Individual HeadlessTests
Java (spine-libgdx)
cd spine-libgdx
./gradlew :spine-libgdx-tests:runHeadlessTest -Pargs="<skeleton-path> <atlas-path> [animation-name]"
# Example with spineboy:
./gradlew :spine-libgdx-tests:runHeadlessTest -Pargs="../examples/spineboy/export/spineboy-pro.json ../examples/spineboy/export/spineboy.atlas walk"
C++ (spine-cpp)
cd spine-cpp
./build.sh # Build if needed
./build/headless-test <skeleton-path> <atlas-path> [animation-name]
# Example with spineboy:
./build/headless-test ../examples/spineboy/export/spineboy-pro.json ../examples/spineboy/export/spineboy.atlas walk
C (spine-c)
cd spine-c
./build.sh # Build if needed
./build/headless-test <skeleton-path> <atlas-path> [animation-name]
# Example with spineboy:
./build/headless-test ../examples/spineboy/export/spineboy-pro.json ../examples/spineboy/export/spineboy.atlas walk
TypeScript (spine-ts)
cd spine-ts/spine-core
npx tsx tests/HeadlessTest.ts <skeleton-path> <atlas-path> [animation-name]
# Example with spineboy:
npx tsx tests/HeadlessTest.ts ../../examples/spineboy/export/spineboy-pro.json ../../examples/spineboy/export/spineboy.atlas walk
Running the Comparison Test
The main test runner compares all runtime outputs automatically:
./tests/headless-test-runner.ts <skeleton-path> <atlas-path> [animation-name]
This script will:
- Check if each runtime's HeadlessTest needs rebuilding
- Build any out-of-date HeadlessTests
- Run each HeadlessTest with the same inputs
- Compare outputs and report any differences
- Save individual outputs to
tests/output/for manual inspection
Example Usage
# Test with spineboy walk animation
./tests/headless-test-runner.ts \
examples/spineboy/export/spineboy-pro.json \
examples/spineboy/export/spineboy-pma.atlas \
walk
# Test without animation (setup pose only)
./tests/headless-test-runner.ts \
examples/spineboy/export/spineboy-pro.json \
examples/spineboy/export/spineboy-pma.atlas
Output Format
Each HeadlessTest outputs:
- SKELETON DATA: Static setup pose data (bones, slots, skins, animations metadata)
- SKELETON STATE: Runtime state after applying animations
- ANIMATION STATE: Current animation state with tracks and mixing information
The output uses consistent JSON formatting:
- Hierarchical structure with 2-space indentation
- Float values formatted to 6 decimal places
- Strings quoted, nulls explicitly shown
- Locale-independent number formatting (always uses
.for decimals) - Circular references marked as
"<circular>"to prevent infinite recursion - Each object includes a
"type"field for easy identification
Development Tools
API Analyzer (Java)
Analyzes the spine-libgdx API to discover all types and their properties:
cd tests
npx tsx analyze-java-api.ts
# Output: output/analysis-result.json
Serializer Generator (Java)
Generates SkeletonSerializer.java from the analysis:
cd tests
npx tsx generate-java-serializer.ts
# Output: ../spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java
Claude Prompt Generator
Generates a prompt for Claude to help port the serializer to other runtimes:
cd tests
npx tsx generate-claude-prompt.ts
# Output: output/port-serializer-prompt.txt
Troubleshooting
If outputs differ between runtimes:
- Check
tests/output/for the full outputs from each runtime - Use a diff tool to compare the files
- Common issues:
- Number formatting differences (should be fixed by locale settings)
- Missing or extra fields in data structures
- Different default values
- Rounding differences