darkness effect + warden targetting fix
This commit is contained in:
parent
7be1b91581
commit
6c66e8e946
|
@ -8,6 +8,7 @@ import com.cursedcauldron.wildbackport.common.registry.WBBlocks;
|
|||
import com.cursedcauldron.wildbackport.common.registry.WBEnchantments;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBGameEvents;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBItems;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBMobEffects;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBPositionSources;
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBFeatures;
|
||||
import com.cursedcauldron.wildbackport.common.registry.worldgen.RootPlacerType;
|
||||
|
@ -43,6 +44,7 @@ public class WildBackport {
|
|||
WBFeatures.FEATURES.register();
|
||||
WBItems.ITEMS.register();
|
||||
WBMemoryModules.MEMORIES.register();
|
||||
WBMobEffects.EFFECTS.register();
|
||||
WBParticleTypes.PARTICLES.register();
|
||||
WBPositionSources.SOURCES.register();
|
||||
RootPlacerType.PLACERS.register();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.cursedcauldron.wildbackport.common.blocks;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBBlocks;
|
||||
import com.cursedcauldron.wildbackport.common.tag.WBBlockTags;
|
||||
import com.cursedcauldron.wildbackport.core.mixin.access.PointedDripstoneBlockAccessor;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
|
@ -18,7 +19,7 @@ public record DrippingFluid(BlockPos pos, Fluid fluid, BlockState sourceState) {
|
|||
Optional<DrippingFluid> fluidAbove = getFluidAboveStalactite(world, blockPos, state);
|
||||
if (fluidAbove.isPresent()) {
|
||||
Fluid fluid = fluidAbove.get().fluid;
|
||||
if (fluidAbove.get().sourceState().is(WBBlocks.MUD.get()) && fluid == Fluids.WATER) {
|
||||
if (fluidAbove.get().sourceState().is(WBBlockTags.MUD) && fluid == Fluids.WATER) {
|
||||
world.setBlockAndUpdate(fluidAbove.get().pos, Blocks.CLAY.defaultBlockState());
|
||||
world.levelEvent(1504, blockPos, 0);
|
||||
ci.cancel();
|
||||
|
@ -30,7 +31,7 @@ public record DrippingFluid(BlockPos pos, Fluid fluid, BlockState sourceState) {
|
|||
return !PointedDripstoneBlockAccessor.callIsStalactite(state) ? Optional.empty() : PointedDripstoneBlockAccessor.callFindRootBlock(level, pos, state, 11).map(blockPos -> {
|
||||
BlockPos position = blockPos.above();
|
||||
BlockState sourceState = level.getBlockState(position);
|
||||
Fluid fluid = sourceState.is(WBBlocks.MUD.get()) && !level.dimensionType().ultraWarm() ? Fluids.WATER : level.getFluidState(position).getType();
|
||||
Fluid fluid = sourceState.is(WBBlockTags.MUD) && !level.dimensionType().ultraWarm() ? Fluids.WATER : level.getFluidState(position).getType();
|
||||
return new DrippingFluid(position, fluid, sourceState);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package com.cursedcauldron.wildbackport.common.effects;
|
||||
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface EffectFactor {
|
||||
static EffectFactor of(MobEffect effect) {
|
||||
return (EffectFactor)effect;
|
||||
}
|
||||
|
||||
MobEffect setFactorCalculationData(Supplier<FactorCalculationData> data);
|
||||
|
||||
Supplier<FactorCalculationData> getFactorCalculationData();
|
||||
|
||||
static Optional<FactorCalculationData> create(MobEffect effect) {
|
||||
return Optional.ofNullable(of(effect).getFactorCalculationData().get());
|
||||
}
|
||||
|
||||
interface Instance {
|
||||
static Instance of(MobEffectInstance instance) {
|
||||
return (Instance)instance;
|
||||
}
|
||||
|
||||
void setFactorCalculationData(Optional<FactorCalculationData> data);
|
||||
|
||||
Optional<FactorCalculationData> getFactorCalculationData();
|
||||
}
|
||||
|
||||
interface Network {
|
||||
static Network of(Packet<?> packet) {
|
||||
return (Network)packet;
|
||||
}
|
||||
|
||||
FactorCalculationData getFactorCalculationData();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.cursedcauldron.wildbackport.common.effects;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
|
||||
public class FactorCalculationData {
|
||||
public static final Codec<FactorCalculationData> CODEC = RecordCodecBuilder.create(instance -> {
|
||||
return instance.group(ExtraCodecs.NON_NEGATIVE_INT.fieldOf("padding_duration").forGetter(data -> {
|
||||
return data.paddingDuration;
|
||||
}), Codec.FLOAT.fieldOf("factor_start").orElse(0.0F).forGetter(data -> {
|
||||
return data.factorStart;
|
||||
}), Codec.FLOAT.fieldOf("factor_target").orElse(1.0F).forGetter(data -> {
|
||||
return data.factorTarget;
|
||||
}), Codec.FLOAT.fieldOf("factor_current").orElse(0.0F).forGetter(data -> {
|
||||
return data.factorCurrent;
|
||||
}), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("effect_changed_timestamp").orElse(0).forGetter(data -> {
|
||||
return data.effectChangedTimestamp;
|
||||
}), Codec.FLOAT.fieldOf("factor_previous_frame").orElse(0.0F).forGetter(data -> {
|
||||
return data.factorPreviousFrame;
|
||||
}), Codec.BOOL.fieldOf("had_effect_last_tick").orElse(false).forGetter(data -> {
|
||||
return data.hadEffectLastTick;
|
||||
})).apply(instance, FactorCalculationData::new);
|
||||
});
|
||||
private final int paddingDuration;
|
||||
private float factorStart;
|
||||
private float factorTarget;
|
||||
private float factorCurrent;
|
||||
public int effectChangedTimestamp;
|
||||
private float factorPreviousFrame;
|
||||
private boolean hadEffectLastTick;
|
||||
|
||||
public FactorCalculationData(int paddingDuration, float factorStart, float factorTarget, float factorCurrent, int effectChangedTimestamp, float factorPreviousFrame, boolean hadEffectLastTick) {
|
||||
this.paddingDuration = paddingDuration;
|
||||
this.factorStart = factorStart;
|
||||
this.factorTarget = factorTarget;
|
||||
this.factorCurrent = factorCurrent;
|
||||
this.effectChangedTimestamp = effectChangedTimestamp;
|
||||
this.factorPreviousFrame = factorPreviousFrame;
|
||||
this.hadEffectLastTick = hadEffectLastTick;
|
||||
}
|
||||
|
||||
public FactorCalculationData(int paddingDuration) {
|
||||
this(paddingDuration, 0.0F, 1.0F, 0.0F, 0, 0.0F, false);
|
||||
}
|
||||
|
||||
public void update(MobEffectInstance instance) {
|
||||
this.factorPreviousFrame = this.factorCurrent;
|
||||
boolean inRange = instance.getDuration() > this.paddingDuration;
|
||||
|
||||
if (this.hadEffectLastTick != inRange) {
|
||||
this.hadEffectLastTick = inRange;
|
||||
this.effectChangedTimestamp = instance.getDuration();
|
||||
this.factorStart = this.factorCurrent;
|
||||
this.factorTarget = inRange ? 1.0F : 0.0F;
|
||||
}
|
||||
|
||||
float delta = Mth.clamp(((float)this.effectChangedTimestamp - (float)instance.getDuration()) / (float)this.paddingDuration, 0.0F, 1.0F);
|
||||
this.factorCurrent = Mth.lerp(delta, this.factorCurrent, this.factorTarget);
|
||||
}
|
||||
|
||||
public float lerp(LivingEntity entity, float factor) {
|
||||
if (entity.isRemoved()) this.factorPreviousFrame = this.factorCurrent;
|
||||
|
||||
return Mth.lerp(factor, this.factorPreviousFrame, this.factorCurrent);
|
||||
}
|
||||
}
|
|
@ -3,13 +3,14 @@ package com.cursedcauldron.wildbackport.common.entities;
|
|||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.client.animation.api.AnimationState;
|
||||
import com.cursedcauldron.wildbackport.client.registry.WBSoundEvents;
|
||||
import com.cursedcauldron.wildbackport.common.entities.access.api.Poses;
|
||||
import com.cursedcauldron.wildbackport.common.entities.brain.WardenBrain;
|
||||
import com.cursedcauldron.wildbackport.common.entities.brain.warden.SonicBoom;
|
||||
import com.cursedcauldron.wildbackport.common.entities.access.api.Poses;
|
||||
import com.cursedcauldron.wildbackport.common.entities.warden.Angriness;
|
||||
import com.cursedcauldron.wildbackport.common.entities.warden.MobPositionSource;
|
||||
import com.cursedcauldron.wildbackport.common.entities.warden.VibrationListenerSource;
|
||||
import com.cursedcauldron.wildbackport.common.entities.warden.WardenAngerManager;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBMobEffects;
|
||||
import com.cursedcauldron.wildbackport.common.registry.entity.WBEntities;
|
||||
import com.cursedcauldron.wildbackport.common.registry.entity.WBMemoryModules;
|
||||
import com.cursedcauldron.wildbackport.common.tag.WBGameEventTags;
|
||||
|
@ -35,7 +36,6 @@ import net.minecraft.world.DifficultyInstance;
|
|||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.damagesource.IndirectEntityDamageSource;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
import net.minecraft.world.entity.EntitySelector;
|
||||
|
@ -68,6 +68,7 @@ import java.util.Random;
|
|||
|
||||
//<>
|
||||
|
||||
//TODO: fix warden not detecting vibrations by players
|
||||
public class Warden extends Monster implements VibrationListenerSource.VibrationConfig {
|
||||
private static final EntityDataAccessor<Integer> ANGER = SynchedEntityData.defineId(Warden.class, EntityDataSerializers.INT);
|
||||
private int tendrilPitchEnd;
|
||||
|
@ -266,7 +267,7 @@ public class Warden extends Monster implements VibrationListenerSource.Vibration
|
|||
}
|
||||
|
||||
private int getHeartRate() {
|
||||
return 40 - Mth.floor(Mth.clamp((float)this.getAnger() / (float) Angriness.ANGRY.getThreshold(), 0.0F, 1.0F) * 30.0F);
|
||||
return 40 - Mth.floor(Mth.clamp((float)this.getAnger() / (float)Angriness.ANGRY.getThreshold(), 0.0F, 1.0F) * 30.0F);
|
||||
}
|
||||
|
||||
public float getTendrilPitch(float tickDelta) {
|
||||
|
@ -353,7 +354,7 @@ public class Warden extends Monster implements VibrationListenerSource.Vibration
|
|||
}
|
||||
|
||||
public static void addDarknessEffectToClosePlayers(ServerLevel level, Vec3 pos, @Nullable Entity entity, int range) {
|
||||
MobEffectInstance instance = new MobEffectInstance(MobEffects.BLINDNESS, 260, 0, false, false);
|
||||
MobEffectInstance instance = new MobEffectInstance(WBMobEffects.DARKNESS.get(), 260, 0, false, false);
|
||||
MobUtils.addEffectToPlayersWithinDistance(level, entity, pos, range, instance, 200);
|
||||
}
|
||||
|
||||
|
@ -408,7 +409,7 @@ public class Warden extends Monster implements VibrationListenerSource.Vibration
|
|||
}
|
||||
}
|
||||
|
||||
public Optional<LivingEntity> getEntityAngryAt() {
|
||||
public Optional<LivingEntity> getPrimeSuspect() {
|
||||
return this.getAngriness().isAngry() ? this.angerManager.getPrimeSuspect() : Optional.empty();
|
||||
}
|
||||
|
||||
|
@ -423,7 +424,7 @@ public class Warden extends Monster implements VibrationListenerSource.Vibration
|
|||
}
|
||||
|
||||
@Nullable @Override
|
||||
public SpawnGroupData finalizeSpawn(ServerLevelAccessor accessor, DifficultyInstance difficulty, MobSpawnType spawn, @Nullable SpawnGroupData groupData, @Nullable CompoundTag tag) {
|
||||
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawn, @Nullable SpawnGroupData groupData, @Nullable CompoundTag tag) {
|
||||
this.getBrain().setMemoryWithExpiry(WBMemoryModules.DIG_COOLDOWN.get(), Unit.INSTANCE, 1200L);
|
||||
if (spawn == MobSpawnType.TRIGGERED) {
|
||||
this.setPose(Poses.EMERGING.get());
|
||||
|
@ -431,7 +432,7 @@ public class Warden extends Monster implements VibrationListenerSource.Vibration
|
|||
this.playSound(WBSoundEvents.WARDEN_AGITATED, 5.0F, 1.0F);
|
||||
}
|
||||
|
||||
return super.finalizeSpawn(accessor, difficulty, spawn, groupData, tag);
|
||||
return super.finalizeSpawn(level, difficulty, spawn, groupData, tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -452,8 +453,8 @@ public class Warden extends Monster implements VibrationListenerSource.Vibration
|
|||
|
||||
public void updateAttackTarget(LivingEntity entity) {
|
||||
this.getBrain().eraseMemory(WBMemoryModules.ROAR_TARGET.get());
|
||||
entity.getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, entity);
|
||||
entity.getBrain().eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE);
|
||||
this.getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, entity);
|
||||
this.getBrain().eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE);
|
||||
SonicBoom.setCooldown(this, 200);
|
||||
}
|
||||
|
||||
|
|
|
@ -95,15 +95,15 @@ public class WardenBrain {
|
|||
}
|
||||
|
||||
private static void initIdleActivity(Brain<Warden> brain) {
|
||||
brain.addActivity(Activity.IDLE, 10, ImmutableList.of(new SetRoarTarget<>(Warden::getEntityAngryAt), new TryToSniff(), new RunOne<>(ImmutableMap.of(WBMemoryModules.IS_SNIFFING.get(), MemoryStatus.VALUE_ABSENT), ImmutableList.of(Pair.of(new RandomStroll(0.5F), 2), Pair.of(new DoNothing(30, 60), 1)))));
|
||||
brain.addActivity(Activity.IDLE, 10, ImmutableList.of(new SetRoarTarget<>(Warden::getPrimeSuspect), new TryToSniff(), new RunOne<>(ImmutableMap.of(WBMemoryModules.IS_SNIFFING.get(), MemoryStatus.VALUE_ABSENT), ImmutableList.of(Pair.of(new RandomStroll(0.5F), 2), Pair.of(new DoNothing(30, 60), 1)))));
|
||||
}
|
||||
|
||||
private static void initInvestigateActivity(Brain<Warden> brain) {
|
||||
brain.addActivityAndRemoveMemoryWhenStopped(WBActivities.INVESTIGATE.get(), 5, ImmutableList.of(new SetRoarTarget<>(Warden::getEntityAngryAt), new GoToTargetLocation<>(WBMemoryModules.DISTURBANCE_LOCATION.get(), 2, 0.7F)), WBMemoryModules.DISTURBANCE_LOCATION.get());
|
||||
brain.addActivityAndRemoveMemoryWhenStopped(WBActivities.INVESTIGATE.get(), 5, ImmutableList.of(new SetRoarTarget<>(Warden::getPrimeSuspect), new GoToTargetLocation<>(WBMemoryModules.DISTURBANCE_LOCATION.get(), 2, 0.7F)), WBMemoryModules.DISTURBANCE_LOCATION.get());
|
||||
}
|
||||
|
||||
private static void initSniffingActivity(Brain<Warden> brain) {
|
||||
brain.addActivityAndRemoveMemoryWhenStopped(WBActivities.SNIFF.get(), 5, ImmutableList.of(new SetRoarTarget<>(Warden::getEntityAngryAt), new Sniffing<>(SNIFFING_DURATION)), WBMemoryModules.IS_SNIFFING.get());
|
||||
brain.addActivityAndRemoveMemoryWhenStopped(WBActivities.SNIFF.get(), 5, ImmutableList.of(new SetRoarTarget<>(Warden::getPrimeSuspect), new Sniffing<>(SNIFFING_DURATION)), WBMemoryModules.IS_SNIFFING.get());
|
||||
}
|
||||
|
||||
private static void initRoarActivity(Brain<Warden> brain) {
|
||||
|
@ -132,7 +132,7 @@ public class WardenBrain {
|
|||
}
|
||||
|
||||
public static void setDisturbanceLocation(Warden warden, BlockPos pos) {
|
||||
if (warden.level.getWorldBorder().isWithinBounds(pos) && warden.getEntityAngryAt().isEmpty() && warden.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).isEmpty()) {
|
||||
if (warden.level.getWorldBorder().isWithinBounds(pos) && warden.getPrimeSuspect().isEmpty() && warden.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).isEmpty()) {
|
||||
setDigCooldown(warden);
|
||||
warden.getBrain().setMemoryWithExpiry(WBMemoryModules.SNIFF_COOLDOWN.get(), Unit.INSTANCE, 100L);
|
||||
warden.getBrain().setMemoryWithExpiry(MemoryModuleType.LOOK_TARGET, new BlockPosTracker(pos), 100L);
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package com.cursedcauldron.wildbackport.common.registry;
|
||||
|
||||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.common.effects.EffectFactor;
|
||||
import com.cursedcauldron.wildbackport.common.effects.FactorCalculationData;
|
||||
import com.cursedcauldron.wildbackport.core.api.CoreRegistry;
|
||||
import com.cursedcauldron.wildbackport.core.mixin.access.MobEffectAccessor;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectCategory;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WBMobEffects {
|
||||
public static final CoreRegistry<MobEffect> EFFECTS = CoreRegistry.create(Registry.MOB_EFFECT, WildBackport.MOD_ID);
|
||||
|
||||
public static final Supplier<MobEffect> DARKNESS = EFFECTS.register("darkness", () -> EffectFactor.of(MobEffectAccessor.createMobEffect(MobEffectCategory.HARMFUL, 2696993)).setFactorCalculationData(() -> new FactorCalculationData(22)));
|
||||
}
|
|
@ -20,4 +20,7 @@ public class WBBlockTags {
|
|||
// Deep Dark
|
||||
public static final TagKey<Block> SCULK_REPLACEABLE = TAGS.create("sculk_replaceable");
|
||||
public static final TagKey<Block> SCULK_REPLACEABLE_WORLD_GEN = TAGS.create("sculk_replaceable_world_gen");
|
||||
|
||||
// Compatibility
|
||||
public static final TagKey<Block> MUD = TAGS.create("mud");
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.access;
|
||||
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectCategory;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(MobEffect.class)
|
||||
public interface MobEffectAccessor {
|
||||
@Invoker("<init>")
|
||||
static MobEffect createMobEffect(MobEffectCategory mobEffectCategory, int i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.client;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.effects.EffectFactor;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBMobEffects;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.material.FogType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(FogRenderer.class)
|
||||
public class FogRendererMixin {
|
||||
@Shadow private static float fogRed;
|
||||
@Shadow private static float fogGreen;
|
||||
@Shadow private static float fogBlue;
|
||||
private static float fogPartialTicks;
|
||||
|
||||
@Inject(method = "setupColor", at = @At("TAIL"))
|
||||
private static void applyDarknessColor(Camera camera, float partialTicks, ClientLevel level, int viewDistance, float skyDarkness, CallbackInfo ci) {
|
||||
FogType type = camera.getFluidInCamera();
|
||||
fogPartialTicks = partialTicks;
|
||||
|
||||
double colorModifier = (camera.getPosition().y - (double)level.getMinBuildHeight()) * level.getLevelData().getClearColorScale();
|
||||
if (camera.getEntity() instanceof LivingEntity living && living.hasEffect(WBMobEffects.DARKNESS.get())) {
|
||||
MobEffectInstance effect = living.getEffect(WBMobEffects.DARKNESS.get());
|
||||
|
||||
if (effect != null) {
|
||||
EffectFactor.Instance instance = EffectFactor.Instance.of(effect);
|
||||
colorModifier = instance.getFactorCalculationData().isPresent() ? 1.0F - instance.getFactorCalculationData().get().lerp(living, partialTicks) : 0.0D;
|
||||
}
|
||||
}
|
||||
|
||||
if (colorModifier < 1.0D && type != FogType.LAVA) {
|
||||
if (colorModifier < 0.0D) {
|
||||
colorModifier = 0.0D;
|
||||
}
|
||||
|
||||
colorModifier *= colorModifier;
|
||||
fogRed = (float)((double)fogRed * colorModifier);
|
||||
fogGreen = (float)((double)fogGreen * colorModifier);
|
||||
fogBlue = (float)((double)fogBlue * colorModifier);
|
||||
}
|
||||
|
||||
if (skyDarkness > 0.0F) {
|
||||
fogRed = fogRed * (1.0F - skyDarkness) + fogRed * 0.7F * skyDarkness;
|
||||
fogGreen = fogGreen * (1.0F - skyDarkness) + fogGreen * 0.6F * skyDarkness;
|
||||
fogBlue = fogBlue * (1.0F - skyDarkness) + fogBlue * 0.6F * skyDarkness;
|
||||
}
|
||||
|
||||
RenderSystem.clearColor(fogRed, fogGreen, fogBlue, 0.0F);
|
||||
}
|
||||
|
||||
@Inject(method = "setupFog", at = @At("TAIL"), remap = false)
|
||||
private static void applyDarknessFog(Camera camera, FogRenderer.FogMode mode, float viewDistance, boolean thickFog, CallbackInfo ci) {
|
||||
FogType fogtype = camera.getFluidInCamera();
|
||||
|
||||
if (fogtype != FogType.WATER) {
|
||||
if (camera.getEntity() instanceof LivingEntity living && living.hasEffect(WBMobEffects.DARKNESS.get())) {
|
||||
MobEffectInstance effect = living.getEffect(WBMobEffects.DARKNESS.get());
|
||||
|
||||
if (effect != null) {
|
||||
EffectFactor.Instance instance = EffectFactor.Instance.of(effect);
|
||||
if (instance.getFactorCalculationData().isPresent()) {
|
||||
float modifier = Mth.lerp(instance.getFactorCalculationData().get().lerp(living, fogPartialTicks), viewDistance, 15.0F);
|
||||
float start = mode == FogRenderer.FogMode.FOG_SKY ? 0.0F : modifier * 0.75F;
|
||||
|
||||
RenderSystem.setShaderFogStart(start);
|
||||
RenderSystem.setShaderFogEnd(modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.client;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.effects.EffectFactor;
|
||||
import com.cursedcauldron.wildbackport.common.registry.WBMobEffects;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.math.Vector3f;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LightTexture.class)
|
||||
public abstract class LightTextureMixin {
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
@Shadow private boolean updateLightTexture;
|
||||
@Shadow private float blockLightRedFlicker;
|
||||
@Shadow protected abstract float getBrightness(Level level, int i);
|
||||
@Shadow @Final private DynamicTexture lightTexture;
|
||||
@Shadow @Final private NativeImage lightPixels;
|
||||
@Shadow protected abstract float notGamma(float f);
|
||||
@Shadow @Final private GameRenderer renderer;
|
||||
|
||||
private LocalPlayer getPlayer() {
|
||||
assert this.minecraft.player != null;
|
||||
return this.minecraft.player;
|
||||
}
|
||||
|
||||
private float getDarknessFactor(float delta) {
|
||||
MobEffectInstance instance = this.getPlayer().getEffect(WBMobEffects.DARKNESS.get());
|
||||
if (this.getPlayer().hasEffect(WBMobEffects.DARKNESS.get()) && instance != null && EffectFactor.Instance.of(instance).getFactorCalculationData().isPresent()) {
|
||||
return EffectFactor.Instance.of(instance).getFactorCalculationData().get().lerp(this.getPlayer(), delta);
|
||||
} else {
|
||||
return 0.0F;
|
||||
}
|
||||
}
|
||||
|
||||
private float getDarkness(LivingEntity entity, float factor, float delta) {
|
||||
return Math.max(0.0F, Mth.cos(((float)entity.tickCount - delta) * (float) Math.PI * 0.025F) * 0.45F * factor);
|
||||
}
|
||||
|
||||
//TODO simplify
|
||||
@Inject(method = "updateLightTexture", at = @At("HEAD"))
|
||||
private void updateLight(float delta, CallbackInfo ci) {
|
||||
if (this.updateLightTexture) {
|
||||
this.updateLightTexture = false;
|
||||
ClientLevel level = this.minecraft.level;
|
||||
if (level != null) {
|
||||
float skyDarken = level.getSkyDarken(1.0F);
|
||||
float skyFlashTime = level.getSkyFlashTime() > 0 ? 1.0F : skyDarken * 0.95F + 0.05F;
|
||||
float darknessFactor = this.getDarknessFactor(delta);
|
||||
float darkness = this.getDarkness(this.getPlayer(), darknessFactor, delta);
|
||||
float waterVision = this.getPlayer().getWaterVision();
|
||||
float visionScale = this.getPlayer().hasEffect(MobEffects.NIGHT_VISION) ? GameRenderer.getNightVisionScale(this.getPlayer(), delta) : (waterVision > 0.0F && this.getPlayer().hasEffect(MobEffects.CONDUIT_POWER) ? waterVision : 0.0F);
|
||||
Vector3f vec3f = new Vector3f(skyDarken, skyDarken, 1.0F);
|
||||
vec3f.lerp(new Vector3f(1.0F, 1.0F, 1.0F), 0.35F);
|
||||
float blockLightFlicker = this.blockLightRedFlicker + 1.5F;
|
||||
Vector3f vec3f2 = new Vector3f();
|
||||
|
||||
for (int skyLight = 0; skyLight < 16; ++skyLight) {
|
||||
for (int blockLight = 0; blockLight < 16; ++blockLight) {
|
||||
float skyBrightness = this.getBrightness(level, skyLight) * skyFlashTime;
|
||||
float blockBrightness = this.getBrightness(level, blockLight) * blockLightFlicker;
|
||||
float yLight = blockBrightness * ((blockBrightness * 0.6F + 0.4F) * 0.6F + 0.4F);
|
||||
float xzLight = blockBrightness * (blockBrightness * blockBrightness * 0.6F + 0.4F);
|
||||
vec3f2.set(blockBrightness, yLight, xzLight);
|
||||
boolean forceLightmap = level.effects().forceBrightLightmap();
|
||||
|
||||
if (forceLightmap) {
|
||||
vec3f2.lerp(new Vector3f(0.99F, 1.12F, 1.0F), 0.25F);
|
||||
vec3f2.clamp(0.0F, 1.0F);
|
||||
} else {
|
||||
Vector3f vec3f3 = vec3f.copy();
|
||||
vec3f3.mul(skyBrightness);
|
||||
vec3f2.add(vec3f3);
|
||||
vec3f2.lerp(new Vector3f(0.75F, 0.75F, 0.75F), 0.04F);
|
||||
if (this.renderer.getDarkenWorldAmount(delta) > 0.0f) {
|
||||
float darkenWorldAmount = this.renderer.getDarkenWorldAmount(delta);
|
||||
Vector3f vec3f4 = vec3f2.copy();
|
||||
vec3f4.mul(0.7F, 0.6F, 0.6F);
|
||||
vec3f2.lerp(vec3f4, darkenWorldAmount);
|
||||
}
|
||||
}
|
||||
|
||||
if (visionScale > 0.0F) {
|
||||
float modifier = Math.max(vec3f2.x(), Math.max(vec3f2.y(), vec3f2.z()));
|
||||
if (modifier < 1.0F) {
|
||||
float scale = 1.0F / modifier;
|
||||
Vector3f vec3f3 = vec3f2.copy();
|
||||
vec3f3.mul(scale);
|
||||
vec3f2.lerp(vec3f3, visionScale);
|
||||
}
|
||||
}
|
||||
|
||||
if (!forceLightmap) {
|
||||
if (darkness > 0.0F) {
|
||||
vec3f2.add(-darkness, -darkness, -darkness);
|
||||
}
|
||||
|
||||
vec3f2.clamp(0.0F, 1.0F);
|
||||
}
|
||||
|
||||
float gamma = (float)this.minecraft.options.gamma;
|
||||
Vector3f vec3f3 = vec3f2.copy();
|
||||
vec3f3.map(this::notGamma);
|
||||
vec3f2.lerp(vec3f3, Math.max(0.0F, gamma - darknessFactor));
|
||||
vec3f2.lerp(new Vector3f(0.75F, 0.75F, 0.75F), 0.04F);
|
||||
vec3f2.clamp(0.0F, 1.0F);
|
||||
vec3f2.mul(255.0F);
|
||||
int x = (int)vec3f2.x();
|
||||
int y = (int)vec3f2.y();
|
||||
int z = (int)vec3f2.z();
|
||||
this.lightPixels.setPixelRGBA(blockLight, skyLight, -16777216 | z << 16 | y << 8 | x);
|
||||
}
|
||||
}
|
||||
|
||||
this.lightTexture.upload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.common;
|
||||
|
||||
import com.cursedcauldron.wildbackport.WildBackport;
|
||||
import com.cursedcauldron.wildbackport.common.effects.EffectFactor;
|
||||
import com.cursedcauldron.wildbackport.common.effects.FactorCalculationData;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(MobEffect.class)
|
||||
public class MobEffectMixin implements EffectFactor {
|
||||
private Supplier<FactorCalculationData> factorCalculationData = () -> null;
|
||||
|
||||
@Override
|
||||
public MobEffect setFactorCalculationData(Supplier<FactorCalculationData> data) {
|
||||
this.factorCalculationData = data;
|
||||
return MobEffect.class.cast(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<FactorCalculationData> getFactorCalculationData() {
|
||||
return this.factorCalculationData;
|
||||
}
|
||||
|
||||
@Mixin(MobEffectInstance.class)
|
||||
public static class MobEffectInstanceMixin implements EffectFactor.Instance {
|
||||
@Shadow @Final private MobEffect effect;
|
||||
@Shadow private int duration;
|
||||
private Optional<FactorCalculationData> factorCalculationData;
|
||||
|
||||
@Inject(method = "<init>(Lnet/minecraft/world/effect/MobEffect;IIZZZLnet/minecraft/world/effect/MobEffectInstance;)V", at = @At("TAIL"))
|
||||
private void wb$create(MobEffect effect, int duration, int amplifier, boolean ambient, boolean showParticles, boolean showIcon, MobEffectInstance hiddenEffect, CallbackInfo ci) {
|
||||
this.setFactorCalculationData(EffectFactor.create(effect));
|
||||
}
|
||||
|
||||
@Inject(method = "<init>(Lnet/minecraft/world/effect/MobEffectInstance;)V", at = @At("TAIL"))
|
||||
private void wb$create(MobEffectInstance instance, CallbackInfo ci) {
|
||||
this.setFactorCalculationData(EffectFactor.create(this.effect));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFactorCalculationData(Optional<FactorCalculationData> data) {
|
||||
this.factorCalculationData = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<FactorCalculationData> getFactorCalculationData() {
|
||||
return this.factorCalculationData;
|
||||
}
|
||||
|
||||
@Inject(method = "update", at = @At("HEAD"), cancellable = true)
|
||||
private void wb$update(MobEffectInstance instance, CallbackInfoReturnable<Boolean> cir) {
|
||||
int i = instance.getDuration();
|
||||
// int i = this.duration;
|
||||
if (i != this.duration) {
|
||||
this.factorCalculationData.ifPresent(data -> data.effectChangedTimestamp += this.duration - i);
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void wb$tick(LivingEntity entity, Runnable runnable, CallbackInfoReturnable<Boolean> cir) {
|
||||
this.factorCalculationData.ifPresent(data -> data.update(MobEffectInstance.class.cast(this)));
|
||||
}
|
||||
|
||||
@Inject(method = "writeDetailsTo", at = @At("TAIL"))
|
||||
private void wb$write(CompoundTag tag, CallbackInfo ci) {
|
||||
this.factorCalculationData.flatMap(instance -> FactorCalculationData.CODEC.encodeStart(NbtOps.INSTANCE, instance).resultOrPartial(WildBackport.LOGGER::error)).ifPresent(data -> tag.put("FactorCalculationData", data));
|
||||
}
|
||||
|
||||
@Inject(method = "loadSpecifiedEffect", at = @At("TAIL"))
|
||||
private static void wb$load(MobEffect effect, CompoundTag tag, CallbackInfoReturnable<MobEffectInstance> cir) {
|
||||
Optional<FactorCalculationData> data = tag.contains("FactorCalculationData", 10) ? FactorCalculationData.CODEC.parse(new Dynamic<>(NbtOps.INSTANCE, tag.getCompound("FactorCalculationData"))).resultOrPartial(WildBackport.LOGGER::error) : Optional.empty();
|
||||
EffectFactor.Instance.of(cir.getReturnValue()).setFactorCalculationData(data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,44 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.network;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.effects.EffectFactor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.network.protocol.PacketUtils;
|
||||
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(ClientPacketListener.class)
|
||||
public class ClientPacketListenerMixin {
|
||||
@Shadow private ClientLevel level;
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
|
||||
//TODO simplify
|
||||
@Inject(method = "handleUpdateMobEffect", at = @At("HEAD"), cancellable = true)
|
||||
private void wb$updateEffect(ClientboundUpdateMobEffectPacket packet, CallbackInfo ci) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft);
|
||||
Entity entity = this.level.getEntity(packet.getEntityId());
|
||||
if (entity instanceof LivingEntity living) {
|
||||
MobEffect effect = MobEffect.byId(packet.getEffectId() & 0xFF);
|
||||
if (effect != null) {
|
||||
MobEffectInstance instance = new MobEffectInstance(effect, packet.getEffectDurationTicks(), packet.getEffectAmplifier(), packet.isEffectAmbient(), packet.isEffectVisible(), packet.effectShowsIcon());
|
||||
instance.setNoCounter(packet.isSuperLongDuration());
|
||||
EffectFactor.Instance.of(instance).setFactorCalculationData(Optional.ofNullable(EffectFactor.Network.of(packet).getFactorCalculationData()));
|
||||
living.forceAddEffect(instance, null);
|
||||
}
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.cursedcauldron.wildbackport.core.mixin.network;
|
||||
|
||||
import com.cursedcauldron.wildbackport.common.effects.EffectFactor;
|
||||
import com.cursedcauldron.wildbackport.common.effects.FactorCalculationData;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Mixin(ClientboundUpdateMobEffectPacket.class)
|
||||
public class ClientboundUpdateMobEffectPacketMixin implements EffectFactor.Network {
|
||||
private FactorCalculationData factorCalculationData;
|
||||
|
||||
@Inject(method = "<init>(ILnet/minecraft/world/effect/MobEffectInstance;)V", at = @At("TAIL"))
|
||||
private void create(int id, MobEffectInstance instance, CallbackInfo ci) {
|
||||
this.factorCalculationData = EffectFactor.Instance.of(instance).getFactorCalculationData().orElse(null);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At("TAIL"))
|
||||
private void create(FriendlyByteBuf buf, CallbackInfo ci) {
|
||||
this.factorCalculationData = this.readNullable(buf, buffer -> buffer.readWithCodec(FactorCalculationData.CODEC));
|
||||
}
|
||||
|
||||
@Inject(method = "write", at = @At("TAIL"))
|
||||
private void writeData(FriendlyByteBuf buf, CallbackInfo ci) {
|
||||
this.writeNullable(buf, this.factorCalculationData, (buffer, data) -> buffer.writeWithCodec(FactorCalculationData.CODEC, data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FactorCalculationData getFactorCalculationData() {
|
||||
return this.factorCalculationData;
|
||||
}
|
||||
|
||||
private <T> T readNullable(FriendlyByteBuf buf, Function<FriendlyByteBuf, T> consumer) {
|
||||
return buf.readBoolean() ? consumer.apply(buf) : null;
|
||||
}
|
||||
|
||||
private <T> void writeNullable(FriendlyByteBuf buf, @Nullable T entry, BiConsumer<FriendlyByteBuf, T> consumer) {
|
||||
if (entry != null) {
|
||||
buf.writeBoolean(true);
|
||||
consumer.accept(buf, entry);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"wildbackport:mud"
|
||||
]
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
"access.DoorBlockAccessor",
|
||||
"access.FireBlockAccessor",
|
||||
"access.MemoryModuleTypeAccessor",
|
||||
"access.MobEffectAccessor",
|
||||
"access.ModelPartAccessor",
|
||||
"access.OverworldBiomesAccessor",
|
||||
"access.PointedDripstoneBlockAccessor",
|
||||
|
@ -32,6 +33,8 @@
|
|||
"common.BlockEntityTypeMixin",
|
||||
"common.FlyNodeEvaluatorMixin",
|
||||
"common.LivingEntityMixin",
|
||||
"common.MobEffectMixin",
|
||||
"common.MobEffectMixin$MobEffectInstanceMixin",
|
||||
"common.NoteBlockMixin",
|
||||
"common.PathfinderMobMixin",
|
||||
"common.PlayerMixin",
|
||||
|
@ -40,9 +43,12 @@
|
|||
"common.SculkSensorBlockMixin",
|
||||
"extension.BoatTypeMixin",
|
||||
"extension.PoseMixin",
|
||||
"network.ClientboundUpdateMobEffectPacketMixin",
|
||||
"network.ServerGamePacketListenerImplMixin"
|
||||
],
|
||||
"client": [
|
||||
"client.FogRendererMixin",
|
||||
"client.LightTextureMixin",
|
||||
"client.LocalPlayerMixin",
|
||||
"client.ModelPartMixin",
|
||||
"client.PartDefinitionMixin",
|
||||
|
|
Loading…
Reference in a new issue