Nick

My command line is
Spine -i Kids.spine -e "toBinary.export.json" -o "./export_out"
Here is the console log:
Spine Launcher 3.8.82
Esoteric Software LLC (C) 2013-2020 | http://esotericsoftware.com
Windows 10 Enterprise x86 10.0
Spine 3.8.97 Professional
Licensed to: XXXXXX
Intel, Intel(R) UHD Graphics 630, 4.6.0 - Build 26.20.100.7263
Binary export: Kids
Complete.
Did I do something wrong?

---

Btw, why is export from command line so slow?
When exporting from UI, exporting without texture packing is almost immediately done.
Bạn không được cấp phép để xem tập tin đính kèm trong bài viết này.
Nick
  • Bài viết: 151

Nate

The order of the parameters is important. Some parameters are used by later parameters, like -i and -o, while others are "terminal" and perform an action, like -e. When -e is encountered the export is performed, so it uses the output path in the .export.json file rather than the path specified with -o. We'll see about making it an error to specify non-terminal parameters at the end of the parameter list.

When Spine needs to render images it uses OpenGL (and similar technology) and has to setup nearly everything needed to run the editor as normal. When exports don't require OpenGL, they are run "headless" and exporting is a lot faster. Since you are packing an atlas, unfortunately the export takes long. It will be faster in v4 though.
Hình đại diện của thành viên
Nate

Nate
  • Bài viết: 9835

Nick

Nice. I changed the order of parameters and now it works as expected.
making it an error to specify non-terminal parameters at the end of the parameter list.
You may want to consider reading all the parameters into a dictionary first and parse accordingly to eliminate the ordering restriction.

Can you add a new parameter, say -skin, to override the skin export checkbox values and have command line being able to export certain skin to certain folder? That would make things much easier because changing output path and the skin export check box values for each export is not that convenient in the editor. Saving them to export script file is more reliable.
Spine -i "Kids.spine" -o "./HomeTownKids" -skin "HomeTown_Boy, HomeTown_Girl" -e "toBinary.export.json"
Thanks
Looking forward to 4.0.
Nick
  • Bài viết: 151

Nate

Nick đã viết:You may want to consider reading all the parameters into a dictionary first and parse accordingly to eliminate the ordering restriction.
Order is important by design. You can write export scripts like this:
spine-runtimes/export.sh at 3.8
Nick đã viết:Can you add a new parameter, say -skin, to override the skin export checkbox values and have command line being able to export certain skin to certain folder?
The could be useful. Maybe we could make it more general purpose, allowing any values in the settings JSON to be overwritten. Eg something like:
spine -i project.spine -o dir --set skin=something --set packAtlas/rotation=false -e settings.export.json
Hình đại diện của thành viên
Nate

Nate
  • Bài viết: 9835

Nick

Order is important by design. You can write export scripts like this:
spine-runtimes/export.sh at 3.8
Ah I see. The arguments are read as a stream of command to have the app exporting multiple projects consecutively.
This is one way to go. Another approach is to let each command run its own spine.exe instance in parallel (may be cap to 4-8 instance to be safe) to make good use of the available system resources. We generally have lost of CPU core + VRAM on today's PC. That could make batch export much faster. Just an idea. Not that important as currently implementation will work too.
Nate đã viết:The could be useful. Maybe we could make it more general purpose
Agree. That is more flexible. Just that don't forget to add the "skin" property when implementing this one as 'skin' prop is not exist in the json yet.

Thanks
Nick
  • Bài viết: 151

Nate

Ah, I thought you meant to choose a skin for image of video export. You mean instead to export JSON or binary data, but only for a single skin? Exporting a partial skeleton is not a workflow we recommend. Can you please explain your needs for this?
Hình đại diện của thành viên
Nate

Nate
  • Bài viết: 9835

Nick

I have characters that share the same skeleton and animations but in different skins.

The kids project i uploaded is one example. Those kids including boys and girls from different locations. In game, they will never be loaded at the same time. Thus I want to make things simple and export them to different folders instead of packing them into one big atlas set.

