242 lines
10 KiB
Java
242 lines
10 KiB
Java
package net.minecraft.client.renderer.item;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import java.util.Map;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.client.multiplayer.ClientLevel;
|
|
import net.minecraft.core.GlobalPos;
|
|
import net.minecraft.core.component.DataComponents;
|
|
import net.minecraft.data.models.ItemModelGenerators;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.HumanoidArm;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.BundleItem;
|
|
import net.minecraft.world.item.CompassItem;
|
|
import net.minecraft.world.item.CrossbowItem;
|
|
import net.minecraft.world.item.ElytraItem;
|
|
import net.minecraft.world.item.FishingRodItem;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.item.armortrim.ArmorTrim;
|
|
import net.minecraft.world.item.component.BlockItemStateProperties;
|
|
import net.minecraft.world.item.component.ChargedProjectiles;
|
|
import net.minecraft.world.item.component.CustomModelData;
|
|
import net.minecraft.world.item.component.LodestoneTracker;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.LightBlock;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class ItemProperties {
|
|
private static final Map<ResourceLocation, ItemPropertyFunction> GENERIC_PROPERTIES = Maps.<ResourceLocation, ItemPropertyFunction>newHashMap();
|
|
private static final ResourceLocation DAMAGED = ResourceLocation.withDefaultNamespace("damaged");
|
|
private static final ResourceLocation DAMAGE = ResourceLocation.withDefaultNamespace("damage");
|
|
private static final ClampedItemPropertyFunction PROPERTY_DAMAGED = (itemStack, clientLevel, livingEntity, i) -> itemStack.isDamaged() ? 1.0F : 0.0F;
|
|
private static final ClampedItemPropertyFunction PROPERTY_DAMAGE = (itemStack, clientLevel, livingEntity, i) -> Mth.clamp(
|
|
(float)itemStack.getDamageValue() / itemStack.getMaxDamage(), 0.0F, 1.0F
|
|
);
|
|
private static final Map<Item, Map<ResourceLocation, ItemPropertyFunction>> PROPERTIES = Maps.<Item, Map<ResourceLocation, ItemPropertyFunction>>newHashMap();
|
|
|
|
private static ClampedItemPropertyFunction registerGeneric(ResourceLocation name, ClampedItemPropertyFunction property) {
|
|
GENERIC_PROPERTIES.put(name, property);
|
|
return property;
|
|
}
|
|
|
|
private static void registerCustomModelData(ItemPropertyFunction property) {
|
|
GENERIC_PROPERTIES.put(ResourceLocation.withDefaultNamespace("custom_model_data"), property);
|
|
}
|
|
|
|
private static void register(Item item, ResourceLocation name, ClampedItemPropertyFunction property) {
|
|
((Map)PROPERTIES.computeIfAbsent(item, itemx -> Maps.newHashMap())).put(name, property);
|
|
}
|
|
|
|
@Nullable
|
|
public static ItemPropertyFunction getProperty(ItemStack stack, ResourceLocation location) {
|
|
if (stack.getMaxDamage() > 0) {
|
|
if (DAMAGE.equals(location)) {
|
|
return PROPERTY_DAMAGE;
|
|
}
|
|
|
|
if (DAMAGED.equals(location)) {
|
|
return PROPERTY_DAMAGED;
|
|
}
|
|
}
|
|
|
|
ItemPropertyFunction itemPropertyFunction = (ItemPropertyFunction)GENERIC_PROPERTIES.get(location);
|
|
if (itemPropertyFunction != null) {
|
|
return itemPropertyFunction;
|
|
} else {
|
|
Map<ResourceLocation, ItemPropertyFunction> map = (Map<ResourceLocation, ItemPropertyFunction>)PROPERTIES.get(stack.getItem());
|
|
return map == null ? null : (ItemPropertyFunction)map.get(location);
|
|
}
|
|
}
|
|
|
|
static {
|
|
registerGeneric(
|
|
ResourceLocation.withDefaultNamespace("lefthanded"),
|
|
(itemStack, clientLevel, livingEntity, i) -> livingEntity != null && livingEntity.getMainArm() != HumanoidArm.RIGHT ? 1.0F : 0.0F
|
|
);
|
|
registerGeneric(
|
|
ResourceLocation.withDefaultNamespace("cooldown"),
|
|
(itemStack, clientLevel, livingEntity, i) -> livingEntity instanceof Player
|
|
? ((Player)livingEntity).getCooldowns().getCooldownPercent(itemStack.getItem(), 0.0F)
|
|
: 0.0F
|
|
);
|
|
ClampedItemPropertyFunction clampedItemPropertyFunction = (itemStack, clientLevel, livingEntity, i) -> {
|
|
ArmorTrim armorTrim = itemStack.get(DataComponents.TRIM);
|
|
return armorTrim != null ? armorTrim.material().value().itemModelIndex() : Float.NEGATIVE_INFINITY;
|
|
};
|
|
registerGeneric(ItemModelGenerators.TRIM_TYPE_PREDICATE_ID, clampedItemPropertyFunction);
|
|
registerCustomModelData(
|
|
(itemStack, clientLevel, livingEntity, i) -> itemStack.getOrDefault(DataComponents.CUSTOM_MODEL_DATA, CustomModelData.DEFAULT).value()
|
|
);
|
|
register(Items.BOW, ResourceLocation.withDefaultNamespace("pull"), (itemStack, clientLevel, livingEntity, i) -> {
|
|
if (livingEntity == null) {
|
|
return 0.0F;
|
|
} else {
|
|
return livingEntity.getUseItem() != itemStack ? 0.0F : (itemStack.getUseDuration(livingEntity) - livingEntity.getUseItemRemainingTicks()) / 20.0F;
|
|
}
|
|
});
|
|
register(
|
|
Items.BRUSH,
|
|
ResourceLocation.withDefaultNamespace("brushing"),
|
|
(itemStack, clientLevel, livingEntity, i) -> livingEntity != null && livingEntity.getUseItem() == itemStack
|
|
? livingEntity.getUseItemRemainingTicks() % 10 / 10.0F
|
|
: 0.0F
|
|
);
|
|
register(
|
|
Items.BOW,
|
|
ResourceLocation.withDefaultNamespace("pulling"),
|
|
(itemStack, clientLevel, livingEntity, i) -> livingEntity != null && livingEntity.isUsingItem() && livingEntity.getUseItem() == itemStack ? 1.0F : 0.0F
|
|
);
|
|
register(Items.BUNDLE, ResourceLocation.withDefaultNamespace("filled"), (itemStack, clientLevel, livingEntity, i) -> BundleItem.getFullnessDisplay(itemStack));
|
|
register(Items.CLOCK, ResourceLocation.withDefaultNamespace("time"), new ClampedItemPropertyFunction() {
|
|
private double rotation;
|
|
private double rota;
|
|
private long lastUpdateTick;
|
|
|
|
@Override
|
|
public float unclampedCall(ItemStack itemStack, @Nullable ClientLevel clientLevel, @Nullable LivingEntity livingEntity, int i) {
|
|
Entity entity = (Entity)(livingEntity != null ? livingEntity : itemStack.getEntityRepresentation());
|
|
if (entity == null) {
|
|
return 0.0F;
|
|
} else {
|
|
if (clientLevel == null && entity.level() instanceof ClientLevel) {
|
|
clientLevel = (ClientLevel)entity.level();
|
|
}
|
|
|
|
if (clientLevel == null) {
|
|
return 0.0F;
|
|
} else {
|
|
double d;
|
|
if (clientLevel.dimensionType().natural()) {
|
|
d = clientLevel.getTimeOfDay(1.0F);
|
|
} else {
|
|
d = Math.random();
|
|
}
|
|
|
|
d = this.wobble(clientLevel, d);
|
|
return (float)d;
|
|
}
|
|
}
|
|
}
|
|
|
|
private double wobble(Level level, double rotation) {
|
|
if (level.getGameTime() != this.lastUpdateTick) {
|
|
this.lastUpdateTick = level.getGameTime();
|
|
double d = rotation - this.rotation;
|
|
d = Mth.positiveModulo(d + 0.5, 1.0) - 0.5;
|
|
this.rota += d * 0.1;
|
|
this.rota *= 0.9;
|
|
this.rotation = Mth.positiveModulo(this.rotation + this.rota, 1.0);
|
|
}
|
|
|
|
return this.rotation;
|
|
}
|
|
});
|
|
register(Items.COMPASS, ResourceLocation.withDefaultNamespace("angle"), new CompassItemPropertyFunction((clientLevel, itemStack, entity) -> {
|
|
LodestoneTracker lodestoneTracker = itemStack.get(DataComponents.LODESTONE_TRACKER);
|
|
return lodestoneTracker != null ? (GlobalPos)lodestoneTracker.target().orElse(null) : CompassItem.getSpawnPosition(clientLevel);
|
|
}));
|
|
register(
|
|
Items.RECOVERY_COMPASS,
|
|
ResourceLocation.withDefaultNamespace("angle"),
|
|
new CompassItemPropertyFunction(
|
|
(clientLevel, itemStack, entity) -> entity instanceof Player player ? (GlobalPos)player.getLastDeathLocation().orElse(null) : null
|
|
)
|
|
);
|
|
register(
|
|
Items.CROSSBOW,
|
|
ResourceLocation.withDefaultNamespace("pull"),
|
|
(itemStack, clientLevel, livingEntity, i) -> {
|
|
if (livingEntity == null) {
|
|
return 0.0F;
|
|
} else {
|
|
return CrossbowItem.isCharged(itemStack)
|
|
? 0.0F
|
|
: (float)(itemStack.getUseDuration(livingEntity) - livingEntity.getUseItemRemainingTicks()) / CrossbowItem.getChargeDuration(itemStack, livingEntity);
|
|
}
|
|
}
|
|
);
|
|
register(
|
|
Items.CROSSBOW,
|
|
ResourceLocation.withDefaultNamespace("pulling"),
|
|
(itemStack, clientLevel, livingEntity, i) -> livingEntity != null
|
|
&& livingEntity.isUsingItem()
|
|
&& livingEntity.getUseItem() == itemStack
|
|
&& !CrossbowItem.isCharged(itemStack)
|
|
? 1.0F
|
|
: 0.0F
|
|
);
|
|
register(
|
|
Items.CROSSBOW,
|
|
ResourceLocation.withDefaultNamespace("charged"),
|
|
(itemStack, clientLevel, livingEntity, i) -> CrossbowItem.isCharged(itemStack) ? 1.0F : 0.0F
|
|
);
|
|
register(Items.CROSSBOW, ResourceLocation.withDefaultNamespace("firework"), (itemStack, clientLevel, livingEntity, i) -> {
|
|
ChargedProjectiles chargedProjectiles = itemStack.get(DataComponents.CHARGED_PROJECTILES);
|
|
return chargedProjectiles != null && chargedProjectiles.contains(Items.FIREWORK_ROCKET) ? 1.0F : 0.0F;
|
|
});
|
|
register(
|
|
Items.ELYTRA, ResourceLocation.withDefaultNamespace("broken"), (itemStack, clientLevel, livingEntity, i) -> ElytraItem.isFlyEnabled(itemStack) ? 0.0F : 1.0F
|
|
);
|
|
register(Items.FISHING_ROD, ResourceLocation.withDefaultNamespace("cast"), (itemStack, clientLevel, livingEntity, i) -> {
|
|
if (livingEntity == null) {
|
|
return 0.0F;
|
|
} else {
|
|
boolean bl = livingEntity.getMainHandItem() == itemStack;
|
|
boolean bl2 = livingEntity.getOffhandItem() == itemStack;
|
|
if (livingEntity.getMainHandItem().getItem() instanceof FishingRodItem) {
|
|
bl2 = false;
|
|
}
|
|
|
|
return (bl || bl2) && livingEntity instanceof Player && ((Player)livingEntity).fishing != null ? 1.0F : 0.0F;
|
|
}
|
|
});
|
|
register(
|
|
Items.SHIELD,
|
|
ResourceLocation.withDefaultNamespace("blocking"),
|
|
(itemStack, clientLevel, livingEntity, i) -> livingEntity != null && livingEntity.isUsingItem() && livingEntity.getUseItem() == itemStack ? 1.0F : 0.0F
|
|
);
|
|
register(
|
|
Items.TRIDENT,
|
|
ResourceLocation.withDefaultNamespace("throwing"),
|
|
(itemStack, clientLevel, livingEntity, i) -> livingEntity != null && livingEntity.isUsingItem() && livingEntity.getUseItem() == itemStack ? 1.0F : 0.0F
|
|
);
|
|
register(Items.LIGHT, ResourceLocation.withDefaultNamespace("level"), (itemStack, clientLevel, livingEntity, i) -> {
|
|
BlockItemStateProperties blockItemStateProperties = itemStack.getOrDefault(DataComponents.BLOCK_STATE, BlockItemStateProperties.EMPTY);
|
|
Integer integer = blockItemStateProperties.get(LightBlock.LEVEL);
|
|
return integer != null ? integer.intValue() / 16.0F : 1.0F;
|
|
});
|
|
register(
|
|
Items.GOAT_HORN,
|
|
ResourceLocation.withDefaultNamespace("tooting"),
|
|
(itemStack, clientLevel, livingEntity, i) -> livingEntity != null && livingEntity.isUsingItem() && livingEntity.getUseItem() == itemStack ? 1.0F : 0.0F
|
|
);
|
|
}
|
|
}
|