Browse Source

[godot] Backport to 4.1

Mario Zechner 3 years ago
parent
commit
68b59271bb
100 changed files with 9292 additions and 43 deletions
  1. 27 0
      .github/actions/setup-godot-deps/action.yml
  2. 363 0
      .github/workflows/spine-godot.yml
  3. 13 0
      .gitignore
  4. 69 25
      examples/export/runtimes.sh
  5. BIN
      examples/raptor/manual-maps/light-sprite.png
  6. 3 1
      formatters/build.gradle
  7. 3 0
      spine-cpp/spine-cpp/include/spine/AnimationStateData.h
  8. 2 0
      spine-cpp/spine-cpp/include/spine/MeshAttachment.h
  9. 5 0
      spine-cpp/spine-cpp/src/spine/AnimationStateData.cpp
  10. 29 17
      spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp
  11. 85 0
      spine-godot/README.md
  12. 125 0
      spine-godot/build/build-templates.sh
  13. 70 0
      spine-godot/build/build.sh
  14. 33 0
      spine-godot/build/custom.py
  15. 124 0
      spine-godot/build/livepp-v4.patch
  16. 123 0
      spine-godot/build/livepp.patch
  17. 39 0
      spine-godot/build/setup.sh
  18. 4 0
      spine-godot/build/sources.lst
  19. BIN
      spine-godot/example-v4/assets/footstep.ogg
  20. 16 0
      spine-godot/example-v4/assets/footstep.ogg.import
  21. 10 0
      spine-godot/example-v4/assets/mix-and-match/mix-and-match-data.tres
  22. 1285 0
      spine-godot/example-v4/assets/mix-and-match/mix-and-match-pro.json
  23. 14 0
      spine-godot/example-v4/assets/mix-and-match/mix-and-match-pro.json.import
  24. 362 0
      spine-godot/example-v4/assets/mix-and-match/mix-and-match.atlas
  25. 15 0
      spine-godot/example-v4/assets/mix-and-match/mix-and-match.atlas.import
  26. BIN
      spine-godot/example-v4/assets/mix-and-match/mix-and-match.png
  27. 34 0
      spine-godot/example-v4/assets/mix-and-match/mix-and-match.png.import
  28. 16 0
      spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.atlas
  29. 15 0
      spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.atlas.import
  30. BIN
      spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.png
  31. 34 0
      spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.png.import
  32. 8 0
      spine-godot/example-v4/assets/raggedyspineboy/raggedy spineboy-res.tres
  33. 46 0
      spine-godot/example-v4/assets/raggedyspineboy/raggedy spineboy.json
  34. 14 0
      spine-godot/example-v4/assets/raggedyspineboy/raggedy spineboy.json.import
  35. BIN
      spine-godot/example-v4/assets/raptor/light-sprite.png
  36. 34 0
      spine-godot/example-v4/assets/raptor/light-sprite.png.import
  37. BIN
      spine-godot/example-v4/assets/raptor/n_raptor.png
  38. 34 0
      spine-godot/example-v4/assets/raptor/n_raptor.png.import
  39. 9 0
      spine-godot/example-v4/assets/raptor/raptor-data.tres
  40. BIN
      spine-godot/example-v4/assets/raptor/raptor-pro.skel
  41. 14 0
      spine-godot/example-v4/assets/raptor/raptor-pro.skel.import
  42. 100 0
      spine-godot/example-v4/assets/raptor/raptor.atlas
  43. 15 0
      spine-godot/example-v4/assets/raptor/raptor.atlas.import
  44. BIN
      spine-godot/example-v4/assets/raptor/raptor.png
  45. 34 0
      spine-godot/example-v4/assets/raptor/raptor.png.import
  46. 20 0
      spine-godot/example-v4/assets/spineboy/spineboy-data-res.tres
  47. 541 0
      spine-godot/example-v4/assets/spineboy/spineboy-pro.json
  48. 14 0
      spine-godot/example-v4/assets/spineboy/spineboy-pro.json.import
  49. BIN
      spine-godot/example-v4/assets/spineboy/spineboy-pro.skel
  50. 14 0
      spine-godot/example-v4/assets/spineboy/spineboy-pro.skel.import
  51. 101 0
      spine-godot/example-v4/assets/spineboy/spineboy.atlas
  52. 15 0
      spine-godot/example-v4/assets/spineboy/spineboy.atlas.import
  53. BIN
      spine-godot/example-v4/assets/spineboy/spineboy.png
  54. 34 0
      spine-godot/example-v4/assets/spineboy/spineboy.png.import
  55. 7 0
      spine-godot/example-v4/default_env.tres
  56. 18 0
      spine-godot/example-v4/examples/01-helloworld/helloworld.tscn
  57. 4 0
      spine-godot/example-v4/examples/01-helloworld/spineboy-helloworld.gd
  58. 38 0
      spine-godot/example-v4/examples/02-animation-state-listeners/animation-state-listeners.gd
  59. 19 0
      spine-godot/example-v4/examples/02-animation-state-listeners/animation-state-listeners.tscn
  60. 22 0
      spine-godot/example-v4/examples/03-mix-and-match/mix-and-match.gd
  61. 15 0
      spine-godot/example-v4/examples/03-mix-and-match/mix-and-match.tscn
  62. 15 0
      spine-godot/example-v4/examples/04-simple-input/simple-input.tscn
  63. 19 0
      spine-godot/example-v4/examples/04-simple-input/spineboy-simple-input.gd
  64. 11 0
      spine-godot/example-v4/examples/05-mouse-following/mouse-following.gd
  65. 22 0
      spine-godot/example-v4/examples/05-mouse-following/mouse-following.tscn
  66. 5 0
      spine-godot/example-v4/examples/06-bone-following/bone-following.gd
  67. 25 0
      spine-godot/example-v4/examples/06-bone-following/bone-following.tscn
  68. 11 0
      spine-godot/example-v4/examples/07-slot-node/slot-node.gd
  69. 56 0
      spine-godot/example-v4/examples/07-slot-node/slot-node.tscn
  70. 33 0
      spine-godot/example-v4/examples/08-animation-player/animation-player.gd
  71. 1942 0
      spine-godot/example-v4/examples/08-animation-player/animation-player.tscn
  72. 43 0
      spine-godot/example-v4/examples/09-custom-material/custom-material.tscn
  73. 4 0
      spine-godot/example-v4/examples/10-2d-lighting/2d-lighting.gd
  74. 25 0
      spine-godot/example-v4/examples/10-2d-lighting/2d-lighting.tscn
  75. 19 0
      spine-godot/example-v4/examples/11-bone-node/bone-node.gd
  76. 47 0
      spine-godot/example-v4/examples/11-bone-node/bone-node.tscn
  77. BIN
      spine-godot/example-v4/icon.png
  78. 34 0
      spine-godot/example-v4/icon.png.import
  79. 35 0
      spine-godot/example-v4/project.godot
  80. 4 0
      spine-godot/example-v4/tests/batch-test.gd
  81. 871 0
      spine-godot/example-v4/tests/batch-test.tscn
  82. 53 0
      spine-godot/example-v4/tests/ragdoll.tscn
  83. 26 0
      spine-godot/example-v4/tests/transforms.tscn
  84. 39 0
      spine-godot/example-v4/tests/unit-tests.gd
  85. 12 0
      spine-godot/example-v4/tests/unit-tests.tscn
  86. BIN
      spine-godot/example/assets/footstep.ogg
  87. 15 0
      spine-godot/example/assets/footstep.ogg.import
  88. 10 0
      spine-godot/example/assets/mix-and-match/mix-and-match-data.tres
  89. 1285 0
      spine-godot/example/assets/mix-and-match/mix-and-match-pro.json
  90. 13 0
      spine-godot/example/assets/mix-and-match/mix-and-match-pro.json.import
  91. 362 0
      spine-godot/example/assets/mix-and-match/mix-and-match.atlas
  92. 14 0
      spine-godot/example/assets/mix-and-match/mix-and-match.atlas.import
  93. BIN
      spine-godot/example/assets/mix-and-match/mix-and-match.png
  94. 35 0
      spine-godot/example/assets/mix-and-match/mix-and-match.png.import
  95. 16 0
      spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.atlas
  96. 14 0
      spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.atlas.import
  97. BIN
      spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.png
  98. 35 0
      spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.png.import
  99. 8 0
      spine-godot/example/assets/raggedyspineboy/raggedy spineboy-res.tres
  100. 46 0
      spine-godot/example/assets/raggedyspineboy/raggedy spineboy.json

+ 27 - 0
.github/actions/setup-godot-deps/action.yml

@@ -0,0 +1,27 @@
+name: Setup python and scons
+description: Setup python, install the pip version of scons.
+inputs:
+  python-version:
+    description: The python version to use.
+    default: "3.x"
+  python-arch:
+    description: The python architecture.
+    default: "x64"
+runs:
+  using: "composite"
+  steps:
+    # Use python 3.x release (works cross platform)
+    - name: Set up Python 3.x
+      uses: actions/setup-python@v2
+      with:
+        # Semantic version range syntax or exact version of a Python version
+        python-version: ${{ inputs.python-version }}
+        # Optional - x64 or x86 architecture, defaults to x64
+        architecture: ${{ inputs.python-arch }}
+
+    - name: Setup scons
+      shell: bash
+      run: |
+        python -c "import sys; print(sys.version)"
+        python -m pip install scons
+        scons --version

+ 363 - 0
.github/workflows/spine-godot.yml

@@ -0,0 +1,363 @@
+name: Build and Publish Godot editor and templates
+
+on:
+  push:
+    paths:
+      - ".github/workflows/spine-godot.yml"
+      - 'spine-godot/**'
+      - 'spine-cpp/**'
+  workflow_dispatch:
+
+env:
+  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+  AWS_EC2_METADATA_DISABLED: true
+  EM_VERSION: 3.1.10
+  GODOT_TAG: 3.4.4-stable
+  GODOT_VERSION: 3.4.4.stable
+
+jobs:
+
+  godot-editor-windows:
+    runs-on: windows-latest
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps
+
+      - name: Build Godot artifact
+        shell: bash
+        run: |          
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build.sh release_debug
+
+      - name: Upload artifacts
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-editor-windows.zip
+          path: spine-godot/godot/bin/godot.windows.opt.tools.64.exe
+
+  godot-editor-linux:
+    runs-on: ubuntu-18.04
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps
+
+      - name: Build Godot artifact
+        shell: bash
+        run: |          
+          sudo apt-get install build-essential scons pkg-config libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build.sh release_debug
+
+      - name: Upload artifacts
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-editor-linux.zip
+          path: spine-godot/godot/bin/godot.x11.opt.tools.64
+
+  godot-editor-macos:
+    runs-on: macos-latest
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps
+
+      - name: Build Godot artifact
+        shell: bash
+        run: |
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build.sh release_debug
+          pushd spine-godot/godot/bin
+          zip -r godot-editor-macos.zip Godot.app
+          popd
+
+      - name: Upload artifacts
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-editor-macos.zip
+          path: spine-godot/godot/bin/godot-editor-macos.zip
+
+  godot-template-ios:
+    runs-on: macos-latest
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps   
+
+      - name: Build Godot artifact
+        run: |          
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build-templates.sh ios
+
+      - name: Upload artifacts
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-ios.zip
+          path: spine-godot/godot/bin/iphone.zip
+
+  godot-template-macos:
+    runs-on: macos-latest
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps   
+
+      - name: Build Godot artifact
+        run: |          
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build-templates.sh macos
+
+      - name: Upload artifacts
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-macos.zip
+          path: spine-godot/godot/bin/osx.zip
+
+  godot-template-linux:
+    runs-on: ubuntu-18.04
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps   
+
+      - name: Build Godot artifact
+        run: |
+          sudo apt-get install build-essential scons pkg-config libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build-templates.sh linux
+
+      - name: Upload artifacts debug
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-linux-debug.zip
+          path: spine-godot/godot/bin/linux_x11_64_debug
+
+      - name: Upload artifacts release
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-linux-release.zip
+          path: spine-godot/godot/bin/linux_x11_64_release
+
+  godot-template-windows:
+    runs-on: windows-latest
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps
+
+      - name: Build Godot artifact
+        shell: bash
+        run: |
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build-templates.sh windows
+
+      - name: Upload artifacts debug
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-windows-debug.zip
+          path: spine-godot/godot/bin/windows_64_debug.exe
+
+      - name: Upload artifacts release
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-windows-release.zip
+          path: spine-godot/godot/bin/windows_64_release.exe
+
+  godot-template-android:
+    runs-on: ubuntu-20.04
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      # Azure repositories are not reliable, we need to prevent azure giving us packages.
+      - name: Make apt sources.list use the default Ubuntu repositories
+        run: |
+          sudo rm -f /etc/apt/sources.list.d/*
+          sudo cp -f spine-godot/build/sources.lst /etc/apt/sources.list
+          sudo apt-get update
+          
+      - name: Set up Java 11
+        uses: actions/setup-java@v1
+        with:
+          java-version: 11
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps
+
+      - name: Build Godot artifact
+        shell: bash
+        run: |
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build-templates.sh android
+
+      - name: Upload artifacts debug
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-android-debug.zip
+          path: spine-godot/godot/bin/android_debug.apk
+
+      - name: Upload artifacts release
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-android-release.zip
+          path: spine-godot/godot/bin/android_release.apk
+
+      - name: Upload artifacts source
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-android-source.zip
+          path: spine-godot/godot/bin/android_source.zip
+
+  godot-template-web:
+    runs-on: ubuntu-20.04
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Set up Emscripten latest
+        uses: mymindstorm/setup-emsdk@v10
+        with:
+          version: ${{env.EM_VERSION}}          
+
+      - name: Verify Emscripten setup
+        run: |
+          emcc -v
+
+      - name: Setup python and scons
+        uses: ./.github/actions/setup-godot-deps   
+
+      - name: Build Godot artifact
+        run: |          
+          ./spine-godot/build/setup.sh $GODOT_TAG false
+          ./spine-godot/build/build-templates.sh web
+
+      - name: Upload artifacts debug
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-web-debug.zip
+          path: spine-godot/godot/bin/webassembly_debug.zip
+
+      - name: Upload artifacts release
+        uses: actions/upload-artifact@v2
+        with:
+          name: godot-template-web-release.zip
+          path: spine-godot/godot/bin/webassembly_release.zip
+
+  upload-to-s3:
+    needs: [godot-editor-windows, godot-editor-linux, godot-editor-macos, godot-template-ios, godot-template-macos, godot-template-windows, godot-template-linux, godot-template-android, godot-template-web]
+    runs-on: ubuntu-latest
+    steps:
+      - name: Download godot-editor-windows artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-editor-windows.zip
+
+      - name: Download godot-editor-linux artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-editor-linux.zip
+
+      - name: Download godot-editor-macos artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-editor-macos.zip
+
+      - name: Download godot-template-ios artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-ios.zip
+
+      - name: Download godot-template-macos artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-macos.zip
+
+      - name: Download godot-template-windows-release artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-windows-release.zip
+
+      - name: Download godot-template-windows-debug artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-windows-debug.zip
+
+      - name: Download godot-template-linux-release artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-linux-release.zip
+          
+      - name: Download godot-template-linux-debug artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-linux-debug.zip
+
+      - name: Download godot-template-android-release artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-android-release.zip
+          
+      - name: Download godot-template-android-debug artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-android-debug.zip
+
+      - name: Download godot-template-android-source artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-android-source.zip
+
+      - name: Download godot-template-web-release artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-web-release.zip
+          
+      - name: Download godot-template-web-debug artifact
+        uses: actions/download-artifact@v2
+        with:
+          name: godot-template-web-debug.zip
+
+      - name: Upload artifacts to S3
+        shell: bash
+        if: env.AWS_ACCESS_KEY_ID != null
+        run: |
+          BRANCH=${GITHUB_REF#refs/heads/}
+          echo "branch: $BRANCH"
+          mv godot.windows.opt.tools.64.exe godot-$BRANCH-$GODOT_TAG.exe
+          mv godot.x11.opt.tools.64 godot-$BRANCH-$GODOT_TAG
+          zip godot-editor-windows.zip godot-$BRANCH-$GODOT_TAG.exe
+          zip godot-editor-linux.zip godot-$BRANCH-$GODOT_TAG
+          aws s3 cp godot-editor-windows.zip s3://spine-godot/$BRANCH/$GODOT_TAG/
+          aws s3 cp godot-editor-linux.zip s3://spine-godot/$BRANCH/$GODOT_TAG/
+          aws s3 cp godot-editor-macos.zip s3://spine-godot/$BRANCH/$GODOT_TAG/
+          echo "$GODOT_VERSION" > version.txt
+          ls -lah
+          zip spine-godot-templates-$BRANCH-$GODOT_TAG.zip iphone.zip osx.zip windows_64_debug.exe windows_64_release.exe linux_x11_64_debug linux_x11_64_release webassembly_debug.zip webassembly_release.zip android_release.apk android_debug.apk android_source.zip version.txt
+          aws s3 cp spine-godot-templates-$BRANCH-$GODOT_TAG.zip s3://spine-godot/$BRANCH/$GODOT_TAG/spine-godot-templates-$BRANCH-$GODOT_TAG.tpz
+
+  

+ 13 - 0
.gitignore

@@ -164,4 +164,17 @@ spine-cocos2dx/example-v4/build-macos
 spine-cocos2dx/example/build-ios
 spine-cocos2dx/example/proj.android/app/.cxx
 spine-cocos2dx/example/build-win
+spine-godot/godot
+spine-godot/spine_godot/*.o
+spine-godot/spine_godot/spine-cpp
+spine-godot/spine_godot/__pycache__
+spine-godot/example/.import
+spine-godot/spine_godot/*.obj
+*.bc
+spine-godot/example/.godot
+spine-godot/example-v4/.godot
 spine-cocos2dx/example/build-macos
+spine-godot/logs
+!spine-godot/build
+spine-ts/spine-ts.zip
+*.d

+ 69 - 25
examples/export/runtimes.sh

@@ -85,31 +85,75 @@ cp -f ../mix-and-match/export/mix-and-match-pro.skel "$ROOT/spine-cocos2dx/examp
 cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-cocos2dx/example/Resources/common/"
 cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-cocos2dx/example/Resources/common/"
 
-rm "$ROOT/spine-cocos2dx/example-v4/Resources/common/"*
-
-cp -f ../coin/export/coin-pro.skel "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../coin/export/coin.atlas "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../coin/export/coin.png "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-
-cp -f ../goblins/export/goblins-pro.json "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../goblins/export/goblins.atlas "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../goblins/export/goblins.png "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-
-cp -f ../raptor/export/raptor-pro.json "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../raptor/export/raptor.atlas "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../raptor/export/raptor.png "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-
-cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../spineboy/export/spineboy.atlas "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../spineboy/export/spineboy.png "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-
-cp -f ../tank/export/tank-pro.skel "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../tank/export/tank.atlas "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../tank/export/tank.png "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-
-cp -f ../mix-and-match/export/mix-and-match-pro.skel "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
-cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
+echo "spine-godot"
+rm -f "$ROOT"/spine-godot/example/assets/spineboy/*.atlas
+rm -f "$ROOT"/spine-godot/example/assets/spineboy/*.png
+rm -f "$ROOT"/spine-godot/example/assets/spineboy/*.json
+rm -f "$ROOT"/spine-godot/example/assets/spineboy/*.skel
+rm -f "$ROOT"/spine-godot/example/assets/raptor/*.atlas
+rm -f "$ROOT"/spine-godot/example/assets/raptor/*.png
+rm -f "$ROOT"/spine-godot/example/assets/raptor/*.skel
+rm -f "$ROOT"/spine-godot/example/assets/mix-and-match/*.atlas
+rm -f "$ROOT"/spine-godot/example/assets/mix-and-match/*.png
+rm -f "$ROOT"/spine-godot/example/assets/mix-and-match/*.json
+rm -f "$ROOT"/spine-godot/example/assets/mix-and-match/*.skel
+rm -f "$ROOT"/spine-godot/example/assets/raggedyspineboy/*.atlas
+rm -f "$ROOT"/spine-godot/example/assets/raggedyspineboy/*.png
+rm -f "$ROOT"/spine-godot/example/assets/raggedyspineboy/*.json
+
+
+cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-godot/example/assets/spineboy/"
+cp -f ../spineboy/export/spineboy-pro.skel "$ROOT/spine-godot/example/assets/spineboy/"
+cp -f ../spineboy/export/spineboy.atlas "$ROOT/spine-godot/example/assets/spineboy/"
+cp -f ../spineboy/export/spineboy.png "$ROOT/spine-godot/example/assets/spineboy/"
+
+cp -f ../mix-and-match/export/mix-and-match-pro.json "$ROOT/spine-godot/example/assets/mix-and-match/"
+cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-godot/example/assets/mix-and-match/"
+cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-godot/example/assets/mix-and-match/"
+
+cp -f ../raptor/export/raptor-pro.skel "$ROOT/spine-godot/example/assets/raptor/"
+cp -f ../raptor/export/raptor.atlas "$ROOT/spine-godot/example/assets/raptor/"
+cp -f ../raptor/export/raptor.png "$ROOT/spine-godot/example/assets/raptor/"
+cp -f ../raptor/manual-maps/raptor-normals.png "$ROOT/spine-godot/example/assets/raptor/n_raptor.png"
+cp -f ../raptor/manual-maps/light-sprite.png "$ROOT/spine-godot/example/assets/raptor/light-sprite.png"
+
+cp -f ../../spine-unity/Assets/Spine\ Examples/Spine\ Skeletons/Raggedy\ Spineboy/raggedy\ spineboy.json "$ROOT/spine-godot/example/assets/raggedyspineboy/"
+cp -f ../../spine-unity/Assets/Spine\ Examples/Spine\ Skeletons/Raggedy\ Spineboy/Raggedy\ Spineboy.atlas.txt "$ROOT/spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.atlas"
+cp -f ../../spine-unity/Assets/Spine\ Examples/Spine\ Skeletons/Raggedy\ Spineboy/Raggedy\ Spineboy.png "$ROOT/spine-godot/example/assets/raggedyspineboy/"
+
+rm -f "$ROOT"/spine-godot/example-v4/assets/spineboy/*.atlas
+rm -f "$ROOT"/spine-godot/example-v4/assets/spineboy/*.png
+rm -f "$ROOT"/spine-godot/example-v4/assets/spineboy/*.json
+rm -f "$ROOT"/spine-godot/example-v4/assets/spineboy/*.skel
+rm -f "$ROOT"/spine-godot/example-v4/assets/raptor/*.atlas
+rm -f "$ROOT"/spine-godot/example-v4/assets/raptor/*.png
+rm -f "$ROOT"/spine-godot/example-v4/assets/raptor/*.skel
+rm -f "$ROOT"/spine-godot/example-v4/assets/mix-and-match/*.atlas
+rm -f "$ROOT"/spine-godot/example-v4/assets/mix-and-match/*.png
+rm -f "$ROOT"/spine-godot/example-v4/assets/mix-and-match/*.json
+rm -f "$ROOT"/spine-godot/example-v4/assets/mix-and-match/*.skel
+rm -f "$ROOT"/spine-godot/example-v4/assets/raggedyspineboy/*.atlas
+rm -f "$ROOT"/spine-godot/example-v4/assets/raggedyspineboy/*.png
+rm -f "$ROOT"/spine-godot/example-v4/assets/raggedyspineboy/*.json
+
+cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-godot/example-v4/assets/spineboy/"
+cp -f ../spineboy/export/spineboy-pro.skel "$ROOT/spine-godot/example-v4/assets/spineboy/"
+cp -f ../spineboy/export/spineboy.atlas "$ROOT/spine-godot/example-v4/assets/spineboy/"
+cp -f ../spineboy/export/spineboy.png "$ROOT/spine-godot/example-v4/assets/spineboy/"
+
+cp -f ../mix-and-match/export/mix-and-match-pro.json "$ROOT/spine-godot/example-v4/assets/mix-and-match/"
+cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-godot/example-v4/assets/mix-and-match/"
+cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-godot/example-v4/assets/mix-and-match/"
+
+cp -f ../raptor/export/raptor-pro.skel "$ROOT/spine-godot/example-v4/assets/raptor/"
+cp -f ../raptor/export/raptor.atlas "$ROOT/spine-godot/example-v4/assets/raptor/"
+cp -f ../raptor/export/raptor.png "$ROOT/spine-godot/example-v4/assets/raptor/"
+cp -f ../raptor/manual-maps/raptor-normals.png "$ROOT/spine-godot/example-v4/assets/raptor/n_raptor.png"
+cp -f ../raptor/manual-maps/light-sprite.png "$ROOT/spine-godot/example-v4/assets/raptor/light-sprite.png"
+
+cp -f ../../spine-unity/Assets/Spine\ Examples/Spine\ Skeletons/Raggedy\ Spineboy/raggedy\ spineboy.json "$ROOT/spine-godot/example-v4/assets/raggedyspineboy/"
+cp -f ../../spine-unity/Assets/Spine\ Examples/Spine\ Skeletons/Raggedy\ Spineboy/Raggedy\ Spineboy.atlas.txt "$ROOT/spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.atlas"
+cp -f ../../spine-unity/Assets/Spine\ Examples/Spine\ Skeletons/Raggedy\ Spineboy/Raggedy\ Spineboy.png "$ROOT/spine-godot/example-v4/assets/raggedyspineboy/"
 
 echo "spine-sfml-c"
 rm "$ROOT/spine-sfml/c/data/"*

BIN
examples/raptor/manual-maps/light-sprite.png


+ 3 - 1
formatters/build.gradle

@@ -25,7 +25,9 @@ spotless {
                'spine-sfml/**/*.cpp',
                'spine-sfml/**/*.h',
                'spine-ue4/**/*.cpp',
