• RuntimesBugs
  • Inconsistent runtime behaviour cross languages for "region not found"

  • Изменено

Problem statement

1) I tried to load a .skel file with spine-c, 2) I'd expect it to be loaded and play like it does with the java runtime, and 3) It failed with

Region not found: empty

Runtime information

My program is built with spine-c tagged 4.1 from github, and I tested the java runtime by building the skeleton viewer from the same revision.
I also tested with SkeletonViewer 4.1.24 jar from the site, the asset loads and plays.

It appears with the Java Runtime, findRegion will return a fake AtlasRegion, when it failed to find the region with a given name, therefore RuntimeException("Region not found in atlas... will never be thrown by the loader.
Whereas with spine-c, it'll set the error message "Region not found: <name>" and abort loading.
Why is the difference? Is it a mistake/bug or by design? If it's by design then it's a bug in design which makes the SkeletonViewer quite useless as a tool for reference.

	public AtlasRegion findRegion (String name) {
		AtlasRegion region = super.findRegion(name);
		if (region == null) {
			// Look for separate image file.
			FileHandle file = viewer.skeletonFile.sibling(name + ".png");
			if (file.exists()) {
				Texture texture = new Texture(file);
				texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
				region = new AtlasRegion(texture, 0, 0, texture.getWidth(), texture.getHeight());
				region.name = name;
			}
		}
		return region != null ? region : fake;
	}
...
			AtlasRegion region = atlas.findRegion(path);
			if (region == null)
				throw new RuntimeException("Region not found in atlas: " + path + " (region attachment: " + name + ")"); // It never throws!?
			attachment.setRegion(region);
spAtlasRegion *spAtlas_findRegion(const spAtlas *self, const char *name) {
	spAtlasRegion *region = self->regions;
	while (region) {
		if (strcmp(region->name, name) == 0) return region;
		region = region->next;
	}
	return 0;
}
spAttachment *_spAtlasAttachmentLoader_createAttachment( ...
                               spAtlasRegion *region = spAtlas_findRegion(self->atlas, path);
				if (!region) {
					spAttachment_dispose(SUPER(attachment));
					_spAttachmentLoader_setError(loader, "Region not found: ", path);
					return 0;
				}
Related Discussions
...

The difference in behavior between the Java and C runtimes regarding the "region not found" issue is by design. In the Java runtime, the findRegion method in the SkeletonViewer creates a "fake" AtlasRegion if the region is not found, allowing the process to continue without throwing an exception. This is useful for visualization purposes in the SkeletonViewer, where missing regions can be ignored to some extent. On the other hand, the spine-c runtime strictly requires all regions to be present in the atlas, and if a region is not found, it sets an error message and aborts loading. This strict behavior is typical for production environments where missing assets should be flagged as errors. The SkeletonViewer's behavior is intended to be more lenient for debugging and visualization, which is why it handles missing regions differently.

  • Agricola ответили на это сообщение.

    Spinebot Thanks for the clarification!
    I'm not convinced by the rationale though. I expected the SkeletonViewer as the reference Spine runtime. It should not be this lenient without even a warning message.

    • Davide ответили на это сообщение.

      Agricola

      The SkeletonViewer is not the reference Spine runtime — spine-libgdx is.
      findRegion should not return a fake texture, and it does not in the reference runtime. spine-libgdx uses findRegion from libgdx directly, which behaves identically to the version in spine-c.

      You should compare AtlasAttachmentLoader.c with AtlasAttachmentLoader.java.
      As you can see, both throw an error if the region does not exist.

      Note that AtlasAttachmentLoader extends AttachmentLoader. AttachmentLoader is one of the runtime components frequently customized to implement specific behaviors, as explained in our runtime documentation.
      A common customization is to modify AtlasAttachmentLoader so that it does not throw an error when a region is missing. This allows users to start their game even if some regions are not yet loaded.

      If you need that behavior, you can simply copy the default AtlasAttachmentLoader and remove the error thrown when a region is not found. You can even return a fake texture with a dummy image.

      We prefer the default AttachmentLoader to fail fast by throwing an error at startup when a region is missing, rather than causing errors unpredictably later when the region is accessed.

      • Agricola ответили на это сообщение.

        Davide Thanks a lot! I just realized that the findRegion method is an extension from SkeletonViewerAtlas.java. Still it'll really help if SkeletonViewer hints what it's allowing in contrast to the standard runtime.