Asset sync

Put a mod's models, textures and sounds in a data pack on the server. Every player receives them on join, with no resource pack to install.

Why

Content that players add (custom characters, say) normally needs two packs: a data pack for the server and a resource pack every player must install. Asset sync makes it one data pack. Strut sends the files during the join, keeps them in a cache, loads them as a resource pack, and only then lets the player spawn.

Using it

Most servers need no code. Put files here, in any data pack:

data/<namespace>/asset_sync/<path>

They reach players as assets/<namespace>/<path>. For example:

In the data packWhat the player sees
data/mymod/asset_sync/strut/models/entity/eve.strutmodelassets/mymod/strut/models/entity/eve.strutmodel
data/mymod/asset_sync/textures/entity/eve.pngassets/mymod/textures/entity/eve.png
data/mymod/asset_sync/sounds/eve/cry1.ogg and sounds.jsonThe same paths under assets/mymod/. sounds.json and lang files merge with the mod's own.
data/mymod/asset_sync/strut/animations/entity/eve.strutanimThe client's animation, and also the server's event timeline. No second copy needed.
data/mymod/asset_sync/strut/event_bindings/eve.jsonAn event binding set.

For a mod that wants to require the assets, or generate some in code:

StrutAssetSync.setRequired(true);
StrutAssetSync.addSource(sink -> sink.add("mymod", "sounds.json", soundsJson));

Sources are called on every data reload, after the data packs, so what they add overrides the packs. On the client:

StrutAssetSyncClient.onAssetsReady(() -> {
	// the server's models, sounds and textures are loaded; the player has not joined yet
});

What is accepted

What happens on join

  1. The server sends the list of files with their hashes.
  2. The client compares it with its cache and asks only for what it lacks.
  3. The server sends those files in chunks, with flow control, and the client verifies every file's hash before keeping it.
  4. The client makes the files one more resource pack, reloads resources once, and tells the server it is done.
  5. The server lets the player in.

A returning player downloads nothing that has not changed. The cache is shared across servers and lives under strut/asset-cache in the game folder.

When the server reloads

A /reload that changes the assets sends each connected player who accepted the earlier ones only the difference, and their client reloads once. A player who declined is not asked again. If a reload removes every asset, connected players drop them.

The player's controls

A server can only offer. The player's limits, in config/strut-client.json, are enforced on the client whatever the server says:

KeyDefaultMeaning
acceptServerAssetstrueTurn asset sync off entirely.
maxDownloadPerServerMiB512The most one sync may download.
cacheLimitMiB1024Least recently used files are deleted above this.
maxTexturePixels67108864The largest a synced PNG may be (8192 x 8192). Larger is refused.

If a player declines or is over their cap, they join without the assets, unless your mod called setRequired(true), in which case they are refused with a clear reason.

Safety

A server that can put files on a player's computer has to be treated as hostile, so the client checks everything:

What remains is the same exposure a vanilla server resource pack has: the game's own image and sound decoders, and other mods that read resource files.

Trying it

Start the game or server with -Dstrut.assetSyncDemo=true. The server offers a small strut_demo namespace. Join and press F9: the overlay shows the assets active and whether the game's own language loader and resource manager can see them. /strut assets status shows what the server offers and each player's progress.