diff --git a/docs/todos/work/2025-01-11-03-02-54-test-suite/task.md b/docs/todos/work/2025-01-11-03-02-54-test-suite/task.md index 50569709f..dc55381f9 100644 --- a/docs/todos/work/2025-01-11-03-02-54-test-suite/task.md +++ b/docs/todos/work/2025-01-11-03-02-54-test-suite/task.md @@ -319,6 +319,7 @@ interface NestedArray { - [x] All exclusions and filtering pre-applied - no post-processing needed - [ ] Update language generators to consume IR: - [x] Replace tests/generate-java-serializer.ts with IR-based version + - [x] Sort skin entries by slot index before emission in Java - [ ] Modify tests/generate-cpp-serializer.ts to use IR - [ ] Create tests/generate-ts-serializer.ts using IR - [ ] Create tests/generate-cs-serializer.ts using IR diff --git a/spine-cpp/include/spine/TextureRegion.h b/spine-cpp/include/spine/TextureRegion.h index 07ae43416..ea065fae2 100644 --- a/spine-cpp/include/spine/TextureRegion.h +++ b/spine-cpp/include/spine/TextureRegion.h @@ -45,17 +45,17 @@ namespace spine { TextureRegion(): rendererObject(NULL), u(0), v(0), u2(0), v2(0), degrees(0), offsetX(0), offsetY(0), width(0), height(0), originalWidth(0), originalHeight(0) {}; ~TextureRegion() {}; - float getU() { return u; }; - float getV() { return v; }; - float getU2() { return u2; }; - float getV2() { return v2; }; - int getDegrees() { return degrees; }; - float getOffsetX() { return offsetX; }; - float getOffsetY() { return offsetY; }; - int getRegionWidth() { return width; }; - int getRegionHeight() { return height; }; - int getOriginalWidth() { return originalWidth; }; - int getOriginalHeight() { return originalHeight; }; + float getU() const { return u; }; + float getV() const { return v; }; + float getU2() const { return u2; }; + float getV2() const { return v2; }; + int getDegrees() const { return degrees; }; + float getOffsetX() const { return offsetX; }; + float getOffsetY() const { return offsetY; }; + int getRegionWidth() const { return width; }; + int getRegionHeight() const { return height; }; + int getOriginalWidth() const { return originalWidth; }; + int getOriginalHeight() const { return originalHeight; }; }; } diff --git a/spine-cpp/tests/SkeletonSerializer.h b/spine-cpp/tests/SkeletonSerializer.h index ae859ffb9..efcfec6b3 100644 --- a/spine-cpp/tests/SkeletonSerializer.h +++ b/spine-cpp/tests/SkeletonSerializer.h @@ -9,7 +9,7 @@ namespace spine { class SkeletonSerializer { - private: +private: HashMap _visitedObjects; JsonWriter _json; @@ -21,7 +21,6 @@ public: _visitedObjects.clear(); _json = JsonWriter(); writeSkeletonData(data); - _json.close(); return _json.getString(); } @@ -29,7 +28,6 @@ public: _visitedObjects.clear(); _json = JsonWriter(); writeSkeleton(skeleton); - _json.close(); return _json.getString(); } @@ -37,7 +35,6 @@ public: _visitedObjects.clear(); _json = JsonWriter(); writeAnimationState(state); - _json.close(); return _json.getString(); } @@ -56,8 +53,7 @@ private: _json.writeName("timelines"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getTimelines().size(); i++) { - Timeline* item = obj->getTimelines()[i]; - writeTimeline(item); + writeTimeline(obj->getTimelines()[i]); } _json.writeArrayEnd(); @@ -65,11 +61,7 @@ private: _json.writeValue(obj->getDuration()); _json.writeName("bones"); - _json.writeArrayStart(); - for (int i = 0; i < obj->getBones().size(); i++) { - _json.writeValue(obj->getBones()[i]); - } - _json.writeArrayEnd(); + writeIntArray(obj->getBones()); _json.writeName("name"); _json.writeValue(obj->getName()); @@ -97,16 +89,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -139,24 +129,21 @@ private: _json.writeName("attachmentNames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getAttachmentNames().size(); i++) { - const String& item = obj->getAttachmentNames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getAttachmentNames()[i]); } _json.writeArrayEnd(); _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -191,11 +178,9 @@ private: for (size_t i = 0; i < obj->getVertices().size(); i++) { Array& nestedArray = obj->getVertices()[i]; _json.writeArrayStart(); - for (size_t i = 0; i < nestedArray.size(); i++) { - float elem = nestedArray[i]; - _json.writeValue(elem); - - } + for (size_t j = 0; j < nestedArray.size(); j++) { + _json.writeValue(nestedArray[j]); + } _json.writeArrayEnd(); } _json.writeArrayEnd(); @@ -206,16 +191,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -247,11 +230,9 @@ private: for (size_t i = 0; i < obj->getDrawOrders().size(); i++) { Array& nestedArray = obj->getDrawOrders()[i]; _json.writeArrayStart(); - for (size_t i = 0; i < nestedArray.size(); i++) { - int elem = nestedArray[i]; - _json.writeValue(elem); - - } + for (size_t j = 0; j < nestedArray.size(); j++) { + _json.writeValue(nestedArray[j]); + } _json.writeArrayEnd(); } _json.writeArrayEnd(); @@ -259,16 +240,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -298,24 +277,21 @@ private: _json.writeName("events"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getEvents().size(); i++) { - Event* item = obj->getEvents()[i]; - writeEvent(item); + writeEvent(obj->getEvents()[i]); } _json.writeArrayEnd(); _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -348,16 +324,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -390,16 +364,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -432,16 +404,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -474,16 +444,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -516,16 +484,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -558,16 +524,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -600,16 +564,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -642,16 +604,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -684,16 +644,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -726,16 +684,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -768,16 +724,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -810,16 +764,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -852,16 +804,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -894,16 +844,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -936,16 +884,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -978,16 +924,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1020,16 +964,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1062,16 +1004,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1104,16 +1044,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1146,16 +1084,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1188,16 +1124,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1233,16 +1167,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1275,16 +1207,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1317,16 +1247,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1359,16 +1287,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1401,16 +1327,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1443,16 +1367,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1539,7 +1461,7 @@ private: } else if (obj->getRTTI().instanceOf(TranslateYTimeline::rtti)) { writeTranslateYTimeline((TranslateYTimeline*)obj); } else { - fprintf(stderr, "Error: Unknown Timeline type: \n"); exit(1); + fprintf(stderr, "Error: Unknown Timeline type\n"); exit(1); } } @@ -1563,16 +1485,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1605,16 +1525,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1647,16 +1565,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1689,16 +1605,14 @@ private: _json.writeName("propertyIds"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPropertyIds().size(); i++) { - PropertyId item = obj->getPropertyIds()[i]; - _json.writeValue(item); + _json.writeValue(obj->getPropertyIds()[i]); } _json.writeArrayEnd(); _json.writeName("frames"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getFrames().size(); i++) { - float item = obj->getFrames()[i]; - _json.writeValue(item); + _json.writeValue(obj->getFrames()[i]); } _json.writeArrayEnd(); @@ -1731,8 +1645,7 @@ private: _json.writeName("tracks"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getTracks().size(); i++) { - TrackEntry* item = obj->getTracks()[i]; - writeTrackEntry(item); + writeTrackEntry(obj->getTracks()[i]); } _json.writeArrayEnd(); @@ -1785,7 +1698,6 @@ private: _json.writeName("timeScale"); _json.writeValue(obj->getTimeScale()); - // Skipping excluded property: getListener() _json.writeName("alpha"); _json.writeValue(obj->getAlpha()); @@ -1824,14 +1736,14 @@ private: _json.writeName("mixBlend"); _json.writeValue([&]() -> String { - switch(obj->getMixBlend()) { - case MixBlend_Setup: return "setup"; - case MixBlend_First: return "first"; - case MixBlend_Replace: return "replace"; - case MixBlend_Add: return "add"; - default: return "unknown"; - } - }()); + switch(obj->getMixBlend()) { + case MixBlend_Setup: return "setup"; + case MixBlend_First: return "first"; + case MixBlend_Replace: return "replace"; + case MixBlend_Add: return "add"; + default: return "unknown"; + } + }()); _json.writeName("mixingFrom"); if (obj->getMixingFrom() == nullptr) { @@ -1893,7 +1805,7 @@ private: } else if (obj->getRTTI().instanceOf(RegionAttachment::rtti)) { writeRegionAttachment((RegionAttachment*)obj); } else { - fprintf(stderr, "Error: Unknown Attachment type: \n"); exit(1); + fprintf(stderr, "Error: Unknown Attachment type\n"); exit(1); } } @@ -1918,8 +1830,7 @@ private: _json.writeName("children"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getChildren().size(); i++) { - Bone* item = obj->getChildren()[i]; - writeBone(item); + writeBone(obj->getChildren()[i]); } _json.writeArrayEnd(); @@ -2014,15 +1925,15 @@ private: _json.writeName("inherit"); _json.writeValue([&]() -> String { - switch(obj->getInherit()) { - case Inherit_Normal: return "normal"; - case Inherit_OnlyTranslation: return "onlyTranslation"; - case Inherit_NoRotationOrReflection: return "noRotationOrReflection"; - case Inherit_NoScale: return "noScale"; - case Inherit_NoScaleOrReflection: return "noScaleOrReflection"; - default: return "unknown"; - } - }()); + switch(obj->getInherit()) { + case Inherit_Normal: return "normal"; + case Inherit_OnlyTranslation: return "onlyTranslation"; + case Inherit_NoRotationOrReflection: return "noRotationOrReflection"; + case Inherit_NoScale: return "noScale"; + case Inherit_NoScaleOrReflection: return "noScaleOrReflection"; + default: return "unknown"; + } + }()); _json.writeObjectEnd(); } @@ -2091,15 +2002,15 @@ private: _json.writeName("inherit"); _json.writeValue([&]() -> String { - switch(obj->getInherit()) { - case Inherit_Normal: return "normal"; - case Inherit_OnlyTranslation: return "onlyTranslation"; - case Inherit_NoRotationOrReflection: return "noRotationOrReflection"; - case Inherit_NoScale: return "noScale"; - case Inherit_NoScaleOrReflection: return "noScaleOrReflection"; - default: return "unknown"; - } - }()); + switch(obj->getInherit()) { + case Inherit_Normal: return "normal"; + case Inherit_OnlyTranslation: return "onlyTranslation"; + case Inherit_NoRotationOrReflection: return "noRotationOrReflection"; + case Inherit_NoScale: return "noScale"; + case Inherit_NoScaleOrReflection: return "noScaleOrReflection"; + default: return "unknown"; + } + }()); _json.writeObjectEnd(); } @@ -2119,19 +2030,16 @@ private: writeColor(obj->getColor()); _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - int item = obj->getBones()[i]; - _json.writeValue(item); - - _json.writeArrayEnd(); + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getBones().size(); i++) { + _json.writeValue(obj->getBones()[i]); } + _json.writeArrayEnd(); _json.writeName("vertices"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getVertices().size(); i++) { - float item = obj->getVertices()[i]; - _json.writeValue(item); + _json.writeValue(obj->getVertices()[i]); } _json.writeArrayEnd(); @@ -2176,19 +2084,16 @@ private: writeColor(obj->getColor()); _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - int item = obj->getBones()[i]; - _json.writeValue(item); - - _json.writeArrayEnd(); + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getBones().size(); i++) { + _json.writeValue(obj->getBones()[i]); } + _json.writeArrayEnd(); _json.writeName("vertices"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getVertices().size(); i++) { - float item = obj->getVertices()[i]; - _json.writeValue(item); + _json.writeValue(obj->getVertices()[i]); } _json.writeArrayEnd(); @@ -2223,7 +2128,7 @@ private: } else if (obj->getRTTI().instanceOf(TransformConstraint::rtti)) { writeTransformConstraint((TransformConstraint*)obj); } else { - fprintf(stderr, "Error: Unknown Constraint type: \n"); exit(1); + fprintf(stderr, "Error: Unknown Constraint type\n"); exit(1); } } @@ -2239,7 +2144,7 @@ private: } else if (obj->getRTTI().instanceOf(TransformConstraintData::rtti)) { writeTransformConstraintData((TransformConstraintData*)obj); } else { - fprintf(stderr, "Error: Unknown ConstraintData type: \n"); exit(1); + fprintf(stderr, "Error: Unknown ConstraintData type\n"); exit(1); } } @@ -2327,8 +2232,7 @@ private: _json.writeName("bones"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getBones().size(); i++) { - BonePose* item = obj->getBones()[i]; - writeBonePose(item); + writeBonePose(obj->getBones()[i]); } _json.writeArrayEnd(); @@ -2361,8 +2265,7 @@ private: _json.writeName("bones"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getBones().size(); i++) { - BoneData* item = obj->getBones()[i]; - writeBoneData(item); + writeBoneData(obj->getBones()[i]); } _json.writeArrayEnd(); @@ -2425,29 +2328,30 @@ private: _json.writeValue("MeshAttachment"); _json.writeName("region"); - writeTextureRegion(obj->getRegion()); + if (obj->getRegion() == nullptr) { + _json.writeNull(); + } else { + writeTextureRegion(obj->getRegion()); + } _json.writeName("triangles"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getTriangles().size(); i++) { - short item = obj->getTriangles()[i]; - _json.writeValue(item); + _json.writeValue(obj->getTriangles()[i]); } _json.writeArrayEnd(); _json.writeName("regionUVs"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getRegionUVs().size(); i++) { - float item = obj->getRegionUVs()[i]; - _json.writeValue(item); + _json.writeValue(obj->getRegionUVs()[i]); } _json.writeArrayEnd(); _json.writeName("uVs"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getUVs().size(); i++) { - float item = obj->getUVs()[i]; - _json.writeValue(item); + _json.writeValue(obj->getUVs()[i]); } _json.writeArrayEnd(); @@ -2461,13 +2365,11 @@ private: _json.writeValue(obj->getHullLength()); _json.writeName("edges"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getEdges().size(); i++) { - short item = obj->getEdges()[i]; - _json.writeValue(item); - - _json.writeArrayEnd(); + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getEdges().size(); i++) { + _json.writeValue(obj->getEdges()[i]); } + _json.writeArrayEnd(); _json.writeName("width"); _json.writeValue(obj->getWidth()); @@ -2490,19 +2392,16 @@ private: } _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - int item = obj->getBones()[i]; - _json.writeValue(item); - - _json.writeArrayEnd(); + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getBones().size(); i++) { + _json.writeValue(obj->getBones()[i]); } + _json.writeArrayEnd(); _json.writeName("vertices"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getVertices().size(); i++) { - float item = obj->getVertices()[i]; - _json.writeValue(item); + _json.writeValue(obj->getVertices()[i]); } _json.writeArrayEnd(); @@ -2545,8 +2444,7 @@ private: _json.writeName("lengths"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getLengths().size(); i++) { - float item = obj->getLengths()[i]; - _json.writeValue(item); + _json.writeValue(obj->getLengths()[i]); } _json.writeArrayEnd(); @@ -2554,19 +2452,16 @@ private: writeColor(obj->getColor()); _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - int item = obj->getBones()[i]; - _json.writeValue(item); - - _json.writeArrayEnd(); + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getBones().size(); i++) { + _json.writeValue(obj->getBones()[i]); } + _json.writeArrayEnd(); _json.writeName("vertices"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getVertices().size(); i++) { - float item = obj->getVertices()[i]; - _json.writeValue(item); + _json.writeValue(obj->getVertices()[i]); } _json.writeArrayEnd(); @@ -2603,8 +2498,7 @@ private: _json.writeName("bones"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getBones().size(); i++) { - BonePose* item = obj->getBones()[i]; - writeBonePose(item); + writeBonePose(obj->getBones()[i]); } _json.writeArrayEnd(); @@ -2637,8 +2531,7 @@ private: _json.writeName("bones"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getBones().size(); i++) { - BoneData* item = obj->getBones()[i]; - writeBoneData(item); + writeBoneData(obj->getBones()[i]); } _json.writeArrayEnd(); @@ -2647,33 +2540,33 @@ private: _json.writeName("positionMode"); _json.writeValue([&]() -> String { - switch(obj->getPositionMode()) { - case PositionMode_Fixed: return "fixed"; - case PositionMode_Percent: return "percent"; - default: return "unknown"; - } - }()); + switch(obj->getPositionMode()) { + case PositionMode_Fixed: return "fixed"; + case PositionMode_Percent: return "percent"; + default: return "unknown"; + } + }()); _json.writeName("spacingMode"); _json.writeValue([&]() -> String { - switch(obj->getSpacingMode()) { - case SpacingMode_Length: return "length"; - case SpacingMode_Fixed: return "fixed"; - case SpacingMode_Percent: return "percent"; - case SpacingMode_Proportional: return "proportional"; - default: return "unknown"; - } - }()); + switch(obj->getSpacingMode()) { + case SpacingMode_Length: return "length"; + case SpacingMode_Fixed: return "fixed"; + case SpacingMode_Percent: return "percent"; + case SpacingMode_Proportional: return "proportional"; + default: return "unknown"; + } + }()); _json.writeName("rotateMode"); _json.writeValue([&]() -> String { - switch(obj->getRotateMode()) { - case RotateMode_Tangent: return "tangent"; - case RotateMode_Chain: return "chain"; - case RotateMode_ChainScale: return "chainScale"; - default: return "unknown"; - } - }()); + switch(obj->getRotateMode()) { + case RotateMode_Tangent: return "tangent"; + case RotateMode_Chain: return "chain"; + case RotateMode_ChainScale: return "chainScale"; + default: return "unknown"; + } + }()); _json.writeName("offsetRotation"); _json.writeValue(obj->getOffsetRotation()); @@ -2889,21 +2782,23 @@ private: _json.writeValue("RegionAttachment"); _json.writeName("region"); - writeTextureRegion(obj->getRegion()); + if (obj->getRegion() == nullptr) { + _json.writeNull(); + } else { + writeTextureRegion(obj->getRegion()); + } _json.writeName("offset"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getOffset().size(); i++) { - float item = obj->getOffset()[i]; - _json.writeValue(item); + _json.writeValue(obj->getOffset()[i]); } _json.writeArrayEnd(); _json.writeName("uVs"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getUVs().size(); i++) { - float item = obj->getUVs()[i]; - _json.writeValue(item); + _json.writeValue(obj->getUVs()[i]); } _json.writeArrayEnd(); @@ -2970,8 +2865,7 @@ private: _json.writeName("regions"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getRegions().size(); i++) { - TextureRegion* item = obj->getRegions()[i]; - writeTextureRegion(item); + writeTextureRegion(obj->getRegions()[i]); } _json.writeArrayEnd(); @@ -2998,16 +2892,14 @@ private: _json.writeName("bones"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getBones().size(); i++) { - Bone* item = obj->getBones()[i]; - writeBone(item); + writeBone(obj->getBones()[i]); } _json.writeArrayEnd(); _json.writeName("updateCache"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getUpdateCache().size(); i++) { - Update* item = obj->getUpdateCache()[i]; - writeUpdate(item); + writeUpdate(obj->getUpdateCache()[i]); } _json.writeArrayEnd(); @@ -3017,16 +2909,14 @@ private: _json.writeName("slots"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getSlots().size(); i++) { - Slot* item = obj->getSlots()[i]; - writeSlot(item); + writeSlot(obj->getSlots()[i]); } _json.writeArrayEnd(); _json.writeName("drawOrder"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getDrawOrder().size(); i++) { - Slot* item = obj->getDrawOrder()[i]; - writeSlot(item); + writeSlot(obj->getDrawOrder()[i]); } _json.writeArrayEnd(); @@ -3040,16 +2930,14 @@ private: _json.writeName("constraints"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getConstraints().size(); i++) { - Constraint* item = obj->getConstraints()[i]; - writeConstraint(item); + writeConstraint(obj->getConstraints()[i]); } _json.writeArrayEnd(); _json.writeName("physicsConstraints"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getPhysicsConstraints().size(); i++) { - PhysicsConstraint* item = obj->getPhysicsConstraints()[i]; - writePhysicsConstraint(item); + writePhysicsConstraint(obj->getPhysicsConstraints()[i]); } _json.writeArrayEnd(); @@ -3100,16 +2988,14 @@ private: _json.writeName("bones"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getBones().size(); i++) { - BoneData* item = obj->getBones()[i]; - writeBoneData(item); + writeBoneData(obj->getBones()[i]); } _json.writeArrayEnd(); _json.writeName("slots"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getSlots().size(); i++) { - SlotData* item = obj->getSlots()[i]; - writeSlotData(item); + writeSlotData(obj->getSlots()[i]); } _json.writeArrayEnd(); @@ -3123,32 +3009,28 @@ private: _json.writeName("skins"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getSkins().size(); i++) { - Skin* item = obj->getSkins()[i]; - writeSkin(item); + writeSkin(obj->getSkins()[i]); } _json.writeArrayEnd(); _json.writeName("events"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getEvents().size(); i++) { - EventData* item = obj->getEvents()[i]; - writeEventData(item); + writeEventData(obj->getEvents()[i]); } _json.writeArrayEnd(); _json.writeName("animations"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getAnimations().size(); i++) { - Animation* item = obj->getAnimations()[i]; - writeAnimation(item); + writeAnimation(obj->getAnimations()[i]); } _json.writeArrayEnd(); _json.writeName("constraints"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getConstraints().size(); i++) { - ConstraintData* item = obj->getConstraints()[i]; - writeConstraintData(item); + writeConstraintData(obj->getConstraints()[i]); } _json.writeArrayEnd(); @@ -3395,14 +3277,14 @@ private: _json.writeName("blendMode"); _json.writeValue([&]() -> String { - switch(obj->getBlendMode()) { - case BlendMode_Normal: return "normal"; - case BlendMode_Additive: return "additive"; - case BlendMode_Multiply: return "multiply"; - case BlendMode_Screen: return "screen"; - default: return "unknown"; - } - }()); + switch(obj->getBlendMode()) { + case BlendMode_Normal: return "normal"; + case BlendMode_Additive: return "additive"; + case BlendMode_Multiply: return "multiply"; + case BlendMode_Screen: return "screen"; + default: return "unknown"; + } + }()); _json.writeName("visible"); _json.writeValue(obj->getVisible()); @@ -3434,7 +3316,11 @@ private: writeColor(obj->getColor()); _json.writeName("darkColor"); - writeColor(obj->getDarkColor()); + if (obj->hasDarkColor()) { + writeColor(&obj->getDarkColor()); + } else { + _json.writeNull(); + } _json.writeName("attachment"); if (obj->getAttachment() == nullptr) { @@ -3447,11 +3333,7 @@ private: _json.writeValue(obj->getSequenceIndex()); _json.writeName("deform"); - _json.writeArrayStart(); - for (int i = 0; i < obj->getDeform().size(); i++) { - _json.writeValue(obj->getDeform()[i]); - } - _json.writeArrayEnd(); + writeFloatArray(obj->getDeform()); _json.writeObjectEnd(); } @@ -3470,8 +3352,7 @@ private: _json.writeName("bones"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getBones().size(); i++) { - BonePose* item = obj->getBones()[i]; - writeBonePose(item); + writeBonePose(obj->getBones()[i]); } _json.writeArrayEnd(); @@ -3504,8 +3385,7 @@ private: _json.writeName("bones"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getBones().size(); i++) { - BoneData* item = obj->getBones()[i]; - writeBoneData(item); + writeBoneData(obj->getBones()[i]); } _json.writeArrayEnd(); @@ -3545,8 +3425,7 @@ private: _json.writeName("properties"); _json.writeArrayStart(); for (size_t i = 0; i < obj->getProperties().size(); i++) { - FromProperty* item = obj->getProperties()[i]; - writeFromProperty(item); + writeFromProperty(obj->getProperties()[i]); } _json.writeArrayEnd(); @@ -3576,7 +3455,7 @@ private: } else if (obj->getRTTI().instanceOf(FromY::rtti)) { writeFromY((FromY*)obj); } else { - fprintf(stderr, "Error: Unknown FromProperty type: \n"); exit(1); + fprintf(stderr, "Error: Unknown FromProperty type\n"); exit(1); } } @@ -3597,8 +3476,7 @@ private: _json.writeName("to"); _json.writeArrayStart(); for (size_t i = 0; i < obj->_to.size(); i++) { - ToProperty* item = obj->_to[i]; - writeToProperty(item); + writeToProperty(obj->_to[i]); } _json.writeArrayEnd(); @@ -3622,8 +3500,7 @@ private: _json.writeName("to"); _json.writeArrayStart(); for (size_t i = 0; i < obj->_to.size(); i++) { - ToProperty* item = obj->_to[i]; - writeToProperty(item); + writeToProperty(obj->_to[i]); } _json.writeArrayEnd(); @@ -3647,8 +3524,7 @@ private: _json.writeName("to"); _json.writeArrayStart(); for (size_t i = 0; i < obj->_to.size(); i++) { - ToProperty* item = obj->_to[i]; - writeToProperty(item); + writeToProperty(obj->_to[i]); } _json.writeArrayEnd(); @@ -3672,8 +3548,7 @@ private: _json.writeName("to"); _json.writeArrayStart(); for (size_t i = 0; i < obj->_to.size(); i++) { - ToProperty* item = obj->_to[i]; - writeToProperty(item); + writeToProperty(obj->_to[i]); } _json.writeArrayEnd(); @@ -3697,8 +3572,7 @@ private: _json.writeName("to"); _json.writeArrayStart(); for (size_t i = 0; i < obj->_to.size(); i++) { - ToProperty* item = obj->_to[i]; - writeToProperty(item); + writeToProperty(obj->_to[i]); } _json.writeArrayEnd(); @@ -3722,8 +3596,7 @@ private: _json.writeName("to"); _json.writeArrayStart(); for (size_t i = 0; i < obj->_to.size(); i++) { - ToProperty* item = obj->_to[i]; - writeToProperty(item); + writeToProperty(obj->_to[i]); } _json.writeArrayEnd(); @@ -3744,7 +3617,7 @@ private: } else if (obj->getRTTI().instanceOf(ToY::rtti)) { writeToY((ToY*)obj); } else { - fprintf(stderr, "Error: Unknown ToProperty type: \n"); exit(1); + fprintf(stderr, "Error: Unknown ToProperty type\n"); exit(1); } } @@ -3932,7 +3805,7 @@ private: } else if (obj->getRTTI().instanceOf(TransformConstraint::rtti)) { writeTransformConstraint((TransformConstraint*)obj); } else { - fprintf(stderr, "Error: Unknown Update type: \n"); exit(1); + fprintf(stderr, "Error: Unknown Update type\n"); exit(1); } } @@ -3946,10 +3819,11 @@ private: } else if (obj->getRTTI().instanceOf(PathAttachment::rtti)) { writePathAttachment((PathAttachment*)obj); } else { - fprintf(stderr, "Error: Unknown VertexAttachment type: \n"); exit(1); + fprintf(stderr, "Error: Unknown VertexAttachment type\n"); exit(1); } } + // Custom helper methods void writeColor(Color* obj) { if (obj == nullptr) { _json.writeNull(); @@ -3967,6 +3841,19 @@ private: } } + void writeColor(const Color& obj) { + _json.writeObjectStart(); + _json.writeName("r"); + _json.writeValue(obj.r); + _json.writeName("g"); + _json.writeValue(obj.g); + _json.writeName("b"); + _json.writeValue(obj.b); + _json.writeName("a"); + _json.writeValue(obj.a); + _json.writeObjectEnd(); + } + void writeTextureRegion(TextureRegion* obj) { if (obj == nullptr) { _json.writeNull(); @@ -3988,6 +3875,40 @@ private: } } + void writeTextureRegion(const TextureRegion& obj) { + _json.writeObjectStart(); + _json.writeName("u"); + _json.writeValue(obj.getU()); + _json.writeName("v"); + _json.writeValue(obj.getV()); + _json.writeName("u2"); + _json.writeValue(obj.getU2()); + _json.writeName("v2"); + _json.writeValue(obj.getV2()); + _json.writeName("width"); + _json.writeValue(obj.getRegionWidth()); + _json.writeName("height"); + _json.writeValue(obj.getRegionHeight()); + _json.writeObjectEnd(); + } + + void writeIntArray(const Array& obj) { + _json.writeArrayStart(); + for (size_t i = 0; i < obj.size(); i++) { + _json.writeValue(obj[i]); + } + _json.writeArrayEnd(); + } + + void writeFloatArray(const Array& obj) { + _json.writeArrayStart(); + for (size_t i = 0; i < obj.size(); i++) { + _json.writeValue(obj[i]); + } + _json.writeArrayEnd(); + } + + // Reference versions of write methods void writeAnimation(const Animation& obj) { writeAnimation(const_cast(&obj)); } @@ -4120,10 +4041,6 @@ private: writeSliderTimeline(const_cast(&obj)); } - void writeTimeline(const Timeline& obj) { - writeTimeline(const_cast(&obj)); - } - void writeTransformConstraintTimeline(const TransformConstraintTimeline& obj) { writeTransformConstraintTimeline(const_cast(&obj)); } @@ -4152,10 +4069,6 @@ private: writeAnimationStateData(const_cast(&obj)); } - void writeAttachment(const Attachment& obj) { - writeAttachment(const_cast(&obj)); - } - void writeBone(const Bone& obj) { writeBone(const_cast(&obj)); } @@ -4180,14 +4093,6 @@ private: writeClippingAttachment(const_cast(&obj)); } - void writeConstraint(const Constraint& obj) { - writeConstraint(const_cast(&obj)); - } - - void writeConstraintData(const ConstraintData& obj) { - writeConstraintData(const_cast(&obj)); - } - void writeEvent(const Event& obj) { writeEvent(const_cast(&obj)); } @@ -4260,10 +4165,6 @@ private: writeSkeletonData(const_cast(&obj)); } - void writeSkin(const Skin& obj) { - writeSkin(const_cast(&obj)); - } - void writeSlider(const Slider& obj) { writeSlider(const_cast(&obj)); } @@ -4296,10 +4197,6 @@ private: writeTransformConstraintData(const_cast(&obj)); } - void writeFromProperty(const FromProperty& obj) { - writeFromProperty(const_cast(&obj)); - } - void writeFromRotate(const FromRotate& obj) { writeFromRotate(const_cast(&obj)); } @@ -4324,10 +4221,6 @@ private: writeFromY(const_cast(&obj)); } - void writeToProperty(const ToProperty& obj) { - writeToProperty(const_cast(&obj)); - } - void writeToRotate(const ToRotate& obj) { writeToRotate(const_cast(&obj)); } @@ -4356,24 +4249,8 @@ private: writeTransformConstraintPose(const_cast(&obj)); } - void writeUpdate(const Update& obj) { - writeUpdate(const_cast(&obj)); - } - - void writeVertexAttachment(const VertexAttachment& obj) { - writeVertexAttachment(const_cast(&obj)); - } - - void writeColor(const Color& obj) { - writeColor(const_cast(&obj)); - } - - void writeTextureRegion(const TextureRegion& obj) { - writeTextureRegion(const_cast(&obj)); - } - -}; // class SkeletonSerializer +}; } // namespace spine -#endif +#endif \ No newline at end of file diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java index 4e669d781..0987962e3 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java @@ -3060,8 +3060,10 @@ public class SkeletonSerializer { json.writeValue("Skin"); json.writeName("attachments"); + Array sortedAttachments = new Array<>(obj.getAttachments()); + sortedAttachments.sort((a, b) -> Integer.compare(a.getSlotIndex(), b.getSlotIndex())); json.writeArrayStart(); - for (SkinEntry item : obj.getAttachments()) { + for (SkinEntry item : sortedAttachments) { writeSkinEntry(item); } json.writeArrayEnd(); diff --git a/tests/generate-cpp-serializer-ast.ts b/tests/generate-cpp-serializer-ast.ts deleted file mode 100644 index 6c5f7c2a5..000000000 --- a/tests/generate-cpp-serializer-ast.ts +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/env tsx - -import * as fs from 'fs'; -import * as path from 'path'; -import { fileURLToPath } from 'url'; -import { parse } from 'java-parser'; -import type { ClassInfo } from './types'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -function addReferenceVersionsForWriteMethods(cpp: string): string { - // Find all writeXXX(XXX* obj) methods - const writeMethodRegex = / void (write\w+)\((\w+)\* obj\) \{/g; - const referenceMethods = []; - - let match; - while ((match = writeMethodRegex.exec(cpp)) !== null) { - const methodName = match[1]; - const typeName = match[2]; - console.log(`Found method: ${methodName}(${typeName}* obj)`); - - // Generate reference version that calls pointer version - const refMethod = ` void ${methodName}(const ${typeName}& obj) { - ${methodName}(const_cast<${typeName}*>(&obj)); - }`; - referenceMethods.push(refMethod); - } - - console.log(`Found ${referenceMethods.length} writeXXX methods, adding reference versions`); - - // Insert before }; // class SkeletonSerializer - const marker = '}; // class SkeletonSerializer'; - const insertPos = cpp.lastIndexOf(marker); - if (insertPos === -1) { - throw new Error('Could not find class end marker'); - } - - const referenceMethodsText = '\n' + referenceMethods.join('\n\n') + '\n\n'; - const before = cpp.substring(0, insertPos); - const after = cpp.substring(insertPos); - - cpp = before + referenceMethodsText + after; - - return cpp; -} - -function transformJavaToCppAST(javaCode: string): string { - // Parse Java code into AST - const ast = parse(javaCode); - - // Load analysis data to get enum information - const analysisFile = path.resolve(__dirname, '..', 'output', 'analysis-result.json'); - const analysisData = JSON.parse(fs.readFileSync(analysisFile, 'utf8')); - const classMap = new Map(analysisData.classMap); - - // Build enum mappings: Java enum name -> C++ enum values - const enumMappings = new Map>(); - - for (const [className, classInfo] of classMap) { - if (classInfo.isEnum && classInfo.enumValues) { - const shortName = className.split('.').pop()!; - const valueMap = new Map(); - - for (const javaValue of classInfo.enumValues) { - // Convert Java enum value to C++ enum value - // e.g. "setup" -> "MixBlend_Setup", "first" -> "MixBlend_First" - const cppValue = `${shortName}_${javaValue.charAt(0).toUpperCase() + javaValue.slice(1)}`; - valueMap.set(javaValue, cppValue); - } - - enumMappings.set(shortName, valueMap); - } - } - - // Define custom function implementations for C++-specific cases - const customFunctions = new Map(); - - // Custom writeColor - Color fields are public without _ prefix - customFunctions.set('writeColor', ` void writeColor(Color* obj) { - if (obj == nullptr) { - _json.writeNull(); - } else { - _json.writeObjectStart(); - _json.writeName("r"); - _json.writeValue(obj->r); - _json.writeName("g"); - _json.writeValue(obj->g); - _json.writeName("b"); - _json.writeValue(obj->b); - _json.writeName("a"); - _json.writeValue(obj->a); - _json.writeObjectEnd(); - } - }`); - - // Custom writeSkinEntry - takes C++ AttachmentMap::Entry instead of Java SkinEntry - customFunctions.set('writeSkinEntry', ` void writeSkinEntry(Skin::AttachmentMap::Entry* obj) { - _json.writeObjectStart(); - _json.writeName("type"); - _json.writeValue("SkinEntry"); - _json.writeName("slotIndex"); - _json.writeValue((int)obj->_slotIndex); - _json.writeName("name"); - _json.writeValue(obj->_name); - _json.writeName("attachment"); - writeAttachment(obj->_attachment); - _json.writeObjectEnd(); - }`); - - // Custom writeSkin - matches Java output exactly - customFunctions.set('writeSkin', ` void writeSkin(Skin* obj) { - if (_visitedObjects.containsKey(obj)) { - _json.writeValue(""); - return; - } - _visitedObjects.put(obj, true); - - _json.writeObjectStart(); - _json.writeName("type"); - _json.writeValue("Skin"); - - _json.writeName("attachments"); - _json.writeArrayStart(); - Skin::AttachmentMap::Entries entries = obj->getAttachments(); - while (entries.hasNext()) { - Skin::AttachmentMap::Entry& entry = entries.next(); - writeSkinEntry(&entry); - } - _json.writeArrayEnd(); - - _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - BoneData* item = obj->getBones()[i]; - writeBoneData(item); - } - _json.writeArrayEnd(); - - _json.writeName("constraints"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getConstraints().size(); i++) { - ConstraintData* item = obj->getConstraints()[i]; - writeConstraintData(item); - } - _json.writeArrayEnd(); - - _json.writeName("name"); - _json.writeValue(obj->getName()); - - _json.writeName("color"); - writeColor(&obj->getColor()); - - _json.writeObjectEnd(); - }`); - - // For now, start with the regex approach but fix the specific for-loop issue - let cpp = javaCode; - - // Remove package declaration and imports - cpp = cpp.replace(/^package .*;$/m, ''); - cpp = cpp.replace(/^import .*;$/gm, ''); - - // Add C++ header - const header = `#ifndef Spine_SkeletonSerializer_h -#define Spine_SkeletonSerializer_h - -#include -#include "JsonWriter.h" -#include -#include - -namespace spine { -`; - - // Transform class declaration - cpp = cpp.replace(/public class SkeletonSerializer \{/, 'class SkeletonSerializer {'); - - // Transform field declarations - add JsonWriter as member - cpp = cpp.replace(/private final Set visitedObjects = new HashSet<>\(\);[\s]*private JsonWriter json;/, 'private:\n HashMap _visitedObjects;\n JsonWriter _json;\n\npublic:\n SkeletonSerializer() {}\n ~SkeletonSerializer() {}'); - - // Transform method signatures - return String not const String& - cpp = cpp.replace(/public String serialize(\w+)\((\w+) (\w+)\) \{/g, - 'String serialize$1($2* $3) {'); - - // Update the method bodies to use member JsonWriter - cpp = cpp.replace(/visitedObjects\.clear\(\);/g, '_visitedObjects.clear();'); - cpp = cpp.replace(/json = new JsonWriter\(\);/g, '_json = JsonWriter();'); - cpp = cpp.replace(/json\.close\(\);/g, '_json.close();'); - cpp = cpp.replace(/return json\.getString\(\);/g, 'return _json.getString();'); - - // Transform private methods - remove dots from type names (Animation.AlphaTimeline -> AlphaTimeline) - cpp = cpp.replace(/private void write(\w+)\(([\w.]+) obj\) \{/g, function(match, methodName, typeName) { - // Remove namespace/class prefix (e.g., Animation.AlphaTimeline -> AlphaTimeline) - const simpleName = typeName.includes('.') ? typeName.split('.').pop() : typeName; - return `void write${methodName}(${simpleName}* obj) {`; - }); - - // Add private: section before first write method - cpp = cpp.replace(/(\n)( void writeAnimation)/, '\nprivate:\n$2'); - - // Transform object access - cpp = cpp.replace(/visitedObjects\.contains\(obj\)/g, '_visitedObjects.containsKey(obj)'); - cpp = cpp.replace(/visitedObjects\.add\(obj\)/g, '_visitedObjects.put(obj, true)'); - - // Transform method calls - cpp = cpp.replace(/obj\.get(\w+)\(\)/g, 'obj->get$1()'); - cpp = cpp.replace(/json\.write/g, '_json.write'); - - // Transform field access from obj.field to obj->field - // Match any valid Java identifier (including $ and _) but not method calls - cpp = cpp.replace(/obj\.([a-zA-Z_$][a-zA-Z0-9_$]*)\b(?!\()/g, 'obj->$1'); - - // Fix C++ field access for underscore-prefixed fields - // C++ private fields are prefixed with underscore but Java fields are not - // Transform obj->field to obj->_field for ALL field accesses (not method calls) - cpp = cpp.replace(/obj->([a-zA-Z][a-zA-Z0-9]*)\b(?!\()/g, 'obj->_$1'); - - // Transform null checks and array/collection operations - cpp = cpp.replace(/== null/g, '== nullptr'); - cpp = cpp.replace(/!= null/g, '!= nullptr'); - cpp = cpp.replace(/\.size/g, '.size()'); - cpp = cpp.replace(/\.get\((\w+)\)/g, '[$1]'); - - // Remove null checks for C++-specific methods that always return references - // BoundingBoxAttachment.getBones(), ClippingAttachment.getBones(), - // MeshAttachment.getBones(), MeshAttachment.getEdges() - const noNullCheckMethods = ['getBones', 'getEdges']; - - for (const method of noNullCheckMethods) { - // Remove if (obj.getMethod() == null) { json.writeNull(); } else { ... } - const nullCheckPattern = new RegExp( - `\\s*if \\(obj->${method}\\(\\) == nullptr\\) \\{[^}]*json\\.writeNull\\(\\);[^}]*\\} else \\{([^}]*)\\}`, - 'gs' - ); - cpp = cpp.replace(nullCheckPattern, '$1'); - - // Also handle the simpler pattern without else - const simpleNullPattern = new RegExp( - `\\s*if \\(obj->${method}\\(\\) == nullptr\\) \\{[^}]*json\\.writeNull\\(\\);[^}]*\\}`, - 'gs' - ); - cpp = cpp.replace(simpleNullPattern, ''); - } - - // FIXED: Transform for-each loops properly with complete blocks - // This handles the complete for-each block, not just the declaration - cpp = cpp.replace(/for \(([\w.]+) (\w+) : obj->get(\w+)\(\)\) \{\s*([^}]+)\s*\}/g, function(match, typeName, varName, getter, body) { - const simpleName = typeName.includes('.') ? typeName.split('.').pop() : typeName; - // Special case for getPropertyIds which returns PropertyId not String - if (getter === 'PropertyIds') { - return `for (size_t i = 0; i < obj->get${getter}().size(); i++) {\n PropertyId ${varName} = obj->get${getter}()[i];\n ${body.trim()}\n }`; - } - // lowercase = primitive type (no pointer), uppercase = class type (pointer) - const isPointer = simpleName[0] === simpleName[0].toUpperCase(); - const cppType = isPointer ? `${simpleName}*` : simpleName; - const accessor = (simpleName === 'String') ? `const String&` : cppType; - return `for (size_t i = 0; i < obj->get${getter}().size(); i++) {\n ${accessor} ${varName} = obj->get${getter}()[i];\n ${body.trim()}\n }`; - }); - - // Transform ALL remaining ranged for loops to indexed loops - cpp = cpp.replace(/for \(([\w&*\s]+) (\w+) : ([^)]+)\) \{\s*([^}]+)\s*\}/g, function(match, type, varName, container, body) { - const cleanType = type.trim(); - // lowercase = primitive type (no pointer), uppercase = class type (pointer) - const isPointer = cleanType[0] === cleanType[0].toUpperCase(); - const cppType = isPointer ? `${cleanType}*` : cleanType; - return `for (size_t i = 0; i < ${container}.size(); i++) {\n ${cppType} ${varName} = ${container}[i];\n ${body.trim()}\n }`; - }); - - // Handle simpler for-each patterns - cpp = cpp.replace(/for \(int i = 0; i < ([\w>()-]+)\.size; i\+\+\) {/g, - 'for (size_t i = 0; i < $1.size(); i++) {'); - - // Special case for DeformTimeline::getVertices() which returns Array> - cpp = cpp.replace(/for \(float\[\] (\w+) : obj->getVertices\(\)\) \{\s*([^}]+)\s*\}/g, - 'for (size_t i = 0; i < obj->getVertices().size(); i++) {\n Array& $1 = obj->getVertices()[i];\n $2\n }'); - - // Also handle the pattern without obj-> prefix - cpp = cpp.replace(/for \(float\[\] (\w+) : (\w+)\.getVertices\(\)\) \{\s*([^}]+)\s*\}/g, - 'for (size_t i = 0; i < $2->getVertices().size(); i++) {\n Array& $1 = $2->getVertices()[i];\n $3\n }'); - - // Special case for other nested arrays like DrawOrderTimeline::getDrawOrders() - cpp = cpp.replace(/for \(int\[\] (\w+) : obj->getDrawOrders\(\)\) \{\s*([^}]+)\s*\}/g, - 'for (size_t i = 0; i < obj->getDrawOrders().size(); i++) {\n Array& $1 = obj->getDrawOrders()[i];\n $2\n }'); - - // Fix remaining array syntax that wasn't caught by the above - cpp = cpp.replace(/for \(([\w]+)\[\]/g, 'for (Array<$1>&'); - - // Transform instanceof and casts - remove dots from type names - cpp = cpp.replace(/obj instanceof ([\w.]+)/g, function(match, typeName) { - const simpleName = typeName.includes('.') ? typeName.split('.').pop() : typeName; - return `obj->getRTTI().instanceOf(${simpleName}::rtti)`; - }); - cpp = cpp.replace(/\(([\w.]+)\) obj/g, function(match, typeName) { - const simpleName = typeName.includes('.') ? typeName.split('.').pop() : typeName; - return `(${simpleName}*)obj`; - }); - - // Transform RuntimeException to fprintf + exit - cpp = cpp.replace(/throw new RuntimeException\("([^"]+)"\);/g, - 'fprintf(stderr, "Error: $1\\n"); exit(1);'); - cpp = cpp.replace(/throw new RuntimeException\("([^"]*)" \+ obj->getClass\(\)\.getName\(\)\);/g, - 'fprintf(stderr, "Error: $1\\n"); exit(1);'); - - // Remove class prefixes from type references, but not method calls - // This handles AnimationState.TrackEntry, TransformConstraintData.FromProperty, etc. - // But preserves obj.method() calls - cpp = cpp.replace(/\b([A-Z]\w*)\.([A-Z]\w+)\b/g, '$2'); - - // Replace enum .name() calls with switch statements - cpp = cpp.replace(/obj->get(\w+)\(\)\.name\(\)/g, (match, methodName) => { - // Extract enum type from method name (e.g. getMixBlend -> MixBlend) - const enumType = methodName.replace(/^get/, ''); - const enumMap = enumMappings.get(enumType); - - if (enumMap && enumMap.size > 0) { - // Generate switch statement - let switchCode = `[&]() -> String {\n`; - switchCode += ` switch(obj->get${methodName}()) {\n`; - - for (const [javaValue, cppValue] of enumMap) { - switchCode += ` case ${cppValue}: return "${javaValue}";\n`; - } - - switchCode += ` default: return "unknown";\n`; - switchCode += ` }\n`; - switchCode += ` }()`; - - return switchCode; - } - - // Fallback if we don't have enum mapping - return `String::valueOf((int)obj->get${methodName}())`; - }); - - // Fix some common patterns - cpp = cpp.replace(/\.length\(\)/g, '.size()'); - cpp = cpp.replace(/new /g, ''); - - // Remove any trailing extra braces before adding proper C++ ending - cpp = cpp.replace(/\n\s*\}\s*$/, ''); - - // Add proper C++ ending - cpp += '\n}; // class SkeletonSerializer\n\n} // namespace spine\n\n#endif\n'; - - // Prepend header - cpp = header + cpp; - - // Clean up multiple empty lines - cpp = cpp.replace(/\n{3,}/g, '\n\n'); - - // Replace auto-generated functions with custom implementations - for (const [functionName, customImpl] of customFunctions) { - // Find and replace the auto-generated function - const functionPattern = new RegExp( - ` void ${functionName}\\([^{]*\\{[\\s\\S]*?^ \\}$`, - 'gm' - ); - - if (cpp.match(functionPattern)) { - cpp = cpp.replace(functionPattern, customImpl); - console.log(`Replaced auto-generated ${functionName} with custom implementation`); - } - } - - // Post-process: Add reference versions for all write methods - cpp = addReferenceVersionsForWriteMethods(cpp); - - return cpp; -} - -function main() { - try { - // Check if java-parser is installed - try { - require.resolve('java-parser'); - } catch (e) { - console.error('java-parser package not found. Please install it with:'); - console.error('npm install java-parser'); - process.exit(1); - } - - // Read the Java SkeletonSerializer - const javaFile = path.resolve( - __dirname, - '..', - 'spine-libgdx', - 'spine-libgdx-tests', - 'src', - 'com', - 'esotericsoftware', - 'spine', - 'utils', - 'SkeletonSerializer.java' - ); - - if (!fs.existsSync(javaFile)) { - console.error(`Java SkeletonSerializer not found at: ${javaFile}`); - console.error('Please run generate-java-serializer.ts first'); - process.exit(1); - } - - const javaCode = fs.readFileSync(javaFile, 'utf-8'); - - // Transform to C++ using AST approach - const cppCode = transformJavaToCppAST(javaCode); - - // Write the C++ file - const cppFile = path.resolve( - __dirname, - '..', - 'spine-cpp', - 'tests', - 'SkeletonSerializer.h' - ); - - fs.mkdirSync(path.dirname(cppFile), { recursive: true }); - fs.writeFileSync(cppFile, cppCode); - - console.log(`Generated C++ serializer using AST approach: ${cppFile}`); - console.log('This version should have proper for-loop structure'); - - } catch (error: any) { - console.error('Error:', error.message); - process.exit(1); - } -} - -main(); \ No newline at end of file diff --git a/tests/generate-cpp-serializer.ts b/tests/generate-cpp-serializer.ts index a993fbe3c..587f7267d 100644 --- a/tests/generate-cpp-serializer.ts +++ b/tests/generate-cpp-serializer.ts @@ -3,391 +3,433 @@ import * as fs from 'fs'; import * as path from 'path'; import { fileURLToPath } from 'url'; -import type { ClassInfo } from './types'; +import type { SerializerIR, PublicMethod, WriteMethod, Property } from './generate-serializer-ir'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -function addReferenceVersionsForWriteMethods(cpp: string): string { - // Find all writeXXX(XXX* obj) methods - const writeMethodRegex = / void (write\w+)\((\w+)\* obj\) \{/g; - const referenceMethods = []; +function transformType(javaType: string): string { + // Remove package prefixes + const simpleName = javaType.includes('.') ? javaType.split('.').pop()! : javaType; - let match; - while ((match = writeMethodRegex.exec(cpp)) !== null) { - const methodName = match[1]; - const typeName = match[2]; - console.log(`Found method: ${methodName}(${typeName}* obj)`); + // Handle primitive types + if (simpleName === 'String') return 'const String&'; + if (simpleName === 'int') return 'int'; + if (simpleName === 'float') return 'float'; + if (simpleName === 'boolean') return 'bool'; + if (simpleName === 'short') return 'short'; - // Generate reference version that calls pointer version - const refMethod = ` void ${methodName}(const ${typeName}& obj) { - ${methodName}(const_cast<${typeName}*>(&obj)); - }`; - referenceMethods.push(refMethod); + // Handle arrays + if (simpleName.endsWith('[]')) { + const baseType = simpleName.slice(0, -2); + return `Array<${transformType(baseType)}>`; } - console.log(`Found ${referenceMethods.length} writeXXX methods, adding reference versions`); - - // Insert before }; // class SkeletonSerializer - const marker = '}; // class SkeletonSerializer'; - const insertPos = cpp.lastIndexOf(marker); - if (insertPos === -1) { - throw new Error('Could not find class end marker'); - } - - const referenceMethodsText = '\n' + referenceMethods.join('\n\n') + '\n\n'; - const before = cpp.substring(0, insertPos); - const after = cpp.substring(insertPos); - - cpp = before + referenceMethodsText + after; - - return cpp; + // Object types become pointers + return simpleName; } -function transformJavaToCpp(javaCode: string): string { - let cpp = javaCode; - - // Load analysis data to get enum information - const analysisFile = path.resolve(__dirname, '..', 'output', 'analysis-result.json'); - const analysisData = JSON.parse(fs.readFileSync(analysisFile, 'utf8')); - const classMap = new Map(analysisData.classMap); - - // Build enum mappings: Java enum name -> C++ enum values - const enumMappings = new Map>(); - - for (const [className, classInfo] of classMap) { - if (classInfo.isEnum && classInfo.enumValues) { - const shortName = className.split('.').pop()!; - const valueMap = new Map(); - - for (const javaValue of classInfo.enumValues) { - // Convert Java enum value to C++ enum value - // e.g. "setup" -> "MixBlend_Setup", "first" -> "MixBlend_First" - const cppValue = `${shortName}_${javaValue.charAt(0).toUpperCase() + javaValue.slice(1)}`; - valueMap.set(javaValue, cppValue); - } - - enumMappings.set(shortName, valueMap); - } - } +function generatePropertyCode(property: Property, indent: string, enumMappings: { [enumName: string]: { [javaValue: string]: string } }): string[] { + const lines: string[] = []; - // Define custom function implementations for C++-specific cases - const customFunctions = new Map(); - - // Custom writeColor - Color fields are public without _ prefix - customFunctions.set('writeColor', ` void writeColor(Color* obj) { - if (obj == nullptr) { - _json.writeNull(); + // Transform field access for C++: add _ prefix except for Color fields + let accessor = `obj->${property.getter}`; + if (!property.getter.includes('()')) { + // This is a field access, not a method call + const fieldName = property.getter; + // Color fields (r, g, b, a) don't get _ prefix, all others do + const isColorField = ['r', 'g', 'b', 'a'].includes(fieldName); + if (!isColorField) { + accessor = `obj->_${fieldName}`; } else { - _json.writeObjectStart(); - _json.writeName("r"); - _json.writeValue(obj->r); - _json.writeName("g"); - _json.writeValue(obj->g); - _json.writeName("b"); - _json.writeValue(obj->b); - _json.writeName("a"); - _json.writeValue(obj->a); - _json.writeObjectEnd(); + accessor = `obj->${fieldName}`; } - }`); - - // Custom writeSkinEntry - takes C++ AttachmentMap::Entry instead of Java SkinEntry - customFunctions.set('writeSkinEntry', ` void writeSkinEntry(Skin::AttachmentMap::Entry* obj) { - _json.writeObjectStart(); - _json.writeName("type"); - _json.writeValue("SkinEntry"); - _json.writeName("slotIndex"); - _json.writeValue((int)obj->_slotIndex); - _json.writeName("name"); - _json.writeValue(obj->_name); - _json.writeName("attachment"); - writeAttachment(obj->_attachment); - _json.writeObjectEnd(); - }`); - - // Custom writeSkin - matches Java output exactly - customFunctions.set('writeSkin', ` void writeSkin(Skin* obj) { - if (_visitedObjects.containsKey(obj)) { - _json.writeValue(""); - return; - } - _visitedObjects.put(obj, true); - - _json.writeObjectStart(); - _json.writeName("type"); - _json.writeValue("Skin"); - - _json.writeName("attachments"); - _json.writeArrayStart(); - Skin::AttachmentMap::Entries entries = obj->getAttachments(); - while (entries.hasNext()) { - Skin::AttachmentMap::Entry& entry = entries.next(); - writeSkinEntry(&entry); - } - _json.writeArrayEnd(); - - _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - BoneData* item = obj->getBones()[i]; - writeBoneData(item); - } - _json.writeArrayEnd(); - - _json.writeName("constraints"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getConstraints().size(); i++) { - ConstraintData* item = obj->getConstraints()[i]; - writeConstraintData(item); - } - _json.writeArrayEnd(); - - _json.writeName("name"); - _json.writeValue(obj->getName()); - - _json.writeName("color"); - writeColor(&obj->getColor()); - - _json.writeObjectEnd(); - }`); - - // Remove package declaration and imports - cpp = cpp.replace(/^package .*;$/m, ''); - cpp = cpp.replace(/^import .*;$/gm, ''); - - // Add C++ header - const header = `#ifndef Spine_SkeletonSerializer_h -#define Spine_SkeletonSerializer_h - -#include -#include "JsonWriter.h" -#include -#include - -namespace spine { -`; - - // Transform class declaration - cpp = cpp.replace(/public class SkeletonSerializer \{/, 'class SkeletonSerializer {'); - - // Transform field declarations - add JsonWriter as member - cpp = cpp.replace(/private final Set visitedObjects = new HashSet<>\(\);[\s]*private JsonWriter json;/, 'private:\n HashMap _visitedObjects;\n JsonWriter _json;\n\npublic:\n SkeletonSerializer() {}\n ~SkeletonSerializer() {}'); - - // Transform method signatures - return String not const String& - cpp = cpp.replace(/public String serialize(\w+)\((\w+) (\w+)\) \{/g, - 'String serialize$1($2* $3) {'); - - // Update the method bodies to use member JsonWriter - cpp = cpp.replace(/visitedObjects\.clear\(\);/g, '_visitedObjects.clear();'); - cpp = cpp.replace(/json = new JsonWriter\(\);/g, '_json = JsonWriter();'); - cpp = cpp.replace(/json\.close\(\);/g, '_json.close();'); - cpp = cpp.replace(/return json\.getString\(\);/g, 'return _json.getString();'); - - // Transform private methods - remove dots from type names (Animation.AlphaTimeline -> AlphaTimeline) - cpp = cpp.replace(/private void write(\w+)\(([\w.]+) obj\) \{/g, function(match, methodName, typeName) { - // Remove namespace/class prefix (e.g., Animation.AlphaTimeline -> AlphaTimeline) - const simpleName = typeName.includes('.') ? typeName.split('.').pop() : typeName; - return `void write${methodName}(${simpleName}* obj) {`; - }); - - // Add private: section before first write method - cpp = cpp.replace(/(\n)( void writeAnimation)/, '\nprivate:\n$2'); - - // Transform object access - cpp = cpp.replace(/visitedObjects\.contains\(obj\)/g, '_visitedObjects.containsKey(obj)'); - cpp = cpp.replace(/visitedObjects\.add\(obj\)/g, '_visitedObjects.put(obj, true)'); - - // Transform method calls - cpp = cpp.replace(/obj\.get(\w+)\(\)/g, 'obj->get$1()'); - cpp = cpp.replace(/json\.write/g, '_json.write'); - - // Transform field access from obj.field to obj->field - // Match any valid Java identifier (including $ and _) but not method calls - cpp = cpp.replace(/obj\.([a-zA-Z_$][a-zA-Z0-9_$]*)\b(?!\()/g, 'obj->$1'); - - // Fix C++ field access for underscore-prefixed fields - // C++ private fields are prefixed with underscore but Java fields are not - // Transform obj->field to obj->_field for ALL field accesses (not method calls) - cpp = cpp.replace(/obj->([a-zA-Z][a-zA-Z0-9]*)\b(?!\()/g, 'obj->_$1'); - - // Transform null checks and array/collection operations - cpp = cpp.replace(/== null/g, '== nullptr'); - cpp = cpp.replace(/!= null/g, '!= nullptr'); - cpp = cpp.replace(/\.size/g, '.size()'); - cpp = cpp.replace(/\.get\((\w+)\)/g, '[$1]'); - - // Remove null checks for C++-specific methods that always return references - // BoundingBoxAttachment.getBones(), ClippingAttachment.getBones(), - // MeshAttachment.getBones(), MeshAttachment.getEdges() - const noNullCheckMethods = ['getBones', 'getEdges']; - - for (const method of noNullCheckMethods) { - // Remove if (obj.getMethod() == null) { json.writeNull(); } else { ... } - const nullCheckPattern = new RegExp( - `\\s*if \\(obj->${method}\\(\\) == nullptr\\) \\{[^}]*json\\.writeNull\\(\\);[^}]*\\} else \\{([^}]*)\\}`, - 'gs' - ); - cpp = cpp.replace(nullCheckPattern, '$1'); - - // Also handle the simpler pattern without else - const simpleNullPattern = new RegExp( - `\\s*if \\(obj->${method}\\(\\) == nullptr\\) \\{[^}]*json\\.writeNull\\(\\);[^}]*\\}`, - 'gs' - ); - cpp = cpp.replace(simpleNullPattern, ''); } - // Transform for-each loops to indexed loops - handle String vs pointer types - cpp = cpp.replace(/for \(([\w.]+) (\w+) : obj->get(\w+)\(\)\) \{/g, function(match, typeName, varName, getter) { - const simpleName = typeName.includes('.') ? typeName.split('.').pop() : typeName; - // Special case for getPropertyIds which returns PropertyId not String - if (getter === 'PropertyIds') { - return `for (size_t i = 0; i < obj->get${getter}().size(); i++) {\n PropertyId ${varName} = obj->get${getter}()[i];`; - } - // lowercase = primitive type (no pointer), uppercase = class type (pointer) - const isPointer = simpleName[0] === simpleName[0].toUpperCase(); - const cppType = isPointer ? `${simpleName}*` : simpleName; - const accessor = (simpleName === 'String') ? `const String&` : cppType; - return `for (size_t i = 0; i < obj->get${getter}().size(); i++) {\n ${accessor} ${varName} = obj->get${getter}()[i];`; - }); + // C++-specific: darkColor specifically has hasDarkColor() method + const isDarkColor = property.kind === "object" && + property.valueType === "Color" && + property.getter === "getDarkColor()"; - // Transform ALL remaining ranged for loops to indexed loops - cpp = cpp.replace(/for \(([\w&*\s]+) (\w+) : ([^)]+)\) {/g, function(match, type, varName, container) { - const cleanType = type.trim(); - // lowercase = primitive type (no pointer), uppercase = class type (pointer) - const isPointer = cleanType[0] === cleanType[0].toUpperCase(); - const cppType = isPointer ? `${cleanType}*` : cleanType; - return `for (size_t i = 0; i < ${container}.size(); i++) {\n ${cppType} ${varName} = ${container}[i];`; - }); + if (isDarkColor) { + const colorAccessor = `&${accessor}`; - // Handle simpler for-each patterns - cpp = cpp.replace(/for \(int i = 0; i < ([\w>()-]+)\.size; i\+\+\) {/g, - 'for (size_t i = 0; i < $1.size(); i++) {'); + lines.push(`${indent}if (obj->hasDarkColor()) {`); + lines.push(`${indent} ${property.writeMethodCall}(${colorAccessor});`); + lines.push(`${indent}} else {`); + lines.push(`${indent} _json.writeNull();`); + lines.push(`${indent}}`); + return lines; + } - // Special case for DeformTimeline::getVertices() which returns Array> - cpp = cpp.replace(/for \(float\[\] (\w+) : obj->getVertices\(\)\) \{/g, - 'for (size_t i = 0; i < obj->getVertices().size(); i++) {\n Array& $1 = obj->getVertices()[i];'); + switch (property.kind) { + case "primitive": + lines.push(`${indent}_json.writeValue(${accessor});`); + break; - // Also handle the pattern without obj-> prefix - cpp = cpp.replace(/for \(float\[\] (\w+) : (\w+)\.getVertices\(\)\) \{/g, - 'for (size_t i = 0; i < $2->getVertices().size(); i++) {\n Array& $1 = $2->getVertices()[i];'); - - // Special case for other nested arrays like DrawOrderTimeline::getDrawOrders() - cpp = cpp.replace(/for \(int\[\] (\w+) : obj->getDrawOrders\(\)\) \{/g, - 'for (size_t i = 0; i < obj->getDrawOrders().size(); i++) {\n Array& $1 = obj->getDrawOrders()[i];'); - - // Fix remaining array syntax that wasn't caught by the above - cpp = cpp.replace(/for \(([\w]+)\[\]/g, 'for (Array<$1>&'); - - // Transform instanceof and casts - remove dots from type names - cpp = cpp.replace(/obj instanceof ([\w.]+)/g, function(match, typeName) { - const simpleName = typeName.includes('.') ? typeName.split('.').pop() : typeName; - return `obj->getRTTI().instanceOf(${simpleName}::rtti)`; - }); - cpp = cpp.replace(/\(([\w.]+)\) obj/g, function(match, typeName) { - const simpleName = typeName.includes('.') ? typeName.split('.').pop() : typeName; - return `(${simpleName}*)obj`; - }); - - // Transform RuntimeException to fprintf + exit - cpp = cpp.replace(/throw new RuntimeException\("([^"]+)"\);/g, - 'fprintf(stderr, "Error: $1\\n"); exit(1);'); - cpp = cpp.replace(/throw new RuntimeException\("([^"]*)" \+ obj->getClass\(\)\.getName\(\)\);/g, - 'fprintf(stderr, "Error: $1\\n"); exit(1);'); - - // Remove class prefixes from type references, but not method calls - // This handles AnimationState.TrackEntry, TransformConstraintData.FromProperty, etc. - // But preserves obj.method() calls - cpp = cpp.replace(/\b([A-Z]\w*)\.([A-Z]\w+)\b/g, '$2'); - - // Replace enum .name() calls with switch statements - cpp = cpp.replace(/obj->get(\w+)\(\)\.name\(\)/g, (match, methodName) => { - // Extract enum type from method name (e.g. getMixBlend -> MixBlend) - const enumType = methodName.replace(/^get/, ''); - const enumMap = enumMappings.get(enumType); - - if (enumMap && enumMap.size > 0) { - // Generate switch statement - let switchCode = `[&]() -> String {\n`; - switchCode += ` switch(obj->get${methodName}()) {\n`; - - for (const [javaValue, cppValue] of enumMap) { - switchCode += ` case ${cppValue}: return "${javaValue}";\n`; + case "object": + if (property.isNullable) { + lines.push(`${indent}if (${accessor} == nullptr) {`); + lines.push(`${indent} _json.writeNull();`); + lines.push(`${indent}} else {`); + lines.push(`${indent} ${property.writeMethodCall}(${accessor});`); + lines.push(`${indent}}`); + } else { + lines.push(`${indent}${property.writeMethodCall}(${accessor});`); } - - switchCode += ` default: return "unknown";\n`; - switchCode += ` }\n`; - switchCode += ` }()`; - - return switchCode; - } - - // Fallback if we don't have enum mapping - return `String::valueOf((int)obj->get${methodName}())`; - }); + break; - // Fix some common patterns - cpp = cpp.replace(/\.length\(\)/g, '.size()'); - cpp = cpp.replace(/new /g, ''); + case "enum": + const enumName = property.enumName; + const enumMap = enumMappings[enumName]; - // Remove any trailing extra braces before adding proper C++ ending - cpp = cpp.replace(/\n\s*\}\s*$/, ''); + if (enumMap && Object.keys(enumMap).length > 0) { + // Generate switch statement for enum + lines.push(`${indent}_json.writeValue([&]() -> String {`); + lines.push(`${indent} switch(${accessor}) {`); - // Add proper C++ ending - cpp += '\n}; // class SkeletonSerializer\n\n} // namespace spine\n\n#endif\n'; + for (const [javaValue, cppValue] of Object.entries(enumMap)) { + lines.push(`${indent} case ${cppValue}: return "${javaValue}";`); + } - // Prepend header - cpp = header + cpp; + lines.push(`${indent} default: return "unknown";`); + lines.push(`${indent} }`); + lines.push(`${indent}}());`); + } else { + // Fallback if no enum mapping + lines.push(`${indent}_json.writeValue(String::valueOf((int)${accessor}));`); + } + break; - // Clean up multiple empty lines - cpp = cpp.replace(/\n{3,}/g, '\n\n'); + case "array": + // In C++, arrays are never null - empty arrays (size() == 0) are equivalent to Java null + lines.push(`${indent}_json.writeArrayStart();`); + lines.push(`${indent}for (size_t i = 0; i < ${accessor}.size(); i++) {`); + const elementAccess = `${accessor}[i]`; + if (property.elementKind === "primitive") { + lines.push(`${indent} _json.writeValue(${elementAccess});`); + } else { + lines.push(`${indent} ${property.writeMethodCall}(${elementAccess});`); + } + lines.push(`${indent}}`); + lines.push(`${indent}_json.writeArrayEnd();`); + break; - // Replace auto-generated functions with custom implementations - for (const [functionName, customImpl] of customFunctions) { - // Find and replace the auto-generated function - const functionPattern = new RegExp( - ` void ${functionName}\\([^{]*\\{[\\s\\S]*?^ \\}$`, - 'gm' - ); - - if (cpp.match(functionPattern)) { - cpp = cpp.replace(functionPattern, customImpl); - console.log(`Replaced auto-generated ${functionName} with custom implementation`); - } + case "nestedArray": + // Nested arrays are always considered non-null in both Java and C++ + lines.push(`${indent}_json.writeArrayStart();`); + lines.push(`${indent}for (size_t i = 0; i < ${accessor}.size(); i++) {`); + lines.push(`${indent} Array<${property.elementType}>& nestedArray = ${accessor}[i];`); + lines.push(`${indent} _json.writeArrayStart();`); + lines.push(`${indent} for (size_t j = 0; j < nestedArray.size(); j++) {`); + lines.push(`${indent} _json.writeValue(nestedArray[j]);`); + lines.push(`${indent} }`); + lines.push(`${indent} _json.writeArrayEnd();`); + lines.push(`${indent}}`); + lines.push(`${indent}_json.writeArrayEnd();`); + break; } - // Post-process: Add reference versions for all write methods - cpp = addReferenceVersionsForWriteMethods(cpp); - - return cpp; + return lines; } -function main() { - try { - // Read the Java SkeletonSerializer - const javaFile = path.resolve( - __dirname, - '..', - 'spine-libgdx', - 'spine-libgdx-tests', - 'src', - 'com', - 'esotericsoftware', - 'spine', - 'utils', - 'SkeletonSerializer.java' - ); +function generateCppFromIR(ir: SerializerIR): string { + const cppOutput: string[] = []; - if (!fs.existsSync(javaFile)) { - console.error(`Java SkeletonSerializer not found at: ${javaFile}`); - console.error('Please run generate-java-serializer.ts first'); + // Generate C++ file header + cppOutput.push('#ifndef Spine_SkeletonSerializer_h'); + cppOutput.push('#define Spine_SkeletonSerializer_h'); + cppOutput.push(''); + cppOutput.push('#include '); + cppOutput.push('#include "JsonWriter.h"'); + cppOutput.push('#include '); + cppOutput.push('#include '); + cppOutput.push(''); + cppOutput.push('namespace spine {'); + cppOutput.push(''); + cppOutput.push('class SkeletonSerializer {'); + cppOutput.push('private:'); + cppOutput.push(' HashMap _visitedObjects;'); + cppOutput.push(' JsonWriter _json;'); + cppOutput.push(''); + cppOutput.push('public:'); + cppOutput.push(' SkeletonSerializer() {}'); + cppOutput.push(' ~SkeletonSerializer() {}'); + cppOutput.push(''); + + // Generate public methods + for (const method of ir.publicMethods) { + const cppParamType = transformType(method.paramType); + cppOutput.push(` String ${method.name}(${cppParamType}* ${method.paramName}) {`); + cppOutput.push(' _visitedObjects.clear();'); + cppOutput.push(' _json = JsonWriter();'); + cppOutput.push(` ${method.writeMethodCall}(${method.paramName});`); + cppOutput.push(' return _json.getString();'); + cppOutput.push(' }'); + cppOutput.push(''); + } + + cppOutput.push('private:'); + + // Generate write methods + for (const method of ir.writeMethods) { + const shortName = method.paramType.split('.').pop()!; + const cppType = transformType(method.paramType); + + // Custom writeSkin and writeSkinEntry implementations + if (method.name === 'writeSkin') { + cppOutput.push(' void writeSkin(Skin* obj) {'); + cppOutput.push(' if (_visitedObjects.containsKey(obj)) {'); + cppOutput.push(' _json.writeValue("");'); + cppOutput.push(' return;'); + cppOutput.push(' }'); + cppOutput.push(' _visitedObjects.put(obj, true);'); + cppOutput.push(''); + cppOutput.push(' _json.writeObjectStart();'); + cppOutput.push(' _json.writeName("type");'); + cppOutput.push(' _json.writeValue("Skin");'); + cppOutput.push(''); + cppOutput.push(' _json.writeName("attachments");'); + cppOutput.push(' _json.writeArrayStart();'); + cppOutput.push(' Skin::AttachmentMap::Entries entries = obj->getAttachments();'); + cppOutput.push(' while (entries.hasNext()) {'); + cppOutput.push(' Skin::AttachmentMap::Entry& entry = entries.next();'); + cppOutput.push(' writeSkinEntry(&entry);'); + cppOutput.push(' }'); + cppOutput.push(' _json.writeArrayEnd();'); + cppOutput.push(''); + cppOutput.push(' _json.writeName("bones");'); + cppOutput.push(' _json.writeArrayStart();'); + cppOutput.push(' for (size_t i = 0; i < obj->getBones().size(); i++) {'); + cppOutput.push(' BoneData* item = obj->getBones()[i];'); + cppOutput.push(' writeBoneData(item);'); + cppOutput.push(' }'); + cppOutput.push(' _json.writeArrayEnd();'); + cppOutput.push(''); + cppOutput.push(' _json.writeName("constraints");'); + cppOutput.push(' _json.writeArrayStart();'); + cppOutput.push(' for (size_t i = 0; i < obj->getConstraints().size(); i++) {'); + cppOutput.push(' ConstraintData* item = obj->getConstraints()[i];'); + cppOutput.push(' writeConstraintData(item);'); + cppOutput.push(' }'); + cppOutput.push(' _json.writeArrayEnd();'); + cppOutput.push(''); + cppOutput.push(' _json.writeName("name");'); + cppOutput.push(' _json.writeValue(obj->getName());'); + cppOutput.push(''); + cppOutput.push(' _json.writeName("color");'); + cppOutput.push(' writeColor(&obj->getColor());'); + cppOutput.push(''); + cppOutput.push(' _json.writeObjectEnd();'); + cppOutput.push(' }'); + cppOutput.push(''); + continue; + } + + // Custom writeSkinEntry + if (method.name === 'writeSkinEntry') { + // Custom writeSkinEntry implementation + cppOutput.push(' void writeSkinEntry(Skin::AttachmentMap::Entry* obj) {'); + cppOutput.push(' _json.writeObjectStart();'); + cppOutput.push(' _json.writeName("type");'); + cppOutput.push(' _json.writeValue("SkinEntry");'); + cppOutput.push(' _json.writeName("slotIndex");'); + cppOutput.push(' _json.writeValue((int)obj->_slotIndex);'); + cppOutput.push(' _json.writeName("name");'); + cppOutput.push(' _json.writeValue(obj->_name);'); + cppOutput.push(' _json.writeName("attachment");'); + cppOutput.push(' writeAttachment(obj->_attachment);'); + cppOutput.push(' _json.writeObjectEnd();'); + cppOutput.push(' }'); + cppOutput.push(''); + continue; + } + + cppOutput.push(` void ${method.name}(${cppType}* obj) {`); + + if (method.isAbstractType) { + // Handle abstract types with instanceof chain + if (method.subtypeChecks && method.subtypeChecks.length > 0) { + let first = true; + for (const subtype of method.subtypeChecks) { + const subtypeShortName = subtype.typeName.split('.').pop()!; + + if (first) { + cppOutput.push(` if (obj->getRTTI().instanceOf(${subtypeShortName}::rtti)) {`); + first = false; + } else { + cppOutput.push(` } else if (obj->getRTTI().instanceOf(${subtypeShortName}::rtti)) {`); + } + cppOutput.push(` ${subtype.writeMethodCall}((${subtypeShortName}*)obj);`); + } + cppOutput.push(' } else {'); + cppOutput.push(` fprintf(stderr, "Error: Unknown ${shortName} type\\n"); exit(1);`); + cppOutput.push(' }'); + } else { + cppOutput.push(' _json.writeNull(); // No concrete implementations after filtering exclusions'); + } + } else { + // Handle concrete types + // Add cycle detection + cppOutput.push(' if (_visitedObjects.containsKey(obj)) {'); + cppOutput.push(' _json.writeValue("");'); + cppOutput.push(' return;'); + cppOutput.push(' }'); + cppOutput.push(' _visitedObjects.put(obj, true);'); + cppOutput.push(''); + + cppOutput.push(' _json.writeObjectStart();'); + + // Write type field + cppOutput.push(' _json.writeName("type");'); + cppOutput.push(` _json.writeValue("${shortName}");`); + + // Write properties + for (const property of method.properties) { + cppOutput.push(''); + cppOutput.push(` _json.writeName("${property.name}");`); + const propertyLines = generatePropertyCode(property, ' ', ir.enumMappings); + cppOutput.push(...propertyLines); + } + + cppOutput.push(''); + cppOutput.push(' _json.writeObjectEnd();'); + } + + cppOutput.push(' }'); + cppOutput.push(''); + } + + // Add custom helper methods for special types + cppOutput.push(' // Custom helper methods'); + cppOutput.push(' void writeColor(Color* obj) {'); + cppOutput.push(' if (obj == nullptr) {'); + cppOutput.push(' _json.writeNull();'); + cppOutput.push(' } else {'); + cppOutput.push(' _json.writeObjectStart();'); + cppOutput.push(' _json.writeName("r");'); + cppOutput.push(' _json.writeValue(obj->r);'); + cppOutput.push(' _json.writeName("g");'); + cppOutput.push(' _json.writeValue(obj->g);'); + cppOutput.push(' _json.writeName("b");'); + cppOutput.push(' _json.writeValue(obj->b);'); + cppOutput.push(' _json.writeName("a");'); + cppOutput.push(' _json.writeValue(obj->a);'); + cppOutput.push(' _json.writeObjectEnd();'); + cppOutput.push(' }'); + cppOutput.push(' }'); + cppOutput.push(''); + + cppOutput.push(' void writeColor(const Color& obj) {'); + cppOutput.push(' _json.writeObjectStart();'); + cppOutput.push(' _json.writeName("r");'); + cppOutput.push(' _json.writeValue(obj.r);'); + cppOutput.push(' _json.writeName("g");'); + cppOutput.push(' _json.writeValue(obj.g);'); + cppOutput.push(' _json.writeName("b");'); + cppOutput.push(' _json.writeValue(obj.b);'); + cppOutput.push(' _json.writeName("a");'); + cppOutput.push(' _json.writeValue(obj.a);'); + cppOutput.push(' _json.writeObjectEnd();'); + cppOutput.push(' }'); + cppOutput.push(''); + + cppOutput.push(' void writeTextureRegion(TextureRegion* obj) {'); + cppOutput.push(' if (obj == nullptr) {'); + cppOutput.push(' _json.writeNull();'); + cppOutput.push(' } else {'); + cppOutput.push(' _json.writeObjectStart();'); + cppOutput.push(' _json.writeName("u");'); + cppOutput.push(' _json.writeValue(obj->getU());'); + cppOutput.push(' _json.writeName("v");'); + cppOutput.push(' _json.writeValue(obj->getV());'); + cppOutput.push(' _json.writeName("u2");'); + cppOutput.push(' _json.writeValue(obj->getU2());'); + cppOutput.push(' _json.writeName("v2");'); + cppOutput.push(' _json.writeValue(obj->getV2());'); + cppOutput.push(' _json.writeName("width");'); + cppOutput.push(' _json.writeValue(obj->getRegionWidth());'); + cppOutput.push(' _json.writeName("height");'); + cppOutput.push(' _json.writeValue(obj->getRegionHeight());'); + cppOutput.push(' _json.writeObjectEnd();'); + cppOutput.push(' }'); + cppOutput.push(' }'); + cppOutput.push(''); + + cppOutput.push(' void writeTextureRegion(const TextureRegion& obj) {'); + cppOutput.push(' _json.writeObjectStart();'); + cppOutput.push(' _json.writeName("u");'); + cppOutput.push(' _json.writeValue(obj.getU());'); + cppOutput.push(' _json.writeName("v");'); + cppOutput.push(' _json.writeValue(obj.getV());'); + cppOutput.push(' _json.writeName("u2");'); + cppOutput.push(' _json.writeValue(obj.getU2());'); + cppOutput.push(' _json.writeName("v2");'); + cppOutput.push(' _json.writeValue(obj.getV2());'); + cppOutput.push(' _json.writeName("width");'); + cppOutput.push(' _json.writeValue(obj.getRegionWidth());'); + cppOutput.push(' _json.writeName("height");'); + cppOutput.push(' _json.writeValue(obj.getRegionHeight());'); + cppOutput.push(' _json.writeObjectEnd();'); + cppOutput.push(' }'); + cppOutput.push(''); + + cppOutput.push(' void writeIntArray(const Array& obj) {'); + cppOutput.push(' _json.writeArrayStart();'); + cppOutput.push(' for (size_t i = 0; i < obj.size(); i++) {'); + cppOutput.push(' _json.writeValue(obj[i]);'); + cppOutput.push(' }'); + cppOutput.push(' _json.writeArrayEnd();'); + cppOutput.push(' }'); + cppOutput.push(''); + + cppOutput.push(' void writeFloatArray(const Array& obj) {'); + cppOutput.push(' _json.writeArrayStart();'); + cppOutput.push(' for (size_t i = 0; i < obj.size(); i++) {'); + cppOutput.push(' _json.writeValue(obj[i]);'); + cppOutput.push(' }'); + cppOutput.push(' _json.writeArrayEnd();'); + cppOutput.push(' }'); + cppOutput.push(''); + + // Add reference versions for write methods (excluding custom implementations) + cppOutput.push(' // Reference versions of write methods'); + const writeMethods = ir.writeMethods.filter(m => + !m.isAbstractType && + m.name !== 'writeSkin' && + m.name !== 'writeSkinEntry' + ); + for (const method of writeMethods) { + const cppType = transformType(method.paramType); + cppOutput.push(` void ${method.name}(const ${cppType}& obj) {`); + cppOutput.push(` ${method.name}(const_cast<${cppType}*>(&obj));`); + cppOutput.push(' }'); + cppOutput.push(''); + } + + + // C++ footer + cppOutput.push('};'); + cppOutput.push(''); + cppOutput.push('} // namespace spine'); + cppOutput.push(''); + cppOutput.push('#endif'); + + return cppOutput.join('\n'); +} + +async function main() { + try { + // Read the IR file + const irFile = path.resolve(__dirname, 'output', 'serializer-ir.json'); + if (!fs.existsSync(irFile)) { + console.error('Serializer IR not found. Run generate-serializer-ir.ts first.'); process.exit(1); } - const javaCode = fs.readFileSync(javaFile, 'utf-8'); + const ir: SerializerIR = JSON.parse(fs.readFileSync(irFile, 'utf8')); - // Transform to C++ - const cppCode = transformJavaToCpp(javaCode); + // Generate C++ serializer from IR + const cppCode = generateCppFromIR(ir); // Write the C++ file const cppFile = path.resolve( @@ -401,16 +443,21 @@ function main() { fs.mkdirSync(path.dirname(cppFile), { recursive: true }); fs.writeFileSync(cppFile, cppCode); - console.log(`Generated C++ serializer: ${cppFile}`); - console.log('Note: Manual review and fixes will be needed for:'); - console.log(' - Complex type transformations'); - console.log(' - Proper handling of nested classes'); - console.log(' - String operations and formatting'); + console.log(`Generated C++ serializer from IR: ${cppFile}`); + console.log(`- ${ir.publicMethods.length} public methods`); + console.log(`- ${ir.writeMethods.length} write methods`); + console.log(`- ${Object.keys(ir.enumMappings).length} enum mappings`); } catch (error: any) { console.error('Error:', error.message); + console.error('Stack:', error.stack); process.exit(1); } } -main(); \ No newline at end of file +// Allow running as a script or importing the function +if (import.meta.url === `file://${process.argv[1]}`) { + main(); +} + +export { generateCppFromIR }; \ No newline at end of file diff --git a/tests/generate-java-serializer.ts b/tests/generate-java-serializer.ts index 3efbef5c0..4ef278d85 100644 --- a/tests/generate-java-serializer.ts +++ b/tests/generate-java-serializer.ts @@ -7,7 +7,7 @@ import type { SerializerIR, PublicMethod, WriteMethod, Property } from './genera const __dirname = path.dirname(fileURLToPath(import.meta.url)); -function generatePropertyCode(property: Property, indent: string): string[] { +function generatePropertyCode(property: Property, indent: string, method?: WriteMethod): string[] { const lines: string[] = []; const accessor = `obj.${property.getter}`; @@ -41,12 +41,21 @@ function generatePropertyCode(property: Property, indent: string): string[] { break; case "array": + // Special handling for Skin attachments - sort by slot index + const isSkinAttachments = method?.paramType === 'Skin' && property.name === 'attachments' && property.elementType === 'SkinEntry'; + const sortedAccessor = isSkinAttachments ? 'sortedAttachments' : accessor; + + if (isSkinAttachments) { + lines.push(`${indent}Array<${property.elementType}> sortedAttachments = new Array<>(${accessor});`); + lines.push(`${indent}sortedAttachments.sort((a, b) -> Integer.compare(a.getSlotIndex(), b.getSlotIndex()));`); + } + if (property.isNullable) { lines.push(`${indent}if (${accessor} == null) {`); lines.push(`${indent} json.writeNull();`); lines.push(`${indent}} else {`); lines.push(`${indent} json.writeArrayStart();`); - lines.push(`${indent} for (${property.elementType} item : ${accessor}) {`); + lines.push(`${indent} for (${property.elementType} item : ${sortedAccessor}) {`); if (property.elementKind === "primitive") { lines.push(`${indent} json.writeValue(item);`); } else { @@ -57,7 +66,7 @@ function generatePropertyCode(property: Property, indent: string): string[] { lines.push(`${indent}}`); } else { lines.push(`${indent}json.writeArrayStart();`); - lines.push(`${indent}for (${property.elementType} item : ${accessor}) {`); + lines.push(`${indent}for (${property.elementType} item : ${sortedAccessor}) {`); if (property.elementKind === "primitive") { lines.push(`${indent} json.writeValue(item);`); } else { @@ -194,7 +203,7 @@ function generateJavaFromIR(ir: SerializerIR): string { for (const property of method.properties) { javaOutput.push(''); javaOutput.push(` json.writeName("${property.name}");`); - const propertyLines = generatePropertyCode(property, ' '); + const propertyLines = generatePropertyCode(property, ' ', method); javaOutput.push(...propertyLines); } diff --git a/tests/headless-test-runner.ts b/tests/headless-test-runner.ts index bef7414fe..57dfa7e31 100755 --- a/tests/headless-test-runner.ts +++ b/tests/headless-test-runner.ts @@ -138,7 +138,8 @@ const runtimes: RuntimeConfig[] = [ : `./build/headless-test "${absoluteSkeletonPath}" "${absoluteAtlasPath}"`, { cwd: path.join(rootDir, 'spine-cpp'), - encoding: 'utf8' + encoding: 'utf8', + maxBuffer: 1024 * 1024 * 10 // 10MB buffer } ).trim(); } @@ -172,7 +173,8 @@ const runtimes: RuntimeConfig[] = [ : `./build/headless-test "${absoluteSkeletonPath}" "${absoluteAtlasPath}"`, { cwd: path.join(rootDir, 'spine-c'), - encoding: 'utf8' + encoding: 'utf8', + maxBuffer: 1024 * 1024 * 10 // 10MB buffer } ).trim(); } @@ -192,7 +194,8 @@ const runtimes: RuntimeConfig[] = [ : `npx tsx tests/HeadlessTest.ts "${absoluteSkeletonPath}" "${absoluteAtlasPath}"`, { cwd: path.join(rootDir, 'spine-ts/spine-core'), - encoding: 'utf8' + encoding: 'utf8', + maxBuffer: 1024 * 1024 * 10 // 10MB buffer } ).trim(); }