Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import net.tfminecraft.armourshop.pack.model.PackPaths;
import net.tfminecraft.armourshop.pack.model.PackSubmission;
import net.tfminecraft.armourshop.pack.util.Model3dUtil;
import net.tfminecraft.armourshop.pack.util.TextureFiles;
import net.tfminecraft.armourshop.pack.writer.armor.ArmorSetWriter;
import net.tfminecraft.armourshop.pack.writer.bow.Bow3dWriter;
import net.tfminecraft.armourshop.pack.writer.bow.BowWriter;
import net.tfminecraft.armourshop.pack.writer.bow.LargeBowWriter;
import net.tfminecraft.armourshop.pack.writer.flat.BookWriter;
Expand Down Expand Up @@ -205,6 +207,7 @@ private static Map<String, Map<String, byte[]>> downloadArmorFiles(
}
tierFiles.put(Model3dUtil.HELMET_MODEL_STEM, modelDl.data);
tierFiles.put(Model3dUtil.HELMET_TEXTURE_STEM, texDl.data);
putOptionalMcmeta(sub, available, texName, Model3dUtil.HELMET_TEXTURE_STEM, tierFiles);
} else {
String filename = tier + "_helmet.png";
if (!available.contains(filename)) {
Expand All @@ -217,6 +220,7 @@ private static Map<String, Map<String, byte[]>> downloadArmorFiles(
throw new IllegalStateException("download " + filename + ": " + dl.error);
}
tierFiles.put("helmet", dl.data);
putOptionalMcmeta(sub, available, filename, "helmet", tierFiles);
}
for (String stem : ARMOR_BODY_STEMS) {
String filename = tier + "_" + stem + ".png";
Expand All @@ -228,12 +232,34 @@ private static Map<String, Map<String, byte[]>> downloadArmorFiles(
throw new IllegalStateException("download " + filename + ": " + dl.error);
}
tierFiles.put(stem, dl.data);
if (!stem.startsWith("layer_")) {
putOptionalMcmeta(sub, available, filename, stem, tierFiles);
}
}
out.put(tier, tierFiles);
}
return out;
}

/** Downloads {@code pngFilename.mcmeta} into {@code stem.mcmeta} when the website lists one. */
private static void putOptionalMcmeta(
ApprovedSubmission sub,
Set<String> available,
String pngFilename,
String stem,
Map<String, byte[]> tierFiles
) {
String metaName = pngFilename + TextureFiles.MCMETA_SUFFIX;
if (!available.contains(metaName)) {
return;
}
DownloadResult dl = ProvinceSystemClient.downloadSubmissionFile(sub.id, metaName);
if (!dl.ok) {
throw new IllegalStateException("download " + metaName + ": " + dl.error);
}
tierFiles.put(TextureFiles.mcmetaStem(stem), dl.data);
}

