• RuntimesBugs
  • Cocos2d-x C++ Crash After Re-Exporting with Spine 4.1

Problem statement

My team and I are moving from Cocos2d-x to the Axmol fork for our most popular game, due to Cocos2d-x dropping support and maintenance back in 2019. Several kind folks have forked Cocos2d-x and continue to support it with bug fixes, updates, and improvements.

Now to get to the point, Axmol is using the Spine 4.1 runtimes, but all of our old spine files were exported with 3.8.75. So we've had to begin re-exporting all of our old json files with Spine to update them to version 4.1.24. This was going smoothly until we got to a specific character who uses a transform constraint...

When we attempt to load this character's .json file, we load up the atlas, and first several animations without issue, but then we attempt to load an animation called "recover" which then causes a failed assertion at line #162 of Vector.h in the Spine C++ runtime files.

We removed any transform constraints from this animation, and re-exported the file again after using Cleanup Animation for the "recover" animation. Looking in the .json file I can't see any transform constraints set to this animation at all, but the failed assertion continues to be hit, which then causes the game to crash.

Any help solving this would be greatly appreciated. We're at a loss as to what's happening here at this point, especially since there doesn't seem to be anything pointing to any transform constraint curves in this animation.

I can provide the spine files upon request if you think it will help us to solve this issue.

Thank you for your time.

Runtime information

Cocos2d-x & C++ v4.1

Stack Trace

#4	0x0000000103cb5da0 in spine::Vector<float>::operator[](unsigned long) at [...]/spine/Vector.h:162
#5	0x0000000103cca02c in spine::CurveTimeline::setBezier(unsigned long, unsigned long, float, float, float, float, float, float, float, float, float) at [...]/spine/CurveTimeline.cpp:65
#6	0x0000000103c97e94 in spine::SkeletonJson::setBezier(spine::CurveTimeline*, int, int, int, float, float, float, float, float, float, float, float) at [...]/spine/SkeletonJson.cpp:798
#7	0x0000000103c97fe0 in spine::SkeletonJson::readCurve(spine::Json*, spine::CurveTimeline*, int, int, int, float, float, float, float, float) at [...]/spine/SkeletonJson.cpp:816
#8	0x0000000103c9587c in spine::SkeletonJson::readAnimation(spine::Json*, spine::SkeletonData*) at [...]spine/SkeletonJson.cpp:1178
#9	0x0000000103c90d1c in spine::SkeletonJson::readSkeletonData(char const*) at [...]/spine/SkeletonJson.cpp:771
#10	0x0000000103c8c19c in spine::SkeletonJson::readSkeletonDataFile(spine::String const&) at [...]/spine/SkeletonJson.cpp:125
#11	0x0000000103c9a140 in spine::SkeletonRenderer::initWithJsonFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, float) at [...]/spine/SkeletonRenderer.cpp:186
#12	0x0000000103cdcc94 in spine::SkeletonAnimation::createWithJsonFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, float) at [...]/spine/SkeletonAnimation.cpp:91
Related Discussions
...

Based on the information provided and the contexts, it seems like the issue you're encountering with the "recover" animation and transform constraints might be related to how the Spine C++ runtime handles the data exported from Spine Editor 4.1.24. The crash at spine::Vector<float>::operator[](unsigned long) suggests there might be an issue with accessing elements in a vector that are not present, possibly due to how bezier curves or transform constraints are represented in the newer version of the exported data.

Given the detailed stack trace you provided, it appears the crash occurs during the processing of bezier curves in the animation data (spine::CurveTimeline::setBezier). This could indicate that the data format or expectations of the runtime regarding bezier curves or transform constraints have changed between Spine 3.8.75 and 4.1.24, leading to issues when attempting to access or interpret this data.

Unfortunately, without the ability to directly inspect the Spine files or make changes to the runtime code, it's challenging to provide a specific solution. However, considering the contexts and the nature of the crash, I recommend closely reviewing any changes in the representation of transform constraints and bezier curves between the versions of Spine you're working with. It might also be beneficial to verify that all runtime files are up to date with the version expected by Spine 4.1.24 exports, as outdated runtime files could lead to compatibility issues.

If the problem persists even after ensuring that all runtime files are up to date and closely inspecting the exported data for anomalies, it might be necessary to reach out to the community or developers maintaining the Axmol fork or the Spine C++ runtime for further assistance, as they might have more insights into the specific changes or issues introduced with the newer versions of Spine and how they interact with the runtime.

4 أيام لاحقا

Does Axmol ship it's own version of spine-cpp/spine-cocos2d-x? You want to replace that with our official one.

