1
0
mirror of https://github.com/GeyserMC/Rainbow.git synced 2025-12-19 14:59:16 +00:00

Attachable generation?

This commit is contained in:
Eclipse
2025-07-01 10:48:01 +00:00
parent 54d7ab20c1
commit ebeee974e2
7 changed files with 189 additions and 1 deletions

View File

@@ -14,6 +14,7 @@ public record BedrockTextures(Map<String, String> textures) {
.xmap(pairs -> pairs.stream().map(pair -> Pair.of(pair.getFirst(), pair.getSecond().getFirst().getSecond())).collect(Pair.toMap()),
map -> map.entrySet().stream().map(entry -> Pair.of(entry.getKey(), List.of(Pair.of("textures", entry.getValue())))).toList())
.xmap(BedrockTextures::new, BedrockTextures::textures);
public static final String TEXTURES_FOLDER = "textures/";
public Builder toBuilder() {
Builder builder = builder();
@@ -26,7 +27,6 @@ public record BedrockTextures(Map<String, String> textures) {
}
public static class Builder {
private static final String TEXTURES_FOLDER = "textures/";
private final Map<String, String> textures = new HashMap<>();
public Builder withItemTexture(GeyserMapping mapping, String texturePath) {

View File

@@ -1,6 +1,7 @@
package org.geysermc.packgenerator.pack;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import java.util.List;
@@ -8,6 +9,20 @@ public record BedrockVersion(int major, int minor, int patch) {
public static final Codec<BedrockVersion> CODEC = Codec.INT.listOf(3, 3)
.xmap(list -> BedrockVersion.of(list.getFirst(), list.get(1), list.getLast()),
version -> List.of(version.major, version.minor, version.patch));
public static final Codec<BedrockVersion> STRING_CODEC = Codec.STRING.comapFlatMap(string -> {
String[] segments = string.split("\.");
if (segments.length != 3) {
return DataResult.error(() -> "Semantic version must consist of 3 versions");
}
try {
int major = Integer.parseInt(segments[0]);
int minor = Integer.parseInt(segments[1]);
int patch = Integer.parseInt(segments[2]);
return DataResult.success(new BedrockVersion(major, minor, patch));
} catch (NumberFormatException exception) {
return DataResult.error(() -> "Failed to parse semantic version number");
}
}, version -> String.format("%d.%d.%d", version.major, version.minor, version.patch));
public static BedrockVersion of(int patch) {
return of(0, 0, patch);

View File

@@ -0,0 +1,137 @@
package org.geysermc.packgenerator.pack.attachable;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.EquipmentSlot;
import org.geysermc.packgenerator.PackConstants;
import org.geysermc.packgenerator.pack.BedrockTextures;
import org.geysermc.packgenerator.pack.BedrockVersion;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo info) {
public static final Codec<BedrockAttachable> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
BedrockVersion.STRING_CODEC.fieldOf("format_version").forGetter(BedrockAttachable::formatVersion),
AttachableInfo.CODEC.fieldOf("description").fieldOf("minecraft:attachable").forGetter(BedrockAttachable::info)
).apply(instance, BedrockAttachable::new)
);
public static Builder builder(ResourceLocation identifier) {
return new Builder(identifier);
}
public static BedrockAttachable equipment(ResourceLocation identifier, EquipmentSlot slot, String texture) {
return builder(identifier)
.withMaterial(DisplaySlot.DEFAULT, "armor")
.withMaterial(DisplaySlot.ENCHANTED, "armor_enchanted")
.withTexture(DisplaySlot.DEFAULT, texture)
.withTexture(DisplaySlot.ENCHANTED, VanillaTextures.ENCHANTED_ACTOR_GLINT)
.withGeometry(DisplaySlot.DEFAULT, VanillaGeometries.fromEquipmentSlot(slot))
.withRenderController(VanillaRenderControllers.ARMOR)
.build();
}
public static class Builder {
private final ResourceLocation identifier;
private final EnumMap<DisplaySlot, String> materials = new EnumMap<>(DisplaySlot.class);
private final EnumMap<DisplaySlot, String> textures = new EnumMap<>(DisplaySlot.class);
private final EnumMap<DisplaySlot, String> geometries = new EnumMap<>(DisplaySlot.class);
private final Map<String, String> animations = new HashMap<>();
private final Map<String, String> scripts = new HashMap<>();
private final List<String> renderControllers = new ArrayList<>();
public Builder(ResourceLocation identifier) {
this.identifier = identifier;
}
public Builder withMaterial(DisplaySlot slot, String material) {
materials.put(slot, material);
return this;
}
public Builder withTexture(DisplaySlot slot, String texture) {
textures.put(slot, BedrockTextures.TEXTURES_FOLDER + texture);
return this;
}
public Builder withGeometry(DisplaySlot slot, String geometry) {
geometries.put(slot, geometry);
return this;
}
public Builder withAnimation(String key, String animation) {
animations.put(key, animation);
return this;
}
public Builder withScript(String key, String script) {
scripts.put(key, script);
return this;
}
public Builder withRenderController(String controller) {
renderControllers.add(controller);
return this;
}
public BedrockAttachable build() {
return new BedrockAttachable(PackConstants.ENGINE_VERSION,
new AttachableInfo(identifier, verifyDefault(materials), verifyDefault(textures), verifyDefault(geometries), Map.copyOf(animations), Map.copyOf(scripts), List.copyOf(renderControllers)));
}
private static DisplayMap verifyDefault(EnumMap<DisplaySlot, String> map) {
if (!map.containsKey(DisplaySlot.DEFAULT)) {
throw new IllegalStateException("DisplayMap must have a default key");
}
return new DisplayMap(map);
}
}
public record AttachableInfo(ResourceLocation identifier, DisplayMap materials, DisplayMap textures,
DisplayMap geometry, Map<String, String> animations, Map<String, String> scripts,
List<String> renderControllers) {
private static final Codec<Map<String, String>> STRING_MAP_CODEC = Codec.unboundedMap(Codec.STRING, Codec.STRING);
public static final Codec<AttachableInfo> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ResourceLocation.CODEC.fieldOf("identifier").forGetter(AttachableInfo::identifier),
DisplayMap.CODEC.fieldOf("materials").forGetter(AttachableInfo::materials),
DisplayMap.CODEC.fieldOf("textures").forGetter(AttachableInfo::textures),
DisplayMap.CODEC.fieldOf("geometry").forGetter(AttachableInfo::geometry),
STRING_MAP_CODEC.optionalFieldOf("animations", Map.of()).forGetter(AttachableInfo::animations),
STRING_MAP_CODEC.optionalFieldOf("scripts", Map.of()).forGetter(AttachableInfo::scripts),
Codec.STRING.listOf().optionalFieldOf("render_controllers", List.of()).forGetter(AttachableInfo::renderControllers)
).apply(instance, AttachableInfo::new)
);
}
public record DisplayMap(EnumMap<DisplaySlot, String> map) {
public static final Codec<DisplayMap> CODEC = Codec.unboundedMap(DisplaySlot.CODEC, Codec.STRING)
.xmap(map -> map.isEmpty() ? new DisplayMap(new EnumMap<>(DisplaySlot.class)) : new DisplayMap(new EnumMap<>(map)), DisplayMap::map);
}
public enum DisplaySlot implements StringRepresentable {
DEFAULT("default"),
ENCHANTED("enchanted");
public static final Codec<DisplaySlot> CODEC = StringRepresentable.fromEnum(DisplaySlot::values);
private final String name;
DisplaySlot(String name) {
this.name = name;
}
@Override
public @NotNull String getSerializedName() {
return name;
}
}
}

View File

@@ -0,0 +1,20 @@
package org.geysermc.packgenerator.pack.attachable;
import net.minecraft.world.entity.EquipmentSlot;
public class VanillaGeometries {
public static final String HELMET = "geometry.player.armor.helmet";
public static final String CHESTPLATE = "geometry.player.armor.chestplate";
public static final String LEGGINGS = "geometry.player.armor.leggings";
public static final String BOOTS = "geometry.player.armor.boots";
public static String fromEquipmentSlot(EquipmentSlot slot) {
return switch (slot) {
case FEET -> BOOTS;
case LEGS -> LEGGINGS;
case CHEST -> CHESTPLATE;
case HEAD -> HELMET;
default -> null;
};
}
}

View File

@@ -0,0 +1,6 @@
package org.geysermc.packgenerator.pack.attachable;
public class VanillaMaterials {
public static final String ARMOR = "armor";
public static final String ARMOR_ENCHANTED = "armor_enchanted";
}

View File

@@ -0,0 +1,5 @@
package org.geysermc.packgenerator.pack.attachable;
public class VanillaRenderControllers {
public static final String ARMOR = "controller.render.armor";
}

View File

@@ -0,0 +1,5 @@
package org.geysermc.packgenerator.pack.attachable;
public class VanillaTextures {
public static final String ENCHANTED_ACTOR_GLINT = "misc/enchanted_actor_glint";
}