/** Writes one tier's armor set as its own pack slug ({@code slug_tier}). */
private static void writeArmorTier(
Path contentsRoot,
Expand Down Expand Up @@ -313,6 +339,30 @@ static String stemFromFilename(String kind, String slug, String filename) {
return null;
}
String name = filename.trim();
// {png}.mcmeta animates that PNG: stem is the PNG's stem + ".mcmeta"
if (name.endsWith(".png" + TextureFiles.MCMETA_SUFFIX)) {
String pngStem = stemFromFilename(
kind, slug, name.substring(0, name.length() - TextureFiles.MCMETA_SUFFIX.length())
);
return pngStem == null ? null : TextureFiles.mcmetaStem(pngStem);
}
if ("bow_3d".equals(kind) || "crossbow_3d".equals(kind)) {
if (name.equals(slug + ".png")) {
return Model3dUtil.TEXTURE_STEM;
}
if (name.equals(slug + ".json")) {
return Model3dUtil.MODEL_STEM;
}
String prefix = slug + "_";
if (name.startsWith(prefix) && name.endsWith(".json")) {
String suffix = name.substring(prefix.length(), name.length() - 5);
if ("0".equals(suffix) || "1".equals(suffix) || "2".equals(suffix)
|| ("crossbow_3d".equals(kind) && "charged".equals(suffix))) {
return Model3dUtil.MODEL_STEM + "_" + suffix;
}
}
return null;
}
if ("book".equals(kind)) {
String prefix = slug + "_";
if (name.startsWith(prefix) && name.endsWith(".png")) {
Expand Down Expand Up @@ -459,6 +509,20 @@ private static void writeKind(
ns
);
return;
case "bow_3d":
case "crossbow_3d": {
PackKind packKind = "bow_3d".equals(kind) ? PackKind.BOW_3D : PackKind.CROSSBOW_3D;
if (!packFiles.containsKey(Model3dUtil.TEXTURE_STEM)) {
throw new IllegalStateException("missing texture");
}
requireStems(packFiles, Bow3dWriter.requiredModelStems(packKind));
Bow3dWriter.write(
contentsRoot,
new PackSubmission(slug, display, packKind, packFiles),
ns
);
return;
}
case "item_3d":
requireModel3d(packFiles);
Item3dWriter.write(
Expand Down Expand Up @@ -554,6 +618,9 @@ private static boolean isModelStem(String stem) {
return false;
}
String s = stem.trim().toLowerCase(Locale.ROOT);
if (TextureFiles.isMcmetaStem(s)) {
return false;
}
return Model3dUtil.MODEL_STEM.equals(s)
|| Model3dUtil.HELMET_MODEL_STEM.equals(s)
|| ShieldWriter.MODEL_BLOCKING_STEM.equals(s)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import net.tfminecraft.armourshop.pack.model.BowFrames;
import net.tfminecraft.armourshop.pack.model.PackPaths;
import net.tfminecraft.armourshop.pack.util.TextureFiles;
import net.tfminecraft.armourshop.pack.writer.flat.BookWriter;
import net.tfminecraft.armourshop.pack.writer.gun.GunWriter;
import net.tfminecraft.armourshop.pack.writer.mask.MasksYml;
Expand Down Expand Up @@ -91,7 +92,7 @@ public static List<Path> remove(
} else if ("gun".equals(k)) {
removed.addAll(GunWriter.remove(contentsRoot, ns, s, gunsSkinsYmlOrNull()));
} else if ("mask".equals(k)) {
removeNonArmorPack(contentsRoot, ns, s, removed);
removeNonArmorPack(contentsRoot, ns, s, k, removed);
try {
MasksYml.remove(masksYmlOrNull(), s);
} catch (RuntimeException e) {
Expand All @@ -102,7 +103,7 @@ public static List<Path> remove(
} else if ("book".equals(k)) {
removed.addAll(BookWriter.remove(contentsRoot, ns, s));
} else {
removeNonArmorPack(contentsRoot, ns, s, removed);
removeNonArmorPack(contentsRoot, ns, s, k, removed);
}

if (log != null) {
Expand All @@ -125,13 +126,13 @@ private static void removeArmorPack(

deleteQuiet(configs.resolve(packSlug + ".yml"), removed);
for (String stem : ARMOR_ICON_STEMS) {
deleteQuiet(icons.resolve(packSlug + "_" + stem + ".png"), removed);
TextureFiles.deleteWithMcmeta(icons.resolve(packSlug + "_" + stem + ".png"), removed);
}
deleteQuiet(layers.resolve(packSlug + "_layer_1.png"), removed);
deleteQuiet(layers.resolve(packSlug + "_layer_2.png"), removed);
// 3D helmet assets (when present)
String helmetId = packSlug + "_helmet";
deleteQuiet(
TextureFiles.deleteWithMcmeta(
PackPaths.itemTexturesDir(contentsRoot, namespace).resolve(helmetId + ".png"),
removed
);
Expand All @@ -145,28 +146,33 @@ private static void removeNonArmorPack(
Path contentsRoot,
String namespace,
String s,
String kind,
List<Path> removed
) throws IOException {
Path configs = PackPaths.configsDir(contentsRoot, namespace);
Path itemTex = PackPaths.itemTexturesDir(contentsRoot, namespace);
Path models = PackPaths.itemModelsDir(contentsRoot, namespace);

deleteQuiet(configs.resolve(s + ".yml"), removed);
deleteQuiet(itemTex.resolve(s + ".png"), removed);
TextureFiles.deleteWithMcmeta(itemTex.resolve(s + ".png"), removed);
deleteQuiet(models.resolve(s + ".json"), removed);
deleteQuiet(models.resolve(s + "_blocking.json"), removed);
for (String stem : BowFrames.CROSSBOW_STEMS) {
deleteQuiet(
TextureFiles.deleteWithMcmeta(
itemTex.resolve(BowFrames.textureFileName(s, stem)),
removed
);
// large_bow frame models (and any stray pull models)
// large_bow / bow_3d / crossbow_3d frame models (and any stray pull models)
deleteQuiet(
models.resolve(s + BowFrames.fileSuffix(stem) + ".json"),
removed
);
}
deleteQuiet(itemTex.resolve(s + "_arrow.png"), removed);
// crossbow_3d firework model is a copy of the charged one
if ("crossbow_3d".equals(kind)) {
deleteQuiet(models.resolve(s + "_firework.json"), removed);
}
TextureFiles.deleteWithMcmeta(itemTex.resolve(s + "_arrow.png"), removed);
}

private static void deleteQuiet(Path path, List<Path> removed) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public enum PackKind {
BOW,
LARGE_BOW,
CROSSBOW,
BOW_3D,
CROSSBOW_3D,
ITEM_3D,
SHIELD,
HELMET_3D,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ private static boolean isItemKind(String kind) {
|| "bow".equals(kind)
|| "large_bow".equals(kind)
|| "crossbow".equals(kind)
|| "bow_3d".equals(kind)
|| "crossbow_3d".equals(kind)
|| "item_3d".equals(kind)
|| "shield".equals(kind)
|| "helmet_3d".equals(kind)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package net.tfminecraft.armourshop.pack.util;

import net.tfminecraft.armourshop.pack.model.PackSubmission;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Locale;

/**
* Writes submission PNGs together with their optional {@code .png.mcmeta} animation.
* A texture stem {@code S} has its animation under stem {@code S.mcmeta}.
*/
public final class TextureFiles {

public static final String MCMETA_SUFFIX = ".mcmeta";

private TextureFiles() {}

public static String mcmetaStem(String stem) {
return stem + MCMETA_SUFFIX;
}

public static boolean isMcmetaStem(String stem) {
return stem != null && stem.trim().toLowerCase(Locale.ROOT).endsWith(MCMETA_SUFFIX);
}

/** {@code foo.png} → {@code foo.png.mcmeta} beside it. */
public static Path mcmetaPath(Path png) {
return png.resolveSibling(png.getFileName().toString() + MCMETA_SUFFIX);
}

/** Writes the stem's PNG to {@code png}, then its animation (if any). */
public static void writePng(
PackSubmission submission,
String stem,
Path png,
List<Path> written
) throws IOException {
Files.write(png, submission.requireFile(stem));
written.add(png);
writeMcmeta(submission, stem, png, written);
}

/**
* Writes {@code png.mcmeta} when the submission animates {@code stem}; otherwise
* removes a stale one left by an earlier apply of the same slug.
*/
public static void writeMcmeta(
PackSubmission submission,
String stem,
Path png,
List<Path> written
) throws IOException {
Path meta = mcmetaPath(png);
byte[] data = submission.files().get(mcmetaStem(stem));
if (data == null || data.length == 0) {
Files.deleteIfExists(meta);
return;
}
Files.write(meta, data);
written.add(meta);
}

/** Deletes {@code png} and its {@code .mcmeta}, recording what was removed. */
public static void deleteWithMcmeta(Path png, List<Path> removed) throws IOException {
if (Files.deleteIfExists(png)) {
removed.add(png);
}
Path meta = mcmetaPath(png);
if (Files.deleteIfExists(meta)) {
removed.add(meta);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import net.tfminecraft.armourshop.pack.model.PackPaths;
import net.tfminecraft.armourshop.pack.model.PackSubmission;
import net.tfminecraft.armourshop.pack.util.Model3dUtil;
import net.tfminecraft.armourshop.pack.util.TextureFiles;
import net.tfminecraft.armourshop.pack.util.YamlUtil;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -74,24 +75,22 @@ public static List<Path> write(
Files.createDirectories(itemTexDir);
String helmetId = slug + "_helmet";
Path tex = itemTexDir.resolve(helmetId + ".png");
Files.write(tex, submission.requireFile(Model3dUtil.HELMET_TEXTURE_STEM));
written.add(tex);
TextureFiles.writePng(submission, Model3dUtil.HELMET_TEXTURE_STEM, tex, written);
Path modelPath = modelsDir.resolve(helmetId + ".json");
Files.write(modelPath, submission.requireFile(Model3dUtil.HELMET_MODEL_STEM));
written.add(modelPath);
} else {
Path out = iconsDir.resolve(slug + "_helmet.png");
Files.write(out, submission.requireFile("helmet"));
written.add(out);
TextureFiles.writePng(submission, "helmet", out, written);
}

for (String stem : BODY_ICON_STEMS) {
Path out = iconsDir.resolve(slug + "_" + stem + ".png");
Files.write(out, submission.requireFile(stem));
written.add(out);
TextureFiles.writePng(submission, stem, out, written);
}
for (String stem : LAYER_STEMS) {
Path out = layersDir.resolve(slug + "_" + stem + ".png");
// Armour layers are not animated.
Files.write(out, submission.requireFile(stem));
written.add(out);
}
Expand Down
Loading
Loading