Example:
<Unity Asset Folder>/units/kingdom/kids
<Unity Asset Folder>/units/hometown/kids
<Unity Asset Folder>/units/harbor/kids

Note that being able to export them separately is also fundamental to create patch file for game update. I cannot ask player to download already downloaded characters again and again just because they shared the same spine project and I just updated very little thing with the project. Say, I fixed some issues with 1 character from a 5 character spine project. I would like to deliver a patch file with only the affected character to the game client.

I found that I could export it correctly by checking / unchecking the 'export' checkbox of the skin in the Spine editor.
However, this also involve setting the output path for each skin export. This not only require quit some effort but is also error prune when compared to doing it in a predefined script file.
That's why I want the script file being able to choose which skins to export. Current command line can already override the output folder. Just missing the skin override to have the magic happens.

For a project has many skins for different characters, if some shared modification happens, all the affected exports need to be updated. Doing the export in command line seems to be the best way to do. No need to change any config. Just run corresponding script file.
Nick
  • Bài viết: 151

Nate

Your kids project binary export is 92KB and 56.7KB zipped. Exporting the same but just one skin is 13-33KB zipped. That is not much savings per skeleton and actually makes the total amount of data larger, as some data is duplicated in each skeleton. 56KB is already very small, eg it is common to see multiple images on a website that size or larger. Other projects may have larger exports, but are still likely to be small enough to not be worth the extra trouble of exporting the skeleton for each skin.

The skeleton data is very small and I haven't yet seen a use case where it makes sense to do a partial export of the skeleton.

Loading that much data at runtime is also unlikely to make a difference. Note you don't need to load the images for the unused skins.
Hình đại diện của thành viên
Nate

Nate
  • Bài viết: 9835

Nick

Your kids project binary export is 92KB and 56.7KB zipped. Exporting the same but just one skin is 13-33KB zipped.
Can't just consider the skeleton export file size without the texture...Content updates could be including both binary data and texture. e.g. adding new characters.

Also its not just about the download file size but also the file placement design. In my game, almost each character, except those mix and match player heroes, are saved under its own folder along with their other configuration files. I just found this much easier to work when they are grouped properly.
<AssetFolder>/Units/Kingdom/A
<AssetFolder>/Units/Kingdom/B
<AssetFolder>/Units/Hometown/C
<AssetFolder>/Units/Hometown/D
<AssetFolder>/Units/Harbor/E
<AssetFolder>/Units/Harbor/F

vs

<AssetFolder>/Units/ABCDEF
As I mentioned before. I am already doing it this way and found it working very well. Just that I want an extra command (-skin) to further improve the workflow making it possible to export fully outside the spine editor. Please consider to take one step further to support it. It would be very appreciated if such command can be added.

Thanks.
Nick
  • Bài viết: 151

Nate

Nick đã viết:Can't just consider the skeleton export file size without the texture...Content updates could be including both binary data and texture.
Understood, but the skeleton data file is separate from the images. The images are generally much larger and it can make sense to break them up per skin, or however else is needed. That can be done while keeping a single skeleton data file, which I still think is the simplest and easiest solution.
Nick đã viết:In my game, almost each character, except those mix and match player heroes, are saved under its own folder along with their other configuration files. I just found this much easier to work when they are grouped properly.
It makes sense to organized the images this way. Are there reasons using a single skeleton data file would be problematic with this organization?

I don't mean to be argumentative, I just want to fully understand the use case. Interrogation like this is helpful not just for considering this feature, but when thinking about the whole application.
Nick đã viết:It would be very appreciated if such command can be added.
By adding such a feature, it will encourage the export of partial skeletons. For us to do that, it needs to be a workflow we want to encourage, or at the very least we think makes sense in some cases even if it is generally suboptimal in most.