-               'spine-ue4/**/*.h'
+               'spine-ue4/**/*.h',
+               'spine-godot/spine_godot/*.cpp',
+               'spine-godot/spine_godot/*.h'
         clangFormat("13.0.1").pathToExe("$System.env.CLANGFORMAT").style('file')
     }
 

+ 3 - 0
spine-cpp/spine-cpp/include/spine/AnimationStateData.h

@@ -67,6 +67,9 @@ namespace spine {
 		/// or the DefaultMix if no mix duration has been set.
 		float getMix(Animation *from, Animation *to);
 
+		/// Removes all mixes and sets the default mix to 0.
+		void clear();
+
 	private:
 		class AnimationPair : public SpineObject {
 		public:

+ 2 - 0
spine-cpp/spine-cpp/include/spine/MeshAttachment.h

@@ -53,6 +53,8 @@ namespace spine {
 
 		virtual ~MeshAttachment();
 
+		using VertexAttachment::computeWorldVertices;
+
 		virtual void computeWorldVertices(Slot &slot, size_t start, size_t count, float *worldVertices, size_t offset,
 		size_t stride = 2);
 

+ 5 - 0
spine-cpp/spine-cpp/src/spine/AnimationStateData.cpp

@@ -73,6 +73,11 @@ void AnimationStateData::setDefaultMix(float inValue) {
 	_defaultMix = inValue;
 }
 
+void AnimationStateData::clear() {
+	_defaultMix = 0;
+	_animationToMixTime.clear();
+}
+
 AnimationStateData::AnimationPair::AnimationPair(Animation *a1, Animation *a2) : _a1(a1), _a2(a2) {
 }
 

+ 29 - 17
spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp

@@ -453,17 +453,29 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
 		skin = new (__FILE__, __LINE__) Skin("default");
 	} else {
 		skin = new (__FILE__, __LINE__) Skin(readStringRef(input, skeletonData));
-		for (int i = 0, n = readVarint(input, true); i < n; i++)
-			skin->getBones().add(skeletonData->_bones[readVarint(input, true)]);
+		for (int i = 0, n = readVarint(input, true); i < n; i++) {
+			int boneIndex = readVarint(input, true);
+			if (boneIndex >= (int) skeletonData->_bones.size()) return NULL;
+			skin->getBones().add(skeletonData->_bones[boneIndex]);
+		}
 
-		for (int i = 0, n = readVarint(input, true); i < n; i++)
-			skin->getConstraints().add(skeletonData->_ikConstraints[readVarint(input, true)]);
+		for (int i = 0, n = readVarint(input, true); i < n; i++) {
+			int ikIndex = readVarint(input, true);
+			if (ikIndex >= (int) skeletonData->_ikConstraints.size()) return NULL;
+			skin->getConstraints().add(skeletonData->_ikConstraints[ikIndex]);
+		}
 
-		for (int i = 0, n = readVarint(input, true); i < n; i++)
-			skin->getConstraints().add(skeletonData->_transformConstraints[readVarint(input, true)]);
+		for (int i = 0, n = readVarint(input, true); i < n; i++) {
+			int transformIndex = readVarint(input, true);
+			if (transformIndex >= (int) skeletonData->_transformConstraints.size()) return NULL;
+			skin->getConstraints().add(skeletonData->_transformConstraints[transformIndex]);
+		}
 
-		for (int i = 0, n = readVarint(input, true); i < n; i++)
-			skin->getConstraints().add(skeletonData->_pathConstraints[readVarint(input, true)]);
+		for (int i = 0, n = readVarint(input, true); i < n; i++) {
+			int pathIndex = readVarint(input, true);
+			if (pathIndex >= (int) skeletonData->_pathConstraints.size()) return NULL;
+			skin->getConstraints().add(skeletonData->_pathConstraints[pathIndex]);
+		}
 		slotCount = readVarint(input, true);
 	}
 
@@ -476,7 +488,7 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
 				skin->setAttachment(slotIndex, String(name), attachment);
 			else {
 				delete skin;
-				return nullptr;
+				return NULL;
 			}
 		}
 	}
@@ -515,7 +527,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			RegionAttachment *region = _attachmentLoader->newRegionAttachment(*skin, String(name), String(path), sequence);
 			if (!region) {
 				setError("Error reading attachment: ", name.buffer());
-				return nullptr;
+				return NULL;
 			}
 			region->_path = path;
 			region->_rotation = rotation;
@@ -536,7 +548,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			BoundingBoxAttachment *box = _attachmentLoader->newBoundingBoxAttachment(*skin, String(name));
 			if (!box) {
 				setError("Error reading attachment: ", name.buffer());
-				return nullptr;
+				return NULL;
 			}
 			readVertices(input, box->getVertices(), box->getBones(), vertexCount);
 			box->setWorldVerticesLength(vertexCount << 1);
@@ -577,7 +589,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path), sequence);
 			if (!mesh) {
 				setError("Error reading attachment: ", name.buffer());
-				return nullptr;
+				return NULL;
 			}
 			mesh->_path = path;
 			mesh->_color.set(color);
@@ -616,7 +628,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path), sequence);
 			if (!mesh) {
 				setError("Error reading attachment: ", name.buffer());
-				return nullptr;
+				return NULL;
 			}
 			mesh->_path = path;
 			mesh->_color.set(color);
@@ -635,7 +647,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			PathAttachment *path = _attachmentLoader->newPathAttachment(*skin, String(name));
 			if (!path) {
 				setError("Error reading attachment: ", name.buffer());
-				return nullptr;
+				return NULL;
 			}
 			path->_closed = readBoolean(input);
 			path->_constantSpeed = readBoolean(input);
@@ -657,7 +669,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			PointAttachment *point = _attachmentLoader->newPointAttachment(*skin, String(name));
 			if (!point) {
 				setError("Error reading attachment: ", name.buffer());
-				return nullptr;
+				return NULL;
 			}
 			point->_rotation = readFloat(input);
 			point->_x = readFloat(input) * _scale;
@@ -675,7 +687,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			ClippingAttachment *clip = _attachmentLoader->newClippingAttachment(*skin, name);
 			if (!clip) {
 				setError("Error reading attachment: ", name.buffer());
-				return nullptr;
+				return NULL;
 			}
 			readVertices(input, clip->getVertices(), clip->getBones(), vertexCount);
 			clip->setWorldVerticesLength(vertexCount << 1);
@@ -687,7 +699,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			return clip;
 		}
 	}
