anvillib/common/src/main/java/net/anvilcraft/anvillib/cosmetics/remote/thread/CosmeticAssetsLoaderThread.java
2023-11-24 21:20:58 +01:00

157 lines
6.1 KiB
Java

package net.anvilcraft.anvillib.cosmetics.remote.thread;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Objects;
import com.google.common.hash.Hashing;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.anvilcraft.anvillib.AnvilLib;
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmetic;
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmeticProvider;
import net.anvilcraft.anvillib.cosmetics.remote.model.AnimationData;
import net.anvilcraft.anvillib.cosmetics.remote.model.CosmeticData;
import net.anvilcraft.anvillib.cosmetics.remote.model.TextureData;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.client.texture.MissingSprite;
import net.minecraft.client.texture.PlayerSkinTexture;
import net.minecraft.client.texture.TextureManager;
import net.minecraft.util.Identifier;
import software.bernie.geckolib3.core.builder.Animation;
import software.bernie.geckolib3.core.molang.MolangParser;
import software.bernie.geckolib3.file.AnimationFile;
import software.bernie.geckolib3.geo.exception.GeckoLibException;
import software.bernie.geckolib3.geo.raw.pojo.Converter;
import software.bernie.geckolib3.geo.raw.pojo.FormatVersion;
import software.bernie.geckolib3.geo.raw.pojo.RawGeoModel;
import software.bernie.geckolib3.geo.raw.tree.RawGeometryTree;
import software.bernie.geckolib3.geo.render.GeoBuilder;
import software.bernie.geckolib3.geo.render.built.GeoModel;
import software.bernie.geckolib3.util.json.JsonAnimationUtils;
public class CosmeticAssetsLoaderThread extends AbstractFileDownloaderThread {
private RemoteCosmetic cosmetic;
private CosmeticData data;
private MolangParser parser = new MolangParser();
private TextureManager textureManager
= MinecraftClient.getInstance().getTextureManager();
private File cacheDir;
private RemoteCosmeticProvider provider;
public CosmeticAssetsLoaderThread(
RemoteCosmetic cosmetic,
CosmeticData data,
File cacheDir,
RemoteCosmeticProvider provider
) {
super("0.2.0");
this.cosmetic = cosmetic;
this.data = data;
this.cacheDir = cacheDir;
this.provider = provider;
}
@Override
public void run() {
this.loadModel(this.data.modelUrl);
this.loadTexture(this.data.textureData);
this.loadAnimations(this.data.animationData);
this.provider.markDirty();
}
private void loadAnimations(AnimationData anim) {
if (anim == null) {
this.cosmetic.loadAnimations(null, anim);
return;
}
AnimationFile animations = null;
try {
URI url = new URI(this.data.animationData.url);
JsonObject data = this.loadJson(url, JsonObject.class);
animations = this.buildAnimationFile(data);
} catch (IOException | URISyntaxException | NullPointerException e) {
AnvilLib.LOGGER.error(
"Could not load animation: {}", this.data.animationData.url, e
);
}
this.cosmetic.loadAnimations(animations, anim);
}
@SuppressWarnings("deprecation")
private void loadTexture(TextureData data) {
String hash = Hashing.sha1().hashUnencodedChars(this.data.id).toString();
AbstractTexture texture = this.textureManager.getOrDefault(
this.cosmetic.getTextureLocation(), MissingSprite.getMissingSpriteTexture()
);
if (texture == MissingSprite.getMissingSpriteTexture()) {
File file = new File(
this.cacheDir, hash.length() > 2 ? hash.substring(0, 2) : "xx"
);
File file2 = new File(file, hash);
texture = new PlayerSkinTexture(
file2, data.url, new Identifier("textures/block/dirt.png"), false, null
);
this.textureManager.registerTexture(
this.cosmetic.getTextureLocation(), texture
);
}
this.cosmetic.loadTexture(data);
}
private void loadModel(String url) {
try {
URI uri = new URI(url);
String data = Objects.requireNonNull(this.getStringForURL(uri));
GeoModel model = this.buildModel(data);
this.cosmetic.loadModel(model);
} catch (
NullPointerException | URISyntaxException | IOException | GeckoLibException e
) {
AnvilLib.LOGGER.error("Can't load remote model: {}", url, e);
this.handleFailure();
}
}
private void handleFailure() {
this.provider.failCosmeticLoading(this.data.id);
}
private AnimationFile buildAnimationFile(JsonObject json) {
AnimationFile animationFile = new AnimationFile();
for (Map.Entry<String, JsonElement> entry :
JsonAnimationUtils.getAnimations(json)) {
String animationName = entry.getKey();
Animation animation;
try {
animation = JsonAnimationUtils.deserializeJsonToAnimation(
JsonAnimationUtils.getAnimation(json, animationName), parser
);
animationFile.putAnimation(animationName, animation);
} catch (Exception e) {
AnvilLib.LOGGER.error("Could not load animation: {}", animationName, e);
throw new RuntimeException(e);
}
}
return animationFile;
}
private GeoModel buildModel(String json) throws IOException {
Identifier location = this.cosmetic.getModelLocation();
RawGeoModel rawModel = Converter.fromJsonString(json);
if (rawModel.getFormatVersion() != FormatVersion.VERSION_1_12_0) {
throw new GeckoLibException(
location, "Wrong geometry json version, expected 1.12.0"
);
}
RawGeometryTree rawGeometryTree = RawGeometryTree.parseHierarchy(rawModel);
return GeoBuilder.getGeoBuilder(location.getNamespace())
.constructGeoModel(rawGeometryTree);
}
}