For example, since the beginning of Spine we've gotten requests to export a skeleton to multiple files, for example each animation in a separate file. Usually the rationale is to be able to update a skeleton piecemeal. This is a Bad Idea for a number of reasons: it's a prematurely optimization since the entire skeleton data is small, but mostly that it will be difficult to manage (ie a huge mess) because the animations have dependencies on the skeleton data. We declined to add such an export and Spine's usage benefits from the simplicity.

Your exporting each skin as a separate skeleton is of course a different solution than that, it was just an example where sometimes it's better for us not to enable a workflow. If you are adamant about your solution, it may be easiest to write a tool that takes an export containing all the skins and saves a file for each skin that contains the entire skeleton but only that skin. Writing a tool for JSON is easier than binary, so you could process the JSON, then use the Spine CLI to convert the JSON files to binary. Here\'s some Java that manipulates skeleton JSON, it could be used as a base for such a tool.
Hình đại diện của thành viên
Nate

Nate
  • Bài viết: 9835

Nick

Hold on, I am a little confused here. Need to confirm on something first.
It makes sense to organized the images this way. Are there reasons using a single skeleton data file would be problematic with this organization?
Before I try to export each skins of a spine project to its own skeleton and texture package using the editor, I actually tried to export them with two script files.

One script for exporting selected skins texture to their corresponding unit folders.
Another script for exporting the same skeleton binary file which include all the skins also to the unit folders.

The Output is something like:

Unit_A\Texture_A
Unit_A\SAME_SKELETON_FILE

Unit_B\Texture_B
Unit_B\SAME_SKELETON_FILE
...

However, in this way, the runtime will give me error because the SAME_SKELETON_FILE always failed to find some sprites due to the texture file only contain sprites from selected skin. That's why I concluded that the skeleton file need to be precise to only export with skins used for it to load correctly. Thus I turned to toggling the "export" check box of the skin during Spine editor export. Finally I am here requesting to be able to do the same from command line.

So my first question is, it is the expected behavior that using the export all skeleton binary with a partially exported skin texture would cause error in runtime?
By adding such a feature, it will encourage the export of partial skeletons.
What does "partial skeleton" means? A skeleton file only use some of the skins from the project? I don't mind the skeleton to be a full skeleton as long as it can load the only skins I exported with it correctly. All I want is to have files of a unit self contained under it own folder for easy management.


About the decision whether to have an extra -skin command, my comment is, if such configuration can be done from the UI, making it to be possible from command line would not do more harm (but it help me in situation like this). If those skin export check boxes are evil, they should not be exist in the first place but they are doing well in my opinion.

The last thing I want to understand is the work to enable the -skin command. I expected it to be as simple as reading the skin names from command line and flipping a few booleans for the skins before export. Just like how it does from UI. Am I getting it wrong? On the other hand, what you mentioned about writing a tool to parse and extract the json and doing binary conversion, that sounds like a lot of work... :(
Nick
  • Bài viết: 151

Nate

Nick đã viết:the runtime will give me error because the SAME_SKELETON_FILE always failed to find some sprites due to the texture file only contain sprites from selected skin. That's why I concluded that the skeleton file need to be precise to only export with skins used for it to load correctly.
See here:
Loading Skeleton Data - Spine Runtimes Guide: JSON and binary data

SkeletonJson/SkeletonBinary load the skeleton data. When an attachment is encountered, an AttachmentLoader is used to create and partially configure the attachment. It is most common to use AtlasAttachmentLoader, which uses the attachment's path to find a texture region in a texture atlas. If it can't find a region, it throws an error, which is likely what you encountered.

Using AtlasAttachmentLoader is not mandatory. You can provide your own AttachmentLoader when the SkeletonJson/SkeletonBinary is created. This allows you to:

1) Customize how attachments are created. For example, you could subclass an attachment class to store additional data or modify its behavior.

2) Do any preparation necessary to render the attachment later. For example, AtlasAttachmentLoader sets the RegionAttachment rendererObject and MeshAttachment rendererObject to the region from the texture atlas (note it also gives the region to the attachment to set the UVs), then rendering code specific to the game toolkit in use gets the renderer object and knows how to draw it.