-	return nullptr;
+	return NULL;
 }
 
 void SkeletonBinary::readVertices(DataInput *input, Vector<float> &vertices, Vector<size_t> &bones, int vertexCount) {

+ 85 - 0
spine-godot/README.md

@@ -0,0 +1,85 @@
+# spine-godot
+
+The spine-godot runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Godot](https://godotengine.org/). spine-godot is based on [spine-cpp](../spine-cpp).
+
+# See the [spine-godot documentation](http://esotericsoftware.com/spine-godot]) for in-depth information.
+
+## Licensing
+
+You are welcome to evaluate the Spine Runtimes and the examples we provide in this repository free of charge.
+
+You can integrate the Spine Runtimes into your software free of charge, but users of your software must have their own [Spine license](https://esotericsoftware.com/spine-purchase). Please make your users aware of this requirement! This option is often chosen by those making development tools, such as an SDK, game toolkit, or software library.
+
+In order to distribute your software containing the Spine Runtimes to others that don't have a Spine license, you need a [Spine license](https://esotericsoftware.com/spine-purchase) at the time of integration. Then you can distribute your software containing the Spine Runtimes however you like, provided others don't modify it or use it to create new software. If others want to do that, they'll need their own Spine license.
+
+For the official legal terms governing the Spine Runtimes, please read the [Spine Runtimes License Agreement](http://esotericsoftware.com/spine-runtimes-license) and Section 2 of the [Spine Editor License Agreement](http://esotericsoftware.com/spine-editor-license#s2).
+
+## Spine version
+
+spine-godot works with data exported from Spine 4.2.xx.
+
+spine-godot supports all Spine features, except two-color tinting and the screen blend mode.
+
+## Setup
+
+spine-godot works with the latest stable Godot 3.4 release. It requires compilation of Godot, as spine-godot is implemented as a module.
+
+> *NOTE:* spine-godot also compiles and works against Godot 4.x. However, we currently can not guarantee stability, as Godot 4.x is still heavily in flux.
+
+### Pre-built Godot editor and export template binaries
+
+We provide prebuilt Godot editor and export template binaries for Godot 3.4.4-stable:
+
+* [Godot Editor Windows](https://spine-godot.s3.eu-central-1.amazonaws.com/4.2-beta/3.4.4-stable/godot-editor-windows.zip)
+* [Godot Editor Linux](https://spine-godot.s3.eu-central-1.amazonaws.com/4.2-beta/3.4.4-stable/godot-editor-linux.zip)
+* [Godot Editor macOS](https://spine-godot.s3.eu-central-1.amazonaws.com/4.2-beta/3.4.4-stable/godot-editor-macos.zip)
+* [Godot export templates for Windows, Linux, macOS, Web, Android, iOS](https://spine-godot.s3.eu-central-1.amazonaws.com/4.2-beta/3.4.4-stable/spine-godot-templates-4.2-beta-3.4.4-stable.tpz)
+
+### Building the Godot editor and export templates locally
+
+If you want to build the Godot editor and export templates yourself, either because you want to add custom engine modules or for engine development, you can use the shell scripts in the `spine-godot/build` folder. 
+
+> *NOTE:* Make sure you have all build dependencies installed before attempting this, as per the [official instructions by Godot](https://docs.godotengine.org/en/stable/development/compiling/index.html).
+
+To build a Godot editor binary, run the following in a Bash shell (use Git Bash on Windows):
+
+```
+cd spine-godot
+./build/setup.sh 3.4.4-stable false
+./build/build.sh release_debug
+```
+
+The first argument to `setup.sh` is the Godot repository branch or commit hash you want to build the Godot editor from. The second argument specifies whether you want to compile the editor for development, which will include support for Live++ on Windows, and disable many modules so compilation is faster.
+
+The first argument to `build.sh` specifies the optimization level of the resulting binary. Supported values are `debug`, which allows full debugging but may be slow due to missing optimizations, and `release_debug`, which is generally used for release builds of the Godot editor.
+
+The resulting Godot editor binary can then be found in `spine-godot/godot/bin`.
+
+To build the export template for a specific platform, run the following in a Bash shell (use Git Bash on Windows):
+
+```
+cd spine-godot
+./build/setup.sh 3.4.4-stable false
+./build/build-templates.sh windows
+```
+
+The first argument to `setup.sh` is the Godot repository branch or commit hash you want to build the Godot editor from. The second argument must be `false`.
+
+The first argument to `built-templates.sh` is the platform to compile the template for. Valid values are `windows`, `linux`, `macos`, `web`, `android`, and `ios`. Note that macOS and iOS export templates can only be build on a machine running macOS. See the [official instructions by Godot](https://docs.godotengine.org/en/stable/development/compiling/index.html).
+
+The resulting Godot export template binary can then be found in `spine-godot/godot/bin`.
+
+### Building the Godot editor and export templates via GitHub Actions
+This repository contains a GitHub workflow in `.github/workflows/spine-godot.yml` that allows building all Godot editor and export template binaries through GitHub actions. This may be simpler than compiling these artifacts locally. To use the GitHub workflow:
+
+1. Clone this repository
+2. Enable GitHub workflows on the cloned repository
+3. Manually trigger the `spine-godot` workflow.
+
+The resulting binaries will be attached as artifacts to a sucessful workflow run.
+
+## Example
+Sample projects for both Godot 3.4.x and Godot 4.x are provided in the `example/` and `example-v4/` folders respectively. They illustrate all spine-godot functionality and can be opened and exported with the pre-built or custom build Godot editor and export template binaries.
+
+
+

+ 125 - 0
spine-godot/build/build-templates.sh

@@ -0,0 +1,125 @@
+#!/bin/bash
+set -e
+
+dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
+pushd $dir > /dev/null
+
+if [ ! "$#" -eq 1 ]; then
+	echo "Usage: ./build-templates.sh <platform>"
+	echo
+	echo "e.g.:"
+	echo "       ./build-templates.sh windows"
+	echo "       ./build-templates.sh linux"
+	echo "       ./build-templates.sh macos"
+	echo "       ./build-templates.sh ios"
+	echo "       ./build-templates.sh android"
+	echo "       ./build-templates.sh web"
+	echo	
+	exit 1
+fi
+
+if [ ! -d ../godot ]; then
+	echo "No Godot clone found. Run ./setup.sh <Godot branch or tag> <dev> first."
+	exit 1
+fi
+
+platform=${1%/}
+
+cpus=2
+if [ "$OSTYPE" = "msys" ]; then
+	cpus=$NUMBER_OF_PROCESSORS
+elif [[ "$OSTYPE" = "darwin"* ]]; then
+	cpus=$(sysctl -n hw.logicalcpu)
+else
+	cpus=$(grep -c ^processor /proc/cpuinfo)
+fi
+
+pushd ../godot
+if [ "$platform" = "windows" ]; then
+	# --- Windows ---
+	#generates windows_64_debug.exe and windows_64_release.exe
+	scons platform=windows tools=no target=release custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=windows tools=no target=release_debug custom_modules="../spine_godot" --jobs=$cpus
+	cp bin/godot.windows.opt.64.exe bin/windows_64_release.exe
+	cp bin/godot.windows.opt.debug.64.exe bin/windows_64_debug.exe
+
+elif [ "$platform" = "macos" ]; then
+	# --- macOS ---
+	# generates osx.zip
+
+	scons platform=osx tools=no target=release arch=x86_64 custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=osx tools=no target=release_debug arch=x86_64 custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=osx tools=no target=release arch=arm64 custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=osx tools=no target=release_debug arch=arm64 custom_modules="../spine_godot" --jobs=$cpus
+	lipo -create bin/godot.osx.opt.x86_64 bin/godot.osx.opt.arm64 -output bin/godot.osx.opt.universal
+	lipo -create bin/godot.osx.opt.debug.x86_64 bin/godot.osx.opt.debug.arm64 -output bin/godot.osx.opt.debug.universal
+	strip -S -x bin/godot.osx.opt.universal
+
+	pushd bin
+	cp -r ../misc/dist/osx_template.app .
+	mkdir -p osx_template.app/Contents/MacOS
+	cp godot.osx.opt.universal osx_template.app/Contents/MacOS/godot_osx_release.64
+	cp godot.osx.opt.debug.universal osx_template.app/Contents/MacOS/godot_osx_debug.64
+	chmod +x osx_template.app/Contents/MacOS/godot_osx*		
+	rm -rf osx.zip
+	zip -q -9 -r osx.zip osx_template.app
+	popd
+elif [ "$platform" = "ios" ]; then
+	# --- iOS --
+	# generates iphone.zip
+
+	scons p=iphone tools=no target=release arch=arm64 custom_modules="../spine_godot" --jobs=$cpus
+	scons p=iphone tools=no target=release_debug arch=arm64 custom_modules="../spine_godot" --jobs=$cpus
+	scons p=iphone tools=no target=release arch=arm64 ios_simulator=yes custom_modules="../spine_godot" --jobs=$cpus
+	scons p=iphone tools=no target=release arch=x86_64 ios_simulator=yes custom_modules="../spine_godot" --jobs=$cpus
+	scons p=iphone tools=no target=release_debug arch=arm64 ios_simulator=yes custom_modules="../spine_godot" --jobs=$cpus
+	scons p=iphone tools=no target=release_debug arch=x86_64 ios_simulator=yes custom_modules="../spine_godot" --jobs=$cpus
+	lipo -create bin/libgodot.iphone.opt.arm64.simulator.a bin/libgodot.iphone.opt.x86_64.simulator.a -output bin/libgodot.iphone.opt.simulator.a
+	lipo -create bin/libgodot.iphone.opt.debug.arm64.simulator.a bin/libgodot.iphone.opt.debug.x86_64.simulator.a -output bin/libgodot.iphone.opt.debug.simulator.a
+	strip -S -x bin/libgodot.iphone.opt.arm64.a
+	strip -S -x bin/libgodot.iphone.opt.simulator.a		
+
+	pushd bin
+	cp -r ../misc/dist/ios_xcode .		
+	cp libgodot.iphone.opt.arm64.a ios_xcode/libgodot.iphone.release.xcframework/ios-arm64/libgodot.a
+	cp libgodot.iphone.opt.simulator.a ios_xcode/libgodot.iphone.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a	
+	cp libgodot.iphone.opt.debug.arm64.a ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64/libgodot.a
+	cp libgodot.iphone.opt.debug.simulator.a ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a	
+	rm -rf iphone.zip
+	pushd ios_xcode
+	zip -q -9 -r ../iphone.zip *
+	popd
+	popd	
+elif [ "$platform" = "web" ]; then
+	# --- WEB ---
+	# generates webassembly_debug.zip, webassembly_release.zip
+	scons platform=javascript tools=no target=release custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=javascript tools=no target=release_debug custom_modules="../spine_godot" --jobs=$cpus
+	mv bin/godot.javascript.opt.zip bin/webassembly_release.zip
+	mv bin/godot.javascript.opt.debug.zip bin/webassembly_debug.zip
+elif [ "$platform" = "android" ]; then
+	# --- ANROID ---
+	# generates android_release.apk, android_debug.apk, android_source.zip
+	scons platform=android target=release android_arch=armv7 custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=android target=release_debug android_arch=armv7 custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=android target=release android_arch=arm64v8 custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=android target=release_debug android_arch=arm64v8 custom_modules="../spine_godot" --jobs=$cpus
+
+	pushd platform/android/java
+		chmod a+x gradlew
+		./gradlew generateGodotTemplates
+	popd
+elif [ "$platform" = "linux" ]; then
+	# --- Linix ---
+	# generates linux_x11_64_release, linux_x11_64_debug
+	scons platform=x11 tools=no target=release bits=64 custom_modules="../spine_godot" --jobs=$cpus
+	scons platform=x11 tools=no target=release_debug bits=64 custom_modules="../spine_godot" --jobs=$cpus
+	strip bin/godot.x11.opt.64
+	strip bin/godot.x11.opt.debug.64
+	cp bin/godot.x11.opt.64 bin/linux_x11_64_release
+	cp bin/godot.x11.opt.debug.64 bin/linux_x11_64_debug
+else
+	echo "Unknown platform: $platform"
+	exit 1
+fi
+popd

+ 70 - 0
spine-godot/build/build.sh

@@ -0,0 +1,70 @@
+#!/bin/bash
+set -e
+
+dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
+pushd $dir > /dev/null
+
+if [ ! "$#" -eq 1 ]; then
+	echo "Usage: ./build.sh <target>"
+	echo
+	echo "e.g.:"
+	echo "       ./build.sh release_debug"
+	echo "       ./build.sh debug"
+	echo	
+	exit 1
+fi
+
+if [ ! -d ../godot ]; then
+	echo "No Godot clone found. Run ./setup.sh <Godot branch or tag> <dev> first."
+	exit 1
+fi
+
+target="target=${1%/}"
+dev="false"
+if [ -f "../godot/custom.py" ]; then
+	dev="true"
+fi
+
+cpus=2
+if [ "$OSTYPE" = "msys" ]; then
+	cpus=$NUMBER_OF_PROCESSORS
+elif [[ "$OSTYPE" = "darwin"* ]]; then
+	cpus=$(sysctl -n hw.logicalcpu)
+else
+	cpus=$(grep -c ^processor /proc/cpuinfo)
+fi
+
+echo "CPUS: $cpus"
+
+pushd ../godot
+if [ `uname` == 'Darwin' ] && [ $dev = "false" ]; then	
+	scons $target arch=x86_64 compiledb=yes custom_modules="../spine_godot" --jobs=$cpus
+	scons $target arch=arm64 compiledb=yes custom_modules="../spine_godot" --jobs=$cpus
+
+	pushd bin
+	cp -r ../misc/dist/osx_tools.app .
+	mv osx_tools.app Godot.app
+	mkdir -p Godot.app/Contents/MacOS
+	if [ "$target" = "debug" ]; then
+		lipo -create godot.osx.tools.x86_64 godot.osx.tools.arm64 -output godot.osx.tools.universal
+		strip -S -x godot.osx.tools.universal
+		cp godot.osx.tools.universal Godot.app/Contents/MacOS/Godot
+	else
+		lipo -create godot.osx.opt.tools.x86_64 godot.osx.opt.tools.arm64 -output godot.osx.opt.tools.universal
+		strip -S -x godot.osx.opt.tools.universal
+		cp godot.osx.opt.tools.universal Godot.app/Contents/MacOS/Godot
+	fi	
+	chmod +x Godot.app/Contents/MacOS/Godot	
+	popd
+else
+	if [ "$OSTYPE" = "msys" ]; then
+		target="$target vsproj=yes livepp=$LIVEPP"
+	fi
+	scons $target compiledb=yes custom_modules="../spine_godot" --jobs=$cpus	
+	if [ -f "bin/godot.x11.opt.tools.64" ]; then
+		strip bin/godot.x11.opt.tools.64
+	fi
+fi
+popd
+
+popd > /dev/null

+ 33 - 0
spine-godot/build/custom.py

@@ -0,0 +1,33 @@
+# list of disabled modules for faster compilation of the engine
+module_arkit_enabled = "no"
+module_assimp_enabled = "no"
+module_bmp_enabled = "no"
+module_denoise_enabled = "no"
+module_bullet_enabled = "no"
+module_raycast_enabled = "no"
+module_camera_enabled = "no"
+module_csg_enabled = "no"
+module_dds_enabled = "no"
+module_enet_enabled = "no"
+module_etc_enabled = "no"
+module_gdnative_enabled = "no"
+module_gridmap_enabled = "no"
+module_hdr_enabled = "no"
+module_jsonrpc_enabled = "no"
+module_mbedtls_enabled = "no"
+module_mobile_vr_enabled = "no"
+module_opensimplex_enabled = "no"
+module_opus_enabled = "no"
+module_pvr_enabled = "no"
+module_recast_enabled = "no"
+module_squish_enabled = "no"
+module_tga_enabled = "no"
+module_theora_enabled = "no"
+module_tinyexr_enabled = "no"
+module_upnp_enabled = "no"
+module_vhacd_enabled = "no"
+module_webm_enabled = "no"
+module_webp_enabled = "no"
+module_webrtc_enabled = "no"
+module_websocket_enabled = "no"
+module_xatlas_unwrap_enabled = "no"

+ 124 - 0
spine-godot/build/livepp-v4.patch

@@ -0,0 +1,124 @@
+diff --git a/methods.py b/methods.py
+index fe84641e9d0625b4f0c4d90a65839337d6120ff8..51ef8550d3a9def0a2ff88a2fde4fa096c085de9 100644
+--- a/methods.py
++++ b/methods.py
+@@ -734,6 +734,7 @@ def generate_vs_project(env, num_jobs):
+                     f"target={configuration_getter}",
+                     "progress=no",
+                     "tools=!tools!",
++                    "livepp=%s" % env["livepp"],
+                     "-j%s" % num_jobs,
+                 ]
+ 
+diff --git a/platform/windows/detect.py b/platform/windows/detect.py
+index 0b18fb74fb145e4d2e88ee91abe99f8f39312a46..04880a8fa8209c4002b49f964d86227974ce9ca8 100644
+--- a/platform/windows/detect.py
++++ b/platform/windows/detect.py
+@@ -44,7 +44,7 @@ def can_build():
+ 
+ 
+ def get_opts():
+-    from SCons.Variables import BoolVariable, EnumVariable
++    from SCons.Variables import BoolVariable, EnumVariable, PathVariable
+ 
+     mingw32 = ""
+     mingw64 = ""
+@@ -73,6 +73,7 @@ def get_opts():
+         BoolVariable("use_thinlto", "Use ThinLTO", False),
+         BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
+         BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
++        PathVariable("livepp", "Path to the Live++ installation", "", PathVariable.PathAccept),
+     ]
+ 
+ 
+@@ -310,6 +311,19 @@ def configure_msvc(env, manual_msvc_config):
+ 
+     env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE)])
+ 
++    # Check if LIVEPP_PATH is set and add #define. Perform
++    # some sanity checks.
++    if env.get("livepp"):
++        if env["target"] == "release_debug" or env["target"] == "debug":
++            print("Found Live++ at %s" % env.get("livepp"))
++            env.AppendUnique(CPPDEFINES=["LIVEPP_PATH=%s" % env.get("livepp")])
++            env.AppendUnique(CPPPATH=[env.get("livepp")])
++            env.AppendUnique(LINKFLAGS=["/FUNCTIONPADMIN"])
++        else:
++            print("Live++ can only be used with targets 'debug' and 'release_debug'")
++    else:
++        print("No Live++ specified.")
++
+ 
+ def configure_mingw(env):
+     # Workaround for MinGW. See:
+diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp
+index 8de3ef294a99c6f02f6f1380e331e4bb598864ce..8e4c15dd66d1b640a352ed826b25b23917f72cc4 100644
+--- a/platform/windows/godot_windows.cpp
++++ b/platform/windows/godot_windows.cpp
+@@ -34,6 +34,11 @@
+ #include <locale.h>
+ #include <stdio.h>
+ 
++#ifdef LIVEPP_PATH
++#include "API/LPP_API.h"
++HMODULE livePP;
++#endif
++
+ // For export templates, add a section; the exporter will patch it to enclose
+ // the data appended to the executable (bundled PCK)
+ #ifndef TOOLS_ENABLED
+@@ -147,6 +152,16 @@ char *wc_to_utf8(const wchar_t *wc) {
+ }
+ 
+ int widechar_main(int argc, wchar_t **argv) {
++#ifdef LIVEPP_PATH
++#define _MKSTR_L(x) _STR_L(x)
++#define _STR_L(x) L#x
++	livePP = lpp::lppLoadAndRegister(_MKSTR_L(LIVEPP_PATH), "Godot");
++	lpp::lppEnableAllCallingModulesSync(livePP);
++	lpp::lppInstallExceptionHandler(livePP);
++#undef _MKSTR_L
++#undef _STR_L
++#endif
++
+ 	OS_Windows os(nullptr);
+ 
+ 	setlocale(LC_CTYPE, "");
+@@ -179,6 +194,11 @@ int widechar_main(int argc, wchar_t **argv) {
+ 	}
+ 	delete[] argv_utf8;
+ 
++#ifdef LIVEPP_PATH
++	lpp::lppShutdown(livePP);
++	::FreeLibrary(livePP);
++#endif
++
+ 	return os.get_exit_code();
+ }
+ 
+diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
+index 8755bc65dce7e4b88fd509d0cbdbec576356c5f5..50e0d8d0b06bf76d5f4d085d010cf6a683a9e64f 100644
+--- a/platform/windows/os_windows.cpp
++++ b/platform/windows/os_windows.cpp
+@@ -53,6 +53,11 @@
+ #include <regstr.h>
+ #include <shlobj.h>
+ 
++#ifdef LIVEPP_PATH
++#include "API/LPP_API.h"
++extern HMODULE livePP;
++#endif
++
+ extern "C" {
+ __declspec(dllexport) DWORD NvOptimusEnablement = 1;
+ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
+@@ -677,6 +682,9 @@ void OS_Windows::run() {
+ 		if (Main::iteration()) {
+ 			break;
+ 		}
++#ifdef LIVEPP_PATH
++		lpp::lppSyncPoint(livePP);
++#endif
+ 	}
+ 
+ 	main_loop->finalize();

+ 123 - 0
spine-godot/build/livepp.patch

@@ -0,0 +1,123 @@
+diff --git a/methods.py b/methods.py
+index 9b8cb38c0c1c0fd4ba2917815fdfb7efafb4b646..874e10bcc637632db26b4ac062a5359cd44eaa25 100644
+--- a/methods.py
++++ b/methods.py
+@@ -688,6 +688,7 @@ def generate_vs_project(env, num_jobs):
+                 "target=$(Configuration)",
+                 "progress=no",
+                 "tools=!tools!",
++                "livepp=%s" % env["livepp"],
+                 "-j%s" % num_jobs,
+             ]
+ 
+diff --git a/platform/windows/detect.py b/platform/windows/detect.py
+index e4facad816b7584fe38dc760356310e0a3937288..2d9da3df65cd3a0b0882ace984002320ebf6c3fc 100644
+--- a/platform/windows/detect.py
++++ b/platform/windows/detect.py
+@@ -44,7 +44,7 @@ def can_build():
+ 
+ 
+ def get_opts():
+-    from SCons.Variables import BoolVariable, EnumVariable
++    from SCons.Variables import BoolVariable, EnumVariable, PathVariable
+ 
+     mingw32 = ""
+     mingw64 = ""
+@@ -72,6 +72,7 @@ def get_opts():
+         BoolVariable("use_thinlto", "Use ThinLTO", False),
+         BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
+         BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
++        PathVariable("livepp", "Path to the Live++ installation", "", PathVariable.PathAccept),
+     ]
+ 
+ 
+@@ -296,6 +297,18 @@ def configure_msvc(env, manual_msvc_config):
+ 
+     env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE)])
+ 
++    # Check if LIVEPP_PATH is set and add #define. Perform
++    # some sanity checks.
++    if env.get("livepp"):
++        if env["target"] == "release_debug" or env["target"] == "debug":
++            print("Found Live++ at %s" % env.get("livepp"))
++            env.AppendUnique(CPPDEFINES=["LIVEPP_PATH=%s" % env.get("livepp")])
++            env.AppendUnique(CPPPATH=[env.get("livepp")])
++            env.AppendUnique(LINKFLAGS=["/FUNCTIONPADMIN"])
++        else:
++            print("Live++ can only be used with targets 'debug' and 'release_debug'")
++    else:
++        print("No Live++ specified.")
+ 
+ def configure_mingw(env):
+     # Workaround for MinGW. See:
+diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp
+index d7d9e4eace00a696abbb47cb9632f40e183a4ec4..e362320e51c725cd01f292887bd93442752c1c48 100644
+--- a/platform/windows/godot_windows.cpp
++++ b/platform/windows/godot_windows.cpp
+@@ -34,6 +34,11 @@
+ #include <locale.h>
+ #include <stdio.h>
+ 
++#ifdef LIVEPP_PATH
++#include "API/LPP_API.h"
++HMODULE livePP;
++#endif
++
+ // For export templates, add a section; the exporter will patch it to enclose
+ // the data appended to the executable (bundled PCK)
+ #ifndef TOOLS_ENABLED
+@@ -136,6 +141,16 @@ char *wc_to_utf8(const wchar_t *wc) {
+ }
+ 
+ __declspec(dllexport) int widechar_main(int argc, wchar_t **argv) {
++#ifdef LIVEPP_PATH
++#define _MKSTR_L(x) _STR_L(x)
++#define _STR_L(x) L#x
++	livePP = lpp::lppLoadAndRegister(_MKSTR_L(LIVEPP_PATH), "Godot");
++	lpp::lppEnableAllCallingModulesSync(livePP);
++	lpp::lppInstallExceptionHandler(livePP);
++#undef _MKSTR_L
++#undef _STR_L
++#endif
++
+ 	OS_Windows os(NULL);
+ 
+ 	setlocale(LC_CTYPE, "");
+@@ -170,6 +185,11 @@ __declspec(dllexport) int widechar_main(int argc, wchar_t **argv) {
+ 	}
+ 	delete[] argv_utf8;
+ 
++#ifdef LIVEPP_PATH
++	lpp::lppShutdown(livePP);
++	::FreeLibrary(livePP);
++#endif
++
+ 	return os.get_exit_code();
+ };
+ 
+diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
+index 8b28cbf1f23d6574aac41a3676fea64ddf786fc4..0124d4ac9652df9ba682ab8cc18b4008461d74cf 100644
+--- a/platform/windows/os_windows.cpp
++++ b/platform/windows/os_windows.cpp
+@@ -53,6 +53,11 @@
+ #include <regstr.h>
+ #include <shlobj.h>
+ 
++#ifdef LIVEPP_PATH
++#include "API/LPP_API.h"
++extern HMODULE livePP;
++#endif
++
+ static const WORD MAX_CONSOLE_LINES = 1500;
+ 
+ extern "C" {
+@@ -3371,6 +3376,9 @@ void OS_Windows::run() {
+ 		process_events(); // get rid of pending events
+ 		if (Main::iteration())
+ 			break;
++#ifdef LIVEPP_PATH
++		lpp::lppSyncPoint(livePP);
++#endif
+ 	};
+ 
+ 	main_loop->finish();

+ 39 - 0
spine-godot/build/setup.sh

@@ -0,0 +1,39 @@
+#!/bin/bash
+set -e
+
+dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
+pushd $dir > /dev/null
+
+if [ ! "$#" -eq 2 ]; then
+	echo "Usage: ./setup.sh <Godot branch or tag> <dev:true|false>"
+	echo
+	echo "e.g.:"
+	echo "       ./setup.sh 3.4.4-stable true"
+	echo "       ./setup.sh master false"
+	echo		
+	exit 1
+fi
+
+branch=${1%/}
+dev=${2%/}
+
+pushd ..
+rm -rf godot
+git clone --depth 1 https://github.com/godotengine/godot.git -b $branch
+if [ $dev = "true" ]; then
+	cp -r .idea godot
+	cp build/custom.py godot
+	rm -rf example/.import
+	rm -rf example/.godot
+
+	if [ "$OSTYPE" = "msys" ]; then
+		pushd godot
+		git apply ../build/livepp.patch
+		git apply ../build/livepp-v4.patch
+		popd
+	fi
+fi
+cp -r ../spine-cpp/spine-cpp spine_godot
+popd
+
+popd > /dev/null

+ 4 - 0
spine-godot/build/sources.lst

@@ -0,0 +1,4 @@
+deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse

BIN
spine-godot/example-v4/assets/footstep.ogg


+ 16 - 0
spine-godot/example-v4/assets/footstep.ogg.import

@@ -0,0 +1,16 @@
+[remap]
+
+importer="oggvorbisstr"
+type="AudioStreamOGGVorbis"
+uid="uid://can7k84o8svum"
+path="res://.godot/imported/footstep.ogg-789c3f1e3c4e0ca3bebcb13f1160f623.oggvorbisstr"
+
+[deps]
+
+source_file="res://assets/footstep.ogg"
+dest_files=["res://.godot/imported/footstep.ogg-789c3f1e3c4e0ca3bebcb13f1160f623.oggvorbisstr"]
+
+[params]
+
+loop=false
+loop_offset=0

+ 10 - 0
spine-godot/example-v4/assets/mix-and-match/mix-and-match-data.tres

@@ -0,0 +1,10 @@
+[gd_resource type="SpineSkeletonDataResource" load_steps=3 format=2]
+
+[ext_resource path="res://assets/mix-and-match/mix-and-match.atlas" type="SpineAtlasResource" id=1]
+[ext_resource path="res://assets/mix-and-match/mix-and-match-pro.json" type="SpineSkeletonFileResource" id=2]
+
+[resource]
+atlas_res = ExtResource( 1 )
+skeleton_file_res = ExtResource( 2 )
+animations = null
+skins = null

File diff suppressed because it is too large
+ 1285 - 0
spine-godot/example-v4/assets/mix-and-match/mix-and-match-pro.json


+ 14 - 0
spine-godot/example-v4/assets/mix-and-match/mix-and-match-pro.json.import

@@ -0,0 +1,14 @@
+[remap]
+
+importer="spine.json"
+type="SpineSkeletonFileResource"
+uid="uid://bijrb2mt3vodc"
+path="res://.godot/imported/mix-and-match-pro.json-57325a5014e6fd56fc4a86824bc458ea.spjson"
+
+[deps]
+
+source_file="res://assets/mix-and-match/mix-and-match-pro.json"
+dest_files=["res://.godot/imported/mix-and-match-pro.json-57325a5014e6fd56fc4a86824bc458ea.spjson"]
+
+[params]
+

+ 362 - 0
spine-godot/example-v4/assets/mix-and-match/mix-and-match.atlas

@@ -0,0 +1,362 @@
+mix-and-match.png
+	size: 1024, 512
+	filter: Linear, Linear
+	scale: 0.5
+base-head
+	bounds: 587, 2, 95, 73
+boy/arm-front
+	bounds: 558, 271, 36, 115
+boy/backpack
+	bounds: 235, 109, 119, 153
+boy/backpack-pocket
+	bounds: 328, 73, 34, 62
+	rotate: 90
+boy/backpack-strap-front
+	bounds: 665, 79, 38, 88
+boy/backpack-up
+	bounds: 395, 364, 21, 70
+	rotate: 90
+boy/body
+	bounds: 251, 264, 97, 132
+	rotate: 90
+boy/boot-ribbon-front
+	bounds: 648, 131, 9, 11
+boy/collar
+	bounds: 744, 4, 73, 29
+	rotate: 90
+boy/ear
+	bounds: 383, 109, 19, 23
+	rotate: 90
+boy/eye-back-low-eyelid
+	bounds: 739, 284, 17, 6
+	rotate: 90
+boy/eye-back-pupil
+	bounds: 832, 443, 8, 9
+	rotate: 90
+boy/eye-back-up-eyelid
+	bounds: 558, 264, 23, 5
+boy/eye-back-up-eyelid-back
+	bounds: 802, 491, 19, 10
+	rotate: 90
+boy/eye-front-low-eyelid
+	bounds: 386, 363, 22, 7
+	rotate: 90
+boy/eye-front-pupil
+	bounds: 816, 389, 9, 9
+boy/eye-front-up-eyelid
+	bounds: 160, 71, 31, 6
+	rotate: 90
+boy/eye-front-up-eyelid-back
+	bounds: 801, 434, 26, 9
+	rotate: 90
+boy/eye-iris-back
+	bounds: 618, 264, 17, 17
+boy/eye-iris-front
+	bounds: 727, 264, 18, 18
+boy/eye-white-back
+	bounds: 580, 131, 20, 12
+boy/eye-white-front
+	bounds: 510, 130, 27, 13
+boy/eyebrow-back
+	bounds: 751, 88, 20, 11
+	rotate: 90
+boy/eyebrow-front
+	bounds: 483, 130, 25, 11
+boy/hair-back
+	bounds: 494, 388, 122, 81
+	rotate: 90
+boy/hair-bangs
+	bounds: 667, 284, 70, 37
+boy/hair-side
+	bounds: 789, 374, 25, 43
+boy/hand-backfingers
+	bounds: 467, 364, 19, 21
+boy/hand-front-fingers
+	bounds: 488, 364, 19, 21
+boy/hat
+	bounds: 615, 417, 93, 56
+	rotate: 90
+boy/leg-front
+	bounds: 138, 104, 31, 158
+boy/mouth-close
+	bounds: 551, 365, 21, 5
+	rotate: 90
+girl-blue-cape/mouth-close
+	bounds: 551, 365, 21, 5
+	rotate: 90
+girl-spring-dress/mouth-close
+	bounds: 551, 365, 21, 5
+	rotate: 90
+girl/mouth-close
+	bounds: 551, 365, 21, 5
+	rotate: 90
+boy/mouth-smile
+	bounds: 705, 79, 29, 7
+boy/nose
+	bounds: 836, 473, 17, 10
+	rotate: 90
+boy/pompom
+	bounds: 747, 273, 48, 43
+	rotate: 90
+boy/zip
+	bounds: 648, 144, 14, 23
+girl-blue-cape/back-eyebrow
+	bounds: 602, 131, 18, 12
+girl-blue-cape/body-dress
+	bounds: 2, 264, 109, 246
+girl-blue-cape/body-ribbon
+	bounds: 615, 283, 50, 38
+girl-blue-cape/cape-back
+	bounds: 2, 69, 134, 193
+girl-blue-cape/cape-back-up
+	bounds: 386, 387, 123, 106
+	rotate: 90
+girl-blue-cape/cape-ribbon
+	bounds: 675, 264, 50, 18
+girl-blue-cape/cape-shoulder-back
+	bounds: 751, 110, 49, 59
+girl-blue-cape/cape-shoulder-front
+	bounds: 113, 264, 62, 76
+	rotate: 90
+girl-blue-cape/cape-up-front
+	bounds: 399, 264, 98, 117
+	rotate: 90
+girl-blue-cape/ear
+	bounds: 775, 2, 19, 23
+girl-spring-dress/ear
+	bounds: 775, 2, 19, 23
+girl/ear
+	bounds: 775, 2, 19, 23
+girl-blue-cape/eye-back-low-eyelid
+	bounds: 802, 463, 17, 6
+girl-spring-dress/eye-back-low-eyelid
+	bounds: 802, 463, 17, 6
+girl/eye-back-low-eyelid
+	bounds: 802, 463, 17, 6
+girl-blue-cape/eye-back-pupil
+	bounds: 816, 367, 8, 9
+girl-spring-dress/eye-back-pupil
+	bounds: 816, 367, 8, 9
+girl/eye-back-pupil
+	bounds: 816, 367, 8, 9
+girl-blue-cape/eye-back-up-eyelid
+	bounds: 554, 131, 24, 12
+girl-spring-dress/eye-back-up-eyelid
+	bounds: 554, 131, 24, 12
+girl/eye-back-up-eyelid
+	bounds: 554, 131, 24, 12
+girl-blue-cape/eye-back-up-eyelid-back
+	bounds: 832, 453, 17, 11
+	rotate: 90
+girl-spring-dress/eye-back-up-eyelid-back
+	bounds: 832, 453, 17, 11
+	rotate: 90
+girl/eye-back-up-eyelid-back
+	bounds: 832, 453, 17, 11
+	rotate: 90
+girl-blue-cape/eye-front-low-eyelid
+	bounds: 739, 303, 18, 6
+	rotate: 90
+girl-spring-dress/eye-front-low-eyelid
+	bounds: 739, 303, 18, 6
+	rotate: 90
+girl/eye-front-low-eyelid
+	bounds: 739, 303, 18, 6
+	rotate: 90
+girl-blue-cape/eye-front-pupil
+	bounds: 816, 378, 9, 9
+girl-spring-dress/eye-front-pupil
+	bounds: 816, 378, 9, 9
+girl/eye-front-pupil
+	bounds: 816, 378, 9, 9
+girl-blue-cape/eye-front-up-eyelid
+	bounds: 392, 77, 30, 14
+	rotate: 90
+girl-spring-dress/eye-front-up-eyelid
+	bounds: 392, 77, 30, 14
+	rotate: 90
+girl/eye-front-up-eyelid
+	bounds: 392, 77, 30, 14
+	rotate: 90
+girl-blue-cape/eye-front-up-eyelid-back
+	bounds: 455, 130, 26, 11
+girl-spring-dress/eye-front-up-eyelid-back
+	bounds: 455, 130, 26, 11
+girl/eye-front-up-eyelid-back
+	bounds: 455, 130, 26, 11
+girl-blue-cape/eye-iris-back
+	bounds: 637, 264, 17, 17
+girl-blue-cape/eye-iris-front
+	bounds: 802, 471, 18, 18
+girl-blue-cape/eye-white-back
+	bounds: 596, 264, 20, 16
+girl-spring-dress/eye-white-back
+	bounds: 596, 264, 20, 16
+girl-blue-cape/eye-white-front
+	bounds: 796, 5, 20, 16
+	rotate: 90
+girl-spring-dress/eye-white-front
+	bounds: 796, 5, 20, 16
+	rotate: 90
+girl/eye-white-front
+	bounds: 796, 5, 20, 16
+	rotate: 90
+girl-blue-cape/front-eyebrow
+	bounds: 608, 149, 18, 12
+	rotate: 90
+girl-blue-cape/hair-back
+	bounds: 508, 145, 117, 98
+	rotate: 90
+girl-blue-cape/hair-bangs
+	bounds: 673, 419, 91, 40
+	rotate: 90
+girl-blue-cape/hair-head-side-back
+	bounds: 196, 331, 30, 52
+	rotate: 90
+girl-blue-cape/hair-head-side-front
+	bounds: 738, 323, 41, 42
+girl-blue-cape/hair-side
+	bounds: 473, 3, 36, 71
+girl-blue-cape/hand-front-fingers
+	bounds: 509, 365, 19, 21
+girl-spring-dress/hand-front-fingers
+	bounds: 509, 365, 19, 21
+girl-blue-cape/leg-front
+	bounds: 168, 72, 30, 158
+	rotate: 90
+girl-blue-cape/mouth-smile
+	bounds: 736, 79, 29, 7
+girl-spring-dress/mouth-smile
+	bounds: 736, 79, 29, 7
+girl/mouth-smile
+	bounds: 736, 79, 29, 7
+girl-blue-cape/nose
+	bounds: 747, 264, 11, 7
+girl-spring-dress/nose
+	bounds: 747, 264, 11, 7
+girl/nose
+	bounds: 747, 264, 11, 7
+girl-blue-cape/sleeve-back
+	bounds: 767, 79, 42, 29
+girl-blue-cape/sleeve-front
+	bounds: 408, 76, 52, 119
+	rotate: 90
+girl-spring-dress/arm-front
+	bounds: 596, 282, 17, 111
+girl-spring-dress/back-eyebrow
+	bounds: 801, 420, 18, 12
+girl-spring-dress/body-up
+	bounds: 179, 4, 64, 66
+girl-spring-dress/cloak-down
+	bounds: 775, 27, 50, 50
+girl-spring-dress/cloak-up
+	bounds: 360, 7, 64, 58
+	rotate: 90
+girl-spring-dress/eye-iris-back
+	bounds: 656, 264, 17, 17
+girl-spring-dress/eye-iris-front
+	bounds: 814, 492, 18, 18
+girl-spring-dress/front-eyebrow
+	bounds: 822, 472, 18, 12
+	rotate: 90
+girl-spring-dress/hair-back
+	bounds: 196, 363, 147, 93
+	rotate: 90
+girl-spring-dress/hair-bangs
+	bounds: 696, 326, 91, 40
+	rotate: 90
+girl-spring-dress/hair-head-side-back
+	bounds: 529, 76, 30, 52
+girl-spring-dress/hair-head-side-front
+	bounds: 781, 323, 41, 42
+girl-spring-dress/hair-side
+	bounds: 511, 3, 36, 71
+girl-spring-dress/leg-front
+	bounds: 171, 104, 30, 158
+girl-spring-dress/neck
+	bounds: 138, 70, 20, 32
+girl-spring-dress/shoulder-ribbon
+	bounds: 622, 131, 36, 24
+	rotate: 90
+girl-spring-dress/skirt
+	bounds: 113, 328, 182, 81
+	rotate: 90
+girl-spring-dress/underskirt
+	bounds: 2, 2, 175, 65
+girl/arm-front
+	bounds: 577, 395, 36, 115
+girl/back-eyebrow
+	bounds: 834, 492, 18, 12
+	rotate: 90
+girl/bag-base
+	bounds: 191, 264, 62, 58
+	rotate: 90
+girl/bag-strap-front
+	bounds: 385, 265, 12, 96
+girl/bag-top
+	bounds: 738, 367, 49, 50
+girl/body
+	bounds: 356, 130, 97, 132
+girl/boot-ribbon-front
+	bounds: 539, 130, 13, 13
+girl/eye-iris-back
+	bounds: 821, 424, 17, 17
+girl/eye-iris-front
+	bounds: 812, 443, 18, 18
+girl/eye-white-back
+	bounds: 814, 5, 20, 16
+	rotate: 90
+girl/front-eyebrow
+	bounds: 816, 400, 18, 12
+	rotate: 90
+girl/hair-back
+	bounds: 291, 363, 147, 93
+	rotate: 90
+girl/hair-bangs
+	bounds: 715, 419, 91, 40
+	rotate: 90
+girl/hair-flap-down-front
+	bounds: 288, 5, 70, 65
+girl/hair-head-side-back
+	bounds: 561, 77, 30, 52
+girl/hair-head-side-front
+	bounds: 757, 419, 41, 42
+	rotate: 90
+girl/hair-patch
+	bounds: 245, 4, 66, 41
+	rotate: 90
+girl/hair-side
+	bounds: 549, 3, 36, 71
+girl/hair-strand-back-1
+	bounds: 684, 3, 58, 74
+girl/hair-strand-back-2
+	bounds: 692, 171, 91, 58
+	rotate: 90
+girl/hair-strand-back-3
+	bounds: 615, 323, 92, 79
+	rotate: 90
+girl/hair-strand-front-1
+	bounds: 518, 269, 38, 94
+girl/hair-strand-front-2
+	bounds: 593, 79, 70, 50
+girl/hair-strand-front-3
+	bounds: 705, 88, 44, 81
+girl/hand-front-fingers
+	bounds: 530, 365, 19, 21
+girl/hat
+	bounds: 608, 169, 93, 82
+	rotate: 90
+girl/leg-front
+	bounds: 203, 104, 30, 158
+girl/pompom
+	bounds: 757, 462, 48, 43
+	rotate: 90
+girl/scarf
+	bounds: 455, 143, 119, 51
+	rotate: 90
+girl/scarf-back
+	bounds: 420, 2, 72, 51
+	rotate: 90
+girl/zip
+	bounds: 356, 109, 19, 25
+	rotate: 90

+ 15 - 0
spine-godot/example-v4/assets/mix-and-match/mix-and-match.atlas.import

@@ -0,0 +1,15 @@
+[remap]
+
+importer="spine.atlas"
+type="SpineAtlasResource"
+uid="uid://cvu8lycjkd245"
+path="res://.godot/imported/mix-and-match.atlas-3d349b543ecdcc01fb29033adaef0841.spatlas"
+
+[deps]
+
+source_file="res://assets/mix-and-match/mix-and-match.atlas"
+dest_files=["res://.godot/imported/mix-and-match.atlas-3d349b543ecdcc01fb29033adaef0841.spatlas"]
+
+[params]
+
+normal_map_prefix="n"

BIN
spine-godot/example-v4/assets/mix-and-match/mix-and-match.png


+ 34 - 0
spine-godot/example-v4/assets/mix-and-match/mix-and-match.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dkpeve6qcxa70"
+path="res://.godot/imported/mix-and-match.png-c2d8e28d9f2efc380ff8b95a22dadcc3.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/mix-and-match/mix-and-match.png"
+dest_files=["res://.godot/imported/mix-and-match.png-c2d8e28d9f2efc380ff8b95a22dadcc3.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

+ 16 - 0
spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.atlas

@@ -0,0 +1,16 @@
+Raggedy Spineboy.png
+	size: 256, 256
+	filter: Linear, Linear
+	pma: true
+arm
+	bounds: 2, 140, 71, 75
+	rotate: 90
+head
+	bounds: 2, 2, 136, 187
+	rotate: 90
+leg
+	bounds: 2, 213, 36, 99
+	rotate: 90
+torso
+	bounds: 103, 187, 62, 95
+	rotate: 90

+ 15 - 0
spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.atlas.import

@@ -0,0 +1,15 @@
+[remap]
+
+importer="spine.atlas"
+type="SpineAtlasResource"
+uid="uid://c75mtwn6dnkwp"
+path="res://.godot/imported/Raggedy Spineboy.atlas-07f7c6b30431397bcf472b18d48851e0.spatlas"
+
+[deps]
+
+source_file="res://assets/raggedyspineboy/Raggedy Spineboy.atlas"
+dest_files=["res://.godot/imported/Raggedy Spineboy.atlas-07f7c6b30431397bcf472b18d48851e0.spatlas"]
+
+[params]
+
+normal_map_prefix="n"

BIN
spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.png


+ 34 - 0
spine-godot/example-v4/assets/raggedyspineboy/Raggedy Spineboy.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://couyrsq850nh6"
+path="res://.godot/imported/Raggedy Spineboy.png-8982b59aad5b612b7ed1a5da8b447d00.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/raggedyspineboy/Raggedy Spineboy.png"
+dest_files=["res://.godot/imported/Raggedy Spineboy.png-8982b59aad5b612b7ed1a5da8b447d00.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

+ 8 - 0
spine-godot/example-v4/assets/raggedyspineboy/raggedy spineboy-res.tres

@@ -0,0 +1,8 @@
+[gd_resource type="SpineSkeletonDataResource" load_steps=3 format=2]
+
+[ext_resource path="res://assets/raggedyspineboy/Raggedy Spineboy.atlas" type="SpineAtlasResource" id=1]
+[ext_resource path="res://assets/raggedyspineboy/raggedy spineboy.json" type="SpineSkeletonFileResource" id=2]
+
+[resource]
+atlas_res = ExtResource( 1 )
+skeleton_file_res = ExtResource( 2 )

File diff suppressed because it is too large
+ 46 - 0
spine-godot/example-v4/assets/raggedyspineboy/raggedy spineboy.json


+ 14 - 0
spine-godot/example-v4/assets/raggedyspineboy/raggedy spineboy.json.import

@@ -0,0 +1,14 @@
+[remap]
+
+importer="spine.json"
+type="SpineSkeletonFileResource"
+uid="uid://bulrbalpjr863"
+path="res://.godot/imported/raggedy spineboy.json-a7000cc987b23355ac0b09613918efcc.spjson"
+
+[deps]
+
+source_file="res://assets/raggedyspineboy/raggedy spineboy.json"
+dest_files=["res://.godot/imported/raggedy spineboy.json-a7000cc987b23355ac0b09613918efcc.spjson"]
+
+[params]
+

BIN
spine-godot/example-v4/assets/raptor/light-sprite.png


+ 34 - 0
spine-godot/example-v4/assets/raptor/light-sprite.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cggfs567rn1ay"
+path="res://.godot/imported/light-sprite.png-346e910021b52658f1de723e4c80e05e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/raptor/light-sprite.png"
+dest_files=["res://.godot/imported/light-sprite.png-346e910021b52658f1de723e4c80e05e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
spine-godot/example-v4/assets/raptor/n_raptor.png


+ 34 - 0
spine-godot/example-v4/assets/raptor/n_raptor.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dnjt8gyvsw0l8"
+path="res://.godot/imported/n_raptor.png-d9af68b4a56af2b4319bb485e366dc90.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/raptor/n_raptor.png"
+dest_files=["res://.godot/imported/n_raptor.png-d9af68b4a56af2b4319bb485e366dc90.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

+ 9 - 0
spine-godot/example-v4/assets/raptor/raptor-data.tres

@@ -0,0 +1,9 @@
+[gd_resource type="SpineSkeletonDataResource" load_steps=3 format=2]
+
+[ext_resource path="res://assets/raptor/raptor.atlas" type="SpineAtlasResource" id=1]
+[ext_resource path="res://assets/raptor/raptor-pro.skel" type="SpineSkeletonFileResource" id=2]
+
+[resource]
+atlas_res = ExtResource( 1 )
+skeleton_file_res = ExtResource( 2 )
+default_mix = 0.2

BIN
spine-godot/example-v4/assets/raptor/raptor-pro.skel


+ 14 - 0
spine-godot/example-v4/assets/raptor/raptor-pro.skel.import

@@ -0,0 +1,14 @@
+[remap]
+
+importer="spine.skel"
+type="SpineSkeletonFileResource"
+uid="uid://dor8huwld4f84"
+path="res://.godot/imported/raptor-pro.skel-022e23a5f5581547a2d7faa9fb2c54e3.spskel"
+
+[deps]
+
+source_file="res://assets/raptor/raptor-pro.skel"
+dest_files=["res://.godot/imported/raptor-pro.skel-022e23a5f5581547a2d7faa9fb2c54e3.spskel"]
+
+[params]
+

+ 100 - 0
spine-godot/example-v4/assets/raptor/raptor.atlas

@@ -0,0 +1,100 @@
+raptor.png
+	size: 1024, 512
+	filter: Linear, Linear
+	scale: 0.5
+back-arm
+	bounds: 829, 88, 46, 25
+	rotate: 90
+back-bracer
+	bounds: 195, 238, 39, 28
+	rotate: 90
+back-hand
+	bounds: 724, 140, 36, 34
+	rotate: 90
+back-knee
+	bounds: 760, 131, 49, 67
+	rotate: 90
+back-thigh
+	bounds: 225, 238, 39, 24
+	rotate: 90
+eyes-open
+	bounds: 975, 204, 47, 45
+front-arm
+	bounds: 969, 112, 48, 26
+front-bracer
+	bounds: 724, 97, 41, 29
+	rotate: 90
+front-hand
+	bounds: 251, 239, 41, 38
+front-open-hand
+	bounds: 856, 76, 43, 44
+	rotate: 90
+front-thigh
+	bounds: 729, 178, 57, 29
+	rotate: 90
+gun
+	bounds: 894, 251, 107, 103
+gun-nohand
+	bounds: 764, 241, 105, 102
+head
+	bounds: 756, 345, 136, 149
+lower-leg
+	bounds: 475, 237, 73, 98
+	rotate: 90
+mouth-grind
+	bounds: 975, 172, 47, 30
+mouth-smile
+	bounds: 975, 140, 47, 30
+neck
+	bounds: 366, 282, 18, 21
+raptor-back-arm
+	bounds: 636, 97, 82, 86
+	rotate: 90
+raptor-body
+	bounds: 2, 2, 632, 233
+raptor-front-arm
+	bounds: 871, 168, 81, 102
+	rotate: 90
+raptor-front-leg
+	bounds: 2, 237, 191, 257
+raptor-hindleg-back
+	bounds: 195, 279, 169, 215
+raptor-horn
+	bounds: 431, 312, 182, 80
+	rotate: 90
+raptor-horn-back
+	bounds: 513, 318, 176, 77
+	rotate: 90
+raptor-jaw
+	bounds: 894, 356, 126, 138
+raptor-jaw-tooth
+	bounds: 294, 240, 37, 48
+	rotate: 90
+raptor-mouth-inside
+	bounds: 344, 241, 36, 41
+	rotate: 90
+raptor-saddle-strap-back
+	bounds: 575, 242, 54, 74
+raptor-saddle-strap-front
+	bounds: 764, 182, 57, 95
+	rotate: 90
+raptor-saddle-w-shadow
+	bounds: 592, 323, 162, 171
+raptor-tail-shadow
+	bounds: 366, 305, 189, 63
+	rotate: 90
+raptor-tongue
+	bounds: 387, 239, 86, 64
+stirrup-back
+	bounds: 829, 136, 44, 35
+	rotate: 90
+stirrup-front
+	bounds: 866, 121, 45, 50
+	rotate: 90
+stirrup-strap
+	bounds: 918, 120, 49, 46
+torso
+	bounds: 636, 181, 54, 91
+	rotate: 90
+visor
+	bounds: 631, 237, 131, 84

+ 15 - 0
spine-godot/example-v4/assets/raptor/raptor.atlas.import

@@ -0,0 +1,15 @@
+[remap]
+
+importer="spine.atlas"
+type="SpineAtlasResource"
+uid="uid://dhtyf5vltqsjg"
+path="res://.godot/imported/raptor.atlas-66da4b831eebf404341993162ba3ddb8.spatlas"
+
+[deps]
+
+source_file="res://assets/raptor/raptor.atlas"
+dest_files=["res://.godot/imported/raptor.atlas-66da4b831eebf404341993162ba3ddb8.spatlas"]
+
+[params]
+
+normal_map_prefix="n"

BIN
spine-godot/example-v4/assets/raptor/raptor.png


+ 34 - 0
spine-godot/example-v4/assets/raptor/raptor.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ucvdpil67hul"
+path="res://.godot/imported/raptor.png-505be50f63fd1d0fb9175a9efbb9776c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/raptor/raptor.png"
+dest_files=["res://.godot/imported/raptor.png-505be50f63fd1d0fb9175a9efbb9776c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

+ 20 - 0
spine-godot/example-v4/assets/spineboy/spineboy-data-res.tres

@@ -0,0 +1,20 @@
+[gd_resource type="SpineSkeletonDataResource" load_steps=5 format=2]
+
+[ext_resource path="res://assets/spineboy/spineboy.atlas" type="SpineAtlasResource" id=1]
+[ext_resource path="res://assets/spineboy/spineboy-pro.json" type="SpineSkeletonFileResource" id=2]
+
+[sub_resource type="SpineAnimationMix" id=1]
+from = "idle"
+to = "run"
+mix = 0.2
+
+[sub_resource type="SpineAnimationMix" id=2]
+from = "run"
+to = "idle"
+mix = 0.2
+
+[resource]
+atlas_res = ExtResource( 1 )
+skeleton_file_res = ExtResource( 2 )
+default_mix = 0.1
+animation_mixes = [ SubResource( 1 ), SubResource( 2 ) ]

File diff suppressed because it is too large
+ 541 - 0
spine-godot/example-v4/assets/spineboy/spineboy-pro.json


+ 14 - 0
spine-godot/example-v4/assets/spineboy/spineboy-pro.json.import

@@ -0,0 +1,14 @@
+[remap]
+
+importer="spine.json"
+type="SpineSkeletonFileResource"
+uid="uid://drl0og0imdkla"
+path="res://.godot/imported/spineboy-pro.json-60444223fe3960c6d4c33b92d7495419.spjson"
+
+[deps]
+
+source_file="res://assets/spineboy/spineboy-pro.json"
+dest_files=["res://.godot/imported/spineboy-pro.json-60444223fe3960c6d4c33b92d7495419.spjson"]
+
+[params]
+

BIN
spine-godot/example-v4/assets/spineboy/spineboy-pro.skel


+ 14 - 0
spine-godot/example-v4/assets/spineboy/spineboy-pro.skel.import

@@ -0,0 +1,14 @@
+[remap]
+
+importer="spine.skel"
+type="SpineSkeletonFileResource"
+uid="uid://cth0eypg16cgi"
+path="res://.godot/imported/spineboy-pro.skel-52781a88227740d2a80cb8d7636ea22e.spskel"
+
+[deps]
+
+source_file="res://assets/spineboy/spineboy-pro.skel"
+dest_files=["res://.godot/imported/spineboy-pro.skel-52781a88227740d2a80cb8d7636ea22e.spskel"]
+
+[params]
+

+ 101 - 0
spine-godot/example-v4/assets/spineboy/spineboy.atlas

@@ -0,0 +1,101 @@
+spineboy.png
+	size: 1024, 256
+	filter: Linear, Linear
+	scale: 0.5
+crosshair
+	bounds: 813, 160, 45, 45
+eye-indifferent
+	bounds: 569, 2, 47, 45
+eye-surprised
+	bounds: 643, 7, 47, 45
+	rotate: 90
+front-bracer
+	bounds: 811, 51, 29, 40
+front-fist-closed
+	bounds: 807, 93, 38, 41
+front-fist-open
+	bounds: 815, 210, 43, 44
+front-foot
+	bounds: 706, 64, 63, 35
+	rotate: 90
+front-shin
+	bounds: 80, 11, 41, 92
+front-thigh
+	bounds: 754, 12, 23, 56
+front-upper-arm
+	bounds: 618, 5, 23, 49
+goggles
+	bounds: 214, 20, 131, 83
+gun
+	bounds: 347, 14, 105, 102
+	rotate: 90
+head
+	bounds: 80, 105, 136, 149
+hoverboard-board
+	bounds: 2, 8, 246, 76
+	rotate: 90
+hoverboard-thruster
+	bounds: 478, 2, 30, 32
+hoverglow-small
+	bounds: 218, 117, 137, 38
+	rotate: 90
+mouth-grind
+	bounds: 775, 80, 47, 30
+	rotate: 90
+mouth-oooo
+	bounds: 779, 31, 47, 30
+	rotate: 90
+mouth-smile
+	bounds: 783, 207, 47, 30
+	rotate: 90
+muzzle-glow
+	bounds: 779, 4, 25, 25
+muzzle-ring
+	bounds: 451, 14, 25, 105
+muzzle01
+	bounds: 664, 60, 67, 40
+	rotate: 90
+muzzle02
+	bounds: 580, 56, 68, 42
+	rotate: 90
+muzzle03
+	bounds: 478, 36, 83, 53
+	rotate: 90
+muzzle04
+	bounds: 533, 49, 75, 45
+	rotate: 90
+muzzle05
+	bounds: 624, 56, 68, 38
+	rotate: 90
+neck
+	bounds: 806, 8, 18, 21
+portal-bg
+	bounds: 258, 121, 133, 133
+portal-flare1
+	bounds: 690, 2, 56, 30
+	rotate: 90
+portal-flare2
+	bounds: 510, 3, 57, 31
+portal-flare3
+	bounds: 722, 4, 58, 30
+	rotate: 90
+portal-shade
+	bounds: 393, 121, 133, 133
+portal-streaks1
+	bounds: 528, 126, 126, 128
+portal-streaks2
+	bounds: 656, 129, 125, 125
+rear-bracer
+	bounds: 826, 13, 28, 36
+rear-foot
+	bounds: 743, 70, 57, 30
+	rotate: 90
+rear-shin
+	bounds: 174, 14, 38, 89
+rear-thigh
+	bounds: 783, 158, 28, 47
+rear-upper-arm
+	bounds: 783, 136, 20, 44
+	rotate: 90
+torso
+	bounds: 123, 13, 49, 90

+ 15 - 0
spine-godot/example-v4/assets/spineboy/spineboy.atlas.import

@@ -0,0 +1,15 @@
+[remap]
+
+importer="spine.atlas"
+type="SpineAtlasResource"
+uid="uid://dt2kctrit34y0"
+path="res://.godot/imported/spineboy.atlas-54c12b5ff1cdaaa1b4e452a7d0d868c9.spatlas"
+
+[deps]
+
+source_file="res://assets/spineboy/spineboy.atlas"
+dest_files=["res://.godot/imported/spineboy.atlas-54c12b5ff1cdaaa1b4e452a7d0d868c9.spatlas"]
+
+[params]
+
+normal_map_prefix="n"

BIN
spine-godot/example-v4/assets/spineboy/spineboy.png


+ 34 - 0
spine-godot/example-v4/assets/spineboy/spineboy.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bh5imhdfuc6m0"
+path="res://.godot/imported/spineboy.png-436dbd6da2b707b6828ede17b7871f43.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/spineboy/spineboy.png"
+dest_files=["res://.godot/imported/spineboy.png-436dbd6da2b707b6828ede17b7871f43.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

+ 7 - 0
spine-godot/example-v4/default_env.tres

@@ -0,0 +1,7 @@
+[gd_resource type="Environment" load_steps=2 format=2]
+
+[sub_resource type="ProceduralSky" id=1]
+
+[resource]
+background_mode = 2
+background_sky = SubResource( 1 )

+ 18 - 0
spine-godot/example-v4/examples/01-helloworld/helloworld.tscn

@@ -0,0 +1,18 @@
+[gd_scene load_steps=3 format=3 uid="uid://d0v5rhv2ysej8"]
+
+[ext_resource type="Script" path="res://examples/01-helloworld/spineboy-helloworld.gd" id="1"]
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="3"]
+
+[node name="Node2D" type="Node2D"]
+
+[node name="Spineboy" type="SpineSprite" parent="."]
+position = Vector2(505, 466)
+scale = Vector2(0.466832, 0.466832)
+skeleton_data_res = ExtResource( "3" )
+bones_color = Color(0.968627, 1, 0, 0.501961)
+paths_color = Color(1, 0.498039, 0, 0.466667)
+paths_clipping = Color(0.8, 0, 0, 0.5)
+preview_animation = "run"
+preview_frame = true
+preview_time = 0.24
+script = ExtResource( "1" )

+ 4 - 0
spine-godot/example-v4/examples/01-helloworld/spineboy-helloworld.gd

@@ -0,0 +1,4 @@
+extends SpineSprite
+
+func _ready():
+	get_animation_state().set_animation("walk", true, 0)

+ 38 - 0
spine-godot/example-v4/examples/02-animation-state-listeners/animation-state-listeners.gd

@@ -0,0 +1,38 @@
+extends Node2D
+
+@onready var footstep_audio: AudioStreamPlayer = $FootstepAudio
+
+func _animation_started(sprite: SpineSprite, animation_state: SpineAnimationState, track_entry: SpineTrackEntry):
+	print("Animation started: " + track_entry.get_animation().get_name())
+
+func _animation_interrupted(sprite: SpineSprite, animation_state: SpineAnimationState, track_entry: SpineTrackEntry):
+	print("Animation interrupted: " + track_entry.get_animation().get_name())
+
+func _animation_ended(sprite: SpineSprite, animation_state: SpineAnimationState, track_entry: SpineTrackEntry):
+	print("Animation ended: " + track_entry.get_animation().get_name())
+
+func _animation_completed(sprite: SpineSprite, animation_state: SpineAnimationState, track_entry: SpineTrackEntry):
+	print("Animation completed: " + track_entry.get_animation().get_name())
+
+func _animation_disposed(sprite: SpineSprite, animation_state: SpineAnimationState, track_entry: SpineTrackEntry):
+	print("Animation disposed: " + track_entry.get_animation().get_name())
+	
+func _animation_event(sprite: SpineSprite, animation_state: SpineAnimationState, track_entry: SpineTrackEntry, event: SpineEvent):
+	print("Animation event: " + track_entry.get_animation().get_name() + ", " + event.get_data().get_event_name())
+	if (event.get_data().get_event_name() == "footstep"):		
+		footstep_audio.play()
+
+func _ready():
+	var spineboy = $Spineboy
+	var animation_state = spineboy.get_animation_state()
+	animation_state.set_animation("jump", false, 0)
+	animation_state.add_animation("walk", 0, true, 0)
+	animation_state.add_animation("run", 2, true, 0)
+	
+	spineboy.animation_started.connect(_animation_started)
+	spineboy.animation_interrupted.connect(_animation_interrupted)
+	spineboy.animation_ended.connect(_animation_ended)
+	spineboy.animation_completed.connect(_animation_completed)
+	spineboy.animation_disposed.connect(_animation_disposed)
+	spineboy.animation_event.connect(_animation_event)
+	pass

+ 19 - 0
spine-godot/example-v4/examples/02-animation-state-listeners/animation-state-listeners.tscn

@@ -0,0 +1,19 @@
+[gd_scene load_steps=4 format=3 uid="uid://c738i3nbdkn0h"]
+
+[ext_resource type="Script" path="res://examples/02-animation-state-listeners/animation-state-listeners.gd" id="1"]
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="2"]
+[ext_resource type="AudioStream" uid="uid://can7k84o8svum" path="res://assets/footstep.ogg" id="3"]
+
+[node name="Node2D" type="Node2D"]
+script = ExtResource( "1" )
+
+[node name="Spineboy" type="SpineSprite" parent="."]
+position = Vector2(473, 487)
+scale = Vector2(0.575051, 0.575051)
+skeleton_data_res = ExtResource( "2" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+
+[node name="FootstepAudio" type="AudioStreamPlayer" parent="."]
+stream = ExtResource( "3" )

+ 22 - 0
spine-godot/example-v4/examples/03-mix-and-match/mix-and-match.gd

@@ -0,0 +1,22 @@
+extends SpineSprite
+
+func _ready():
+	var data = get_skeleton().get_data()
+	var custom_skin = new_skin("custom-skin")
+	var skin_base = data.find_skin("skin-base")
+	custom_skin.add_skin(skin_base)
+	custom_skin.add_skin(data.find_skin("nose/short"))
+	custom_skin.add_skin(data.find_skin("eyelids/girly"))
+	custom_skin.add_skin(data.find_skin("eyes/violet"))
+	custom_skin.add_skin(data.find_skin("hair/brown"))
+	custom_skin.add_skin(data.find_skin("clothes/hoodie-orange"))
+	custom_skin.add_skin(data.find_skin("legs/pants-jeans"))
+	custom_skin.add_skin(data.find_skin("accessories/bag"))
+	custom_skin.add_skin(data.find_skin("accessories/hat-red-yellow"))
+	get_skeleton().set_skin(custom_skin);
+
+	for el in custom_skin.get_attachments():
+		var entry: SpineSkinEntry = el
+		print(str(entry.get_slot_index()) + " " + entry.get_name())
+
+	get_animation_state().set_animation("dance", true, 0)

+ 15 - 0
spine-godot/example-v4/examples/03-mix-and-match/mix-and-match.tscn

@@ -0,0 +1,15 @@
+[gd_scene load_steps=3 format=3 uid="uid://dodvuj07fsynd"]
+
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/mix-and-match/mix-and-match-data.tres" id="1"]
+[ext_resource type="Script" path="res://examples/03-mix-and-match/mix-and-match.gd" id="2"]
+
+[node name="Node2D" type="Node2D"]
+
+[node name="MixAndMatch" type="SpineSprite" parent="."]
+position = Vector2(532.982, 480.287)
+scale = Vector2(0.441932, 0.441932)
+skeleton_data_res = ExtResource( "1" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( "2" )

+ 15 - 0
spine-godot/example-v4/examples/04-simple-input/simple-input.tscn

@@ -0,0 +1,15 @@
+[gd_scene load_steps=3 format=3 uid="uid://bgdpghp11j3kg"]
+
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="1"]
+[ext_resource type="Script" path="res://examples/04-simple-input/spineboy-simple-input.gd" id="2"]
+
+[node name="Node2D" type="Node2D"]
+
+[node name="Spineboy" type="SpineSprite" parent="."]
+position = Vector2(501.503, 472.035)
+scale = Vector2(0.518624, 0.518624)
+skeleton_data_res = ExtResource( "1" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( "2" )

+ 19 - 0
spine-godot/example-v4/examples/04-simple-input/spineboy-simple-input.gd

@@ -0,0 +1,19 @@
+extends SpineSprite
+
+func _ready():
+	get_animation_state().set_animation("idle", true, 0)
+
+func _process(_delta):
+	if Input.is_action_just_pressed("ui_left"):
+		get_animation_state().set_animation("run", true, 0)
+		get_skeleton().set_scale_x(-1)
+		
+	if Input.is_action_just_released("ui_left"):
+		get_animation_state().set_animation("idle", true, 0)
+		
+	if (Input.is_action_just_pressed("ui_right")):
+		get_animation_state().set_animation("run", true, 0)
+		get_skeleton().set_scale_x(1)
+		
+	if Input.is_action_just_released("ui_right"):
+		get_animation_state().set_animation("idle", true, 0)

+ 11 - 0
spine-godot/example-v4/examples/05-mouse-following/mouse-following.gd

@@ -0,0 +1,11 @@
+extends Node2D
+
+@onready var spineboy: SpineSprite = $Spineboy
+@onready var crosshair_bone: SpineBoneNode = $Spineboy/CrosshairBone
+
+func _ready():
+	spineboy.get_animation_state().set_animation("walk", true, 0)
+	spineboy.get_animation_state().set_animation("aim", true, 1)
+	
+func _process(_delta):
+	crosshair_bone.global_position = get_viewport().get_mouse_position()

+ 22 - 0
spine-godot/example-v4/examples/05-mouse-following/mouse-following.tscn

@@ -0,0 +1,22 @@
+[gd_scene load_steps=3 format=3 uid="uid://borp2l17n5xw1"]
+
+[ext_resource type="Script" path="res://examples/05-mouse-following/mouse-following.gd" id="1"]
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="2"]
+
+[node name="Node2D" type="Node2D"]
+script = ExtResource( "1" )
+
+[node name="Spineboy" type="SpineSprite" parent="."]
+position = Vector2(481, 457)
+scale = Vector2(0.5, 0.5)
+skeleton_data_res = ExtResource( "2" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+
+[node name="CrosshairBone" type="SpineBoneNode" parent="Spineboy"]
+show_behind_parent = true
+position = Vector2(302.333, -569.714)
+rotation = -0.000872665
+bone_name = "crosshair"
+bone_mode = 1

+ 5 - 0
spine-godot/example-v4/examples/06-bone-following/bone-following.gd

@@ -0,0 +1,5 @@
+extends Node2D
+
+func _ready():
+	var spineboy: SpineSprite = $Spineboy
+	spineboy.get_animation_state().set_animation("walk", true, 0)	

+ 25 - 0
spine-godot/example-v4/examples/06-bone-following/bone-following.tscn

@@ -0,0 +1,25 @@
+[gd_scene load_steps=4 format=3 uid="uid://bir7yvf0qwdge"]
+
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="1"]
+[ext_resource type="Script" path="res://examples/06-bone-following/bone-following.gd" id="2"]
+[ext_resource type="Texture2D" uid="uid://8ud5n2ywp5ba" path="res://icon.png" id="3"]
+
+[node name="Node2D" type="Node2D"]
+script = ExtResource( "2" )
+
+[node name="Spineboy" type="SpineSprite" parent="."]
+position = Vector2(478, 483)
+scale = Vector2(0.58461, 0.58461)
+skeleton_data_res = ExtResource( "1" )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+
+[node name="GunTipBone" type="SpineBoneNode" parent="Spineboy"]
+show_behind_parent = true
+position = Vector2(214.298, -162.047)
+rotation = 0.713316
+bone_name = "gun-tip"
+
+[node name="Sprite" type="Sprite2D" parent="Spineboy/GunTipBone"]
+texture = ExtResource( "3" )

+ 11 - 0
spine-godot/example-v4/examples/07-slot-node/slot-node.gd

@@ -0,0 +1,11 @@
+extends Node2D
+
+@onready var spineboy: SpineSprite = $Spineboy
+@onready var raptor: SpineSprite = $Spineboy/GunSlot/Raptor
+@onready var tiny_spineboy: SpineSprite = $Spineboy/FrontFistSlot/TinySpineboy
+
+func _ready():	
+	var entry = spineboy.get_animation_state().set_animation("run", true, 0)
+	entry.set_time_scale(0.1)
+	raptor.get_animation_state().set_animation("walk", true, 0)
+	tiny_spineboy.get_animation_state().set_animation("walk", true, 0)

+ 56 - 0
spine-godot/example-v4/examples/07-slot-node/slot-node.tscn

@@ -0,0 +1,56 @@
+[gd_scene load_steps=5 format=3 uid="uid://bhht8dees2pyq"]
+
+[ext_resource type="Script" path="res://examples/07-slot-node/slot-node.gd" id="1"]
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="2"]
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/raptor/raptor-data.tres" id="3"]
+[ext_resource type="Texture2D" uid="uid://8ud5n2ywp5ba" path="res://icon.png" id="4"]
+
+[node name="Node2D" type="Node2D"]
+script = ExtResource( "1" )
+
+[node name="Spineboy" type="SpineSprite" parent="."]
+position = Vector2(474, 506)
+scale = Vector2(0.560712, 0.560712)
+skeleton_data_res = ExtResource( "2" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+
+[node name="GunSlot" type="SpineSlotNode" parent="Spineboy"]
+show_behind_parent = true
+position = Vector2(40.8753, -276.036)
+rotation = 0.837234
+slot_name = "gun"
+
+[node name="Raptor" type="SpineSprite" parent="Spineboy/GunSlot"]
+position = Vector2(84.6909, -67.9174)
+scale = Vector2(0.193472, 0.193472)
+skeleton_data_res = ExtResource( "3" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+
+[node name="EyeSlot" type="SpineSlotNode" parent="Spineboy"]
+show_behind_parent = true
+position = Vector2(-23.4598, -402.301)
+rotation = -1.71793
+slot_name = "eye"
+
+[node name="Sprite" type="Sprite2D" parent="Spineboy/EyeSlot"]
+position = Vector2(84.4734, 43.4469)
+rotation = 1.66344
+texture = ExtResource( "4" )
+
+[node name="FrontFistSlot" type="SpineSlotNode" parent="Spineboy"]
+show_behind_parent = true
+position = Vector2(-29.0298, -241.577)
+rotation = 0.995187
+slot_name = "front-fist"
+
+[node name="TinySpineboy" type="SpineSprite" parent="Spineboy/FrontFistSlot"]
+position = Vector2(-2.64624, -10.8111)
+scale = Vector2(0.193389, 0.193389)
+skeleton_data_res = ExtResource( "2" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0

+ 33 - 0
spine-godot/example-v4/examples/08-animation-player/animation-player.gd

@@ -0,0 +1,33 @@
+extends Node2D
+
+@onready var player = $AnimationPlayer
+@onready var spineboy = $Spineboy
+
+var speed = 400;
+var velocity_x = 0;
+
+func _ready():
+	player.play("cutscene")
+	pass
+
+func _process(delta):
+	if (!player.is_playing()):
+		if Input.is_action_just_released("ui_left"):
+			spineboy.get_animation_state().set_animation("idle", true, 0)
+			velocity_x = 0
+
+		if Input.is_action_just_released("ui_right"):
+			spineboy.get_animation_state().set_animation("idle", true, 0)
+			velocity_x = 0
+
+		if (Input.is_action_just_pressed("ui_right")):
+			spineboy.get_animation_state().set_animation("run", true, 0)
+			spineboy.get_skeleton().set_scale_x(1)
+			velocity_x = 1
+
+		if Input.is_action_just_pressed("ui_left"):
+			spineboy.get_animation_state().set_animation("run", true, 0)
+			spineboy.get_skeleton().set_scale_x(-1)
+			velocity_x = -1
+
+		spineboy.position.x += velocity_x * speed * delta

+ 1942 - 0
spine-godot/example-v4/examples/08-animation-player/animation-player.tscn

@@ -0,0 +1,1942 @@
+[gd_scene load_steps=68 format=3 uid="uid://dmddd1ll1y0bm"]
+
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="1"]
+[ext_resource type="Script" path="res://examples/08-animation-player/animation-player.gd" id="2"]
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/raptor/raptor-data.tres" id="3"]
+
+[sub_resource type="Animation" id="Animation_t6m4d"]
+resource_name = "aim_looped"
+length = 0.5
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["aim"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_njcku"]
+resource_name = "aim"
+length = 0.5
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["aim"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_uj85l"]
+resource_name = "death_looped"
+length = 4.9333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["death"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_irg42"]
+resource_name = "death"
+length = 4.9333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["death"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_u0h4m"]
+resource_name = "hoverboard_looped"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["hoverboard"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_ksgd8"]
+resource_name = "hoverboard"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["hoverboard"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_onrph"]
+resource_name = "idle_looped"
+length = 1.6667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["idle"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_uq46m"]
+resource_name = "idle"
+length = 1.6667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["idle"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_vm3do"]
+resource_name = "idle-turn_looped"
+length = 0.2667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["idle-turn"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_tlrtt"]
+resource_name = "idle-turn"
+length = 0.2667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["idle-turn"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_8gf4p"]
+resource_name = "jump_looped"
+length = 1.3333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["jump"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_e3mt7"]
+resource_name = "jump"
+length = 1.3333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["jump"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_q7d0d"]
+resource_name = "portal_looped"
+length = 3.1667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["portal"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_hu1qx"]
+resource_name = "portal"
+length = 3.1667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["portal"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_4qvwn"]
+resource_name = "run_looped"
+length = 0.6667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["run"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_rcbj7"]
+resource_name = "run"
+length = 0.6667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["run"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_xaopv"]
+resource_name = "run-to-idle_looped"
+length = 0.2667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["run-to-idle"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_hhaj8"]
+resource_name = "run-to-idle"
+length = 0.2667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["run-to-idle"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_2epiy"]
+resource_name = "shoot_looped"
+length = 0.6333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["shoot"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_xvf75"]
+resource_name = "shoot"
+length = 0.6333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["shoot"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_ailgk"]
+resource_name = "walk_looped"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["walk"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_1ifml"]
+resource_name = "walk"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["walk"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_13jvi"]
+resource_name = "RESET"
+length = 0.5
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [""]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_3juul"]
+_data = {
+"-- Empty --": SubResource( "Animation_13jvi" ),
+"RESET": SubResource( "Animation_13jvi" ),
+"aim": SubResource( "Animation_njcku" ),
+"aim_looped": SubResource( "Animation_t6m4d" ),
+"death": SubResource( "Animation_irg42" ),
+"death_looped": SubResource( "Animation_uj85l" ),
+"hoverboard": SubResource( "Animation_ksgd8" ),
+"hoverboard_looped": SubResource( "Animation_u0h4m" ),
+"idle": SubResource( "Animation_uq46m" ),
+"idle-turn": SubResource( "Animation_tlrtt" ),
+"idle-turn_looped": SubResource( "Animation_vm3do" ),
+"idle_looped": SubResource( "Animation_onrph" ),
+"jump": SubResource( "Animation_e3mt7" ),
+"jump_looped": SubResource( "Animation_8gf4p" ),
+"portal": SubResource( "Animation_hu1qx" ),
+"portal_looped": SubResource( "Animation_q7d0d" ),
+"run": SubResource( "Animation_rcbj7" ),
+"run-to-idle": SubResource( "Animation_hhaj8" ),
+"run-to-idle_looped": SubResource( "Animation_xaopv" ),
+"run_looped": SubResource( "Animation_4qvwn" ),
+"shoot": SubResource( "Animation_xvf75" ),
+"shoot_looped": SubResource( "Animation_2epiy" ),
+"walk": SubResource( "Animation_1ifml" ),
+"walk_looped": SubResource( "Animation_ailgk" )
+}
+
+[sub_resource type="Animation" id="Animation_43jug"]
+resource_name = "aim_looped"
+length = 0.5
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["aim"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_npdlv"]
+resource_name = "aim"
+length = 0.5
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["aim"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_v5dry"]
+resource_name = "death_looped"
+length = 4.9333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["death"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_wthcu"]
+resource_name = "death"
+length = 4.9333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["death"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_0t4px"]
+resource_name = "hoverboard_looped"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["hoverboard"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_cflga"]
+resource_name = "hoverboard"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["hoverboard"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_4l5af"]
+resource_name = "idle_looped"
+length = 1.6667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["idle"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_3kd2q"]
+resource_name = "idle"
+length = 1.6667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["idle"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_pcovu"]
+resource_name = "idle-turn_looped"
+length = 0.2667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["idle-turn"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_ji8c3"]
+resource_name = "idle-turn"
+length = 0.2667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["idle-turn"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_hxqi7"]
+resource_name = "jump_looped"
+length = 1.3333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["jump"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_h822y"]
+resource_name = "jump"
+length = 1.3333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["jump"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_8f1h5"]
+resource_name = "portal_looped"
+length = 3.1667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["portal"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_i0wgj"]
+resource_name = "portal"
+length = 3.1667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["portal"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_0q41s"]
+resource_name = "run_looped"
+length = 0.6667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["run"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_og3lw"]
+resource_name = "run"
+length = 0.6667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["run"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_q7ndl"]
+resource_name = "run-to-idle_looped"
+length = 0.2667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["run-to-idle"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_nxlcc"]
+resource_name = "run-to-idle"
+length = 0.2667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["run-to-idle"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_riqly"]
+resource_name = "shoot_looped"
+length = 0.6333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["shoot"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_e7tup"]
+resource_name = "shoot"
+length = 0.6333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["shoot"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_5q6ru"]
+resource_name = "walk_looped"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["walk"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_rbpim"]
+resource_name = "walk"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["walk"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_n4owa"]
+resource_name = "RESET"
+length = 0.5
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [""]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_weodw"]
+_data = {
+"-- Empty --": SubResource( "Animation_n4owa" ),
+"RESET": SubResource( "Animation_n4owa" ),
+"aim": SubResource( "Animation_npdlv" ),
+"aim_looped": SubResource( "Animation_43jug" ),
+"death": SubResource( "Animation_wthcu" ),
+"death_looped": SubResource( "Animation_v5dry" ),
+"hoverboard": SubResource( "Animation_cflga" ),
+"hoverboard_looped": SubResource( "Animation_0t4px" ),
+"idle": SubResource( "Animation_3kd2q" ),
+"idle-turn": SubResource( "Animation_ji8c3" ),
+"idle-turn_looped": SubResource( "Animation_pcovu" ),
+"idle_looped": SubResource( "Animation_4l5af" ),
+"jump": SubResource( "Animation_h822y" ),
+"jump_looped": SubResource( "Animation_hxqi7" ),
+"portal": SubResource( "Animation_i0wgj" ),
+"portal_looped": SubResource( "Animation_8f1h5" ),
+"run": SubResource( "Animation_og3lw" ),
+"run-to-idle": SubResource( "Animation_nxlcc" ),
+"run-to-idle_looped": SubResource( "Animation_q7ndl" ),
+"run_looped": SubResource( "Animation_0q41s" ),
+"shoot": SubResource( "Animation_e7tup" ),
+"shoot_looped": SubResource( "Animation_riqly" ),
+"walk": SubResource( "Animation_rbpim" ),
+"walk_looped": SubResource( "Animation_5q6ru" )
+}
+
+[sub_resource type="Animation" id="Animation_g0fba"]
+resource_name = "gun-grab_looped"
+length = 0.666667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["gun-grab"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_tnmwm"]
+resource_name = "gun-grab"
+length = 0.666667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["gun-grab"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_scefx"]
+resource_name = "gun-holster_looped"
+length = 0.666667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["gun-holster"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_6lq4v"]
+resource_name = "gun-holster"
+length = 0.666667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["gun-holster"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_b7ns0"]
+resource_name = "jump_looped"
+length = 1.53333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["jump"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_l4kgf"]
+resource_name = "jump"
+length = 1.53333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["jump"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_jt8r5"]
+resource_name = "roar_looped"
+length = 2.13333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["roar"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_wlr0r"]
+resource_name = "roar"
+length = 2.13333
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["roar"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_0e04p"]
+resource_name = "walk_looped"
+length = 1.26667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["walk"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_ysb1x"]
+resource_name = "walk"
+length = 1.26667
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": ["walk"]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_j5g3u"]
+resource_name = "RESET"
+length = 0.5
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:animation_name")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [""]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:loop")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [false]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_nir4m"]
+_data = {
+"-- Empty --": SubResource( "Animation_j5g3u" ),
+"RESET": SubResource( "Animation_j5g3u" ),
+"gun-grab": SubResource( "Animation_tnmwm" ),
+"gun-grab_looped": SubResource( "Animation_g0fba" ),
+"gun-holster": SubResource( "Animation_6lq4v" ),
+"gun-holster_looped": SubResource( "Animation_scefx" ),
+"jump": SubResource( "Animation_l4kgf" ),
+"jump_looped": SubResource( "Animation_b7ns0" ),
+"roar": SubResource( "Animation_wlr0r" ),
+"roar_looped": SubResource( "Animation_jt8r5" ),
+"walk": SubResource( "Animation_ysb1x" ),
+"walk_looped": SubResource( "Animation_0e04p" )
+}
+
+[sub_resource type="Animation" id="25"]
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Spineboy:position")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [Vector2(72.0001, 520)]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Raptor:position")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [Vector2(1284, 520)]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Spineboy/SpineAnimationTrack:mix_duration")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [-1.0]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("Spineboy/SpineAnimationTrack:reverse")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/4/type = "value"
+tracks/4/imported = false
+tracks/4/enabled = true
+tracks/4/path = NodePath("Raptor/SpineAnimationTrack:mix_duration")
+tracks/4/interp = 1
+tracks/4/loop_wrap = true
+tracks/4/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [-1.0]
+}
+tracks/5/type = "value"
+tracks/5/imported = false
+tracks/5/enabled = true
+tracks/5/path = NodePath("Spineboy/SpineAnimationTrack:time_scale")
+tracks/5/interp = 1
+tracks/5/loop_wrap = true
+tracks/5/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [1.0]
+}
+
+[sub_resource type="Animation" id="1"]
+resource_name = "cutscene"
+length = 10.0
+step = 0.02
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Spineboy:position")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 4, 10),
+"transitions": PackedFloat32Array(1, 1, 1),
+"update": 0,
+"values": [Vector2(72.0001, 520), Vector2(500, 520), Vector2(500, 520)]
+}
+tracks/1/type = "animation"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Spineboy/SpineAnimationTrack/Spineboy Track 0")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"clips": PackedStringArray("walk_looped", "idle", "death", "idle"),
+"times": PackedFloat32Array(0, 4, 4.34, 8.86)
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Spineboy/SpineAnimationTrack2:mix_duration")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0.1]
+}
+tracks/3/type = "animation"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("Spineboy/SpineAnimationTrack2/Spineboy Track 1")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"clips": PackedStringArray("-- Empty --", "aim", "-- Empty --"),
+"times": PackedFloat32Array(0.14, 2.5, 3.94)
+}
+tracks/4/type = "value"
+tracks/4/imported = false
+tracks/4/enabled = true
+tracks/4/path = NodePath("Raptor:position")
+tracks/4/interp = 1
+tracks/4/loop_wrap = true
+tracks/4/keys = {
+"times": PackedFloat32Array(0, 2.02, 3.7, 10),
+"transitions": PackedFloat32Array(1, 1, 1, 1),
+"update": 0,
+"values": [Vector2(1284, 520), Vector2(1284, 520), Vector2(750, 520), Vector2(750, 520)]
+}
+tracks/5/type = "animation"
+tracks/5/imported = false
+tracks/5/enabled = true
+tracks/5/path = NodePath("Raptor/SpineAnimationTrack/Raptor Track 0")
+tracks/5/interp = 1
+tracks/5/loop_wrap = true
+tracks/5/keys = {
+"clips": PackedStringArray("walk_looped", "roar_looped", "-- Empty --"),
+"times": PackedFloat32Array(0.46, 3.7, 9.64)
+}
+tracks/6/type = "value"
+tracks/6/imported = false
+tracks/6/enabled = true
+tracks/6/path = NodePath("Spineboy/SpineAnimationTrack:mix_duration")
+tracks/6/interp = 1
+tracks/6/loop_wrap = true
+tracks/6/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [0.2]
+}
+tracks/7/type = "value"
+tracks/7/imported = false
+tracks/7/enabled = true
+tracks/7/path = NodePath("Raptor/SpineAnimationTrack:mix_duration")
+tracks/7/interp = 1
+tracks/7/loop_wrap = true
+tracks/7/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [0.2]
+}
+
+[sub_resource type="Animation" id="83"]
+resource_name = "slow-moonwalk"
+length = 5.0
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Spineboy:position")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 5),
+"transitions": PackedFloat32Array(1, 1),
+"update": 0,
+"values": [Vector2(905, 565), Vector2(70, 565)]
+}
+tracks/1/type = "animation"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Spineboy/SpineAnimationTrack/Spineboy Track 0")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"clips": PackedStringArray("walk_looped"),
+"times": PackedFloat32Array(0)
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Spineboy/SpineAnimationTrack:reverse")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [true]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("Spineboy/SpineAnimationTrack:time_scale")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [0.5]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_3lgey"]
+_data = {
+"RESET": SubResource( "25" ),
+"cutscene": SubResource( "1" ),
+"slow-moonwalk": SubResource( "83" )
+}
+
+[node name="Node2D2" type="Node2D"]
+script = ExtResource( "2" )
+
+[node name="Spineboy" type="SpineSprite" parent="."]
+position = Vector2(72.0001, 520)
+scale = Vector2(0.323942, 0.323942)
+skeleton_data_res = ExtResource( "1" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+
+[node name="SpineAnimationTrack" type="SpineAnimationTrack" parent="Spineboy"]
+track_index = 0
+debug = true
+
+[node name="Spineboy Track 0" type="AnimationPlayer" parent="Spineboy/SpineAnimationTrack"]
+libraries = {
+"": SubResource( "AnimationLibrary_3juul" )
+}
+
+[node name="SpineAnimationTrack2" type="SpineAnimationTrack" parent="Spineboy"]
+track_index = 1
+mix_duration = 0.1
+debug = true
+
+[node name="Spineboy Track 1" type="AnimationPlayer" parent="Spineboy/SpineAnimationTrack2"]
+libraries = {
+"": SubResource( "AnimationLibrary_weodw" )
+}
+
+[node name="Raptor" type="SpineSprite" parent="."]
+position = Vector2(1284, 520)
+scale = Vector2(-0.328761, 0.328761)
+skeleton_data_res = ExtResource( "3" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+
+[node name="SpineAnimationTrack" type="SpineAnimationTrack" parent="Raptor"]
+track_index = 0
+
+[node name="Raptor Track 0" type="AnimationPlayer" parent="Raptor/SpineAnimationTrack"]
+libraries = {
+"": SubResource( "AnimationLibrary_nir4m" )
+}
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+"": SubResource( "AnimationLibrary_3lgey" )
+}

+ 43 - 0
spine-godot/example-v4/examples/09-custom-material/custom-material.tscn

@@ -0,0 +1,43 @@
+[gd_scene load_steps=6 format=3 uid="uid://b4p2vn7bwm52a"]
+
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="1"]
+
+[sub_resource type="Shader" id="1"]
+code = "shader_type canvas_item;
+
+void fragment() {
+	COLOR = texture(TEXTURE, UV);
+	COLOR.r = 0.0;
+}"
+
+[sub_resource type="ShaderMaterial" id="2"]
+shader = SubResource( "1" )
+
+[sub_resource type="Shader" id="3"]
+code = "shader_type canvas_item;
+
+void fragment() {
+	COLOR = texture(TEXTURE, UV);
+	COLOR.b = 0.0;
+}"
+
+[sub_resource type="ShaderMaterial" id="4"]
+shader = SubResource( "3" )
+
+[node name="Node2D" type="Node2D"]
+
+[node name="SpineSprite" type="SpineSprite" parent="."]
+position = Vector2(501, 507)
+scale = Vector2(0.546374, 0.546373)
+skeleton_data_res = ExtResource( "1" )
+normal_material = SubResource( "2" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+
+[node name="GunSlot" type="SpineSlotNode" parent="SpineSprite"]
+show_behind_parent = true
+position = Vector2(40.8753, -276.036)
+rotation = 0.837234
+slot_name = "gun"
+normal_material = SubResource( "4" )

+ 4 - 0
spine-godot/example-v4/examples/10-2d-lighting/2d-lighting.gd

@@ -0,0 +1,4 @@
+extends Node2D
+
+func _ready():
+	$SpineSprite.get_animation_state().set_animation("walk");

+ 25 - 0
spine-godot/example-v4/examples/10-2d-lighting/2d-lighting.tscn

@@ -0,0 +1,25 @@
+[gd_scene load_steps=4 format=3 uid="uid://rt2llskmx7xm"]
+
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/raptor/raptor-data.tres" id="1"]
+[ext_resource type="Texture2D" uid="uid://cggfs567rn1ay" path="res://assets/raptor/light-sprite.png" id="2"]
+[ext_resource type="Script" path="res://examples/10-2d-lighting/2d-lighting.gd" id="3"]
+
+[node name="Node2D" type="Node2D"]
+script = ExtResource( "3" )
+
+[node name="SpineSprite" type="SpineSprite" parent="."]
+position = Vector2(576, 506)
+scale = Vector2(0.458967, 0.458967)
+skeleton_data_res = ExtResource( "1" )
+preview_animation = "-- Empty --"
+preview_frame = false
+preview_time = 0.0
+
+[node name="Light2D" type="PointLight2D" parent="."]
+position = Vector2(822, 270)
+scale = Vector2(1.51563, 1.51563)
+color = Color(1, 0.0117647, 0.0117647, 1)
+texture = ExtResource( "2" )
+
+[node name="CanvasModulate" type="CanvasModulate" parent="."]
+color = Color(0.145098, 0.0980392, 0.0980392, 1)

+ 19 - 0
spine-godot/example-v4/examples/11-bone-node/bone-node.gd

@@ -0,0 +1,19 @@
+extends Node2D
+
+@onready var spineboy = $SpineSprite
+@onready var center_bone = $SpineSprite/HoverboardCenterBone
+@onready var center_ray = $SpineSprite/HoverboardCenterBone/RayCast2D
+@onready var target_bone = $SpineSprite/HoverboardTargetBone
+@onready var target_ray = $SpineSprite/HoverboardTargetBone/RayCast2D
+
+func _ready():
+	spineboy.get_animation_state().set_animation("hoverboard", true, 0)
+
+func _physics_process(delta):
+	if target_ray.is_colliding():
+		target_bone.global_position.y = target_ray.get_collision_point().y - 50
+	if center_ray.is_colliding():
+		center_bone.global_position.y = center_ray.get_collision_point().y - 50
+
+	spineboy.global_position.x += delta * 150;
+	spineboy.global_position.y = center_bone.global_position.y

+ 47 - 0
spine-godot/example-v4/examples/11-bone-node/bone-node.tscn

@@ -0,0 +1,47 @@
+[gd_scene load_steps=3 format=3 uid="uid://chrw4i0nksphn"]
+
+[ext_resource type="Script" path="res://examples/11-bone-node/bone-node.gd" id="1"]
+[ext_resource type="SpineSkeletonDataResource" path="res://assets/spineboy/spineboy-data-res.tres" id="2"]
+
+[node name="Node2D" type="Node2D"]
+script = ExtResource( "1" )
+
+[node name="SpineSprite" type="SpineSprite" parent="."]
+position = Vector2(8, 553)
+scale = Vector2(0.278096, 0.278096)
+skeleton_data_res = ExtResource( "2" )
+update_mode = 1
+preview_animation = "hoverboard"
+preview_frame = true
+preview_time = 0.0
+
+[node name="HoverboardCenterBone" type="SpineBoneNode" parent="SpineSprite"]
+show_behind_parent = true
+bone_name = "hoverboard-controller"
+bone_mode = 1
+
+[node name="RayCast2D" type="RayCast2D" parent="SpineSprite/HoverboardCenterBone"]
+
+[node name="HoverboardTargetBone" type="SpineBoneNode" parent="SpineSprite"]
+show_behind_parent = true
+position = Vector2(262.499, 0)
+rotation = -0.000872665
+bone_name = "board-ik"
+bone_mode = 1
+
+[node name="RayCast2D" type="RayCast2D" parent="SpineSprite/HoverboardTargetBone"]
+
+[node name="HipBone" type="SpineBoneNode" parent="SpineSprite"]
+show_behind_parent = true
+position = Vector2(0, -169.006)
+rotation = -0.000872665
+bone_name = "hip"
+bone_mode = 1
+
+[node name="Polygon2D" type="Polygon2D" parent="."]
+polygon = PackedVector2Array(0, 596, 309, 471, 516, 515, 762, 447, 984, 504, 1023, 505, 1024, 596)
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Polygon2D"]
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Polygon2D/StaticBody2D"]
+polygon = PackedVector2Array(3, 592, 304, 469, 516, 514, 762, 443, 984, 499, 1252, 498, 1280, 596)

BIN
spine-godot/example-v4/icon.png


+ 34 - 0
spine-godot/example-v4/icon.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://8ud5n2ywp5ba"
+path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.png"
+dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/bptc_ldr=0
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

+ 35 - 0
spine-godot/example-v4/project.godot

@@ -0,0 +1,35 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+;   [section] ; section goes between []
+;   param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="spine-godot-examples"
+run/main_scene="res://examples/08-animation-player/animation-player.tscn"
+run/low_processor_mode=true
+config/icon="res://icon.png"
+config/features=PackedStringArray("4.0")
+
+[global]
+
+batch=false
+
+[physics]
+
+common/enable_pause_aware_picking=true
+
+[rendering]
+
+batching/parameters/max_join_item_commands=100
+batching/parameters/batch_buffer_size=65535
+batching/parameters/item_reordering_lookahead=100
+quality/driver/driver_name="GLES2"
+vram_compression/import_etc=true
+vram_compression/import_etc2=false
+environment/default_environment="res://default_env.tres"

+ 4 - 0
spine-godot/example-v4/tests/batch-test.gd

@@ -0,0 +1,4 @@
+extends SpineSprite
+
+func _ready():
+	get_animation_state().set_animation("walk", true)

+ 871 - 0
spine-godot/example-v4/tests/batch-test.tscn

@@ -0,0 +1,871 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://assets/spineboy/spineboy-data-res.tres" type="SpineSkeletonDataResource" id=1]
+[ext_resource path="res://tests/batch-test.gd" type="Script" id=2]
+
+[node name="Node2D" type="Node2D"]
+rotation = -3.67884e-05
+
+[node name="SpineSprite" type="SpineSprite" parent="."]
+position = Vector2( 53.8037, 119.483 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite2" type="SpineSprite" parent="."]
+position = Vector2( 111.488, 119.485 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite3" type="SpineSprite" parent="."]
+position = Vector2( 164.678, 119.487 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = true
+preview_time = 2.36477e-39
+script = ExtResource( 2 )
+
+[node name="SpineSprite4" type="SpineSprite" parent="."]
+position = Vector2( 217.119, 121.736 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = true
+preview_time = 6.85235e-43
+script = ExtResource( 2 )
+
+[node name="SpineSprite5" type="SpineSprite" parent="."]
+position = Vector2( 277.051, 120.989 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite6" type="SpineSprite" parent="."]
+position = Vector2( 337.733, 118.744 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite7" type="SpineSprite" parent="."]
+position = Vector2( 403.658, 120.994 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite8" type="SpineSprite" parent="."]
+position = Vector2( 464.34, 120.996 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite9" type="SpineSprite" parent="."]
+position = Vector2( 525.021, 120.998 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 51.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite10" type="SpineSprite" parent="."]
+position = Vector2( 589.448, 121.001 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite11" type="SpineSprite" parent="."]
+position = Vector2( 649.381, 121.752 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite12" type="SpineSprite" parent="."]
+position = Vector2( 709.313, 123.253 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite13" type="SpineSprite" parent="."]
+position = Vector2( 769.245, 119.509 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite14" type="SpineSprite" parent="."]
+position = Vector2( 830.676, 119.511 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite15" type="SpineSprite" parent="."]
+position = Vector2( 892.106, 121.761 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite16" type="SpineSprite" parent="."]
+position = Vector2( 953.537, 121.763 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite17" type="SpineSprite" parent="."]
+position = Vector2( 56.0478, 207.883 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite18" type="SpineSprite" parent="."]
+position = Vector2( 113.733, 207.885 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite19" type="SpineSprite" parent="."]
+position = Vector2( 166.923, 207.887 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite20" type="SpineSprite" parent="."]
+position = Vector2( 219.363, 210.136 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite21" type="SpineSprite" parent="."]
+position = Vector2( 279.295, 209.389 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite22" type="SpineSprite" parent="."]
+position = Vector2( 339.977, 207.144 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite23" type="SpineSprite" parent="."]
+position = Vector2( 405.902, 209.394 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite24" type="SpineSprite" parent="."]
+position = Vector2( 466.584, 209.396 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite25" type="SpineSprite" parent="."]
+position = Vector2( 527.265, 209.399 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite26" type="SpineSprite" parent="."]
+position = Vector2( 591.692, 209.401 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite27" type="SpineSprite" parent="."]
+position = Vector2( 651.625, 210.152 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite28" type="SpineSprite" parent="."]
+position = Vector2( 711.557, 211.653 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite29" type="SpineSprite" parent="."]
+position = Vector2( 771.489, 207.909 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite30" type="SpineSprite" parent="."]
+position = Vector2( 832.92, 207.911 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite31" type="SpineSprite" parent="."]
+position = Vector2( 894.351, 210.161 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite32" type="SpineSprite" parent="."]
+position = Vector2( 955.781, 210.163 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite33" type="SpineSprite" parent="."]
+position = Vector2( 60.5394, 300.778 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite34" type="SpineSprite" parent="."]
+position = Vector2( 118.224, 300.78 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite35" type="SpineSprite" parent="."]
+position = Vector2( 171.414, 300.782 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite36" type="SpineSprite" parent="."]
+position = Vector2( 223.855, 303.032 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite37" type="SpineSprite" parent="."]
+position = Vector2( 283.787, 302.285 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite38" type="SpineSprite" parent="."]
+position = Vector2( 344.468, 300.039 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite39" type="SpineSprite" parent="."]
+position = Vector2( 410.394, 302.289 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite40" type="SpineSprite" parent="."]
+position = Vector2( 471.075, 302.292 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite41" type="SpineSprite" parent="."]
+position = Vector2( 531.757, 302.294 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite42" type="SpineSprite" parent="."]
+position = Vector2( 596.184, 302.296 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite43" type="SpineSprite" parent="."]
+position = Vector2( 656.116, 303.047 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite44" type="SpineSprite" parent="."]
+position = Vector2( 716.048, 304.548 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite45" type="SpineSprite" parent="."]
+position = Vector2( 775.981, 300.804 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite46" type="SpineSprite" parent="."]
+position = Vector2( 837.411, 300.807 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite47" type="SpineSprite" parent="."]
+position = Vector2( 898.842, 303.056 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite48" type="SpineSprite" parent="."]
+position = Vector2( 960.273, 303.059 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite49" type="SpineSprite" parent="."]
+position = Vector2( 60.5361, 389.178 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite50" type="SpineSprite" parent="."]
+position = Vector2( 118.221, 389.18 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite51" type="SpineSprite" parent="."]
+position = Vector2( 171.411, 389.182 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite52" type="SpineSprite" parent="."]
+position = Vector2( 223.851, 391.432 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite53" type="SpineSprite" parent="."]
+position = Vector2( 283.784, 390.685 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite54" type="SpineSprite" parent="."]
+position = Vector2( 344.465, 388.44 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite55" type="SpineSprite" parent="."]
+position = Vector2( 410.391, 390.689 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite56" type="SpineSprite" parent="."]
+position = Vector2( 471.072, 390.692 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite57" type="SpineSprite" parent="."]
+position = Vector2( 531.753, 390.694 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite58" type="SpineSprite" parent="."]
+position = Vector2( 596.181, 390.696 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite59" type="SpineSprite" parent="."]
+position = Vector2( 656.113, 391.448 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite60" type="SpineSprite" parent="."]
+position = Vector2( 716.045, 392.948 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite61" type="SpineSprite" parent="."]
+position = Vector2( 775.978, 389.204 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite62" type="SpineSprite" parent="."]
+position = Vector2( 837.408, 389.207 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite63" type="SpineSprite" parent="."]
+position = Vector2( 898.839, 391.456 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite64" type="SpineSprite" parent="."]
+position = Vector2( 960.269, 391.459 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite65" type="SpineSprite" parent="."]
+position = Vector2( 62.0311, 477.578 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite66" type="SpineSprite" parent="."]
+position = Vector2( 119.716, 477.581 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite67" type="SpineSprite" parent="."]
+position = Vector2( 172.906, 477.583 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite68" type="SpineSprite" parent="."]
+position = Vector2( 225.346, 479.832 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite69" type="SpineSprite" parent="."]
+position = Vector2( 285.279, 479.085 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite70" type="SpineSprite" parent="."]
+position = Vector2( 345.96, 476.84 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite71" type="SpineSprite" parent="."]
+position = Vector2( 411.886, 479.09 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite72" type="SpineSprite" parent="."]
+position = Vector2( 472.567, 479.092 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite73" type="SpineSprite" parent="."]
+position = Vector2( 533.248, 479.094 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite74" type="SpineSprite" parent="."]
+position = Vector2( 597.676, 479.096 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite75" type="SpineSprite" parent="."]
+position = Vector2( 657.608, 479.848 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite76" type="SpineSprite" parent="."]
+position = Vector2( 717.54, 481.348 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite77" type="SpineSprite" parent="."]
+position = Vector2( 777.473, 477.605 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite78" type="SpineSprite" parent="."]
+position = Vector2( 838.903, 477.607 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite79" type="SpineSprite" parent="."]
+position = Vector2( 900.334, 479.857 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite80" type="SpineSprite" parent="."]
+position = Vector2( 961.765, 479.859 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite81" type="SpineSprite" parent="."]
+position = Vector2( 66.5229, 562.233 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite82" type="SpineSprite" parent="."]
+position = Vector2( 124.208, 562.235 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite83" type="SpineSprite" parent="."]
+position = Vector2( 177.398, 562.237 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite84" type="SpineSprite" parent="."]
+position = Vector2( 229.838, 564.486 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite85" type="SpineSprite" parent="."]
+position = Vector2( 289.77, 563.74 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite86" type="SpineSprite" parent="."]
+position = Vector2( 350.452, 561.494 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite87" type="SpineSprite" parent="."]
+position = Vector2( 416.377, 563.744 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite88" type="SpineSprite" parent="."]
+position = Vector2( 477.059, 563.746 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite89" type="SpineSprite" parent="."]
+position = Vector2( 537.74, 563.749 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite90" type="SpineSprite" parent="."]
+position = Vector2( 602.167, 563.751 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite91" type="SpineSprite" parent="."]
+position = Vector2( 662.1, 564.502 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite92" type="SpineSprite" parent="."]
+position = Vector2( 722.032, 566.003 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite93" type="SpineSprite" parent="."]
+position = Vector2( 781.964, 562.259 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite94" type="SpineSprite" parent="."]
+position = Vector2( 843.395, 562.261 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite95" type="SpineSprite" parent="."]
+position = Vector2( 904.826, 564.511 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )
+
+[node name="SpineSprite96" type="SpineSprite" parent="."]
+position = Vector2( 966.256, 564.513 )
+scale = Vector2( 0.1, 0.1 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = ""
+preview_frame = false
+preview_time = 0.0
+script = ExtResource( 2 )

+ 53 - 0
spine-godot/example-v4/tests/ragdoll.tscn

@@ -0,0 +1,53 @@
+[gd_scene format=2]
+
+[node name="Node2D" type="Node2D"]
+
+[node name="A" type="RigidBody2D" parent="."]
+position = Vector2( 483, 158 )
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="A"]
+position = Vector2( 6, 17 )
+polygon = PoolVector2Array( -38, 6, 28, 6, 28, -45, -40, -45 )
+__meta__ = {
+"_edit_lock_": true
+}
+
+[node name="B" type="RigidBody2D" parent="."]
+position = Vector2( 484, 228 )
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="B"]
+position = Vector2( 6, 17 )
+polygon = PoolVector2Array( -38, 6, 28, 6, 28, -45, -40, -45 )
+__meta__ = {
+"_edit_lock_": true
+}
+
+[node name="C" type="RigidBody2D" parent="."]
+position = Vector2( 485, 296 )
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="C"]
+position = Vector2( 6, 17 )
+polygon = PoolVector2Array( -38, 6, 28, 6, 28, -45, -40, -45 )
+__meta__ = {
+"_edit_lock_": true
+}
+
+[node name="PinJoint2D" type="PinJoint2D" parent="."]
+position = Vector2( 484, 189 )
+node_a = NodePath("../A")
+node_b = NodePath("../B")
+bias = 0.9
+disable_collision = false
+
+[node name="PinJoint2D2" type="PinJoint2D" parent="."]
+position = Vector2( 486, 257 )
+node_a = NodePath("../B")
+node_b = NodePath("../C")
+bias = 0.9
+disable_collision = false
+
+[node name="Ground" type="StaticBody2D" parent="."]
+position = Vector2( 489, 478 )
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Ground"]
+polygon = PoolVector2Array( -116, -4, 128, -100, 204, 34, -156, 48 )

+ 26 - 0
spine-godot/example-v4/tests/transforms.tscn

@@ -0,0 +1,26 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://assets/spineboy/spineboy-data-res.tres" type="SpineSkeletonDataResource" id=1]
+[ext_resource path="res://icon.png" type="Texture" id=2]
+
+[node name="Node2D" type="Node2D"]
+
+[node name="SpineSprite" type="SpineSprite" parent="."]
+position = Vector2( 459.397, 501.236 )
+scale = Vector2( 0.742335, 0.742335 )
+skeleton_data_res = ExtResource( 1 )
+preview_animation = "aim"
+preview_frame = true
+preview_time = 0.0
+
+[node name="SpineBoneNode" type="SpineBoneNode" parent="SpineSprite"]
+position = Vector2( 40.8752, -276.036 )
+rotation = 0.837234
+bone_name = "gun"
+bone_mode = 1
+enabled = false
+color = Color( 0, 1, 0.0627451, 0.466667 )
+
+[node name="Sprite" type="Sprite" parent="SpineSprite/SpineBoneNode"]
+visible = false
+texture = ExtResource( 2 )

+ 39 - 0
spine-godot/example-v4/tests/unit-tests.gd

@@ -0,0 +1,39 @@
+extends SpineSprite
+
+func test_spine_animation():
+	var walkAnim: SpineAnimation = get_skeleton().get_data().find_animation("walk")
+	assert(walkAnim.get_name() == "walk")
+	var duration = walkAnim.get_duration()
+	walkAnim.set_duration(duration + 1)
+	assert(walkAnim.get_duration() == duration + 1)
+	assert(walkAnim.get_timelines().size() == 39)
+	var timeline: SpineTimeline = walkAnim.get_timelines()[0]
+	var propertyIds = timeline.get_property_ids()
+	assert(walkAnim.has_timeline(propertyIds))
+	assert(!walkAnim.has_timeline([0]))
+	
+func test_spine_timeline():
+	var walkAnim: SpineAnimation = get_skeleton().get_data().find_animation("walk")
+	var timeline: SpineTimeline = walkAnim.get_timelines()[0]
+	assert(timeline.get_duration() == 1)
+	assert(timeline.get_property_ids() == [4294967300])
+	assert(timeline.get_type() == "RotateTimeline")
+
+func test_spine_object_invalidation():
+	var skeleton_data = get_skeleton().get_data()
+	var bone_data = skeleton_data.find_bone("gun");
+	var old_bone_data_x = bone_data.get_x();
+	var bone = get_skeleton().find_bone("gun")
+	var old_bone_x = bone.get_x()
+	skeleton_data_res = null
+	assert(old_bone_x != bone.get_x())
+	assert(old_bone_data_x == bone_data.get_x())
+	skeleton_data.atlas_res = null;
+	assert(old_bone_data_x != bone_data.get_x())
+
+func _ready():
+	
+	test_spine_animation()
+	test_spine_timeline()
+	test_spine_object_invalidation()
+	print("All tests passed")

+ 12 - 0
spine-godot/example-v4/tests/unit-tests.tscn

@@ -0,0 +1,12 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://tests/unit-tests.gd" type="Script" id=1]
+[ext_resource path="res://assets/spineboy/spineboy-data-res.tres" type="SpineSkeletonDataResource" id=2]
+
+[node name="Node2D" type="Node2D"]
+position = Vector2( 496.659, 431.634 )
+scale = Vector2( 0.7, 0.7 )
+
+[node name="SpineSprite" type="SpineSprite" parent="."]
+skeleton_data_res = ExtResource( 2 )
+script = ExtResource( 1 )

BIN
spine-godot/example/assets/footstep.ogg


+ 15 - 0
spine-godot/example/assets/footstep.ogg.import

@@ -0,0 +1,15 @@
+[remap]
+
+importer="ogg_vorbis"
+type="AudioStreamOGGVorbis"
+path="res://.import/footstep.ogg-789c3f1e3c4e0ca3bebcb13f1160f623.oggstr"
+
+[deps]
+
+source_file="res://assets/footstep.ogg"
+dest_files=[ "res://.import/footstep.ogg-789c3f1e3c4e0ca3bebcb13f1160f623.oggstr" ]
+
+[params]
+
+loop=false
+loop_offset=0

+ 10 - 0
spine-godot/example/assets/mix-and-match/mix-and-match-data.tres

@@ -0,0 +1,10 @@
+[gd_resource type="SpineSkeletonDataResource" load_steps=3 format=2]
+
+[ext_resource path="res://assets/mix-and-match/mix-and-match.atlas" type="SpineAtlasResource" id=1]
+[ext_resource path="res://assets/mix-and-match/mix-and-match-pro.json" type="SpineSkeletonFileResource" id=2]
+
+[resource]
+atlas_res = ExtResource( 1 )
+skeleton_file_res = ExtResource( 2 )
+animations = null
+skins = null

File diff suppressed because it is too large
+ 1285 - 0
spine-godot/example/assets/mix-and-match/mix-and-match-pro.json


+ 13 - 0
spine-godot/example/assets/mix-and-match/mix-and-match-pro.json.import

@@ -0,0 +1,13 @@
+[remap]
+
+importer="spine.json"
+type="SpineSkeletonFileResource"
+path="res://.import/mix-and-match-pro.json-57325a5014e6fd56fc4a86824bc458ea.spjson"
+
+[deps]
+
+source_file="res://assets/mix-and-match/mix-and-match-pro.json"
+dest_files=[ "res://.import/mix-and-match-pro.json-57325a5014e6fd56fc4a86824bc458ea.spjson" ]
+
+[params]
+

+ 362 - 0
spine-godot/example/assets/mix-and-match/mix-and-match.atlas

@@ -0,0 +1,362 @@
+mix-and-match.png
+	size: 1024, 512
+	filter: Linear, Linear
+	scale: 0.5
+base-head
+	bounds: 587, 2, 95, 73
+boy/arm-front
+	bounds: 558, 271, 36, 115
+boy/backpack
+	bounds: 235, 109, 119, 153
+boy/backpack-pocket
+	bounds: 328, 73, 34, 62
+	rotate: 90
+boy/backpack-strap-front
+	bounds: 665, 79, 38, 88
+boy/backpack-up
+	bounds: 395, 364, 21, 70
+	rotate: 90
+boy/body
+	bounds: 251, 264, 97, 132
+	rotate: 90
+boy/boot-ribbon-front
+	bounds: 648, 131, 9, 11
+boy/collar
+	bounds: 744, 4, 73, 29
+	rotate: 90
+boy/ear
+	bounds: 383, 109, 19, 23
+	rotate: 90
+boy/eye-back-low-eyelid
+	bounds: 739, 284, 17, 6
+	rotate: 90
+boy/eye-back-pupil
+	bounds: 832, 443, 8, 9
+	rotate: 90
+boy/eye-back-up-eyelid
+	bounds: 558, 264, 23, 5
+boy/eye-back-up-eyelid-back
+	bounds: 802, 491, 19, 10
+	rotate: 90
+boy/eye-front-low-eyelid
+	bounds: 386, 363, 22, 7
+	rotate: 90
+boy/eye-front-pupil
+	bounds: 816, 389, 9, 9
+boy/eye-front-up-eyelid
+	bounds: 160, 71, 31, 6
+	rotate: 90
+boy/eye-front-up-eyelid-back
+	bounds: 801, 434, 26, 9
+	rotate: 90
+boy/eye-iris-back
+	bounds: 618, 264, 17, 17
+boy/eye-iris-front
+	bounds: 727, 264, 18, 18
+boy/eye-white-back
+	bounds: 580, 131, 20, 12
+boy/eye-white-front
+	bounds: 510, 130, 27, 13
+boy/eyebrow-back
+	bounds: 751, 88, 20, 11
+	rotate: 90
+boy/eyebrow-front
+	bounds: 483, 130, 25, 11
+boy/hair-back
+	bounds: 494, 388, 122, 81
+	rotate: 90
+boy/hair-bangs
+	bounds: 667, 284, 70, 37
+boy/hair-side
+	bounds: 789, 374, 25, 43
+boy/hand-backfingers
+	bounds: 467, 364, 19, 21
+boy/hand-front-fingers
+	bounds: 488, 364, 19, 21
+boy/hat
+	bounds: 615, 417, 93, 56
+	rotate: 90
+boy/leg-front
+	bounds: 138, 104, 31, 158
+boy/mouth-close
+	bounds: 551, 365, 21, 5
+	rotate: 90
+girl-blue-cape/mouth-close
+	bounds: 551, 365, 21, 5
+	rotate: 90
+girl-spring-dress/mouth-close
+	bounds: 551, 365, 21, 5
+	rotate: 90
+girl/mouth-close
+	bounds: 551, 365, 21, 5
+	rotate: 90
+boy/mouth-smile
+	bounds: 705, 79, 29, 7
+boy/nose
+	bounds: 836, 473, 17, 10
+	rotate: 90
+boy/pompom
+	bounds: 747, 273, 48, 43
+	rotate: 90
+boy/zip
+	bounds: 648, 144, 14, 23
+girl-blue-cape/back-eyebrow
+	bounds: 602, 131, 18, 12
+girl-blue-cape/body-dress
+	bounds: 2, 264, 109, 246
+girl-blue-cape/body-ribbon
+	bounds: 615, 283, 50, 38
+girl-blue-cape/cape-back
+	bounds: 2, 69, 134, 193
+girl-blue-cape/cape-back-up
+	bounds: 386, 387, 123, 106
+	rotate: 90
+girl-blue-cape/cape-ribbon
+	bounds: 675, 264, 50, 18
+girl-blue-cape/cape-shoulder-back
+	bounds: 751, 110, 49, 59
+girl-blue-cape/cape-shoulder-front
+	bounds: 113, 264, 62, 76
+	rotate: 90
+girl-blue-cape/cape-up-front
+	bounds: 399, 264, 98, 117
+	rotate: 90
+girl-blue-cape/ear
+	bounds: 775, 2, 19, 23
+girl-spring-dress/ear
+	bounds: 775, 2, 19, 23
+girl/ear
+	bounds: 775, 2, 19, 23
+girl-blue-cape/eye-back-low-eyelid
+	bounds: 802, 463, 17, 6
+girl-spring-dress/eye-back-low-eyelid
+	bounds: 802, 463, 17, 6
+girl/eye-back-low-eyelid
+	bounds: 802, 463, 17, 6
+girl-blue-cape/eye-back-pupil
+	bounds: 816, 367, 8, 9
+girl-spring-dress/eye-back-pupil
+	bounds: 816, 367, 8, 9
+girl/eye-back-pupil
+	bounds: 816, 367, 8, 9
+girl-blue-cape/eye-back-up-eyelid
+	bounds: 554, 131, 24, 12
+girl-spring-dress/eye-back-up-eyelid
+	bounds: 554, 131, 24, 12
+girl/eye-back-up-eyelid
+	bounds: 554, 131, 24, 12
+girl-blue-cape/eye-back-up-eyelid-back
+	bounds: 832, 453, 17, 11
+	rotate: 90
+girl-spring-dress/eye-back-up-eyelid-back
+	bounds: 832, 453, 17, 11
+	rotate: 90
+girl/eye-back-up-eyelid-back
+	bounds: 832, 453, 17, 11
+	rotate: 90
+girl-blue-cape/eye-front-low-eyelid
+	bounds: 739, 303, 18, 6
+	rotate: 90
+girl-spring-dress/eye-front-low-eyelid
+	bounds: 739, 303, 18, 6
+	rotate: 90
+girl/eye-front-low-eyelid
+	bounds: 739, 303, 18, 6
+	rotate: 90
+girl-blue-cape/eye-front-pupil
+	bounds: 816, 378, 9, 9
+girl-spring-dress/eye-front-pupil
+	bounds: 816, 378, 9, 9
+girl/eye-front-pupil
+	bounds: 816, 378, 9, 9
+girl-blue-cape/eye-front-up-eyelid
+	bounds: 392, 77, 30, 14
+	rotate: 90
+girl-spring-dress/eye-front-up-eyelid
+	bounds: 392, 77, 30, 14
+	rotate: 90
+girl/eye-front-up-eyelid
+	bounds: 392, 77, 30, 14
+	rotate: 90
+girl-blue-cape/eye-front-up-eyelid-back
+	bounds: 455, 130, 26, 11
+girl-spring-dress/eye-front-up-eyelid-back
+	bounds: 455, 130, 26, 11
+girl/eye-front-up-eyelid-back
+	bounds: 455, 130, 26, 11
+girl-blue-cape/eye-iris-back
+	bounds: 637, 264, 17, 17
+girl-blue-cape/eye-iris-front
+	bounds: 802, 471, 18, 18
+girl-blue-cape/eye-white-back
+	bounds: 596, 264, 20, 16
+girl-spring-dress/eye-white-back
+	bounds: 596, 264, 20, 16
+girl-blue-cape/eye-white-front
+	bounds: 796, 5, 20, 16
+	rotate: 90
+girl-spring-dress/eye-white-front
+	bounds: 796, 5, 20, 16
+	rotate: 90
+girl/eye-white-front
+	bounds: 796, 5, 20, 16
+	rotate: 90
+girl-blue-cape/front-eyebrow
+	bounds: 608, 149, 18, 12
+	rotate: 90
+girl-blue-cape/hair-back
+	bounds: 508, 145, 117, 98
+	rotate: 90
+girl-blue-cape/hair-bangs
+	bounds: 673, 419, 91, 40
+	rotate: 90
+girl-blue-cape/hair-head-side-back
+	bounds: 196, 331, 30, 52
+	rotate: 90
+girl-blue-cape/hair-head-side-front
+	bounds: 738, 323, 41, 42
+girl-blue-cape/hair-side
+	bounds: 473, 3, 36, 71
+girl-blue-cape/hand-front-fingers
+	bounds: 509, 365, 19, 21
+girl-spring-dress/hand-front-fingers
+	bounds: 509, 365, 19, 21
+girl-blue-cape/leg-front
+	bounds: 168, 72, 30, 158
+	rotate: 90
+girl-blue-cape/mouth-smile
+	bounds: 736, 79, 29, 7
+girl-spring-dress/mouth-smile
+	bounds: 736, 79, 29, 7
+girl/mouth-smile
+	bounds: 736, 79, 29, 7
+girl-blue-cape/nose
+	bounds: 747, 264, 11, 7
+girl-spring-dress/nose
+	bounds: 747, 264, 11, 7
+girl/nose
+	bounds: 747, 264, 11, 7
+girl-blue-cape/sleeve-back
+	bounds: 767, 79, 42, 29
+girl-blue-cape/sleeve-front
+	bounds: 408, 76, 52, 119
+	rotate: 90
+girl-spring-dress/arm-front
+	bounds: 596, 282, 17, 111
+girl-spring-dress/back-eyebrow
+	bounds: 801, 420, 18, 12
+girl-spring-dress/body-up
+	bounds: 179, 4, 64, 66
+girl-spring-dress/cloak-down
+	bounds: 775, 27, 50, 50
+girl-spring-dress/cloak-up
+	bounds: 360, 7, 64, 58
+	rotate: 90
+girl-spring-dress/eye-iris-back
+	bounds: 656, 264, 17, 17
+girl-spring-dress/eye-iris-front
+	bounds: 814, 492, 18, 18
+girl-spring-dress/front-eyebrow
+	bounds: 822, 472, 18, 12
+	rotate: 90
+girl-spring-dress/hair-back
+	bounds: 196, 363, 147, 93
+	rotate: 90
+girl-spring-dress/hair-bangs
+	bounds: 696, 326, 91, 40
+	rotate: 90
+girl-spring-dress/hair-head-side-back
+	bounds: 529, 76, 30, 52
+girl-spring-dress/hair-head-side-front
+	bounds: 781, 323, 41, 42
+girl-spring-dress/hair-side
+	bounds: 511, 3, 36, 71
+girl-spring-dress/leg-front
+	bounds: 171, 104, 30, 158
+girl-spring-dress/neck
+	bounds: 138, 70, 20, 32
+girl-spring-dress/shoulder-ribbon
+	bounds: 622, 131, 36, 24
+	rotate: 90
+girl-spring-dress/skirt
+	bounds: 113, 328, 182, 81
+	rotate: 90
+girl-spring-dress/underskirt
+	bounds: 2, 2, 175, 65
+girl/arm-front
+	bounds: 577, 395, 36, 115
+girl/back-eyebrow
+	bounds: 834, 492, 18, 12
+	rotate: 90
+girl/bag-base
+	bounds: 191, 264, 62, 58
+	rotate: 90
+girl/bag-strap-front
+	bounds: 385, 265, 12, 96
+girl/bag-top
+	bounds: 738, 367, 49, 50
+girl/body
+	bounds: 356, 130, 97, 132
+girl/boot-ribbon-front
+	bounds: 539, 130, 13, 13
+girl/eye-iris-back
+	bounds: 821, 424, 17, 17
+girl/eye-iris-front
+	bounds: 812, 443, 18, 18
+girl/eye-white-back
+	bounds: 814, 5, 20, 16
+	rotate: 90
+girl/front-eyebrow
+	bounds: 816, 400, 18, 12
+	rotate: 90
+girl/hair-back
+	bounds: 291, 363, 147, 93
+	rotate: 90
+girl/hair-bangs
+	bounds: 715, 419, 91, 40
+	rotate: 90
+girl/hair-flap-down-front
+	bounds: 288, 5, 70, 65
+girl/hair-head-side-back
+	bounds: 561, 77, 30, 52
+girl/hair-head-side-front
+	bounds: 757, 419, 41, 42
+	rotate: 90
+girl/hair-patch
+	bounds: 245, 4, 66, 41
+	rotate: 90
+girl/hair-side
+	bounds: 549, 3, 36, 71
+girl/hair-strand-back-1
+	bounds: 684, 3, 58, 74
+girl/hair-strand-back-2
+	bounds: 692, 171, 91, 58
+	rotate: 90
+girl/hair-strand-back-3
+	bounds: 615, 323, 92, 79
+	rotate: 90
+girl/hair-strand-front-1
+	bounds: 518, 269, 38, 94
+girl/hair-strand-front-2
+	bounds: 593, 79, 70, 50
+girl/hair-strand-front-3
+	bounds: 705, 88, 44, 81
+girl/hand-front-fingers
+	bounds: 530, 365, 19, 21
+girl/hat
+	bounds: 608, 169, 93, 82
+	rotate: 90
+girl/leg-front
+	bounds: 203, 104, 30, 158
+girl/pompom
+	bounds: 757, 462, 48, 43
+	rotate: 90
+girl/scarf
+	bounds: 455, 143, 119, 51
+	rotate: 90
+girl/scarf-back
+	bounds: 420, 2, 72, 51
+	rotate: 90
+girl/zip
+	bounds: 356, 109, 19, 25
+	rotate: 90

+ 14 - 0
spine-godot/example/assets/mix-and-match/mix-and-match.atlas.import

@@ -0,0 +1,14 @@
+[remap]
+
+importer="spine.atlas"
+type="SpineAtlasResource"
+path="res://.import/mix-and-match.atlas-3d349b543ecdcc01fb29033adaef0841.spatlas"
+
+[deps]
+
+source_file="res://assets/mix-and-match/mix-and-match.atlas"
+dest_files=[ "res://.import/mix-and-match.atlas-3d349b543ecdcc01fb29033adaef0841.spatlas" ]
+
+[params]
+
+normal_map_prefix="n"

BIN
spine-godot/example/assets/mix-and-match/mix-and-match.png


+ 35 - 0
spine-godot/example/assets/mix-and-match/mix-and-match.png.import

@@ -0,0 +1,35 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/mix-and-match.png-c2d8e28d9f2efc380ff8b95a22dadcc3.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/mix-and-match/mix-and-match.png"
+dest_files=[ "res://.import/mix-and-match.png-c2d8e28d9f2efc380ff8b95a22dadcc3.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+process/normal_map_invert_y=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0

+ 16 - 0
spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.atlas

@@ -0,0 +1,16 @@
+Raggedy Spineboy.png
+	size: 256, 256
+	filter: Linear, Linear
+	pma: true
+arm
+	bounds: 2, 140, 71, 75
+	rotate: 90
+head
+	bounds: 2, 2, 136, 187
+	rotate: 90
+leg
+	bounds: 2, 213, 36, 99
+	rotate: 90
+torso
+	bounds: 103, 187, 62, 95
+	rotate: 90

+ 14 - 0
spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.atlas.import

@@ -0,0 +1,14 @@
+[remap]
+
+importer="spine.atlas"
+type="SpineAtlasResource"
+path="res://.import/Raggedy Spineboy.atlas-07f7c6b30431397bcf472b18d48851e0.spatlas"
+
+[deps]
+
+source_file="res://assets/raggedyspineboy/Raggedy Spineboy.atlas"
+dest_files=[ "res://.import/Raggedy Spineboy.atlas-07f7c6b30431397bcf472b18d48851e0.spatlas" ]
+
+[params]
+
+normal_map_prefix="n"

BIN
spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.png


+ 35 - 0
spine-godot/example/assets/raggedyspineboy/Raggedy Spineboy.png.import

@@ -0,0 +1,35 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/Raggedy Spineboy.png-8982b59aad5b612b7ed1a5da8b447d00.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/raggedyspineboy/Raggedy Spineboy.png"
+dest_files=[ "res://.import/Raggedy Spineboy.png-8982b59aad5b612b7ed1a5da8b447d00.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+process/normal_map_invert_y=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0

+ 8 - 0
spine-godot/example/assets/raggedyspineboy/raggedy spineboy-res.tres

@@ -0,0 +1,8 @@
+[gd_resource type="SpineSkeletonDataResource" load_steps=3 format=2]
+
+[ext_resource path="res://assets/raggedyspineboy/Raggedy Spineboy.atlas" type="SpineAtlasResource" id=1]
+[ext_resource path="res://assets/raggedyspineboy/raggedy spineboy.json" type="SpineSkeletonFileResource" id=2]
+
+[resource]
+atlas_res = ExtResource( 1 )
+skeleton_file_res = ExtResource( 2 )

File diff suppressed because it is too large
+ 46 - 0
spine-godot/example/assets/raggedyspineboy/raggedy spineboy.json


Some files were not shown because too many files changed in this diff