diff --git a/src/main/java/xyz/eclipseisoffline/geyser/GeyserMapping.java b/src/main/java/xyz/eclipseisoffline/geyser/GeyserMapping.java index 6bd612b..4ced37b 100644 --- a/src/main/java/xyz/eclipseisoffline/geyser/GeyserMapping.java +++ b/src/main/java/xyz/eclipseisoffline/geyser/GeyserMapping.java @@ -3,18 +3,33 @@ package xyz.eclipseisoffline.geyser; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.component.TypedDataComponent; import net.minecraft.resources.ResourceLocation; +import java.util.List; import java.util.Optional; +import java.util.function.Function; public record GeyserMapping(ResourceLocation model, ResourceLocation bedrockIdentifier, BedrockOptions bedrockOptions, DataComponentMap components) { + private static final List> SUPPORTED_COMPONENTS = List.of(DataComponents.CONSUMABLE, DataComponents.EQUIPPABLE, DataComponents.FOOD, + DataComponents.MAX_DAMAGE, DataComponents.MAX_STACK_SIZE, DataComponents.USE_COOLDOWN, DataComponents.ENCHANTABLE, DataComponents.ENCHANTMENT_GLINT_OVERRIDE); + + private static final Codec FILTERED_COMPONENT_MAP_CODEC = DataComponentMap.CODEC.xmap(Function.identity(), map -> { + DataComponentMap.Builder filtered = DataComponentMap.builder(); + map.stream().filter(component -> SUPPORTED_COMPONENTS.contains(component.type())) + .forEach(component -> setTypedComponent(filtered, component)); + return filtered.build(); + }); + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Codec.STRING.fieldOf("type").forGetter(mapping -> "definition"), ResourceLocation.CODEC.fieldOf("model").forGetter(GeyserMapping::model), ResourceLocation.CODEC.fieldOf("bedrock_identifier").forGetter(GeyserMapping::bedrockIdentifier), BedrockOptions.CODEC.fieldOf("bedrock_options").forGetter(GeyserMapping::bedrockOptions), - DataComponentMap.CODEC.fieldOf("components").forGetter(GeyserMapping::components) + FILTERED_COMPONENT_MAP_CODEC.fieldOf("components").forGetter(GeyserMapping::components) ).apply(instance, (type, model, bedrockIdentifier, bedrockOptions, components) -> new GeyserMapping(model, bedrockIdentifier, bedrockOptions, components)) ); @@ -29,4 +44,8 @@ public record GeyserMapping(ResourceLocation model, ResourceLocation bedrockIden ).apply(instance, BedrockOptions::new) ); } + + private static void setTypedComponent(DataComponentMap.Builder builder, TypedDataComponent component) { + builder.set(component.type(), component.value()); + } } diff --git a/src/main/java/xyz/eclipseisoffline/geyser/GeyserMappingsGenerator.java b/src/main/java/xyz/eclipseisoffline/geyser/GeyserMappingsGenerator.java index 03b93a0..e3f1b2c 100644 --- a/src/main/java/xyz/eclipseisoffline/geyser/GeyserMappingsGenerator.java +++ b/src/main/java/xyz/eclipseisoffline/geyser/GeyserMappingsGenerator.java @@ -30,11 +30,23 @@ public class GeyserMappingsGenerator implements ClientModInitializer { .then(ClientCommandManager.literal("map") .executes(context -> { ItemStack heldItem = context.getSource().getPlayer().getMainHandItem(); - PackManager.getInstance().map(heldItem); + PackManager.getInstance().map(heldItem, true); context.getSource().sendFeedback(Component.literal("Added held item to Geyser mappings")); return 0; }) ) + .then(ClientCommandManager.literal("mapinventory") + .executes(context -> { + int mapped = 0; + for (ItemStack stack : context.getSource().getPlayer().getInventory()) { + if (PackManager.getInstance().map(stack, false)) { + mapped++; + } + } + context.getSource().sendFeedback(Component.literal("Mapped " + mapped + " items from your inventory")); + return 0; + }) + ) .then(ClientCommandManager.literal("finish") .executes(context -> { PackManager.getInstance().finish(); diff --git a/src/main/java/xyz/eclipseisoffline/geyser/PackManager.java b/src/main/java/xyz/eclipseisoffline/geyser/PackManager.java index 027ef49..0dd1f7f 100644 --- a/src/main/java/xyz/eclipseisoffline/geyser/PackManager.java +++ b/src/main/java/xyz/eclipseisoffline/geyser/PackManager.java @@ -1,10 +1,8 @@ package xyz.eclipseisoffline.geyser; -import com.google.gson.FormattingStyle; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; -import com.google.gson.stream.JsonWriter; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.serialization.JsonOps; @@ -14,8 +12,6 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -42,13 +38,16 @@ public final class PackManager { mappings = new GeyserMappings(); } - public void map(ItemStack stack) throws CommandSyntaxException { + public boolean map(ItemStack stack, boolean throwOnModelMissing) throws CommandSyntaxException { ensurePackIsCreated(); Optional patchedModel = stack.getComponentsPatch().get(DataComponents.ITEM_MODEL); //noinspection OptionalAssignedToNull - annoying Mojang if (patchedModel == null || patchedModel.isEmpty()) { - throw new SimpleCommandExceptionType(Component.literal("Item stack does not have a custom model")).create(); + if (throwOnModelMissing) { + throw new SimpleCommandExceptionType(Component.literal("Item stack does not have a custom model")).create(); + } + return false; } ResourceLocation model = patchedModel.get(); @@ -56,6 +55,8 @@ public final class PackManager { new GeyserMapping.BedrockOptions(Optional.empty(), true, false, 0), stack.getComponentsPatch().split().added()); // TODO removed components mappings.map(stack.getItemHolder(), mapping); + + return true; } public void finish() throws CommandSyntaxException {