Your AttachmentLoader can customize this. For example, you don't have to use a texture atlas, you could prepare SVG or do whatever else you need. Note that you may need to also customize the skeleton rendering to match.

Finally getting around to the point of all this fantastic storytelling, your AttachmentLoader doesn't have to set the renderer object at all. Note that the attachment's skin is passed to the AttachmentLoader. You could copy/paste AtlasAttachmentLoader and modify it to skip looking up atlas regions except for a particular skin. Of course you probably won't be able to render attachments with no renderer object, but that can be OK if you know you don't want to render those anyway, or you could resolve the renderer object later.

Some projects have thousands of attachments and they use an AttachmentLoader that doesn't load any images. Later, they configure all their skeletons with the attachments based on the game state, then they load the images needed only for those attachments (you may want to also consider attachments set by animations). Some projects even pack an atlas at runtime containing only the necessary images (spine-unity has utility functions to do this).

You might notice the AttachmentLoader methods say you can return null to skip loading the attachment completely. This could save you a little bit of memory and load faster, since it won't bother creating and populating attachment objects for attachments you know you won't render. Be wary of doing this for meshes though, if null is returned for a source mesh, all linked meshes for that source mesh should also return null. Since you only get the skin, name, and path of the mesh, there's not actually enough information to know if it's a source mesh. We should improve this.
Nick đã viết:What does "partial skeleton" means?
I mean that the data export is a configuration of the skeleton that differs from the project file. Your use case at least has the whole skeleton and the difference is just which skins are included, so it's not as bad as, for example, exporting animations to separate files.
Nick đã viết:If those skin export check boxes are evil, they should not be exist in the first place
It's a pretty different scenario to see a skin in the editor and not want it exported for reasons versus exporting the same skeleton many times with different skins.
Nick đã viết:what you mentioned about writing a tool to parse and extract the json and doing binary conversion, that sounds like a lot of work
Neither are terribly hard really. The JsonRollback tool almost does what is needed already. It's more about whether setting the skin export flag from the CLI is the right thing to add, as well as us having thousands of not terribly hard things on top of the many hard things we are working on.
Hình đại diện của thành viên
Nate

Nate
  • Bài viết: 9835

Nick

Thank you for your detailed response.

Sorry to let you know that, as an indie game developer doing coding and artworks, I am already working 10+ hrs a day 7x24 and I don't really have much time to dig into these custom loader stuff. I think I will stick to custom exporting from the editor UI right now although it is not as convenient as command line, it is simple enough for me. I may have time to explore what you mentioned about the JsonRollback in the future but now is just not the right time.
Nick
  • Bài viết: 151

Nate

I certainly understand not having enough time in the day! A custom AttachmentLoader is normal Spine Runtimes usage though. Maybe it sounded more complex than it is, as I wanted to give an understanding of the whole thing. The simplest thing you can do is copy/paste AtlasAttachmentLoader and simply not throw an error if the region is not found in the atlas. That way you can load your skeleton data with an atlas that only has images for one skin. I would recommend this rather than skin export checkboxes or JSON processing.
Hình đại diện của thành viên
Nate

Nate
  • Bài viết: 9835

Nick

You mean I just modify the runtime code directly and change
if (region == null)
throw new ArgumentException(string.Format("Region not found in atlas: {0} (region attachment: {1})",
path, name));
to
if (region == null)
return null;
in the NewRegionAttachment()? because I don't see I could pass a new AtlasAttachmentLoader to the runtime. It is making its instance internally.

If it is that simple, I will definitely do it this way.
Nick
  • Bài viết: 151

Nate

Modifying AtlasAttachmentLoader would work yeah. Or you can pass the attachment loader when you create the SkeletonJson or SkeletonBinary. There is a constructor that takes an AttachmentLoader.
Hình đại diện của thành viên
Nate

Nate
  • Bài viết: 9835


Quay về Editor