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.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public record GeyserGroupDefinition(Optional<ResourceLocation> model, List<GeyserMapping> definitions) implements GeyserMapping {
|
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)
|
).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
|
@Override
|
||||||
public Type type() {
|
public Type type() {
|
||||||
return Type.GROUP;
|
return Type.GROUP;
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public class GeyserItemMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GeyserSingleDefinition create(ResourceLocation bedrockIdentifier) {
|
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
|
new GeyserSingleDefinition.BedrockOptions(Optional.empty(), true, false, protectionValue), // TODO handheld prediction
|
||||||
componentPatch);
|
componentPatch);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
package org.geysermc.packgenerator.mapping.geyser;
|
package org.geysermc.packgenerator.mapping.geyser;
|
||||||
|
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import net.minecraft.util.StringRepresentable;
|
import net.minecraft.util.StringRepresentable;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public interface GeyserMapping {
|
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();
|
Type type();
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ import org.geysermc.packgenerator.CodecUtil;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
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.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
// TODO group definitions
|
|
||||||
public class GeyserMappings {
|
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 ->
|
public static final Codec<GeyserMappings> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
instance.group(
|
instance.group(
|
||||||
@@ -30,24 +30,45 @@ public class GeyserMappings {
|
|||||||
).apply(instance, (format, mappings) -> new GeyserMappings(mappings))
|
).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() {}
|
public GeyserMappings() {}
|
||||||
|
|
||||||
private GeyserMappings(Map<Holder<Item>, Collection<GeyserSingleDefinition>> mappings) {
|
private GeyserMappings(Map<Holder<Item>, Collection<GeyserMapping>> mappings) {
|
||||||
for (Holder<Item> item : mappings.keySet()) {
|
for (Holder<Item> item : mappings.keySet()) {
|
||||||
this.mappings.putAll(item, mappings.get(item));
|
this.mappings.putAll(item, mappings.get(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void map(Holder<Item> item, GeyserSingleDefinition mapping) {
|
public void map(Holder<Item> item, GeyserSingleDefinition mapping) {
|
||||||
for (GeyserSingleDefinition existing : mappings.get(item)) {
|
ResourceLocation model = mapping.model().orElseThrow();
|
||||||
if (existing.conflictsWith(mapping)) {
|
Optional<GeyserGroupDefinition> modelGroup = Optional.empty();
|
||||||
throw new IllegalArgumentException("Mapping conflicts with existing mapping");
|
|
||||||
|
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);
|
mappings.put(item, mapping);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
return mappings.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();
|
return mappings.asMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import java.util.function.Function;
|
|||||||
|
|
||||||
// TODO other keys, etc.
|
// TODO other keys, etc.
|
||||||
// TODO sometimes still includes components key when patch before filtering is not empty but after is
|
// 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 {
|
List<GeyserPredicate> predicates, BedrockOptions bedrockOptions, DataComponentPatch components) implements GeyserMapping {
|
||||||
private static final List<DataComponentType<?>> SUPPORTED_COMPONENTS = List.of(DataComponents.CONSUMABLE, DataComponents.EQUIPPABLE, DataComponents.FOOD,
|
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);
|
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 ->
|
public static final MapCodec<GeyserSingleDefinition> CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||||||
instance.group(
|
instance.group(
|
||||||
ResourceLocation.CODEC.fieldOf("model").forGetter(GeyserSingleDefinition::model),
|
ResourceLocation.CODEC.optionalFieldOf("model").forGetter(GeyserSingleDefinition::model),
|
||||||
ResourceLocation.CODEC.fieldOf("bedrock_identifier").forGetter(GeyserSingleDefinition::bedrockIdentifier),
|
ResourceLocation.CODEC.fieldOf("bedrock_identifier").forGetter(GeyserSingleDefinition::bedrockIdentifier),
|
||||||
Codec.STRING.optionalFieldOf("display_name").forGetter(GeyserSingleDefinition::displayName),
|
Codec.STRING.optionalFieldOf("display_name").forGetter(GeyserSingleDefinition::displayName),
|
||||||
GeyserPredicate.LIST_CODEC.optionalFieldOf("predicate", List.of()).forGetter(GeyserSingleDefinition::predicates),
|
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));
|
return bedrockOptions.icon.orElse(iconFromResourceLocation(bedrockIdentifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean conflictsWith(GeyserSingleDefinition other) {
|
public boolean conflictsWith(Optional<ResourceLocation> parentModel, GeyserSingleDefinition other) {
|
||||||
if (!model.equals(other.model)) {
|
ResourceLocation thisModel = model.or(() -> parentModel).orElseThrow();
|
||||||
|
ResourceLocation otherModel = other.model.or(() -> parentModel).orElseThrow();
|
||||||
|
if (!thisModel.equals(otherModel)) {
|
||||||
return false;
|
return false;
|
||||||
} else if (predicates.size() == other.predicates.size()) {
|
} else if (predicates.size() == other.predicates.size()) {
|
||||||
boolean predicatesAreEqual = true;
|
boolean predicatesAreEqual = true;
|
||||||
@@ -65,6 +67,10 @@ public record GeyserSingleDefinition(ResourceLocation model, ResourceLocation be
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GeyserSingleDefinition withoutModel() {
|
||||||
|
return new GeyserSingleDefinition(Optional.empty(), bedrockIdentifier, displayName, predicates, bedrockOptions, components);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type type() {
|
public Type type() {
|
||||||
return Type.SINGLE;
|
return Type.SINGLE;
|
||||||
|
|||||||
Reference in New Issue
Block a user