We'll also need the files you are trying to load, to debug the issue. You can share them here or via email at contact@esotericsoftware.com

    Mario Hey Mario, I apologize for the delay in responding.

    Axmol does ship with it's own version of the Spine C++ and a modified version of the Spine Cocos2d-x Runtimes, specifically it looks like they are currently shipping with v4.1-54fac9d.

    Upon replacing the Spine runtimes with the latest files off GitHub, rather than using the v4.1 Release files, it solved the crash. It must've been related to some of the IK fixes that were pulled into the GitHub repo after the v4.1 release was cut.

    Thank you for your help, and I apologize for any time of yours that I wasted with this.

    P.S. That said there is a new issue you might be able to help with... Specifically most, but not all, of our character skeletons will load in and animate properly, but not render for the first second or so after loading. We do preload the textures for the atlases before we ever start loading the character skeletons too...

      Can you provide a repro project that allows us to see and debug the issue? I can not repro this with or example project. Ideally, you'd open an issue on the spine-runtimes issue tracker with a link to a reproduction Git repo.

        Mario Hey, I apologize. I haven't had time to setup a repro project for you, as I've been working on other things for this update still. I hope to have time to setup a repro project for you early next week, unless I can solve this issue on my own.

        In my tests I did find some more information however, this is only happening on SkeletonAnimations which we have called setTwoColorTint(true) on during their initialization functions. The skeletons without this bug never enable two color tinting.

        I've double checked the SkeletonRenderer.cpp used by the Cocos2d-x runtimes, as well as the Axmol fork of Cocos2d-x, and the renderer code is identical: which means I assume this bug must also occur with Cocos2d-x v4.0 when enabling two color tint on a SkeletonAnimation before it's onEnter is called.

        This bug didn't occur with two color tinting on Cocos2d-x v3.17.2, but the code around the two color tint has pre-processor checks for the Cocos2d-x version to either set/get the GLProgramState, or a boolean called _twoColorTint instead for any versions greater than or equal to v4.0. The Axmol fork also defines all of the Cocos2d-x pre-processor definitions, including the COCOS2D_VERSION to 0x00040000 (which is the value the Spine Runtimes checks against).

        If I'm able to determine the cause of this bug I'll let you all know. In the meantime any help, tips, or advice would be appreciated!

        Thank you.

        Most of our example scenes have two color tinting enabled and don't crash. I'm afraid without a way to reproduce the issue on our end, I don't really have any tips or advice :/

        The stack trace happens during loading of the skeleton data, so I don't quite see how it can be connected to two color tinting. At that point, two color tinting doesn't matter at all for what the spine-cpp code is doing.

          Mario Oh it doesn't crash, it just fails to render for the first second or so after calling spine::SkeletonAnimation::createWithJsonFile followed by setTwoColorTint(true); on the returned SkeletonAnimation from createWithJsonFile.

          Mario Most of our example scenes have two color tinting enabled and don't crash.

          I looked through the Cocos2d-x Examples and the only example that sets twoColorTinting here is the RaptorExample.cpp

          Has this specific example been testing with Cocos2d-x v4.0 on a Mac, as this is where we're seeing the issue specifically. Cocos2d-x v4.0 uses the Metal renderer and refactored GL code to support it, and so your Spine runtimes contain conditional macros to handle both pre and post-v4.0 Cocos2d-x. This bug wasn't present with Cocos2d-x v3.17.2, so it must be something that has changed between v3.x and v4.x: most likely around the renderer or shader code surrounding two-color tinted skeletons as the issue only exists with these skeletons.

          Mario The stack trace happens during loading of the skeleton data, so I don't quite see how it can be connected to two color tinting. At that point, two color tinting doesn't matter at all for what the spine-cpp code is doing.

          I apologize, and understand your confusion for thinking this was a crash now.

          I should've made a separate thread for this second question to avoid this confusion: this whole time I've been responding to you about my "P.S." in my original post, specifically:

          ExNull-Tyelor That said there is a new issue you might be able to help with... Specifically most, but not all, of our character skeletons will load in and animate properly, but not render for the first second or so after loading. We do preload the textures for the atlases before we ever start loading the character skeletons too...

          This issue is entirely unrelated to the first issue, and is not a crash and doesn't give a stack trace because of that. This issue will render the debug bones, symbols, meshes, etc. for the skeleton for those first second or two: but not the skeleton itself. And only with two-color tint enabled.

          Mario I'm afraid without a way to reproduce the issue on our end, I don't really have any tips or advice :/

          I'm able to reproduce this bug with Cocos2d-x v4.0, the Spine Runtimes v4.1.x, on an M1 Macbook when using the Metal renderer.

          Steps:

          1. After getting the Cocos2d-x v4.0 project building and running on M1 Macs, update the Spine runtimes to the latest version off GitHub.
          2. To better see this issue change line #107 of AppDelegate.cpp from director->setAnimationInterval(1.0f / 60); to director->setAnimationInterval(1.0f); (This gives us longer to see the first frame failing to render properly.)
          3. In AppDelegate.cpp include "RaptorExample.h", un-comment line #113 and then comment out line #114, this way the AppDelegate loads up directly into the example that uses two-color tinting.
          4. Add the following lines to the RaptorExample.cpp before it's added as a child (e.g. between lines #53 and #54): skeletonNode->setDebugBonesEnabled(true); skeletonNode->setDebugMeshesEnabled(true); (This shows that the skeleton is loaded and should be rendered on the first frame, but isn't while two-color tint is enabled.)
          5. Run the project on your arm64 Mac, and observe that the Spine-boy Raptor skeleton doesn't render anything except the debug bones and meshes for the first frame, and then renders correctly after that.
          6. For posterity, comment out line #52 of the RaptorExample.cpp class to disable two-color tinting here, and then re-build and re-run the project, observe that this time the Spine-boy Raptor skeleton properly renders on the first frame, as well as subsequent frames.

          For some reason for our Spine characters it takes many frames from this initial creation and first 'render' before the characters actually start rendering, but the problem is observable with the Spine examples as well with the reproduction steps I've outlined.

          @Mario let me know you if want me to make a separate forum post, a GitHub issue request, and/or email you with the Cocos2d-x project that I've setup as a repro project.

          Thanks again for your help and for the awesome software that is Spine!

          @ExNull-Tyelor oh, those are great reproduction steps, thank you! I've opened an issue for the "no rendering on first frame" issue here:
          EsotericSoftware/spine-runtimes2501

          I don't really need a project in this case, as I can reproduce it with our Cocos2d-x example project. Following your steps.