1
0
Fork 0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-03-13 11:18:19 +01:00

Work on range dispatch predicate

This commit is contained in:
Eclipse 2024-12-06 10:17:48 +00:00
parent 52f2b9f142
commit 49f31c9661
No known key found for this signature in database
GPG key ID: 95E6998F82EC938A
14 changed files with 102 additions and 37 deletions

View file

@ -23,11 +23,8 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.item.custom.v2.predicate.data;
package org.geysermc.geyser.api.item.custom.v2.predicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.CustomItemPredicate;
// TODO maybe type should be a generic class with data, but this works for now
public record ConditionPredicate(ConditionProperty property, boolean expected, int index) implements CustomItemPredicate {
// TODO maybe we can extend this

View file

@ -25,5 +25,5 @@
package org.geysermc.geyser.api.item.custom.v2.predicate;
public interface CustomItemPredicate { // TODO this probably needs to be different since people can implement this
public sealed interface CustomItemPredicate permits ConditionPredicate, MatchPredicate, RangeDispatchPredicate { // TODO maybe we need to move the predicate classes out of API
}

View file

@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.item.custom.v2.predicate.data;
package org.geysermc.geyser.api.item.custom.v2.predicate;
public record CustomModelDataPredicate<T>(T data, int index) {
public record CustomModelDataProperty<T>(T data, int index) {
}

View file

@ -23,9 +23,9 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.item.custom.v2.predicate.data.match;
package org.geysermc.geyser.api.item.custom.v2.predicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.CustomItemPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.match.MatchPredicateProperty;
public record MatchPredicate<T>(MatchPredicateProperty<T> property, T data) implements CustomItemPredicate {
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.item.custom.v2.predicate;
public record RangeDispatchPredicate(RangeDispatchProperty property, double threshold, double scale, boolean normalizeIfPossible, int index) implements CustomItemPredicate {
// TODO check if we can change items while bedrock is using them, and if bedrock will continue to use them
public enum RangeDispatchProperty {
BUNDLE_FULLNESS,
DAMAGE,
COUNT,
CUSTOM_MODEL_DATA
}
}

View file

@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.item.custom.v2.predicate.data.match;
package org.geysermc.geyser.api.item.custom.v2.predicate.match;
public enum ChargeType {
NONE,

View file

@ -23,10 +23,10 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.item.custom.v2.predicate.data.match;
package org.geysermc.geyser.api.item.custom.v2.predicate.match;
import net.kyori.adventure.key.Key;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.CustomModelDataPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.CustomModelDataProperty;
// TODO can we do more?
public class MatchPredicateProperty<T> {
@ -34,7 +34,9 @@ public class MatchPredicateProperty<T> {
public static final MatchPredicateProperty<ChargeType> CHARGE_TYPE = create();
public static final MatchPredicateProperty<Key> TRIM_MATERIAL = create();
public static final MatchPredicateProperty<Key> CONTEXT_DIMENSION = create();
public static final MatchPredicateProperty<CustomModelDataPredicate<String>> CUSTOM_MODEL_DATA = create();
public static final MatchPredicateProperty<CustomModelDataProperty<String>> CUSTOM_MODEL_DATA = create();
private MatchPredicateProperty() {}
private static <T> MatchPredicateProperty<T> create() {
return new MatchPredicateProperty<>();

View file

@ -125,7 +125,7 @@ public class Item {
.damage(mapping.getBedrockData())
.count(count);
ItemTranslator.translateCustomItem(session, components, builder, mapping);
ItemTranslator.translateCustomItem(session, count, components, builder, mapping);
return builder;
}

View file

@ -49,7 +49,7 @@ public class PotionItem extends Item {
if (components == null) return super.translateToBedrock(session, count, components, mapping, mappings);
PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS);
if (potionContents != null) {
ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(session, components, mapping);
ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(session, count, components, mapping);
if (customItemDefinition == null) {
Potion potion = Potion.getByJavaId(potionContents.getPotionId());
if (potion != null) {

View file

@ -74,7 +74,7 @@ public class ShulkerBoxItem extends BlockItem {
if (boxComponents != null) {
// Check for custom items
ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(session, boxComponents, boxMapping);
ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(session, item.getAmount(), boxComponents, boxMapping);
if (customItemDefinition != null) {
bedrockIdentifier = customItemDefinition.getIdentifier();
bedrockData = 0;

View file

@ -35,11 +35,11 @@ import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.item.custom.v2.BedrockCreativeTab;
import org.geysermc.geyser.api.item.custom.v2.CustomItemBedrockOptions;
import org.geysermc.geyser.api.item.custom.v2.CustomItemDefinition;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.ConditionPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.CustomModelDataPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.ChargeType;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.MatchPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.MatchPredicateProperty;
import org.geysermc.geyser.api.item.custom.v2.predicate.ConditionPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.CustomModelDataProperty;
import org.geysermc.geyser.api.item.custom.v2.predicate.match.ChargeType;
import org.geysermc.geyser.api.item.custom.v2.predicate.MatchPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.match.MatchPredicateProperty;
import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException;
import org.geysermc.geyser.registry.mappings.components.DataComponentReaders;
import org.geysermc.geyser.registry.mappings.util.CustomBlockMapping;
@ -270,9 +270,9 @@ public class MappingsReader_v2 extends MappingsReader {
case "custom_model_data" -> {
JsonNode index = node.get("index");
if (index == null || !index.isIntegralNumber()) {
throw new InvalidCustomMappingsFileException("Predicate missing index key");
throw new InvalidCustomMappingsFileException("Predicate missing index key"); // TODO default to 0
}
builder.predicate(new MatchPredicate<>(MatchPredicateProperty.CUSTOM_MODEL_DATA, new CustomModelDataPredicate<>(value.asText(), index.asInt())));
builder.predicate(new MatchPredicate<>(MatchPredicateProperty.CUSTOM_MODEL_DATA, new CustomModelDataProperty<>(value.asText(), index.asInt())));
}
default -> throw new InvalidCustomMappingsFileException("Unknown property " + property);
}

View file

@ -30,10 +30,11 @@ import net.kyori.adventure.key.Key;
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
import org.geysermc.geyser.api.item.custom.v2.CustomItemDefinition;
import org.geysermc.geyser.api.item.custom.v2.predicate.CustomItemPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.ConditionPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.ChargeType;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.MatchPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.MatchPredicateProperty;
import org.geysermc.geyser.api.item.custom.v2.predicate.ConditionPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.RangeDispatchPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.match.ChargeType;
import org.geysermc.geyser.api.item.custom.v2.predicate.MatchPredicate;
import org.geysermc.geyser.api.item.custom.v2.predicate.match.MatchPredicateProperty;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.session.GeyserSession;
@ -57,7 +58,7 @@ import java.util.List;
public final class CustomItemTranslator {
@Nullable
public static ItemDefinition getCustomItem(GeyserSession session, DataComponents components, ItemMapping mapping) {
public static ItemDefinition getCustomItem(GeyserSession session, int stackSize, DataComponents components, ItemMapping mapping) {
if (components == null) {
return null;
}
@ -78,7 +79,7 @@ public final class CustomItemTranslator {
if (customModel.first().model().equals(itemModel)) {
boolean allMatch = true;
for (CustomItemPredicate predicate : customModel.first().predicates()) {
if (!predicateMatches(session, predicate, components)) {
if (!predicateMatches(session, predicate, stackSize, components)) {
allMatch = false;
break;
}
@ -91,7 +92,7 @@ public final class CustomItemTranslator {
return null;
}
private static boolean predicateMatches(GeyserSession session, CustomItemPredicate predicate, DataComponents components) {
private static boolean predicateMatches(GeyserSession session, CustomItemPredicate predicate, int stackSize, DataComponents components) {
if (predicate instanceof ConditionPredicate condition) {
return switch (condition.property()) {
case BROKEN -> nextDamageWillBreak(components);
@ -124,18 +125,46 @@ public final class CustomItemTranslator {
} else if (match.property() == MatchPredicateProperty.CONTEXT_DIMENSION) {
Key dimension = (Key) match.data();
RegistryEntryData<JavaDimension> registered = session.getRegistryCache().dimensions().entryByValue(session.getDimensionType());
return registered != null && dimension.equals(registered.key()); // TODO check if this works
return registered != null && dimension.equals(registered.key());
} else if (match.property() == MatchPredicateProperty.CUSTOM_MODEL_DATA) {
// TODO 1.21.4
return false;
}
} else if (predicate instanceof RangeDispatchPredicate rangeDispatch) {
double propertyValue = switch (rangeDispatch.property()) {
case BUNDLE_FULLNESS -> {
List<ItemStack> stacks = components.get(DataComponentType.BUNDLE_CONTENTS);
if (stacks == null) {
yield 0;
}
int bundleWeight = 0;
for (ItemStack stack : stacks) {
bundleWeight += stack.getAmount();
}
yield bundleWeight;
}
case DAMAGE -> tryNormalize(rangeDispatch, components.get(DataComponentType.DAMAGE), components.get(DataComponentType.MAX_DAMAGE));
case COUNT -> tryNormalize(rangeDispatch, stackSize, components.get(DataComponentType.MAX_STACK_SIZE));
case CUSTOM_MODEL_DATA -> 0.0; // TODO 1.21.4
} * rangeDispatch.scale();
return propertyValue >= rangeDispatch.threshold();
}
throw new IllegalStateException("Unimplemented predicate type");
}
/* These three functions are based off their Mojmap equivalents from 1.21.3 */
private static double tryNormalize(RangeDispatchPredicate predicate, @Nullable Integer value, @Nullable Integer max) {
if (value == null) {
return 0.0;
} else if (max == null) {
return value;
} else if (!predicate.normalizeIfPossible()) {
return Math.min(value, max);
}
return Math.max(0.0, Math.min(1.0, (double) value / max));
}
/* These three functions are based off their Mojmap equivalents from 1.21.3 */
private static boolean nextDamageWillBreak(DataComponents components) {
return isDamageableItem(components) && components.getOrDefault(DataComponentType.DAMAGE, 0) >= components.getOrDefault(DataComponentType.MAX_DAMAGE, 0) - 1;
}

View file

@ -215,7 +215,7 @@ public final class ItemTranslator {
translatePlayerHead(session, components, builder);
}
translateCustomItem(session, components, builder, bedrockItem);
translateCustomItem(session, count, components, builder, bedrockItem);
if (components != null) {
// Translate the canDestroy and canPlaceOn Java components
@ -428,7 +428,7 @@ public final class ItemTranslator {
}
}
ItemDefinition definition = CustomItemTranslator.getCustomItem(session, itemStack.getComponents(), mapping);
ItemDefinition definition = CustomItemTranslator.getCustomItem(session, itemStack.getAmount(), itemStack.getComponents(), mapping);
if (definition == null) {
// No custom item
return itemDefinition;
@ -469,8 +469,8 @@ public final class ItemTranslator {
/**
* Translates the custom model data of an item
*/
public static void translateCustomItem(GeyserSession session, DataComponents components, ItemData.Builder builder, ItemMapping mapping) {
ItemDefinition definition = CustomItemTranslator.getCustomItem(session, components, mapping);
public static void translateCustomItem(GeyserSession session, int stackSize, DataComponents components, ItemData.Builder builder, ItemMapping mapping) {
ItemDefinition definition = CustomItemTranslator.getCustomItem(session, stackSize, components, mapping);
if (definition != null) {
builder.definition(definition);
builder.blockDefinition(null);

View file

@ -93,7 +93,7 @@ final class BedrockBlockActions {
// If the block is custom or the breaking item is custom, we must keep track of break time ourselves
GeyserItemStack item = session.getPlayerInventory().getItemInHand();
ItemMapping mapping = item.getMapping(session);
ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(session, item.getComponents(), mapping) : null;
ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(session, item.getAmount(), item.getComponents(), mapping) : null;
CustomBlockState blockStateOverride = BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get(blockState);
SkullCache.Skull skull = session.getSkullCache().getSkulls().get(vector);