mirror of
https://github.com/GeyserMC/Rainbow.git
synced 2025-12-19 14:59:16 +00:00
Proper handheld detection and model -> texture
This commit is contained in:
@@ -16,6 +16,8 @@ import net.minecraft.client.renderer.item.properties.select.Charge;
|
|||||||
import net.minecraft.client.renderer.item.properties.select.ContextDimension;
|
import net.minecraft.client.renderer.item.properties.select.ContextDimension;
|
||||||
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperty;
|
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperty;
|
||||||
import net.minecraft.client.renderer.item.properties.select.TrimMaterialProperty;
|
import net.minecraft.client.renderer.item.properties.select.TrimMaterialProperty;
|
||||||
|
import net.minecraft.client.resources.model.Material;
|
||||||
|
import net.minecraft.client.resources.model.ResolvedModel;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -34,49 +36,56 @@ import org.geysermc.packgenerator.mixin.SelectItemModelAccessor;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class GeyserItemMapper {
|
public class GeyserItemMapper {
|
||||||
|
private static final List<ResourceLocation> HANDHELD_MODELS = Stream.of("item/handheld", "item/handheld_rod", "item/handheld_mace")
|
||||||
|
.map(ResourceLocation::withDefaultNamespace)
|
||||||
|
.toList();
|
||||||
|
|
||||||
public static Stream<GeyserSingleDefinition> mapItem(ResourceLocation modelLocation, String displayName, int protectionValue, DataComponentPatch componentPatch,
|
public static void mapItem(ResourceLocation modelLocation, String displayName, int protectionValue, DataComponentPatch componentPatch, ProblemReporter reporter,
|
||||||
ProblemReporter reporter) {
|
BiConsumer<GeyserSingleDefinition, ResourceLocation> mappingTextureConsumer) {
|
||||||
ItemModel model = Minecraft.getInstance().getModelManager().getItemModel(modelLocation);
|
ItemModel model = Minecraft.getInstance().getModelManager().getItemModel(modelLocation);
|
||||||
MappingContext context = new MappingContext(List.of(), modelLocation, displayName, protectionValue, componentPatch, reporter.forChild(() -> "client item definition " + modelLocation + " "));
|
MappingContext context = new MappingContext(List.of(), modelLocation, displayName, protectionValue, componentPatch, reporter.forChild(() -> "client item definition " + modelLocation + " "), mappingTextureConsumer);
|
||||||
return mapItem(model, context);
|
mapItem(model, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<GeyserSingleDefinition> mapItem(ItemModel model, MappingContext context) {
|
private static void mapItem(ItemModel model, MappingContext context) {
|
||||||
switch (model) {
|
switch (model) {
|
||||||
case BlockModelWrapper modelWrapper -> {
|
case BlockModelWrapper modelWrapper -> {
|
||||||
ResourceLocation itemModelLocation = ((BlockModelWrapperLocationAccessor) modelWrapper).geyser_mappings_generator$getModelOrigin();
|
ResourceLocation itemModelLocation = ((BlockModelWrapperLocationAccessor) modelWrapper).geyser_mappings_generator$getModelOrigin();
|
||||||
|
|
||||||
return ((ResolvedModelAccessor) Minecraft.getInstance().getModelManager()).geyser_mappings_generator$getResolvedModel(itemModelLocation)
|
((ResolvedModelAccessor) Minecraft.getInstance().getModelManager()).geyser_mappings_generator$getResolvedModel(itemModelLocation)
|
||||||
.map(itemModel -> {
|
.ifPresentOrElse(itemModel -> {
|
||||||
|
ResolvedModel parentModel = itemModel.parent();
|
||||||
|
boolean handheld = false;
|
||||||
|
if (parentModel != null) {
|
||||||
|
// debugName() returns the resource location of the model as a string
|
||||||
|
handheld = HANDHELD_MODELS.contains(ResourceLocation.parse(parentModel.debugName()));
|
||||||
|
}
|
||||||
|
|
||||||
ResourceLocation bedrockIdentifier = itemModelLocation;
|
ResourceLocation bedrockIdentifier = itemModelLocation;
|
||||||
if (bedrockIdentifier.getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) {
|
if (bedrockIdentifier.getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) {
|
||||||
bedrockIdentifier = ResourceLocation.fromNamespaceAndPath("geyser_mc", itemModelLocation.getPath());
|
bedrockIdentifier = ResourceLocation.fromNamespaceAndPath("geyser_mc", itemModelLocation.getPath());
|
||||||
}
|
}
|
||||||
return Stream.of(context.create(bedrockIdentifier));
|
|
||||||
})
|
ResourceLocation texture = itemModelLocation;
|
||||||
.orElseGet(() -> {
|
Material layer0Texture = itemModel.getTopTextureSlots().getMaterial("layer0");
|
||||||
context.reporter.report(() -> "missing block model " + itemModelLocation);
|
if (layer0Texture != null) {
|
||||||
return Stream.empty();
|
texture = layer0Texture.texture();
|
||||||
});
|
}
|
||||||
|
context.create(bedrockIdentifier, texture, handheld);
|
||||||
|
}, () -> context.reporter.report(() -> "missing block model " + itemModelLocation));
|
||||||
}
|
}
|
||||||
case ConditionalItemModel conditional -> {
|
case ConditionalItemModel conditional -> mapConditionalModel(conditional, context.child("condition " + conditional + " "));
|
||||||
return mapConditionalModel(conditional, context.child("condition " + conditional + " "));
|
case SelectItemModel<?> select -> mapSelectModel(select, context.child("select " + select + " "));
|
||||||
}
|
default -> context.reporter.report(() -> "unable to map item model " + model.getClass());
|
||||||
case SelectItemModel<?> select -> {
|
|
||||||
return mapSelectModel(select, context.child("select " + select + " "));
|
|
||||||
}
|
|
||||||
default -> {}
|
|
||||||
}
|
}
|
||||||
context.reporter.report(() -> "unable to map item model " + model.getClass());
|
|
||||||
return Stream.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<GeyserSingleDefinition> mapConditionalModel(ConditionalItemModel model, MappingContext context) {
|
private static void mapConditionalModel(ConditionalItemModel model, MappingContext context) {
|
||||||
ItemModelPropertyTest property = ((ConditionalItemModelAccessor) model).getProperty();
|
ItemModelPropertyTest property = ((ConditionalItemModelAccessor) model).getProperty();
|
||||||
GeyserConditionPredicate.Property predicateProperty = switch (property) {
|
GeyserConditionPredicate.Property predicateProperty = switch (property) {
|
||||||
case Broken ignored -> GeyserConditionPredicate.BROKEN;
|
case Broken ignored -> GeyserConditionPredicate.BROKEN;
|
||||||
@@ -88,19 +97,17 @@ public class GeyserItemMapper {
|
|||||||
};
|
};
|
||||||
if (predicateProperty == null) {
|
if (predicateProperty == null) {
|
||||||
context.reporter.report(() -> "unsupported conditional model property " + property);
|
context.reporter.report(() -> "unsupported conditional model property " + property);
|
||||||
return Stream.empty();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemModel onTrue = ((ConditionalItemModelAccessor) model).getOnTrue();
|
ItemModel onTrue = ((ConditionalItemModelAccessor) model).getOnTrue();
|
||||||
ItemModel onFalse = ((ConditionalItemModelAccessor) model).getOnFalse();
|
ItemModel onFalse = ((ConditionalItemModelAccessor) model).getOnFalse();
|
||||||
|
|
||||||
return Stream.concat(
|
mapItem(onTrue, context.with(new GeyserConditionPredicate(predicateProperty, true), "condition on true "));
|
||||||
mapItem(onTrue, context.with(new GeyserConditionPredicate(predicateProperty, true), "condition on true ")),
|
mapItem(onFalse, context.with(new GeyserConditionPredicate(predicateProperty, false), "condition on false "));
|
||||||
mapItem(onFalse, context.with(new GeyserConditionPredicate(predicateProperty, false), "condition on false "))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> Stream<GeyserSingleDefinition> mapSelectModel(SelectItemModel<T> model, MappingContext context) {
|
private static <T> void mapSelectModel(SelectItemModel<T> model, MappingContext context) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
SelectItemModelProperty<T> property = ((SelectItemModelAccessor<T>) model).getProperty();
|
SelectItemModelProperty<T> property = ((SelectItemModelAccessor<T>) model).getProperty();
|
||||||
Function<T, GeyserMatchPredicate.MatchPredicateData> dataConstructor = switch (property) {
|
Function<T, GeyserMatchPredicate.MatchPredicateData> dataConstructor = switch (property) {
|
||||||
@@ -113,34 +120,31 @@ public class GeyserItemMapper {
|
|||||||
};
|
};
|
||||||
if (dataConstructor == null) {
|
if (dataConstructor == null) {
|
||||||
context.reporter.report(() -> "unsupported select model property " + property);
|
context.reporter.report(() -> "unsupported select model property " + property);
|
||||||
return Stream.empty();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
Object2ObjectMap<T, ItemModel> cases = ((SelectItemModelCasesAccessor<T>) model).geyser_mappings_generator$getCases();
|
Object2ObjectMap<T, ItemModel> cases = ((SelectItemModelCasesAccessor<T>) model).geyser_mappings_generator$getCases();
|
||||||
return Stream.concat(
|
|
||||||
cases.entrySet().stream()
|
cases.entrySet().forEach(caze -> mapItem(caze.getValue(), context.with(new GeyserMatchPredicate(dataConstructor.apply(caze.getKey())), "select case " + caze.getKey() + " ")));
|
||||||
.flatMap(caze -> mapItem(caze.getValue(), context.with(new GeyserMatchPredicate(dataConstructor.apply(caze.getKey())), "select case " + caze.getKey() + " "))),
|
mapItem(cases.defaultReturnValue(), context.child("default case "));
|
||||||
mapItem(cases.defaultReturnValue(), context.child("default case "))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private record MappingContext(List<GeyserPredicate> predicateStack, ResourceLocation model, String displayName, int protectionValue, DataComponentPatch componentPatch,
|
private record MappingContext(List<GeyserPredicate> predicateStack, ResourceLocation model, String displayName, int protectionValue, DataComponentPatch componentPatch, ProblemReporter reporter,
|
||||||
ProblemReporter reporter) {
|
BiConsumer<GeyserSingleDefinition, ResourceLocation> mappingTextureConsumer) {
|
||||||
|
|
||||||
public MappingContext with(GeyserPredicate predicate, String childName) {
|
public MappingContext with(GeyserPredicate predicate, String childName) {
|
||||||
return new MappingContext(Stream.concat(predicateStack.stream(), Stream.of(predicate)).toList(), model, displayName, protectionValue, componentPatch,
|
return new MappingContext(Stream.concat(predicateStack.stream(), Stream.of(predicate)).toList(), model, displayName, protectionValue, componentPatch,
|
||||||
reporter.forChild(() -> childName));
|
reporter.forChild(() -> childName), mappingTextureConsumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MappingContext child(String childName) {
|
public MappingContext child(String childName) {
|
||||||
return new MappingContext(predicateStack, model, displayName, protectionValue, componentPatch, reporter.forChild(() -> childName));
|
return new MappingContext(predicateStack, model, displayName, protectionValue, componentPatch, reporter.forChild(() -> childName), mappingTextureConsumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeyserSingleDefinition create(ResourceLocation bedrockIdentifier) {
|
public void create(ResourceLocation bedrockIdentifier, ResourceLocation texture, boolean displayHandheld) {
|
||||||
return new GeyserSingleDefinition(Optional.of(model), bedrockIdentifier, Optional.of(displayName), predicateStack,
|
mappingTextureConsumer.accept(new GeyserSingleDefinition(Optional.of(model), bedrockIdentifier, Optional.of(displayName), predicateStack,
|
||||||
new GeyserSingleDefinition.BedrockOptions(Optional.empty(), true, false, protectionValue), // TODO handheld prediction
|
new GeyserSingleDefinition.BedrockOptions(Optional.empty(), true, displayHandheld, protectionValue), componentPatch), texture);
|
||||||
componentPatch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@@ -74,19 +75,19 @@ public class GeyserMappings {
|
|||||||
return mappings.size();
|
return mappings.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void map(ItemStack stack, ResourceLocation model, ProblemReporter reporter, Consumer<GeyserSingleDefinition> mappingConsumer) {
|
public void map(ItemStack stack, ResourceLocation model, ProblemReporter reporter, BiConsumer<GeyserSingleDefinition, ResourceLocation> mappingTextureConsumer) {
|
||||||
String displayName = stack.getHoverName().getString();
|
String displayName = stack.getHoverName().getString();
|
||||||
int protectionValue = 0; // TODO check the attributes
|
int protectionValue = 0; // TODO check the attributes
|
||||||
|
|
||||||
GeyserItemMapper.mapItem(model, displayName, protectionValue, stack.getComponentsPatch(), reporter)
|
GeyserItemMapper.mapItem(model, displayName, protectionValue, stack.getComponentsPatch(), reporter,
|
||||||
.forEach(mapping -> {
|
(mapping, texture) -> {
|
||||||
try {
|
try {
|
||||||
map(stack.getItemHolder(), mapping);
|
map(stack.getItemHolder(), mapping);
|
||||||
} catch (IllegalArgumentException exception) {
|
} catch (IllegalArgumentException exception) {
|
||||||
reporter.forChild(() -> "mapping with bedrock identifier " + mapping.bedrockIdentifier() + " ").report(() -> "failed to add mapping to mappings file: " + exception.getMessage());
|
reporter.forChild(() -> "mapping with bedrock identifier " + mapping.bedrockIdentifier() + " ").report(() -> "failed to add mapping to mappings file: " + exception.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mappingConsumer.accept(mapping);
|
mappingTextureConsumer.accept(mapping, texture);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public abstract class ModelManagerMixin implements PreparableReloadListener, Aut
|
|||||||
Object resolved = original.call(instance);
|
Object resolved = original.call(instance);
|
||||||
try {
|
try {
|
||||||
// Couldn't be bothered setting up access wideners, this resolves the second component of the ResolvedModels record, which is called "models"
|
// Couldn't be bothered setting up access wideners, this resolves the second component of the ResolvedModels record, which is called "models"
|
||||||
|
// Ideally we'd somehow use the "this" instance, but that's not possible here since the lambda we inject into is a static one
|
||||||
((ModelManagerMixin) (Object) Minecraft.getInstance().getModelManager()).unbakedResolvedModels = (Map<ResourceLocation, ResolvedModel>) resolved.getClass().getRecordComponents()[1].getAccessor().invoke(resolved);
|
((ModelManagerMixin) (Object) Minecraft.getInstance().getModelManager()).unbakedResolvedModels = (Map<ResourceLocation, ResolvedModel>) resolved.getClass().getRecordComponents()[1].getAccessor().invoke(resolved);
|
||||||
} catch (IllegalAccessException | InvocationTargetException | ClassCastException exception) {
|
} catch (IllegalAccessException | InvocationTargetException | ClassCastException exception) {
|
||||||
throw new RuntimeException(exception);
|
throw new RuntimeException(exception);
|
||||||
|
|||||||
@@ -101,13 +101,8 @@ public class BedrockPack {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mappings.map(stack, model, mapReporter, mapping -> {
|
mappings.map(stack, model, mapReporter, (mapping, texture) -> {
|
||||||
// TODO a proper way to get texture from item model
|
itemTextures.withItemTexture(mapping, texture.getPath());
|
||||||
itemTextures.withItemTexture(mapping, mapping.bedrockIdentifier().getPath());
|
|
||||||
ResourceLocation texture = mapping.bedrockIdentifier();
|
|
||||||
if (texture.getNamespace().equals("geyser_mc")) {
|
|
||||||
texture = ResourceLocation.withDefaultNamespace(texture.getPath());
|
|
||||||
}
|
|
||||||
texturesToExport.add(texture);
|
texturesToExport.add(texture);
|
||||||
AttachableMapper.mapItem(stack, mapping.bedrockIdentifier(), texturesToExport::add).ifPresent(attachables::add);
|
AttachableMapper.mapItem(stack, mapping.bedrockIdentifier(), texturesToExport::add).ifPresent(attachables::add);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user