-
Notifications
You must be signed in to change notification settings - Fork 8
Plugin Docs: Texture Plugins
MoreMcmeta texture plugins implement texturing effects.
Every texture plugin is applied to a particular texture if its metadata contains the plugin's section name. The section
name is returned by the sectionName() method of MoreMcmetaTexturePlugin.
For example, the section name of the MoreMcmeta default animation plugin is "animation". If an "animation" sub view
is present in a texture's MetadataView, then the animation plugin will be applied to that texture.
If two plugins have the same section name, and one plugin is a default plugin, then the default plugin will be disabled. If two plugins have the same section name, but neither is a default plugin, then there will be a conflict.
The MetadataAnalyzer takes a MetadataView that contains all metadata for a given section. You do not need to
retrieve the sub view assigned to your plugin's section name; that sub view is already provided to you.
MetadataView allows for values of all the Java primitive types, as well as InputStreams for binary data. If a value
cannot be coerced into the requested typed, or a value does not exist at the given key or index, then the view returns
Optional.empty(). Numerical conversions are lossless; MetadataView will not do lossy conversions. MetadataView
does not differentiate between key-value objects and arrays: they are both treated as a "sub view." If you expect an
array-like structure, you can retrieve values by index rather than by key.
The analyzer returns AnalyzedMetadata, which contains texture plugin-specific information read from the metadata.
Plugins should implement this interface so that the AnalyzedMetadata holds whatever information the plugin needs. The
exact same object will be provided to build() of the same plugin's ComponentBuilder.
The analyze() method may throw an InvalidMetadataException if the metadata is not valid. MoreMcmeta will handle
these exceptions and log warnings with the exception message.
Keep the average user in mind: not everyone configuring textures will be a technical expert. Try to explain the problem simply and be specific as to where the issue is. Don't throw an exception with a message that amounts to "error."
MoreMcmeta will not handle exceptions besides InvalidMetadataException, and other exceptions may crash the game.
If you use code that throws other exception types, you must catch and rethrow them as InvalidMetadataExceptions.
The AnalyzedMetadata interface stipulates four default methods: frameWidth(), frameHeight(), blur(), and
clamp(). For each of these methods, the analyzer can return metadata with a value or return Optional.empty() to
signal "no opinion." If two plugins provide a value, and those values are not equal, then there is a conflict and the
metadata is considered invalid. There is no conflict when multiple plugins provide equal values or when no plugins
provide a value. If no value is provided, MoreMcmeta will use a default.
Methods in the MetadataAnalyzer may be called from multiple threads. If any internal state is required, it must be
thread-safe.
The ComponentBuilder takes AnalyzedMetadata and produces a TextureComponent, which responds to texture events.
In addition, the builder may write colors to any frame of the texture being configured. Before discussing the build
process in more detail, background information about plugin layering is necessary.
MoreMcmeta gives each plugin its own "layer:" a two-dimensional grid of pixels. The original image is considered the bottommost layer, with plugins making up the layers above.
The plugins applied first, those whose sections are first in a texture's MetadataView, have lower layers. Each plugin
can only write to its own layer. The plugin can read colors from the layer below, but it has no knowledge of any layers
above. If nothing has been written to the layer below at a particular pixel, then the plugin reads the color from the
uppermost layer below its own layer that wrote to that pixel. However, the plugin does not know exactly which layer
the color came from.
No matter the order of reads and writes, a plugin using a lower layer will not see any of the changes from a plugin using an upper layer. For example, say there are four layers, from bottom to top: the original image, plugin L, and plugin M, and plugin U. The original color of pixel (1, 2) is orange. Plugin M writes a magenta color to pixel (1, 2). If plugin L then reads (1, 2), it will see orange, not magenta. Plugin L is completely oblivious to writes by plugin M. When plugin M reads (1, 2), it will also see orange. However, if plugin U reads (1, 2), it see magenta.
By default, MoreMcmeta does not blend partially-transparent colors with colors from lower layers. However, you can use
the Color.alphaBlend() method to blend a partially-transparent color with that in the layer below. MoreMcmeta does not
do alpha blending automatically because it would make plugins that erase pixels impossible to create.
While the layering mechanism is useful to create overlays, it has limitations. MoreMcmeta does not render layers as additional quads. This means that all layers are rendered with the same brightness; you cannot make one layer emissive. ("Emissive textures" are actually full-brightness quads.) Furthermore, per-layer translations are impossible. For example, Minecraft's enchantment effect translates the texture to create an "animation." Currently, this effect cannot be replicated with MoreMcmeta's layering.
In build(), the ComponentBuilder converts AnalyzedMetadata to a TextureComponent. Furthermore, the builder can
write to the plugin's layer and read from layers below. This is useful to create static overlays that do not change
regardless of what changes in the layers below, or change the texture's initial appearance.
Methods in the ComponentBuilder may be called from multiple threads. If any internal state is required, it must be
thread-safe.
The TextureComponent can write colors to the texture onTick() (every 1/20th of a second) and onClose() (when the
texture is being destroyed on game close or resource reloading). The onClose() is more useful to release resources
needed by the component, if any.
Before the first tick, the texture is initialized with the first frame and its layers.
TextureComponent methods do not provide access to colors in the plugin's layer; you can only access colors in the
layer below. If you need the current layer's colors, you should keep track of them inside the TextureComponent.
(Most plugins simply keep a state variable and do not need access to all the current colors, so only direct access
to the layer below is provided.)
Please report errors or suggest improvements to this wiki using the documentation template on the issue tracker.
User Docs are written for regular Minecraft players and resource pack authors.
- User Docs: Animation Format
- User Docs: Emissive Format
- User Docs: Install Plugins
- User Docs: Troubleshooting
Plugin Docs are written for plugin developers.
- Plugin Docs: Overview
- Plugin Docs: Maven
- Plugin Docs: Plugin Registration
- Plugin Docs: Parser Plugins
- Plugin Docs: Texture Plugins
Dev Docs are written for MoreMcmeta developers.