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:
parent
52f2b9f142
commit
49f31c9661
14 changed files with 102 additions and 37 deletions
api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate
ConditionPredicate.javaCustomItemPredicate.javaCustomModelDataProperty.javaMatchPredicate.javaRangeDispatchPredicate.java
match
core/src/main/java/org/geysermc/geyser
item/type
registry/mappings/versions
translator
item
protocol/bedrock/entity/player/input
|
@ -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
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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,
|
|
@ -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<>();
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue