2025-11-24 22:52:51 +03:00

117 lines
9.2 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.datafixers.kinds.App
* com.mojang.datafixers.kinds.Applicative
* com.mojang.serialization.Codec
* com.mojang.serialization.codecs.RecordCodecBuilder
* io.netty.buffer.ByteBuf
*/
package net.minecraft.world.item.component;
import com.mojang.datafixers.kinds.App;
import com.mojang.datafixers.kinds.Applicative;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.netty.buffer.ByteBuf;
import java.util.Optional;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.Holder;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.PiercingWeapon;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.Vec3;
public record KineticWeapon(float minReach, float maxReach, float hitboxMargin, int contactCooldownTicks, int delayTicks, Optional<Condition> dismountConditions, Optional<Condition> knockbackConditions, Optional<Condition> damageConditions, float forwardMovement, float damageMultiplier, Optional<Holder<SoundEvent>> sound, Optional<Holder<SoundEvent>> hitSound) {
public static final Codec<KineticWeapon> CODEC = RecordCodecBuilder.create(i -> i.group((App)ExtraCodecs.floatRange(0.0f, 128.0f).optionalFieldOf("min_reach", (Object)Float.valueOf(0.0f)).forGetter(KineticWeapon::minReach), (App)ExtraCodecs.floatRange(0.0f, 128.0f).optionalFieldOf("max_reach", (Object)Float.valueOf(3.0f)).forGetter(KineticWeapon::maxReach), (App)ExtraCodecs.floatRange(0.0f, 1.0f).optionalFieldOf("hitbox_margin", (Object)Float.valueOf(0.3f)).forGetter(KineticWeapon::hitboxMargin), (App)ExtraCodecs.NON_NEGATIVE_INT.optionalFieldOf("contact_cooldown_ticks", (Object)10).forGetter(KineticWeapon::contactCooldownTicks), (App)ExtraCodecs.NON_NEGATIVE_INT.optionalFieldOf("delay_ticks", (Object)0).forGetter(KineticWeapon::delayTicks), (App)Condition.CODEC.optionalFieldOf("dismount_conditions").forGetter(KineticWeapon::dismountConditions), (App)Condition.CODEC.optionalFieldOf("knockback_conditions").forGetter(KineticWeapon::knockbackConditions), (App)Condition.CODEC.optionalFieldOf("damage_conditions").forGetter(KineticWeapon::damageConditions), (App)Codec.FLOAT.optionalFieldOf("forward_movement", (Object)Float.valueOf(0.0f)).forGetter(KineticWeapon::forwardMovement), (App)Codec.FLOAT.optionalFieldOf("damage_multiplier", (Object)Float.valueOf(1.0f)).forGetter(KineticWeapon::damageMultiplier), (App)SoundEvent.CODEC.optionalFieldOf("sound").forGetter(KineticWeapon::sound), (App)SoundEvent.CODEC.optionalFieldOf("hit_sound").forGetter(KineticWeapon::hitSound)).apply((Applicative)i, KineticWeapon::new));
public static final StreamCodec<RegistryFriendlyByteBuf, KineticWeapon> STREAM_CODEC = StreamCodec.composite(ByteBufCodecs.FLOAT, KineticWeapon::minReach, ByteBufCodecs.FLOAT, KineticWeapon::maxReach, ByteBufCodecs.FLOAT, KineticWeapon::hitboxMargin, ByteBufCodecs.VAR_INT, KineticWeapon::contactCooldownTicks, ByteBufCodecs.VAR_INT, KineticWeapon::delayTicks, Condition.STREAM_CODEC.apply(ByteBufCodecs::optional), KineticWeapon::dismountConditions, Condition.STREAM_CODEC.apply(ByteBufCodecs::optional), KineticWeapon::knockbackConditions, Condition.STREAM_CODEC.apply(ByteBufCodecs::optional), KineticWeapon::damageConditions, ByteBufCodecs.FLOAT, KineticWeapon::forwardMovement, ByteBufCodecs.FLOAT, KineticWeapon::damageMultiplier, SoundEvent.STREAM_CODEC.apply(ByteBufCodecs::optional), KineticWeapon::sound, SoundEvent.STREAM_CODEC.apply(ByteBufCodecs::optional), KineticWeapon::hitSound, KineticWeapon::new);
public static Vec3 getMotion(Entity livingEntity) {
if (!(livingEntity instanceof Player) && livingEntity.isPassenger()) {
livingEntity = livingEntity.getRootVehicle();
}
return livingEntity.getKnownSpeed().scale(20.0);
}
public void makeSound(Entity causer) {
this.sound.ifPresent(s -> causer.level().playSound(causer, causer.getX(), causer.getY(), causer.getZ(), (Holder<SoundEvent>)s, causer.getSoundSource(), 1.0f, 1.0f));
}
public void makeHitSound(Entity causer) {
this.hitSound.ifPresent(s -> causer.level().playSound(null, causer.getX(), causer.getY(), causer.getZ(), (Holder<SoundEvent>)s, causer.getSoundSource(), 1.0f, 1.0f));
}
public int computeDamageUseDuration() {
return this.delayTicks + this.damageConditions.map(Condition::maxDurationTicks).orElse(0);
}
public void damageEntities(ItemStack stack, int ticksRemaining, LivingEntity livingEntity, EquipmentSlot equipmentSlot) {
int ticksUsed = stack.getUseDuration(livingEntity) - ticksRemaining;
if (ticksUsed < this.delayTicks) {
return;
}
ticksUsed -= this.delayTicks;
Vec3 attackerLookVector = livingEntity.getLookAngle();
double attackerSpeedProjection = attackerLookVector.dot(KineticWeapon.getMotion(livingEntity));
float actionFactor = livingEntity instanceof Player ? 1.0f : 0.2f;
float rangeFactor = livingEntity instanceof Player ? 1.0f : 0.5f;
double baseMobDamage = livingEntity.getAttributeBaseValue(Attributes.ATTACK_DAMAGE);
boolean affected = false;
for (EntityHitResult hitResult : ProjectileUtil.getHitEntitiesAlong(livingEntity, rangeFactor * this.minReach, rangeFactor * this.maxReach, this.hitboxMargin, e -> PiercingWeapon.canHitEntity(livingEntity, e))) {
boolean dealsDamage;
Entity otherEntity = hitResult.getEntity();
boolean wasStabbed = livingEntity.wasRecentlyStabbed(otherEntity, this.contactCooldownTicks);
livingEntity.rememberStabbedEntity(otherEntity);
if (wasStabbed) continue;
double targetSpeedProjection = attackerLookVector.dot(KineticWeapon.getMotion(otherEntity));
double relativeSpeed = Math.max(0.0, attackerSpeedProjection - targetSpeedProjection);
boolean dealsDismount = this.dismountConditions.isPresent() && this.dismountConditions.get().test(ticksUsed, attackerSpeedProjection, relativeSpeed, actionFactor);
boolean dealsKnockback = this.knockbackConditions.isPresent() && this.knockbackConditions.get().test(ticksUsed, attackerSpeedProjection, relativeSpeed, actionFactor);
boolean bl = dealsDamage = this.damageConditions.isPresent() && this.damageConditions.get().test(ticksUsed, attackerSpeedProjection, relativeSpeed, actionFactor);
if (!dealsDismount && !dealsKnockback && !dealsDamage) continue;
float damageDealt = (float)baseMobDamage + (float)Mth.floor(relativeSpeed * (double)this.damageMultiplier);
affected |= livingEntity.stabAttack(equipmentSlot, otherEntity, damageDealt, dealsDamage, dealsKnockback, dealsDismount);
}
if (affected) {
this.makeHitSound(livingEntity);
livingEntity.level().broadcastEntityEvent(livingEntity, (byte)2);
if (livingEntity instanceof ServerPlayer) {
ServerPlayer player = (ServerPlayer)livingEntity;
CriteriaTriggers.SPEAR_MOBS_TRIGGER.trigger(player, livingEntity.stabbedEntities());
}
}
}
public record Condition(int maxDurationTicks, float minSpeed, float minRelativeSpeed) {
public static final Codec<Condition> CODEC = RecordCodecBuilder.create(i -> i.group((App)ExtraCodecs.NON_NEGATIVE_INT.fieldOf("max_duration_ticks").forGetter(Condition::maxDurationTicks), (App)Codec.FLOAT.optionalFieldOf("min_speed", (Object)Float.valueOf(0.0f)).forGetter(Condition::minSpeed), (App)Codec.FLOAT.optionalFieldOf("min_relative_speed", (Object)Float.valueOf(0.0f)).forGetter(Condition::minRelativeSpeed)).apply((Applicative)i, Condition::new));
public static final StreamCodec<ByteBuf, Condition> STREAM_CODEC = StreamCodec.composite(ByteBufCodecs.VAR_INT, Condition::maxDurationTicks, ByteBufCodecs.FLOAT, Condition::minSpeed, ByteBufCodecs.FLOAT, Condition::minRelativeSpeed, Condition::new);
public boolean test(int ticksUsed, double attackerSpeed, double relativeSpeed, double entityFactor) {
return ticksUsed <= this.maxDurationTicks && attackerSpeed >= (double)this.minSpeed * entityFactor && relativeSpeed >= (double)this.minRelativeSpeed * entityFactor;
}
public static Optional<Condition> ofAttackerSpeed(int untilTicks, float minAttackerSpeed) {
return Optional.of(new Condition(untilTicks, minAttackerSpeed, 0.0f));
}
public static Optional<Condition> ofRelativeSpeed(int untilTicks, float minRelativeSpeed) {
return Optional.of(new Condition(untilTicks, 0.0f, minRelativeSpeed));
}
}
}