mirror of
https://github.com/GeyserMC/Rainbow.git
synced 2025-12-19 14:59:16 +00:00
Texture atlas generation, refactor pack managing
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -114,6 +114,7 @@ gradle-app.setting
|
|||||||
# Common working directory
|
# Common working directory
|
||||||
run/
|
run/
|
||||||
runs/
|
runs/
|
||||||
|
run-server/
|
||||||
|
|
||||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
!gradle-wrapper.jar
|
!gradle-wrapper.jar
|
||||||
|
|||||||
@@ -74,3 +74,11 @@ publishing {
|
|||||||
|
|
||||||
repositories {}
|
repositories {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loom {
|
||||||
|
runs {
|
||||||
|
named("server") {
|
||||||
|
runDir = "run-server"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class CodecUtil {
|
public class CodecUtil {
|
||||||
|
|
||||||
@@ -19,12 +20,19 @@ public class CodecUtil {
|
|||||||
public static <O, T> RecordCodecBuilder<O, T> unitVerifyCodec(Codec<T> codec, String field, T value) {
|
public static <O, T> RecordCodecBuilder<O, T> unitVerifyCodec(Codec<T> codec, String field, T value) {
|
||||||
return codec.validate(read -> {
|
return codec.validate(read -> {
|
||||||
if (!read.equals(value)) {
|
if (!read.equals(value)) {
|
||||||
return DataResult.error(() -> field + " must equal " + value);
|
return DataResult.error(() -> field + " must equal " + value + ", was " + read);
|
||||||
}
|
}
|
||||||
return DataResult.success(read);
|
return DataResult.success(read);
|
||||||
}).fieldOf(field).forGetter(object -> value);
|
}).fieldOf(field).forGetter(object -> value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T readOrCompute(Codec<T> codec, Path path, Supplier<T> supplier) throws IOException {
|
||||||
|
if (Files.exists(path)) {
|
||||||
|
return tryReadJson(codec, path);
|
||||||
|
}
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> T tryReadJson(Codec<T> codec, Path path) throws IOException {
|
public static <T> T tryReadJson(Codec<T> codec, Path path) throws IOException {
|
||||||
try {
|
try {
|
||||||
String raw = Files.readString(path);
|
String raw = Files.readString(path);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import java.io.IOException;
|
|||||||
public class GeyserMappingsGenerator implements ClientModInitializer {
|
public class GeyserMappingsGenerator implements ClientModInitializer {
|
||||||
|
|
||||||
public static final String MOD_ID = "geyser-mappings-generator";
|
public static final String MOD_ID = "geyser-mappings-generator";
|
||||||
public static final String NAME = "Geyser Mappings Generator";
|
public static final String MOD_NAME = "Geyser Mappings Generator";
|
||||||
public static final Logger LOGGER = LogUtils.getLogger();
|
public static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ package org.geysermc.packgenerator;
|
|||||||
import org.geysermc.packgenerator.pack.BedrockVersion;
|
import org.geysermc.packgenerator.pack.BedrockVersion;
|
||||||
|
|
||||||
public class PackConstants {
|
public class PackConstants {
|
||||||
public static final String DEFAULT_PACK_DESCRIPTION = "A resourcepack generated by " + GeyserMappingsGenerator.NAME;
|
public static final String DEFAULT_PACK_DESCRIPTION = "A resourcepack generated by " + GeyserMappingsGenerator.MOD_NAME;
|
||||||
public static final BedrockVersion ENGINE_VERSION = BedrockVersion.of(1, 21, 0);
|
public static final BedrockVersion ENGINE_VERSION = BedrockVersion.of(1, 21, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,53 +2,33 @@ package org.geysermc.packgenerator;
|
|||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.geysermc.packgenerator.mappings.GeyserMappings;
|
import org.geysermc.packgenerator.pack.BedrockPack;
|
||||||
import org.geysermc.packgenerator.pack.BedrockVersion;
|
|
||||||
import org.geysermc.packgenerator.pack.PackManifest;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public final class PackManager {
|
public final class PackManager {
|
||||||
private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve("geyser");
|
|
||||||
private static final Path PACK_DIRECTORY = Path.of("pack");
|
|
||||||
|
|
||||||
private static final Path MAPPINGS_FILE = Path.of("geyser_mappings.json");
|
|
||||||
private static final Path MANIFEST_FILE = Path.of("manifest.json");
|
|
||||||
|
|
||||||
private static final PackManager INSTANCE = new PackManager();
|
private static final PackManager INSTANCE = new PackManager();
|
||||||
|
|
||||||
private String currentPackName;
|
private BedrockPack currentPack;
|
||||||
private Path exportPath;
|
|
||||||
private Path packPath;
|
|
||||||
private GeyserMappings mappings;
|
|
||||||
private PackManifest manifest;
|
|
||||||
|
|
||||||
private PackManager() {}
|
private PackManager() {}
|
||||||
|
|
||||||
public void startPack(String name) throws CommandSyntaxException, IOException {
|
public void startPack(String name) throws CommandSyntaxException, IOException {
|
||||||
if (currentPackName != null) {
|
if (currentPack != null) {
|
||||||
throw new SimpleCommandExceptionType(Component.literal("Already started a pack (" + currentPackName + ")")).create();
|
throw new SimpleCommandExceptionType(Component.literal("Already started a pack (" + currentPack.name() + ")")).create();
|
||||||
}
|
}
|
||||||
|
|
||||||
exportPath = createPackDirectory(name);
|
currentPack = new BedrockPack(name);
|
||||||
packPath = exportPath.resolve(PACK_DIRECTORY);
|
|
||||||
mappings = readOrCreateMappings(exportPath.resolve(MAPPINGS_FILE));
|
|
||||||
manifest = readOrCreateManifest(name, packPath.resolve(MANIFEST_FILE));
|
|
||||||
currentPackName = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean map(ItemStack stack, boolean throwOnModelMissing) throws CommandSyntaxException {
|
public boolean map(ItemStack stack, boolean throwOnModelMissing) throws CommandSyntaxException {
|
||||||
ensurePackIsCreated();
|
ensurePackIsCreated();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mappings.map(stack);
|
currentPack.map(stack);
|
||||||
return true;
|
return true;
|
||||||
} catch (IllegalArgumentException exception) {
|
} catch (IllegalArgumentException exception) {
|
||||||
if (throwOnModelMissing) {
|
if (throwOnModelMissing) {
|
||||||
@@ -61,41 +41,16 @@ public final class PackManager {
|
|||||||
|
|
||||||
public void finish() throws CommandSyntaxException, IOException {
|
public void finish() throws CommandSyntaxException, IOException {
|
||||||
ensurePackIsCreated();
|
ensurePackIsCreated();
|
||||||
|
currentPack.save();
|
||||||
CodecUtil.trySaveJson(GeyserMappings.CODEC, mappings, exportPath.resolve(MAPPINGS_FILE));
|
currentPack = null;
|
||||||
CodecUtil.trySaveJson(PackManifest.CODEC, manifest, packPath.resolve(MANIFEST_FILE));
|
|
||||||
|
|
||||||
currentPackName = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensurePackIsCreated() throws CommandSyntaxException {
|
private void ensurePackIsCreated() throws CommandSyntaxException {
|
||||||
if (currentPackName == null) {
|
if (currentPack == null) {
|
||||||
throw new SimpleCommandExceptionType(Component.literal("Create a new pack first!")).create();
|
throw new SimpleCommandExceptionType(Component.literal("Create a new pack first!")).create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Path createPackDirectory(String name) throws IOException {
|
|
||||||
Path path = EXPORT_DIRECTORY.resolve(name);
|
|
||||||
CodecUtil.ensureDirectoryExists(path);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static GeyserMappings readOrCreateMappings(Path path) throws IOException {
|
|
||||||
if (Files.exists(path)) {
|
|
||||||
return CodecUtil.tryReadJson(GeyserMappings.CODEC, path);
|
|
||||||
}
|
|
||||||
return new GeyserMappings();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PackManifest readOrCreateManifest(String name, Path path) throws IOException {
|
|
||||||
if (Files.exists(path)) {
|
|
||||||
return CodecUtil.tryReadJson(PackManifest.CODEC, path).increment();
|
|
||||||
}
|
|
||||||
return new PackManifest(
|
|
||||||
new PackManifest.Header(name, PackConstants.DEFAULT_PACK_DESCRIPTION, UUID.randomUUID(), BedrockVersion.of(1), PackConstants.ENGINE_VERSION),
|
|
||||||
List.of(new PackManifest.Module(name, PackConstants.DEFAULT_PACK_DESCRIPTION, UUID.randomUUID(), BedrockVersion.of(1))));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PackManager getInstance() {
|
public static PackManager getInstance() {
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,16 +45,12 @@ public record GeyserMapping(ResourceLocation model, ResourceLocation bedrockIden
|
|||||||
-> new GeyserMapping(model, bedrockIdentifier, displayName, predicates, bedrockOptions, components))
|
-> new GeyserMapping(model, bedrockIdentifier, displayName, predicates, bedrockOptions, components))
|
||||||
);
|
);
|
||||||
|
|
||||||
public record BedrockOptions(Optional<String> icon, boolean allowOffhand, boolean displayHandheld, int protectionValue) {
|
public String textureName() {
|
||||||
public static final Codec<BedrockOptions> CODEC = RecordCodecBuilder.create(instance ->
|
return bedrockOptions.icon.orElse(iconFromResourceLocation(bedrockIdentifier));
|
||||||
instance.group(
|
}
|
||||||
Codec.STRING.optionalFieldOf("icon").forGetter(BedrockOptions::icon),
|
|
||||||
Codec.BOOL.optionalFieldOf("allow_offhand", true).forGetter(BedrockOptions::allowOffhand),
|
private static String iconFromResourceLocation(ResourceLocation location) {
|
||||||
Codec.BOOL.optionalFieldOf("display_handheld", false).forGetter(BedrockOptions::displayHandheld),
|
return location.toString().replace(':', '.').replace('/', '_');
|
||||||
Codec.INT.optionalFieldOf("protection_value", 0).forGetter(BedrockOptions::protectionValue)
|
|
||||||
).apply(instance, BedrockOptions::new)
|
|
||||||
);
|
|
||||||
public static final BedrockOptions DEFAULT = new BedrockOptions(Optional.empty(), true, false, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean conflictsWith(GeyserMapping other) {
|
public boolean conflictsWith(GeyserMapping other) {
|
||||||
@@ -72,4 +68,16 @@ public record GeyserMapping(ResourceLocation model, ResourceLocation bedrockIden
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record BedrockOptions(Optional<String> icon, boolean allowOffhand, boolean displayHandheld, int protectionValue) {
|
||||||
|
public static final Codec<BedrockOptions> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
Codec.STRING.optionalFieldOf("icon").forGetter(BedrockOptions::icon),
|
||||||
|
Codec.BOOL.optionalFieldOf("allow_offhand", true).forGetter(BedrockOptions::allowOffhand),
|
||||||
|
Codec.BOOL.optionalFieldOf("display_handheld", false).forGetter(BedrockOptions::displayHandheld),
|
||||||
|
Codec.INT.optionalFieldOf("protection_value", 0).forGetter(BedrockOptions::protectionValue)
|
||||||
|
).apply(instance, BedrockOptions::new)
|
||||||
|
);
|
||||||
|
public static final BedrockOptions DEFAULT = new BedrockOptions(Optional.empty(), true, false, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
// TODO group definitions
|
// TODO group definitions
|
||||||
@@ -47,7 +48,7 @@ public class GeyserMappings {
|
|||||||
mappings.put(item, mapping);
|
mappings.put(item, mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void map(ItemStack stack) {
|
public void map(ItemStack stack, Consumer<GeyserMapping> mappingConsumer) {
|
||||||
Optional<? extends ResourceLocation> patchedModel = stack.getComponentsPatch().get(DataComponents.ITEM_MODEL);
|
Optional<? extends ResourceLocation> patchedModel = stack.getComponentsPatch().get(DataComponents.ITEM_MODEL);
|
||||||
//noinspection OptionalAssignedToNull - annoying Mojang
|
//noinspection OptionalAssignedToNull - annoying Mojang
|
||||||
if (patchedModel == null || patchedModel.isEmpty()) {
|
if (patchedModel == null || patchedModel.isEmpty()) {
|
||||||
@@ -59,7 +60,10 @@ public class GeyserMappings {
|
|||||||
int protectionValue = 0; // TODO check the attributes
|
int protectionValue = 0; // TODO check the attributes
|
||||||
|
|
||||||
GeyserItemMapper.mapItem(model, displayName, protectionValue, stack.getComponentsPatch())
|
GeyserItemMapper.mapItem(model, displayName, protectionValue, stack.getComponentsPatch())
|
||||||
.forEach(mapping -> map(stack.getItemHolder(), mapping));
|
.forEach(mapping -> {
|
||||||
|
map(stack.getItemHolder(), mapping);
|
||||||
|
mappingConsumer.accept(mapping);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Holder<Item>, Collection<GeyserMapping>> mappings() {
|
public Map<Holder<Item>, Collection<GeyserMapping>> mappings() {
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.geysermc.packgenerator.pack;
|
||||||
|
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.geysermc.packgenerator.CodecUtil;
|
||||||
|
import org.geysermc.packgenerator.PackConstants;
|
||||||
|
import org.geysermc.packgenerator.mappings.GeyserMappings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class BedrockPack {
|
||||||
|
private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve("geyser");
|
||||||
|
private static final Path PACK_DIRECTORY = Path.of("pack");
|
||||||
|
|
||||||
|
private static final Path MAPPINGS_FILE = Path.of("geyser_mappings.json");
|
||||||
|
private static final Path MANIFEST_FILE = Path.of("manifest.json");
|
||||||
|
private static final Path ITEM_ATLAS_FILE = Path.of("textures/item_texture.json");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final Path exportPath;
|
||||||
|
private final Path packPath;
|
||||||
|
private final PackManifest manifest;
|
||||||
|
private final GeyserMappings mappings;
|
||||||
|
private final BedrockTextures.Builder itemTextures;
|
||||||
|
|
||||||
|
public BedrockPack(String name) throws IOException {
|
||||||
|
this.name = name;
|
||||||
|
exportPath = createPackDirectory(name);
|
||||||
|
packPath = exportPath.resolve(PACK_DIRECTORY);
|
||||||
|
mappings = CodecUtil.readOrCompute(GeyserMappings.CODEC, exportPath.resolve(MAPPINGS_FILE), GeyserMappings::new);
|
||||||
|
manifest = CodecUtil.readOrCompute(PackManifest.CODEC, packPath.resolve(MANIFEST_FILE), () -> defaultManifest(name)).increment();
|
||||||
|
itemTextures = CodecUtil.readOrCompute(BedrockTextureAtlas.ITEM_ATLAS_CODEC, packPath.resolve(ITEM_ATLAS_FILE),
|
||||||
|
() -> BedrockTextureAtlas.itemAtlas(name, BedrockTextures.builder())).textures().toBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void map(ItemStack stack) {
|
||||||
|
mappings.map(stack, mapping -> itemTextures.withItemTexture(mapping, mapping.bedrockIdentifier().getPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() throws IOException {
|
||||||
|
CodecUtil.trySaveJson(GeyserMappings.CODEC, mappings, exportPath.resolve(MAPPINGS_FILE));
|
||||||
|
CodecUtil.trySaveJson(PackManifest.CODEC, manifest, packPath.resolve(MANIFEST_FILE));
|
||||||
|
CodecUtil.trySaveJson(BedrockTextureAtlas.CODEC, BedrockTextureAtlas.itemAtlas(name, itemTextures), packPath.resolve(ITEM_ATLAS_FILE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path createPackDirectory(String name) throws IOException {
|
||||||
|
Path path = EXPORT_DIRECTORY.resolve(name);
|
||||||
|
CodecUtil.ensureDirectoryExists(path);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PackManifest defaultManifest(String name) {
|
||||||
|
return new PackManifest(new PackManifest.Header(name, PackConstants.DEFAULT_PACK_DESCRIPTION, UUID.randomUUID(), BedrockVersion.of(0), PackConstants.ENGINE_VERSION),
|
||||||
|
List.of(new PackManifest.Module(name, PackConstants.DEFAULT_PACK_DESCRIPTION, UUID.randomUUID(), BedrockVersion.of(0))));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.geysermc.packgenerator.pack;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
|
||||||
|
public record BedrockTextureAtlas(String resourcePackName, String atlasName, BedrockTextures textures) {
|
||||||
|
public static final String ITEM_ATLAS = "atlas.items";
|
||||||
|
public static final Codec<BedrockTextureAtlas> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
Codec.STRING.fieldOf("resource_pack_name").forGetter(BedrockTextureAtlas::resourcePackName),
|
||||||
|
Codec.STRING.fieldOf("texture_name").forGetter(BedrockTextureAtlas::atlasName),
|
||||||
|
BedrockTextures.CODEC.fieldOf("texture_data").forGetter(BedrockTextureAtlas::textures)
|
||||||
|
).apply(instance, BedrockTextureAtlas::new)
|
||||||
|
);
|
||||||
|
public static final Codec<BedrockTextureAtlas> ITEM_ATLAS_CODEC = CODEC.validate(atlas -> {
|
||||||
|
if (!ITEM_ATLAS.equals(atlas.atlasName)) {
|
||||||
|
return DataResult.error(() -> "Expected atlas to be " + ITEM_ATLAS + ", got " + atlas.atlasName);
|
||||||
|
}
|
||||||
|
return DataResult.success(atlas);
|
||||||
|
});
|
||||||
|
|
||||||
|
public static BedrockTextureAtlas itemAtlas(String resourcePackName, BedrockTextures.Builder textures) {
|
||||||
|
return new BedrockTextureAtlas(resourcePackName, ITEM_ATLAS, textures.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package org.geysermc.packgenerator.pack;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import org.geysermc.packgenerator.mappings.GeyserMapping;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public record BedrockTextures(Map<String, String> textures) {
|
||||||
|
public static final Codec<BedrockTextures> CODEC =
|
||||||
|
Codec.compoundList(Codec.STRING, Codec.compoundList(Codec.STRING, Codec.STRING))
|
||||||
|
.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 Builder toBuilder() {
|
||||||
|
Builder builder = builder();
|
||||||
|
builder.textures.putAll(textures);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return withTexture(mapping.textureName(), TEXTURES_FOLDER + texturePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withTexture(String name, String texture) {
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Name cannot be empty");
|
||||||
|
}
|
||||||
|
String currentTexture = textures.get(name);
|
||||||
|
if (currentTexture != null) {
|
||||||
|
if (!texture.equals(currentTexture)) {
|
||||||
|
throw new IllegalArgumentException("Texture conflict (name=" + name + ", existing=" + currentTexture + ", new=" + texture + ")");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textures.put(name, texture);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BedrockTextures build() {
|
||||||
|
return new BedrockTextures(Map.copyOf(textures));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user