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

Work on actually looking into block model geometry/handheld/texture info

This commit is contained in:
Eclipse
2025-07-04 10:49:53 +00:00
parent b685d9c0df
commit fce70853e0
8 changed files with 74 additions and 8 deletions

View File

@@ -21,6 +21,7 @@ public class GeyserMappingsGenerator implements ClientModInitializer {
private final PackManager packManager = new PackManager();
private final PackMapper packMapper = new PackMapper(packManager);
// TODO export language overrides
@Override
public void onInitializeClient() {
ClientCommandRegistrationCallback.EVENT.register((dispatcher, buildContext) -> PackGeneratorCommand.register(dispatcher, packManager, packMapper));

View File

@@ -2,7 +2,7 @@ package org.geysermc.packgenerator.accessor;
import net.minecraft.resources.ResourceLocation;
// Implemented on BlockModelWrapper, since this class doesn't store its model, we have to store it manually
// Implemented on BlockModelWrapper, since this class doesn't store its model after baking, we have to store it manually
public interface BlockModelWrapperLocationAccessor {
ResourceLocation geyser_mappings_generator$getModelOrigin();

View File

@@ -0,0 +1,12 @@
package org.geysermc.packgenerator.accessor;
import net.minecraft.client.resources.model.ResolvedModel;
import net.minecraft.resources.ResourceLocation;
import java.util.Optional;
// Implemented on ModelManager, since this class doesn't keep the resolved models after baking, we have to store it manually
public interface ResolvedModelAccessor {
Optional<ResolvedModel> geyser_mappings_generator$getResolvedModel(ResourceLocation location);
}

View File

@@ -3,7 +3,7 @@ package org.geysermc.packgenerator.accessor;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import net.minecraft.client.renderer.item.ItemModel;
// Implemented on BlockModelWrapper, since this class doesn't store the cases it has in a nice format, we have to store it manually
// Implemented on BlockModelWrapper, since this class doesn't store the cases it has in a nice format after baking, we have to store it manually
public interface SelectItemModelCasesAccessor<T> {
Object2ObjectMap<T, ItemModel> geyser_mappings_generator$getCases();

View File

@@ -24,6 +24,7 @@ import net.minecraft.world.item.CrossbowItem;
import net.minecraft.world.item.equipment.trim.TrimMaterial;
import net.minecraft.world.level.Level;
import org.geysermc.packgenerator.accessor.BlockModelWrapperLocationAccessor;
import org.geysermc.packgenerator.accessor.ResolvedModelAccessor;
import org.geysermc.packgenerator.accessor.SelectItemModelCasesAccessor;
import org.geysermc.packgenerator.mapping.geyser.predicate.GeyserConditionPredicate;
import org.geysermc.packgenerator.mapping.geyser.predicate.GeyserMatchPredicate;
@@ -41,18 +42,27 @@ public class GeyserItemMapper {
public static Stream<GeyserSingleDefinition> mapItem(ResourceLocation modelLocation, String displayName, int protectionValue, DataComponentPatch componentPatch,
ProblemReporter reporter) {
ItemModel model = Minecraft.getInstance().getModelManager().getItemModel(modelLocation);
MappingContext context = new MappingContext(List.of(), modelLocation, displayName, protectionValue, componentPatch, reporter.forChild(() -> "model " + modelLocation + " "));
MappingContext context = new MappingContext(List.of(), modelLocation, displayName, protectionValue, componentPatch, reporter.forChild(() -> "client item definition " + modelLocation + " "));
return mapItem(model, context);
}
private static Stream<GeyserSingleDefinition> mapItem(ItemModel model, MappingContext context) {
switch (model) {
case BlockModelWrapper modelWrapper -> {
ResourceLocation itemModel = ((BlockModelWrapperLocationAccessor) modelWrapper).geyser_mappings_generator$getModelOrigin();
if (itemModel.getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) {
itemModel = ResourceLocation.fromNamespaceAndPath("geyser_mc", itemModel.getPath());
}
return Stream.of(context.create(itemModel));
ResourceLocation itemModelLocation = ((BlockModelWrapperLocationAccessor) modelWrapper).geyser_mappings_generator$getModelOrigin();
return ((ResolvedModelAccessor) Minecraft.getInstance().getModelManager()).geyser_mappings_generator$getResolvedModel(itemModelLocation)
.map(itemModel -> {
ResourceLocation bedrockIdentifier = itemModelLocation;
if (bedrockIdentifier.getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) {
bedrockIdentifier = ResourceLocation.fromNamespaceAndPath("geyser_mc", itemModelLocation.getPath());
}
return Stream.of(context.create(bedrockIdentifier));
})
.orElseGet(() -> {
context.reporter.report(() -> "missing block model " + itemModelLocation);
return Stream.empty();
});
}
case ConditionalItemModel conditional -> {
return mapConditionalModel(conditional, context.child("condition " + conditional + " "));

View File

@@ -15,6 +15,7 @@ import java.util.function.Function;
// TODO other keys, etc.
// TODO sometimes still includes components key when patch before filtering is not empty but after is
// TODO display name can be a component
public record GeyserSingleDefinition(Optional<ResourceLocation> model, ResourceLocation bedrockIdentifier, Optional<String> displayName,
List<GeyserPredicate> predicates, BedrockOptions bedrockOptions, DataComponentPatch components) implements GeyserMapping {
private static final List<DataComponentType<?>> SUPPORTED_COMPONENTS = List.of(DataComponents.CONSUMABLE, DataComponents.EQUIPPABLE, DataComponents.FOOD,

View File

@@ -0,0 +1,41 @@
package org.geysermc.packgenerator.mixin;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ResolvedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import org.geysermc.packgenerator.accessor.ResolvedModelAccessor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Mixin(ModelManager.class)
public abstract class ModelManagerMixin implements PreparableReloadListener, AutoCloseable, ResolvedModelAccessor {
@Unique
private Map<ResourceLocation, ResolvedModel> unbakedResolvedModels;
@WrapOperation(method = "method_65753", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;join()Ljava/lang/Object;", ordinal = 0))
private static Object setResolvedModels(CompletableFuture<?> instance, Operation<Object> original) {
Object resolved = original.call(instance);
try {
// Couldn't be bothered setting up access wideners, this resolves the second component of the ResolvedModels record, which is called "models"
((ModelManagerMixin) (Object) Minecraft.getInstance().getModelManager()).unbakedResolvedModels = (Map<ResourceLocation, ResolvedModel>) resolved.getClass().getRecordComponents()[1].getAccessor().invoke(resolved);
} catch (IllegalAccessException | InvocationTargetException | ClassCastException exception) {
throw new RuntimeException(exception);
}
return resolved;
}
@Override
public Optional<ResolvedModel> geyser_mappings_generator$getResolvedModel(ResourceLocation location) {
return unbakedResolvedModels == null ? Optional.empty() : Optional.ofNullable(unbakedResolvedModels.get(location));
}
}

View File

@@ -9,6 +9,7 @@
"BlockModelWrapperMixin$UnbakedMixin",
"ConditionalItemModelAccessor",
"EntityRenderDispatcherAccessor",
"ModelManagerMixin",
"SelectItemModelAccessor",
"SelectItemModelMixin",
"SelectItemModelMixin$UnbakedSwitchMixin",