mirror of
https://github.com/GeyserMC/Rainbow.git
synced 2025-12-19 14:59:16 +00:00
Use group definitions when generating mappings
This commit is contained in:
@@ -6,6 +6,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public record GeyserGroupDefinition(Optional<ResourceLocation> model, List<GeyserMapping> definitions) implements GeyserMapping {
|
||||
|
||||
@@ -16,6 +17,26 @@ public record GeyserGroupDefinition(Optional<ResourceLocation> model, List<Geyse
|
||||
).apply(instance, GeyserGroupDefinition::new)
|
||||
);
|
||||
|
||||
public GeyserGroupDefinition with(GeyserMapping mapping) {
|
||||
return new GeyserGroupDefinition(model, Stream.concat(definitions.stream(), Stream.of(mapping)).toList());
|
||||
}
|
||||
|
||||
public boolean isFor(ResourceLocation model) {
|
||||
return this.model.isPresent() && this.model.get().equals(model);
|
||||
}
|
||||
|
||||
public boolean conflictsWith(Optional<ResourceLocation> parentModel, GeyserSingleDefinition other) {
|
||||
Optional<ResourceLocation> thisModel = model.or(() -> parentModel);
|
||||
for (GeyserMapping definition : definitions) {
|
||||
if (definition instanceof GeyserGroupDefinition group && group.conflictsWith(thisModel, other)) {
|
||||
return true;
|
||||
} else if (definition instanceof GeyserSingleDefinition single && single.conflictsWith(thisModel, other)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return Type.GROUP;
|
||||
|
||||
@@ -128,7 +128,7 @@ public class GeyserItemMapper {
|
||||
}
|
||||
|
||||
public GeyserSingleDefinition create(ResourceLocation bedrockIdentifier) {
|
||||
return new GeyserSingleDefinition(model, bedrockIdentifier, Optional.of(displayName), predicateStack,
|
||||
return new GeyserSingleDefinition(Optional.of(model), bedrockIdentifier, Optional.of(displayName), predicateStack,
|
||||
new GeyserSingleDefinition.BedrockOptions(Optional.empty(), true, false, protectionValue), // TODO handheld prediction
|
||||
componentPatch);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
package org.geysermc.packgenerator.mapping.geyser;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface GeyserMapping {
|
||||
|
||||
Codec<GeyserMapping> CODEC = Type.CODEC.dispatch(GeyserMapping::type, Type::codec);
|
||||
Codec<GeyserMapping> CODEC = Codec.lazyInitialized(() -> Type.CODEC.dispatch(GeyserMapping::type, Type::codec));
|
||||
// Not perfect since we're not checking single definitions in groups without a model... but good enough
|
||||
Codec<GeyserMapping> MODEL_SAFE_CODEC = CODEC.validate(mapping -> {
|
||||
if (mapping instanceof GeyserSingleDefinition single && single.model().isEmpty()) {
|
||||
return DataResult.error(() -> "Top level single definition must have a model");
|
||||
}
|
||||
return DataResult.success(mapping);
|
||||
});
|
||||
|
||||
Type type();
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ import org.geysermc.packgenerator.CodecUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
// TODO group definitions
|
||||
public class GeyserMappings {
|
||||
private static final Codec<Map<Holder<Item>, Collection<GeyserSingleDefinition>>> MAPPINGS_CODEC = Codec.unboundedMap(Item.CODEC, GeyserSingleDefinition.CODEC.listOf().xmap(Function.identity(), ArrayList::new));
|
||||
private static final Codec<Map<Holder<Item>, Collection<GeyserMapping>>> MAPPINGS_CODEC = Codec.unboundedMap(Item.CODEC, GeyserMapping.MODEL_SAFE_CODEC.listOf().xmap(Function.identity(), ArrayList::new));
|
||||
|
||||
public static final Codec<GeyserMappings> CODEC = RecordCodecBuilder.create(instance ->
|
||||
instance.group(
|
||||
@@ -30,24 +30,45 @@ public class GeyserMappings {
|
||||
).apply(instance, (format, mappings) -> new GeyserMappings(mappings))
|
||||
);
|
||||
|
||||
private final Multimap<Holder<Item>, GeyserSingleDefinition> mappings = MultimapBuilder.hashKeys().hashSetValues().build();
|
||||
private final Multimap<Holder<Item>, GeyserMapping> mappings = MultimapBuilder.hashKeys().hashSetValues().build();
|
||||
|
||||
public GeyserMappings() {}
|
||||
|
||||
private GeyserMappings(Map<Holder<Item>, Collection<GeyserSingleDefinition>> mappings) {
|
||||
private GeyserMappings(Map<Holder<Item>, Collection<GeyserMapping>> mappings) {
|
||||
for (Holder<Item> item : mappings.keySet()) {
|
||||
this.mappings.putAll(item, mappings.get(item));
|
||||
}
|
||||
}
|
||||
|
||||
public void map(Holder<Item> item, GeyserSingleDefinition mapping) {
|
||||
for (GeyserSingleDefinition existing : mappings.get(item)) {
|
||||
if (existing.conflictsWith(mapping)) {
|
||||
throw new IllegalArgumentException("Mapping conflicts with existing mapping");
|
||||
ResourceLocation model = mapping.model().orElseThrow();
|
||||
Optional<GeyserGroupDefinition> modelGroup = Optional.empty();
|
||||
|
||||
Collection<GeyserMapping> existingMappings = new ArrayList<>(mappings.get(item));
|
||||
for (GeyserMapping existing : existingMappings) {
|
||||
if (existing instanceof GeyserGroupDefinition existingGroup && existingGroup.isFor(model)) {
|
||||
if (existingGroup.conflictsWith(Optional.empty(), mapping)) {
|
||||
throw new IllegalArgumentException("Mapping conflicts with existing group mapping");
|
||||
}
|
||||
modelGroup = Optional.of(existingGroup);
|
||||
break;
|
||||
} else if (existing instanceof GeyserSingleDefinition single) {
|
||||
if (single.conflictsWith(Optional.empty(), mapping)) {
|
||||
throw new IllegalArgumentException("Mapping conflicts with existing single mapping");
|
||||
} else if (model.equals(single.model().orElseThrow())) {
|
||||
mappings.remove(item, single);
|
||||
modelGroup = Optional.of(new GeyserGroupDefinition(Optional.of(model), List.of(single.withoutModel())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modelGroup.isPresent()) {
|
||||
mappings.remove(item, modelGroup.get());
|
||||
mappings.put(item, modelGroup.get().with(mapping.withoutModel()));
|
||||
} else {
|
||||
mappings.put(item, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return mappings.size();
|
||||
@@ -76,7 +97,7 @@ public class GeyserMappings {
|
||||
});
|
||||
}
|
||||
|
||||
public Map<Holder<Item>, Collection<GeyserSingleDefinition>> mappings() {
|
||||
public Map<Holder<Item>, Collection<GeyserMapping>> mappings() {
|
||||
return mappings.asMap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +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
|
||||
public record GeyserSingleDefinition(ResourceLocation model, ResourceLocation bedrockIdentifier, Optional<String> displayName,
|
||||
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,
|
||||
DataComponents.MAX_DAMAGE, DataComponents.MAX_STACK_SIZE, DataComponents.USE_COOLDOWN, DataComponents.ENCHANTABLE, DataComponents.ENCHANTMENT_GLINT_OVERRIDE);
|
||||
@@ -36,7 +36,7 @@ public record GeyserSingleDefinition(ResourceLocation model, ResourceLocation be
|
||||
|
||||
public static final MapCodec<GeyserSingleDefinition> CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||||
instance.group(
|
||||
ResourceLocation.CODEC.fieldOf("model").forGetter(GeyserSingleDefinition::model),
|
||||
ResourceLocation.CODEC.optionalFieldOf("model").forGetter(GeyserSingleDefinition::model),
|
||||
ResourceLocation.CODEC.fieldOf("bedrock_identifier").forGetter(GeyserSingleDefinition::bedrockIdentifier),
|
||||
Codec.STRING.optionalFieldOf("display_name").forGetter(GeyserSingleDefinition::displayName),
|
||||
GeyserPredicate.LIST_CODEC.optionalFieldOf("predicate", List.of()).forGetter(GeyserSingleDefinition::predicates),
|
||||
@@ -49,8 +49,10 @@ public record GeyserSingleDefinition(ResourceLocation model, ResourceLocation be
|
||||
return bedrockOptions.icon.orElse(iconFromResourceLocation(bedrockIdentifier));
|
||||
}
|
||||
|
||||
public boolean conflictsWith(GeyserSingleDefinition other) {
|
||||
if (!model.equals(other.model)) {
|
||||
public boolean conflictsWith(Optional<ResourceLocation> parentModel, GeyserSingleDefinition other) {
|
||||
ResourceLocation thisModel = model.or(() -> parentModel).orElseThrow();
|
||||
ResourceLocation otherModel = other.model.or(() -> parentModel).orElseThrow();
|
||||
if (!thisModel.equals(otherModel)) {
|
||||
return false;
|
||||
} else if (predicates.size() == other.predicates.size()) {
|
||||
boolean predicatesAreEqual = true;
|
||||
@@ -65,6 +67,10 @@ public record GeyserSingleDefinition(ResourceLocation model, ResourceLocation be
|
||||
return false;
|
||||
}
|
||||
|
||||
public GeyserSingleDefinition withoutModel() {
|
||||
return new GeyserSingleDefinition(Optional.empty(), bedrockIdentifier, displayName, predicates, bedrockOptions, components);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return Type.SINGLE;
|
||||
|
||||
Reference in New Issue
Block a user