delete stuff
This commit is contained in:
		@@ -1,7 +1,8 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.effects;
 | 
					package dev.xkmc.l2core.base.effects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.xkmc.l2core.capability.attachment.GeneralCapabilityTemplate;
 | 
					import dev.xkmc.l2core.capability.attachment.GeneralCapabilityTemplate;
 | 
				
			||||||
import dev.xkmc.l2serial.serialization.SerialClass;
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialClass;
 | 
				
			||||||
 | 
					import net.minecraft.core.Holder;
 | 
				
			||||||
import net.minecraft.world.effect.MobEffect;
 | 
					import net.minecraft.world.effect.MobEffect;
 | 
				
			||||||
import net.minecraft.world.entity.LivingEntity;
 | 
					import net.minecraft.world.entity.LivingEntity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,6 +13,6 @@ import java.util.TreeMap;
 | 
				
			|||||||
@SerialClass
 | 
					@SerialClass
 | 
				
			||||||
public class ClientEffectCap extends GeneralCapabilityTemplate<LivingEntity, ClientEffectCap> {
 | 
					public class ClientEffectCap extends GeneralCapabilityTemplate<LivingEntity, ClientEffectCap> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public final Map<MobEffect, Integer> map = new TreeMap<>(Comparator.comparing(MobEffect::getDescriptionId));
 | 
						public final Map<Holder<MobEffect>, Integer> map = new TreeMap<>(Comparator.comparing(Holder::getRegisteredName));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.effects;
 | 
					package dev.xkmc.l2core.base.effects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.minecraft.core.Holder;
 | 
				
			||||||
import net.minecraft.world.effect.MobEffect;
 | 
					import net.minecraft.world.effect.MobEffect;
 | 
				
			||||||
import net.minecraft.world.effect.MobEffectInstance;
 | 
					import net.minecraft.world.effect.MobEffectInstance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -11,7 +12,7 @@ public class EffectBuilder {
 | 
				
			|||||||
		this.ins = ins;
 | 
							this.ins = ins;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public EffectBuilder(MobEffect effect) {
 | 
						public EffectBuilder(Holder<MobEffect> effect) {
 | 
				
			||||||
		this.ins = new MobEffectInstance(effect, 1, 0);
 | 
							this.ins = new MobEffectInstance(effect, 1, 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.effects;
 | 
					package dev.xkmc.l2core.base.effects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.xkmc.l2core.init.events.ClientEffectRenderEvents;
 | 
					import dev.xkmc.l2core.events.ClientEffectRenderEvents;
 | 
				
			||||||
import dev.xkmc.l2serial.network.SerialPacketBase;
 | 
					import dev.xkmc.l2serial.network.SerialPacketBase;
 | 
				
			||||||
import dev.xkmc.l2serial.serialization.SerialClass;
 | 
					import net.minecraft.core.Holder;
 | 
				
			||||||
import net.minecraft.world.effect.MobEffect;
 | 
					import net.minecraft.world.effect.MobEffect;
 | 
				
			||||||
import net.minecraft.world.entity.player.Player;
 | 
					import net.minecraft.world.entity.player.Player;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public record EffectToClient(int entity, MobEffect effect, boolean exist, int level)
 | 
					public record EffectToClient(int entity, Holder<MobEffect> effect, boolean exist, int level)
 | 
				
			||||||
		implements SerialPacketBase<EffectToClient> {
 | 
							implements SerialPacketBase<EffectToClient> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ import dev.xkmc.l2core.base.effects.api.ForceEffect;
 | 
				
			|||||||
import net.minecraft.world.effect.MobEffectInstance;
 | 
					import net.minecraft.world.effect.MobEffectInstance;
 | 
				
			||||||
import net.minecraft.world.entity.Entity;
 | 
					import net.minecraft.world.entity.Entity;
 | 
				
			||||||
import net.minecraft.world.entity.LivingEntity;
 | 
					import net.minecraft.world.entity.LivingEntity;
 | 
				
			||||||
import net.neoforged.bus.api.Event;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.common.NeoForge;
 | 
					import net.neoforged.neoforge.common.NeoForge;
 | 
				
			||||||
import net.neoforged.neoforge.event.EventHooks;
 | 
					import net.neoforged.neoforge.event.EventHooks;
 | 
				
			||||||
import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
 | 
					import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
 | 
				
			||||||
@@ -15,53 +14,46 @@ import java.util.function.Predicate;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public class EffectUtil {
 | 
					public class EffectUtil {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public enum AddReason {
 | 
					 | 
				
			||||||
		NONE, PROF, FORCE, SKILL, SELF
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static final ThreadLocal<AddReason> REASON = new ThreadLocal<>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * force add effect, make hard not override
 | 
						 * force add effect, make hard not override
 | 
				
			||||||
	 * for icon use only, such as Arcane Mark on Wither and Ender Dragon
 | 
						 * for icon use only, such as Arcane Mark on Wither and Ender Dragon
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	private static void forceAddEffect(LivingEntity e, MobEffectInstance ins, @Nullable Entity source) {
 | 
						private static void forceAddEffect(LivingEntity e, MobEffectInstance ins, @Nullable Entity source) {
 | 
				
			||||||
		MobEffectInstance effectinstance = e.getActiveEffectsMap().get(ins.getEffect());
 | 
							MobEffectInstance old = e.activeEffects.get(ins.getEffect());
 | 
				
			||||||
		var event = new ForceAddEffectEvent(e, ins);
 | 
							var event = new ForceAddEffectEvent(e, ins);
 | 
				
			||||||
		NeoForge.EVENT_BUS.post(event);
 | 
							NeoForge.EVENT_BUS.post(event);
 | 
				
			||||||
		if (event.getResult() == Event.Result.DENY) {
 | 
							if (event.isCanceled()) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		NeoForge.EVENT_BUS.post(new MobEffectEvent.Added(e, effectinstance, ins, source));
 | 
							NeoForge.EVENT_BUS.post(new MobEffectEvent.Added(e, old, ins, source));
 | 
				
			||||||
		if (effectinstance == null) {
 | 
							if (old == null) {
 | 
				
			||||||
			e.getActiveEffectsMap().put(ins.getEffect(), ins);
 | 
								e.activeEffects.put(ins.getEffect(), ins);
 | 
				
			||||||
			e.onEffectAdded(ins, source);
 | 
								e.onEffectAdded(ins, source);
 | 
				
			||||||
		} else if (effectinstance.update(ins)) {
 | 
								ins.onEffectAdded(e);
 | 
				
			||||||
			e.onEffectUpdated(effectinstance, true, source);
 | 
							} else if (old.update(ins)) {
 | 
				
			||||||
 | 
								e.onEffectUpdated(old, true, source);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ins.onEffectStarted(e);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static void addEffect(LivingEntity entity, MobEffectInstance ins, AddReason reason, @Nullable Entity source) {
 | 
						public static void addEffect(LivingEntity entity, MobEffectInstance ins, @Nullable Entity source) {
 | 
				
			||||||
		if (entity == source)
 | 
					 | 
				
			||||||
			reason = AddReason.SELF;
 | 
					 | 
				
			||||||
		if (ins.getEffect() instanceof ForceEffect)
 | 
					 | 
				
			||||||
			reason = AddReason.FORCE;
 | 
					 | 
				
			||||||
		ins = new MobEffectInstance(ins.getEffect(), ins.getDuration(), ins.getAmplifier(),
 | 
							ins = new MobEffectInstance(ins.getEffect(), ins.getDuration(), ins.getAmplifier(),
 | 
				
			||||||
				ins.isAmbient(), reason != AddReason.FORCE && ins.isVisible(), ins.showIcon());
 | 
									ins.isAmbient(), ins.isVisible(), ins.showIcon());
 | 
				
			||||||
		REASON.set(reason);
 | 
					 | 
				
			||||||
		if (ins.getEffect() instanceof ForceEffect)
 | 
							if (ins.getEffect() instanceof ForceEffect)
 | 
				
			||||||
			forceAddEffect(entity, ins, source);
 | 
								forceAddEffect(entity, ins, source);
 | 
				
			||||||
		else if (ins.getEffect().isInstantenous())
 | 
							else if (ins.getEffect().value().isInstantenous())
 | 
				
			||||||
			ins.getEffect().applyInstantenousEffect(null, null, entity, ins.getAmplifier(), 1);
 | 
								ins.getEffect().value().applyInstantenousEffect(null, null, entity, ins.getAmplifier(), 1);
 | 
				
			||||||
		else entity.addEffect(ins, source);
 | 
							else entity.addEffect(ins, source);
 | 
				
			||||||
		REASON.set(AddReason.NONE);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static void refreshEffect(LivingEntity entity, MobEffectInstance ins, AddReason reason, Entity source) {
 | 
						public static void refreshEffect(LivingEntity entity, MobEffectInstance ins, Entity source) {
 | 
				
			||||||
		if (ins.duration < 40) ins.duration = 40;
 | 
							if (ins.duration < 40) ins.duration = 40;
 | 
				
			||||||
		MobEffectInstance cur = entity.getEffect(ins.getEffect());
 | 
							MobEffectInstance cur = entity.getEffect(ins.getEffect());
 | 
				
			||||||
		if (cur == null || cur.getAmplifier() < ins.getAmplifier() || cur.getAmplifier() == ins.getAmplifier() && cur.getDuration() < ins.getDuration() / 2)
 | 
							if (cur == null ||
 | 
				
			||||||
			addEffect(entity, ins, reason, source);
 | 
									cur.getAmplifier() < ins.getAmplifier() ||
 | 
				
			||||||
 | 
									cur.getAmplifier() == ins.getAmplifier() &&
 | 
				
			||||||
 | 
											cur.getDuration() < ins.getDuration() / 2
 | 
				
			||||||
 | 
							) addEffect(entity, ins, source);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static void removeEffect(LivingEntity entity, Predicate<MobEffectInstance> pred) {
 | 
						public static void removeEffect(LivingEntity entity, Predicate<MobEffectInstance> pred) {
 | 
				
			||||||
@@ -76,9 +68,4 @@ public class EffectUtil {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static AddReason getReason() {
 | 
					 | 
				
			||||||
		AddReason ans = REASON.get();
 | 
					 | 
				
			||||||
		return ans == null ? AddReason.NONE : ans;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,11 @@ package dev.xkmc.l2core.base.effects;
 | 
				
			|||||||
import net.minecraft.world.effect.MobEffectInstance;
 | 
					import net.minecraft.world.effect.MobEffectInstance;
 | 
				
			||||||
import net.minecraft.world.entity.LivingEntity;
 | 
					import net.minecraft.world.entity.LivingEntity;
 | 
				
			||||||
import net.neoforged.bus.api.Event;
 | 
					import net.neoforged.bus.api.Event;
 | 
				
			||||||
 | 
					import net.neoforged.bus.api.ICancellableEvent;
 | 
				
			||||||
import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
 | 
					import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Event.HasResult
 | 
					public class ForceAddEffectEvent extends MobEffectEvent implements ICancellableEvent {
 | 
				
			||||||
public class ForceAddEffectEvent extends MobEffectEvent {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public ForceAddEffectEvent(LivingEntity living, @NotNull MobEffectInstance effectInstance) {
 | 
						public ForceAddEffectEvent(LivingEntity living, @NotNull MobEffectInstance effectInstance) {
 | 
				
			||||||
		super(living, effectInstance);
 | 
							super(living, effectInstance);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,49 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.xkmc.l2serial.serialization.SerialClass;
 | 
					 | 
				
			||||||
import dev.xkmc.l2serial.serialization.codec.PacketCodec;
 | 
					 | 
				
			||||||
import dev.xkmc.l2serial.serialization.codec.TagCodec;
 | 
					 | 
				
			||||||
import dev.xkmc.l2serial.util.Wrappers;
 | 
					 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					 | 
				
			||||||
import net.minecraft.nbt.CompoundTag;
 | 
					 | 
				
			||||||
import net.minecraft.network.FriendlyByteBuf;
 | 
					 | 
				
			||||||
import net.minecraft.world.entity.Entity;
 | 
					 | 
				
			||||||
import net.minecraft.world.entity.EntityType;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.Level;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.entity.IEntityWithComplexSpawn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@SerialClass
 | 
					 | 
				
			||||||
@ParametersAreNonnullByDefault
 | 
					 | 
				
			||||||
@MethodsReturnNonnullByDefault
 | 
					 | 
				
			||||||
public abstract class BaseEntity extends Entity implements IEntityWithComplexSpawn {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public BaseEntity(EntityType<?> type, Level world) {
 | 
					 | 
				
			||||||
		super(type, world);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	protected void addAdditionalSaveData(CompoundTag tag) {
 | 
					 | 
				
			||||||
		tag.put("auto-serial", TagCodec.toTag(new CompoundTag(), this));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	protected void readAdditionalSaveData(CompoundTag tag) {
 | 
					 | 
				
			||||||
		if (!tag.contains("auto-serial"))
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		Wrappers.run(() -> TagCodec.fromTag(tag.getCompound("auto-serial"), this.getClass(), this, f -> true));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void writeSpawnData(FriendlyByteBuf buffer) {
 | 
					 | 
				
			||||||
		PacketCodec.to(buffer, this);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@SuppressWarnings({"rawtypes", "unchecked"})
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void readSpawnData(FriendlyByteBuf data) {
 | 
					 | 
				
			||||||
		PacketCodec.from(data, (Class) this.getClass(), this);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
@MethodsReturnNonnullByDefault
 | 
					 | 
				
			||||||
@ParametersAreNonnullByDefault
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package dev.xkmc.l2core.base.entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
					 | 
				
			||||||
@@ -1,29 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.explosion;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.world.entity.Entity;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.Explosion;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class BaseExplosion extends Explosion {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public final BaseExplosionContext base;
 | 
					 | 
				
			||||||
	public final ModExplosionContext mod;
 | 
					 | 
				
			||||||
	public final VanillaExplosionContext mc;
 | 
					 | 
				
			||||||
	public final ParticleExplosionContext particle;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public BaseExplosion(BaseExplosionContext base, VanillaExplosionContext mc, ModExplosionContext mod, ParticleExplosionContext particle) {
 | 
					 | 
				
			||||||
		super(base.level(), mc.entity(), mc.source(), mc.calculator(), base.x(), base.y(), base.z(), base.r(), mc.fire(), mc.type(),
 | 
					 | 
				
			||||||
				particle.small(), particle.large(), particle.sound());
 | 
					 | 
				
			||||||
		this.base = base;
 | 
					 | 
				
			||||||
		this.mod = mod;
 | 
					 | 
				
			||||||
		this.mc = mc;
 | 
					 | 
				
			||||||
		this.particle = particle;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * return false to cancel hurt
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public boolean hurtEntity(Entity entity) {
 | 
					 | 
				
			||||||
		return mod.hurtEntity(entity);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,6 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.explosion;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.world.level.Level;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public record BaseExplosionContext(Level level, double x, double y, double z, float r) {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,37 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.explosion;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.network.protocol.game.ClientboundExplodePacket;
 | 
					 | 
				
			||||||
import net.minecraft.server.level.ServerPlayer;
 | 
					 | 
				
			||||||
import net.minecraft.world.entity.player.Player;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.Explosion;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.Level;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.event.EventHooks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class ExplosionHandler {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static void explode(BaseExplosion exp) {
 | 
					 | 
				
			||||||
		if (exp.base.level().isClientSide()) return;
 | 
					 | 
				
			||||||
		if (EventHooks.onExplosionStart(exp.base.level(), exp)) return;
 | 
					 | 
				
			||||||
		exp.explode();
 | 
					 | 
				
			||||||
		Level level = exp.base.level();
 | 
					 | 
				
			||||||
		exp.finalizeExplosion(level.isClientSide());
 | 
					 | 
				
			||||||
		double x = exp.base.x();
 | 
					 | 
				
			||||||
		double y = exp.base.y();
 | 
					 | 
				
			||||||
		double z = exp.base.z();
 | 
					 | 
				
			||||||
		float r = exp.base.r();
 | 
					 | 
				
			||||||
		boolean flag = exp.mc.type() == Explosion.BlockInteraction.KEEP;
 | 
					 | 
				
			||||||
		if (flag) {
 | 
					 | 
				
			||||||
			exp.clearToBlow();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		for (Player player : level.players()) {
 | 
					 | 
				
			||||||
			if (player instanceof ServerPlayer serverplayer) {
 | 
					 | 
				
			||||||
				if (serverplayer.distanceToSqr(x, y, z) < 4096.0D) {
 | 
					 | 
				
			||||||
					serverplayer.connection.send(new ClientboundExplodePacket(x, y, z, r,
 | 
					 | 
				
			||||||
							exp.getToBlow(), exp.getHitPlayers().get(serverplayer), exp.mc.type(),
 | 
					 | 
				
			||||||
							exp.particle.small(), exp.particle.large(), exp.particle.sound()));
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.explosion;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.world.entity.Entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public interface ModExplosionContext {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * return false to cancel damage
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	boolean hurtEntity(Entity entity);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,9 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.explosion;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.core.particles.ParticleOptions;
 | 
					 | 
				
			||||||
import net.minecraft.sounds.SoundEvent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public record ParticleExplosionContext(ParticleOptions small,
 | 
					 | 
				
			||||||
									   ParticleOptions large,
 | 
					 | 
				
			||||||
									   SoundEvent sound) {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.explosion;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.world.damagesource.DamageSource;
 | 
					 | 
				
			||||||
import net.minecraft.world.entity.Entity;
 | 
					 | 
				
			||||||
import net.minecraft.world.entity.LivingEntity;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.Explosion;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.ExplosionDamageCalculator;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.GameRules;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.Level;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.event.EventHooks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public record VanillaExplosionContext(@Nullable Entity entity, @Nullable DamageSource source,
 | 
					 | 
				
			||||||
									  @Nullable ExplosionDamageCalculator calculator,
 | 
					 | 
				
			||||||
									  boolean fire, Explosion.BlockInteraction type) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public VanillaExplosionContext(Level level, @Nullable Entity entity, @Nullable DamageSource source,
 | 
					 | 
				
			||||||
								   @Nullable ExplosionDamageCalculator calculator,
 | 
					 | 
				
			||||||
								   boolean fire, Level.ExplosionInteraction type) {
 | 
					 | 
				
			||||||
		this(entity, source, calculator, fire, getType(level, entity, type));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static Explosion.BlockInteraction getType(Level level, @Nullable Entity entity, Level.ExplosionInteraction type) {
 | 
					 | 
				
			||||||
		return switch (type) {
 | 
					 | 
				
			||||||
			case NONE -> Explosion.BlockInteraction.KEEP;
 | 
					 | 
				
			||||||
			case BLOCK -> level.getDestroyType(GameRules.RULE_BLOCK_EXPLOSION_DROP_DECAY);
 | 
					 | 
				
			||||||
			case MOB -> EventHooks.getMobGriefingEvent(level, entity instanceof LivingEntity le ? le : null) ?
 | 
					 | 
				
			||||||
					level.getDestroyType(GameRules.RULE_MOB_EXPLOSION_DROP_DECAY) :
 | 
					 | 
				
			||||||
					Explosion.BlockInteraction.KEEP;
 | 
					 | 
				
			||||||
			case TNT -> level.getDestroyType(GameRules.RULE_TNT_EXPLOSION_DROP_DECAY);
 | 
					 | 
				
			||||||
			case BLOW -> Explosion.BlockInteraction.TRIGGER_BLOCK;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
@MethodsReturnNonnullByDefault
 | 
					 | 
				
			||||||
@ParametersAreNonnullByDefault
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package dev.xkmc.l2core.base.explosion;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
					 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.menu.base;
 | 
					package dev.xkmc.l2core.base.menu.base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.xkmc.l2serial.serialization.SerialClass;
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialClass;
 | 
				
			||||||
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialField;
 | 
				
			||||||
import net.minecraft.client.gui.GuiGraphics;
 | 
					import net.minecraft.client.gui.GuiGraphics;
 | 
				
			||||||
import net.minecraft.client.gui.screens.Screen;
 | 
					import net.minecraft.client.gui.screens.Screen;
 | 
				
			||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
 | 
					import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
 | 
				
			||||||
@@ -17,7 +18,7 @@ import java.util.HashMap;
 | 
				
			|||||||
public record MenuLayoutConfig(int height, HashMap<String, Rect> side, HashMap<String, Rect> comp) {
 | 
					public record MenuLayoutConfig(int height, HashMap<String, Rect> side, HashMap<String, Rect> comp) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static ResourceLocation getTexture(ResourceLocation id) {
 | 
						public static ResourceLocation getTexture(ResourceLocation id) {
 | 
				
			||||||
		return new ResourceLocation(id.getNamespace(), "textures/gui/container/" + id.getPath() + ".png");
 | 
							return ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "textures/gui/container/" + id.getPath() + ".png");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -109,7 +110,7 @@ public record MenuLayoutConfig(int height, HashMap<String, Rect> side, HashMap<S
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		public static final Rect ZERO = new Rect();
 | 
							public static final Rect ZERO = new Rect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		@SerialClass.SerialField
 | 
							@SerialField
 | 
				
			||||||
		public int x, y, w, h, rx = 1, ry = 1;
 | 
							public int x, y, w, h, rx = 1, ry = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Rect() {
 | 
							public Rect() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ import net.minecraft.resources.ResourceLocation;
 | 
				
			|||||||
public record SpriteManager(ResourceLocation id) {
 | 
					public record SpriteManager(ResourceLocation id) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public SpriteManager(String modid, String path) {
 | 
						public SpriteManager(String modid, String path) {
 | 
				
			||||||
		this(new ResourceLocation(modid, path));
 | 
							this(ResourceLocation.fromNamespaceAndPath(modid, path));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public MenuLayoutConfig get() {
 | 
						public MenuLayoutConfig get() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,40 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.overlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.init.L2LibraryConfig;
 | 
					 | 
				
			||||||
import net.minecraft.client.Minecraft;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.GuiGraphics;
 | 
					 | 
				
			||||||
import net.minecraft.network.chat.Component;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.client.gui.overlay.ExtendedGui;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.client.gui.overlay.IGuiOverlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public abstract class InfoSideBar<S extends SideBar.Signature<S>> extends SideBar<S> implements IGuiOverlay {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public InfoSideBar(float duration, float ease) {
 | 
					 | 
				
			||||||
		super(duration, ease);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void render(ExtendedGui gui, GuiGraphics g, float partialTick, int width, int height) {
 | 
					 | 
				
			||||||
		if (!ease(gui.getGuiTicks() + partialTick))
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		var text = getText();
 | 
					 | 
				
			||||||
		if (text.isEmpty()) return;
 | 
					 | 
				
			||||||
		int anchor = L2LibraryConfig.CLIENT.infoAnchor.get();
 | 
					 | 
				
			||||||
		int y = height * anchor / 2;
 | 
					 | 
				
			||||||
		int w = (int) (width * L2LibraryConfig.CLIENT.infoMaxWidth.get());
 | 
					 | 
				
			||||||
		new TextBox(g, 0, anchor, getXOffset(width), y, w)
 | 
					 | 
				
			||||||
				.renderLongText(Minecraft.getInstance().font, text);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected abstract List<Component> getText();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	protected int getXOffset(int width) {
 | 
					 | 
				
			||||||
		float progress = (max_ease - ease_time) / max_ease;
 | 
					 | 
				
			||||||
		return Math.round(-progress * width / 2 + 8);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1,46 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.overlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.client.Minecraft;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.GuiGraphics;
 | 
					 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public abstract class ItemSelSideBar<S extends SideBar.Signature<S>> extends SelectionSideBar<ItemStack, S> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ItemSelSideBar(float duration, float ease) {
 | 
					 | 
				
			||||||
		super(duration, ease);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	protected void renderEntry(Context ctx, ItemStack stack, int i, int selected) {
 | 
					 | 
				
			||||||
		boolean shift = Minecraft.getInstance().options.keyShift.isDown();
 | 
					 | 
				
			||||||
		int y = 18 * i + ctx.y0();
 | 
					 | 
				
			||||||
		renderSelection(ctx.g(), ctx.x0(), y, shift ? 127 : 64, isAvailable(stack), selected == i);
 | 
					 | 
				
			||||||
		if (selected == i) {
 | 
					 | 
				
			||||||
			if (!stack.isEmpty() && ease_time == max_ease) {
 | 
					 | 
				
			||||||
				boolean onCenter = onCenter();
 | 
					 | 
				
			||||||
				ctx.g().renderTooltip(ctx.font(), stack.getHoverName(), 0, 0);
 | 
					 | 
				
			||||||
				TextBox box = new TextBox(ctx.g(), onCenter ? 0 : 2, 1, ctx.x0() + (onCenter ? 22 : -6), y + 8, -1);
 | 
					 | 
				
			||||||
				box.renderLongText(ctx.font(), List.of(stack.getHoverName()));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ctx.renderItem(stack, ctx.x0(), y);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void renderSelection(GuiGraphics g, int x, int y, int a, boolean available, boolean selected) {
 | 
					 | 
				
			||||||
		if (available) {
 | 
					 | 
				
			||||||
			OverlayUtil.fillRect(g, x, y, 16, 16, color(255, 255, 255, a));
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			OverlayUtil.fillRect(g, x, y, 16, 16, color(255, 0, 0, a));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (selected) {
 | 
					 | 
				
			||||||
			OverlayUtil.drawRect(g, x, y, 16, 16, color(255, 170, 0, 255));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static int color(int r, int g, int b, int a) {
 | 
					 | 
				
			||||||
		return a << 24 | r << 16 | g << 8 | b;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,43 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.overlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.GuiGraphics;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public record L2TooltipRenderUtil(GuiGraphics fill, int bg, int bs, int be) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void renderTooltipBackground(int x, int y, int w, int h, int z) {
 | 
					 | 
				
			||||||
		int x1 = x - 3;
 | 
					 | 
				
			||||||
		int y1 = y - 3;
 | 
					 | 
				
			||||||
		int w1 = w + 3 + 3;
 | 
					 | 
				
			||||||
		int h1 = h + 3 + 3;
 | 
					 | 
				
			||||||
		renderHorizontalLine(x1, y1 - 1, w1, z, bg);
 | 
					 | 
				
			||||||
		renderHorizontalLine(x1, y1 + h1, w1, z, bg);
 | 
					 | 
				
			||||||
		renderRectangle(x1, y1, w1, h1, z, bg);
 | 
					 | 
				
			||||||
		renderVerticalLine(x1 - 1, y1, h1, z, bg);
 | 
					 | 
				
			||||||
		renderVerticalLine(x1 + w1, y1, h1, z, bg);
 | 
					 | 
				
			||||||
		renderFrameGradient(x1, y1 + 1, w1, h1, z, bs, be);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private void renderFrameGradient(int x, int y, int w, int h, int z, int c0, int c1) {
 | 
					 | 
				
			||||||
		renderVerticalLineGradient(x, y, h - 2, z, c0, c1);
 | 
					 | 
				
			||||||
		renderVerticalLineGradient(x + w - 1, y, h - 2, z, c0, c1);
 | 
					 | 
				
			||||||
		renderHorizontalLine(x, y - 1, w, z, c0);
 | 
					 | 
				
			||||||
		renderHorizontalLine(x, y - 1 + h - 1, w, z, c1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private void renderVerticalLine(int x, int y, int h, int z, int c) {
 | 
					 | 
				
			||||||
		fill.fillGradient(x, y, x + 1, y + h, z, c, c);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private void renderVerticalLineGradient(int x, int y, int h, int z, int c0, int c1) {
 | 
					 | 
				
			||||||
		fill.fillGradient(x, y, x + 1, y + h, z, c0, c1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private void renderHorizontalLine(int x, int y, int w, int z, int c) {
 | 
					 | 
				
			||||||
		fill.fillGradient(x, y, x + w, y + 1, z, c, c);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private void renderRectangle(int x, int y, int w, int h, int z, int c) {
 | 
					 | 
				
			||||||
		fill.fillGradient(x, y, x + w, y + h, z, c, c);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,105 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.overlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.init.L2LibraryConfig;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.Font;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.GuiGraphics;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipPositioner;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.screens.inventory.tooltip.TooltipRenderUtil;
 | 
					 | 
				
			||||||
import net.minecraft.network.chat.Component;
 | 
					 | 
				
			||||||
import org.joml.Vector2i;
 | 
					 | 
				
			||||||
import org.joml.Vector2ic;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class OverlayUtil implements ClientTooltipPositioner {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static int getBGColor() {
 | 
					 | 
				
			||||||
		return (int) (Math.round(L2LibraryConfig.CLIENT.infoAlpha.get() * 255)) << 24 | 0x100010;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public int bg = getBGColor();
 | 
					 | 
				
			||||||
	public int bs = 0x505000FF;
 | 
					 | 
				
			||||||
	public int be = 0x5028007f;
 | 
					 | 
				
			||||||
	public int tc = 0xFFFFFFFF;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected final GuiGraphics g;
 | 
					 | 
				
			||||||
	protected final int x0, y0, maxW;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public OverlayUtil(GuiGraphics g, int x0, int y0, int maxW) {
 | 
					 | 
				
			||||||
		this.g = g;
 | 
					 | 
				
			||||||
		this.x0 = x0;
 | 
					 | 
				
			||||||
		this.y0 = y0;
 | 
					 | 
				
			||||||
		this.maxW = maxW < 0 ? getMaxWidth() : maxW;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public int getMaxWidth() {
 | 
					 | 
				
			||||||
		return g.guiWidth() / 4;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void renderLongText(Font font, List<Component> list) {
 | 
					 | 
				
			||||||
		List<ClientTooltipComponent> ans = list.stream().flatMap(text -> font.split(text, maxW).stream())
 | 
					 | 
				
			||||||
				.map(ClientTooltipComponent::create).toList();
 | 
					 | 
				
			||||||
		renderTooltipInternal(font, ans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void renderTooltipInternal(Font font, List<ClientTooltipComponent> list) {
 | 
					 | 
				
			||||||
		if (list.isEmpty()) return;
 | 
					 | 
				
			||||||
		int w = 0;
 | 
					 | 
				
			||||||
		int h = list.size() == 1 ? -2 : 0;
 | 
					 | 
				
			||||||
		for (ClientTooltipComponent c : list) {
 | 
					 | 
				
			||||||
			int wi = c.getWidth(font);
 | 
					 | 
				
			||||||
			if (wi > w) {
 | 
					 | 
				
			||||||
				w = wi;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			h += c.getHeight();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		int wf = w;
 | 
					 | 
				
			||||||
		int hf = h;
 | 
					 | 
				
			||||||
		Vector2ic pos = positionTooltip(g.guiWidth(), g.guiHeight(), x0, y0, wf, hf);
 | 
					 | 
				
			||||||
		int xf = pos.x();
 | 
					 | 
				
			||||||
		int yf = pos.y();
 | 
					 | 
				
			||||||
		g.pose().pushPose();
 | 
					 | 
				
			||||||
		int z = 400;
 | 
					 | 
				
			||||||
		g.drawManaged(() -> TooltipRenderUtil.renderTooltipBackground(g, xf, yf, wf, hf, z, bg, bg, bs, be));
 | 
					 | 
				
			||||||
		g.pose().translate(0.0F, 0.0F, z);
 | 
					 | 
				
			||||||
		int yi = yf;
 | 
					 | 
				
			||||||
		for (int i = 0; i < list.size(); ++i) {
 | 
					 | 
				
			||||||
			ClientTooltipComponent c = list.get(i);
 | 
					 | 
				
			||||||
			c.renderText(font, xf, yi, g.pose().last().pose(), g.bufferSource());
 | 
					 | 
				
			||||||
			yi += c.getHeight() + (i == 0 ? 2 : 0);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		yi = yf;
 | 
					 | 
				
			||||||
		for (int i = 0; i < list.size(); ++i) {
 | 
					 | 
				
			||||||
			ClientTooltipComponent c = list.get(i);
 | 
					 | 
				
			||||||
			c.renderImage(font, xf, yi, g);
 | 
					 | 
				
			||||||
			yi += c.getHeight() + (i == 0 ? 2 : 0);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		g.pose().popPose();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public Vector2ic positionTooltip(int gw, int gh, int x, int y, int tw, int th) {
 | 
					 | 
				
			||||||
		if (x < 0) x = Math.round(gw / 8f);
 | 
					 | 
				
			||||||
		if (y < 0) y = Math.round((gh - th) / 2f);
 | 
					 | 
				
			||||||
		return new Vector2i(x, y);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * specifies outer size
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public static void fillRect(GuiGraphics g, int x, int y, int w, int h, int col) {
 | 
					 | 
				
			||||||
		g.fill(x, y, x + w, y + h, col);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * specifies inner size
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public static void drawRect(GuiGraphics g, int x, int y, int w, int h, int col) {
 | 
					 | 
				
			||||||
		fillRect(g, x - 1, y - 1, w + 2, 1, col);
 | 
					 | 
				
			||||||
		fillRect(g, x - 1, y - 1, 1, h + 2, col);
 | 
					 | 
				
			||||||
		fillRect(g, x - 1, y + h, w + 2, 1, col);
 | 
					 | 
				
			||||||
		fillRect(g, x + w, y - 1, 1, h + 2, col);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,61 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.overlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.mojang.datafixers.util.Pair;
 | 
					 | 
				
			||||||
import net.minecraft.client.Minecraft;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.Font;
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.GuiGraphics;
 | 
					 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.client.gui.overlay.ExtendedGui;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.client.gui.overlay.IGuiOverlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public abstract class SelectionSideBar<T, S extends SideBar.Signature<S>> extends SideBar<S> implements IGuiOverlay {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public SelectionSideBar(float duration, float ease) {
 | 
					 | 
				
			||||||
		super(duration, ease);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public abstract Pair<List<T>, Integer> getItems();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public abstract boolean isAvailable(T t);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public abstract boolean onCenter();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void initRender() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void render(ExtendedGui gui, GuiGraphics g, float partialTick, int width, int height) {
 | 
					 | 
				
			||||||
		if (!ease(gui.getGuiTicks() + partialTick))
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		initRender();
 | 
					 | 
				
			||||||
		gui.setupOverlayRenderState(true, false);
 | 
					 | 
				
			||||||
		int x0 = this.getXOffset(width);
 | 
					 | 
				
			||||||
		int y0 = this.getYOffset(height);
 | 
					 | 
				
			||||||
		Context ctx = new Context(gui, g, partialTick, Minecraft.getInstance().font, x0, y0);
 | 
					 | 
				
			||||||
		renderContent(ctx);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void renderContent(Context ctx) {
 | 
					 | 
				
			||||||
		Pair<List<T>, Integer> content = getItems();
 | 
					 | 
				
			||||||
		var list = content.getFirst();
 | 
					 | 
				
			||||||
		for (int i = 0; i < list.size(); i++) {
 | 
					 | 
				
			||||||
			renderEntry(ctx, list.get(i), i, content.getSecond());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected abstract void renderEntry(Context ctx, T t, int index, int select);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public record Context(ExtendedGui gui, GuiGraphics g, float pTick, Font font, int x0, int y0) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public void renderItem(ItemStack stack, int x, int y) {
 | 
					 | 
				
			||||||
			if (!stack.isEmpty()) {
 | 
					 | 
				
			||||||
				g.renderItem(stack, x, y);
 | 
					 | 
				
			||||||
				g.renderItemDecorations(font, stack, x, y);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,95 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.overlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.client.Minecraft;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public abstract class SideBar<S extends SideBar.Signature<S>> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public interface Signature<S extends Signature<S>> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		boolean shouldRefreshIdle(SideBar<?> sideBar, @Nullable S old);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public record IntSignature(int val) implements Signature<IntSignature> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		@Override
 | 
					 | 
				
			||||||
		public boolean shouldRefreshIdle(SideBar<?> sideBar, @Nullable SideBar.IntSignature old) {
 | 
					 | 
				
			||||||
			return old == null || val != old.val;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected final float max_time;
 | 
					 | 
				
			||||||
	protected final float max_ease;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Nullable
 | 
					 | 
				
			||||||
	protected S prev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected float idle = 0;
 | 
					 | 
				
			||||||
	protected float ease_time = 0;
 | 
					 | 
				
			||||||
	protected float prev_time = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public SideBar(float duration, float ease) {
 | 
					 | 
				
			||||||
		this.max_time = duration;
 | 
					 | 
				
			||||||
		this.max_ease = ease;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public abstract S getSignature();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public abstract boolean isScreenOn();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected boolean isOnHold() {
 | 
					 | 
				
			||||||
		return Minecraft.getInstance().options.keyShift.isDown();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected boolean ease(float current_time) {
 | 
					 | 
				
			||||||
		if (!isScreenOn()) {
 | 
					 | 
				
			||||||
			prev = null;
 | 
					 | 
				
			||||||
			idle = max_time;
 | 
					 | 
				
			||||||
			ease_time = 0;
 | 
					 | 
				
			||||||
			prev_time = -1;
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		float time_diff = prev_time < 0 ? 0 : (current_time - prev_time);
 | 
					 | 
				
			||||||
		prev_time = current_time;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		S signature = getSignature();
 | 
					 | 
				
			||||||
		if (signature.shouldRefreshIdle(this, prev) || isOnHold()) {
 | 
					 | 
				
			||||||
			idle = 0;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			idle += time_diff;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		prev = signature;
 | 
					 | 
				
			||||||
		if (idle < max_time) {
 | 
					 | 
				
			||||||
			if (ease_time < max_ease) {
 | 
					 | 
				
			||||||
				ease_time += time_diff;
 | 
					 | 
				
			||||||
				if (ease_time > max_ease) {
 | 
					 | 
				
			||||||
					ease_time = max_ease;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if (ease_time > 0) {
 | 
					 | 
				
			||||||
				ease_time -= time_diff;
 | 
					 | 
				
			||||||
				if (ease_time < 0) {
 | 
					 | 
				
			||||||
					ease_time = 0;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return ease_time > 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public boolean isRendering() {
 | 
					 | 
				
			||||||
		return isScreenOn() && ease_time > 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected int getXOffset(int width) {
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected int getYOffset(int height) {
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,30 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.overlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.client.gui.GuiGraphics;
 | 
					 | 
				
			||||||
import org.joml.Vector2i;
 | 
					 | 
				
			||||||
import org.joml.Vector2ic;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class TextBox extends OverlayUtil {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private final int anchorX, anchorY;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public TextBox(GuiGraphics g, int anchorX, int anchorY, int x, int y, int width) {
 | 
					 | 
				
			||||||
		super(g, x, y, width);
 | 
					 | 
				
			||||||
		this.anchorX = anchorX;
 | 
					 | 
				
			||||||
		this.anchorY = anchorY;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public Vector2ic positionTooltip(int gw, int gh, int x, int y, int tw, int th) {
 | 
					 | 
				
			||||||
		return new Vector2i(x - tw * anchorX / 2, y - th * anchorY / 2);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public int getMaxWidth() {
 | 
					 | 
				
			||||||
		if (anchorX == 0) return g.guiWidth() - x0 - 8;
 | 
					 | 
				
			||||||
		if (anchorX == 1) return Math.max(x0 / 2 - 4, g.guiWidth() - x0 / 2 - 4);
 | 
					 | 
				
			||||||
		if (anchorX == 2) return x0 - 8;
 | 
					 | 
				
			||||||
		return g.guiWidth();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
@MethodsReturnNonnullByDefault
 | 
					 | 
				
			||||||
@ParametersAreNonnullByDefault
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package dev.xkmc.l2core.base.overlay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
					 | 
				
			||||||
@@ -1,11 +1,12 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.tile;
 | 
					package dev.xkmc.l2core.base.tile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.xkmc.l2core.util.ServerOnly;
 | 
					import dev.xkmc.l2core.util.ServerOnly;
 | 
				
			||||||
import dev.xkmc.l2serial.serialization.SerialClass;
 | 
					 | 
				
			||||||
import dev.xkmc.l2serial.serialization.codec.TagCodec;
 | 
					import dev.xkmc.l2serial.serialization.codec.TagCodec;
 | 
				
			||||||
import dev.xkmc.l2serial.util.Wrappers;
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialClass;
 | 
				
			||||||
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialField;
 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					import net.minecraft.MethodsReturnNonnullByDefault;
 | 
				
			||||||
import net.minecraft.core.BlockPos;
 | 
					import net.minecraft.core.BlockPos;
 | 
				
			||||||
 | 
					import net.minecraft.core.HolderLookup;
 | 
				
			||||||
import net.minecraft.nbt.CompoundTag;
 | 
					import net.minecraft.nbt.CompoundTag;
 | 
				
			||||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
 | 
					import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
 | 
				
			||||||
import net.minecraft.world.level.block.entity.BlockEntity;
 | 
					import net.minecraft.world.level.block.entity.BlockEntity;
 | 
				
			||||||
@@ -24,16 +25,16 @@ public class BaseBlockEntity extends BlockEntity {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public void load(CompoundTag tag) {
 | 
						public void loadAdditional(CompoundTag tag, HolderLookup.Provider pvd) {
 | 
				
			||||||
		super.load(tag);
 | 
							super.loadAdditional(tag, pvd);
 | 
				
			||||||
		if (tag.contains("auto-serial"))
 | 
							if (tag.contains("auto-serial"))
 | 
				
			||||||
			Wrappers.run(() -> TagCodec.fromTag(tag.getCompound("auto-serial"), getClass(), this, f -> true));
 | 
								new TagCodec(pvd).fromTag(tag.getCompound("auto-serial"), getClass(), this);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public void saveAdditional(CompoundTag tag) {
 | 
						public void saveAdditional(CompoundTag tag, HolderLookup.Provider pvd) {
 | 
				
			||||||
		super.saveAdditional(tag);
 | 
							super.saveAdditional(tag, pvd);
 | 
				
			||||||
		CompoundTag ser = Wrappers.get(() -> TagCodec.toTag(new CompoundTag(), getClass(), this, f -> true));
 | 
							CompoundTag ser = new TagCodec(pvd).toTag(new CompoundTag(), getClass(), this);
 | 
				
			||||||
		if (ser != null) tag.put("auto-serial", ser);
 | 
							if (ser != null) tag.put("auto-serial", ser);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,9 +54,10 @@ public class BaseBlockEntity extends BlockEntity {
 | 
				
			|||||||
	 * Generate data packet from server to client, called from getUpdatePacket()
 | 
						 * Generate data packet from server to client, called from getUpdatePacket()
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public CompoundTag getUpdateTag() {
 | 
						public CompoundTag getUpdateTag(HolderLookup.Provider pvd) {
 | 
				
			||||||
		CompoundTag ans = super.getUpdateTag();
 | 
							CompoundTag ans = super.getUpdateTag(pvd);
 | 
				
			||||||
		CompoundTag ser = Wrappers.get(() -> TagCodec.toTag(new CompoundTag(), getClass(), this, SerialClass.SerialField::toClient));
 | 
							CompoundTag ser = new TagCodec(pvd).pred(SerialField::toClient)
 | 
				
			||||||
 | 
									.toTag(new CompoundTag(), getClass(), this);
 | 
				
			||||||
		if (ser != null) ans.put("auto-serial", ser);
 | 
							if (ser != null) ans.put("auto-serial", ser);
 | 
				
			||||||
		return ans;
 | 
							return ans;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ public class BaseContainer<T extends BaseContainer<T>> extends SimpleContainer i
 | 
				
			|||||||
		for (ItemStack stack : items) {
 | 
							for (ItemStack stack : items) {
 | 
				
			||||||
			if (stack.isEmpty())
 | 
								if (stack.isEmpty())
 | 
				
			||||||
				ans++;
 | 
									ans++;
 | 
				
			||||||
			else if (ItemStack.isSameItemSameTags(stack, add) &&
 | 
								else if (ItemStack.isSameItemSameComponents(stack, add) &&
 | 
				
			||||||
					stack.getCount() + add.getCount() <=
 | 
										stack.getCount() + add.getCount() <=
 | 
				
			||||||
							Math.min(stack.getMaxStackSize(), getMaxStackSize())) {
 | 
												Math.min(stack.getMaxStackSize(), getMaxStackSize())) {
 | 
				
			||||||
				return true;
 | 
									return true;
 | 
				
			||||||
@@ -61,7 +61,7 @@ public class BaseContainer<T extends BaseContainer<T>> extends SimpleContainer i
 | 
				
			|||||||
	public boolean canRecipeAddItem(ItemStack stack) {
 | 
						public boolean canRecipeAddItem(ItemStack stack) {
 | 
				
			||||||
		stack = stack.copy();
 | 
							stack = stack.copy();
 | 
				
			||||||
		for (ItemStack slot : this.items) {
 | 
							for (ItemStack slot : this.items) {
 | 
				
			||||||
			if (slot.isEmpty() || ItemStack.isSameItemSameTags(slot, stack)) {
 | 
								if (slot.isEmpty() || ItemStack.isSameItemSameComponents(slot, stack)) {
 | 
				
			||||||
				int cap = Math.min(getMaxStackSize(), slot.getMaxStackSize());
 | 
									int cap = Math.min(getMaxStackSize(), slot.getMaxStackSize());
 | 
				
			||||||
				int amount = Math.min(stack.getCount(), cap - slot.getCount());
 | 
									int amount = Math.min(stack.getCount(), cap - slot.getCount());
 | 
				
			||||||
				if (amount > 0) {
 | 
									if (amount > 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
package dev.xkmc.l2core.base.tile;
 | 
					package dev.xkmc.l2core.base.tile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.xkmc.l2serial.serialization.SerialClass;
 | 
					 | 
				
			||||||
import dev.xkmc.l2serial.serialization.codec.AliasCollection;
 | 
					import dev.xkmc.l2serial.serialization.codec.AliasCollection;
 | 
				
			||||||
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialClass;
 | 
				
			||||||
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialField;
 | 
				
			||||||
import net.minecraft.core.NonNullList;
 | 
					import net.minecraft.core.NonNullList;
 | 
				
			||||||
import net.neoforged.neoforge.fluids.FluidStack;
 | 
					import net.neoforged.neoforge.fluids.FluidStack;
 | 
				
			||||||
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
 | 
					import net.neoforged.neoforge.fluids.capability.IFluidHandler;
 | 
				
			||||||
@@ -21,7 +22,7 @@ public class BaseTank implements IFluidHandler, AliasCollection<FluidStack> {
 | 
				
			|||||||
	private Predicate<FluidStack> predicate = e -> true;
 | 
						private Predicate<FluidStack> predicate = e -> true;
 | 
				
			||||||
	private BooleanSupplier allowExtract = () -> true;
 | 
						private BooleanSupplier allowExtract = () -> true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@SerialClass.SerialField
 | 
						@SerialField
 | 
				
			||||||
	public NonNullList<FluidStack> list;
 | 
						public NonNullList<FluidStack> list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private int click_max;
 | 
						private int click_max;
 | 
				
			||||||
@@ -82,7 +83,7 @@ public class BaseTank implements IFluidHandler, AliasCollection<FluidStack> {
 | 
				
			|||||||
		int filled = 0;
 | 
							int filled = 0;
 | 
				
			||||||
		for (int i = 0; i < size; i++) {
 | 
							for (int i = 0; i < size; i++) {
 | 
				
			||||||
			FluidStack stack = list.get(i);
 | 
								FluidStack stack = list.get(i);
 | 
				
			||||||
			if (stack.isFluidEqual(resource)) {
 | 
								if (FluidStack.isSameFluidSameComponents(stack, resource)) {
 | 
				
			||||||
				int remain = capacity - stack.getAmount();
 | 
									int remain = capacity - stack.getAmount();
 | 
				
			||||||
				int fill = Math.min(to_fill, remain);
 | 
									int fill = Math.min(to_fill, remain);
 | 
				
			||||||
				filled += fill;
 | 
									filled += fill;
 | 
				
			||||||
@@ -123,7 +124,7 @@ public class BaseTank implements IFluidHandler, AliasCollection<FluidStack> {
 | 
				
			|||||||
		int drained = 0;
 | 
							int drained = 0;
 | 
				
			||||||
		for (int i = 0; i < size; i++) {
 | 
							for (int i = 0; i < size; i++) {
 | 
				
			||||||
			FluidStack stack = list.get(i);
 | 
								FluidStack stack = list.get(i);
 | 
				
			||||||
			if (stack.isFluidEqual(resource)) {
 | 
								if (FluidStack.isSameFluidSameComponents(stack, resource)) {
 | 
				
			||||||
				int remain = stack.getAmount();
 | 
									int remain = stack.getAmount();
 | 
				
			||||||
				int drain = Math.min(to_drain, remain);
 | 
									int drain = Math.min(to_drain, remain);
 | 
				
			||||||
				drained += drain;
 | 
									drained += drain;
 | 
				
			||||||
@@ -155,7 +156,7 @@ public class BaseTank implements IFluidHandler, AliasCollection<FluidStack> {
 | 
				
			|||||||
		int drained = 0;
 | 
							int drained = 0;
 | 
				
			||||||
		for (int i = 0; i < size; i++) {
 | 
							for (int i = 0; i < size; i++) {
 | 
				
			||||||
			FluidStack stack = list.get(i);
 | 
								FluidStack stack = list.get(i);
 | 
				
			||||||
			if (!stack.isEmpty() && (ans == null || stack.isFluidEqual(ans))) {
 | 
								if (!stack.isEmpty() && (ans == null || FluidStack.isSameFluidSameComponents(stack, ans))) {
 | 
				
			||||||
				int remain = stack.getAmount();
 | 
									int remain = stack.getAmount();
 | 
				
			||||||
				int drain = Math.min(to_drain, remain);
 | 
									int drain = Math.min(to_drain, remain);
 | 
				
			||||||
				drained += drain;
 | 
									drained += drain;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ package dev.xkmc.l2core.base.tile;
 | 
				
			|||||||
import com.mojang.datafixers.util.Pair;
 | 
					import com.mojang.datafixers.util.Pair;
 | 
				
			||||||
import net.neoforged.neoforge.fluids.FluidStack;
 | 
					import net.neoforged.neoforge.fluids.FluidStack;
 | 
				
			||||||
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
 | 
					import net.neoforged.neoforge.fluids.capability.IFluidHandler;
 | 
				
			||||||
import net.neoforged.neoforge.items.wrapper.EmptyHandler;
 | 
					import net.neoforged.neoforge.fluids.capability.templates.EmptyFluidHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
@@ -85,36 +85,31 @@ public class CombinedTankWrapper implements IFluidHandler {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public int fill(FluidStack resource, FluidAction action) {
 | 
						public int fill(FluidStack input, FluidAction action) {
 | 
				
			||||||
		if (resource.isEmpty())
 | 
							if (input.isEmpty())
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int filled = 0;
 | 
							int ans = 0;
 | 
				
			||||||
		resource = resource.copy();
 | 
							input = input.copy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							boolean found = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		boolean fittingHandlerFound = false;
 | 
					 | 
				
			||||||
		Outer:
 | 
					 | 
				
			||||||
		for (boolean searchPass : new boolean[]{true, false}) {
 | 
							for (boolean searchPass : new boolean[]{true, false}) {
 | 
				
			||||||
			for (IFluidHandler iFluidHandler : fillable()) {
 | 
								for (IFluidHandler handler : fillable()) {
 | 
				
			||||||
 | 
									for (int i = 0; i < handler.getTanks(); i++)
 | 
				
			||||||
				for (int i = 0; i < iFluidHandler.getTanks(); i++)
 | 
										if (searchPass && FluidStack.isSameFluidSameComponents(handler.getFluidInTank(i), input))
 | 
				
			||||||
					if (searchPass && iFluidHandler.getFluidInTank(i)
 | 
											found = true;
 | 
				
			||||||
							.isFluidEqual(resource))
 | 
									if (searchPass && !found)
 | 
				
			||||||
						fittingHandlerFound = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (searchPass && !fittingHandlerFound)
 | 
					 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
 | 
									int filler = handler.fill(input, action);
 | 
				
			||||||
				int filledIntoCurrent = iFluidHandler.fill(resource, action);
 | 
									input.shrink(filler);
 | 
				
			||||||
				resource.shrink(filledIntoCurrent);
 | 
									ans += filler;
 | 
				
			||||||
				filled += filledIntoCurrent;
 | 
									if (input.isEmpty() || found || enforceVariety && filler != 0)
 | 
				
			||||||
 | 
										return ans;
 | 
				
			||||||
				if (resource.isEmpty() || fittingHandlerFound || enforceVariety && filledIntoCurrent != 0)
 | 
					 | 
				
			||||||
					break Outer;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return filled;
 | 
							return ans;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
@@ -122,41 +117,41 @@ public class CombinedTankWrapper implements IFluidHandler {
 | 
				
			|||||||
		if (resource.isEmpty())
 | 
							if (resource.isEmpty())
 | 
				
			||||||
			return resource;
 | 
								return resource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		FluidStack drained = FluidStack.EMPTY;
 | 
							FluidStack ans = FluidStack.EMPTY;
 | 
				
			||||||
		resource = resource.copy();
 | 
							resource = resource.copy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (IFluidHandler iFluidHandler : drainable()) {
 | 
							for (IFluidHandler handler : drainable()) {
 | 
				
			||||||
			FluidStack drainedFromCurrent = iFluidHandler.drain(resource, action);
 | 
								FluidStack drained = handler.drain(resource, action);
 | 
				
			||||||
			int amount = drainedFromCurrent.getAmount();
 | 
								int amount = drained.getAmount();
 | 
				
			||||||
			resource.shrink(amount);
 | 
								resource.shrink(amount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!drainedFromCurrent.isEmpty() && (drained.isEmpty() || drainedFromCurrent.isFluidEqual(drained)))
 | 
								if (!drained.isEmpty() && (ans.isEmpty() || FluidStack.isSameFluidSameComponents(drained, ans)))
 | 
				
			||||||
				drained = new FluidStack(drainedFromCurrent.getFluid(), amount + drained.getAmount(),
 | 
									ans = new FluidStack(drained.getFluidHolder(), amount + ans.getAmount(),
 | 
				
			||||||
						drainedFromCurrent.getTag());
 | 
											drained.getComponentsPatch());
 | 
				
			||||||
			if (resource.isEmpty())
 | 
								if (resource.isEmpty())
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return drained;
 | 
							return ans;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public FluidStack drain(int maxDrain, FluidAction action) {
 | 
						public FluidStack drain(int maxDrain, FluidAction action) {
 | 
				
			||||||
		FluidStack drained = FluidStack.EMPTY;
 | 
							FluidStack ans = FluidStack.EMPTY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (IFluidHandler iFluidHandler : drainable()) {
 | 
							for (IFluidHandler iFluidHandler : drainable()) {
 | 
				
			||||||
			FluidStack drainedFromCurrent = iFluidHandler.drain(maxDrain, action);
 | 
								FluidStack drained = iFluidHandler.drain(maxDrain, action);
 | 
				
			||||||
			int amount = drainedFromCurrent.getAmount();
 | 
								int amount = drained.getAmount();
 | 
				
			||||||
			maxDrain -= amount;
 | 
								maxDrain -= amount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!drainedFromCurrent.isEmpty() && (drained.isEmpty() || drainedFromCurrent.isFluidEqual(drained)))
 | 
								if (!drained.isEmpty() && (ans.isEmpty() || FluidStack.isSameFluidSameComponents(drained, ans)))
 | 
				
			||||||
				drained = new FluidStack(drainedFromCurrent.getFluid(), amount + drained.getAmount(),
 | 
									ans = new FluidStack(drained.getFluidHolder(), amount + ans.getAmount(),
 | 
				
			||||||
						drainedFromCurrent.getTag());
 | 
											drained.getComponentsPatch());
 | 
				
			||||||
			if (maxDrain == 0)
 | 
								if (maxDrain == 0)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return drained;
 | 
							return ans;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected int getIndexForSlot(int slot) {
 | 
						protected int getIndexForSlot(int slot) {
 | 
				
			||||||
@@ -170,7 +165,7 @@ public class CombinedTankWrapper implements IFluidHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	protected IFluidHandler getHandlerFromIndex(int index) {
 | 
						protected IFluidHandler getHandlerFromIndex(int index) {
 | 
				
			||||||
		if (index < 0 || index >= list.size())
 | 
							if (index < 0 || index >= list.size())
 | 
				
			||||||
			return (IFluidHandler) EmptyHandler.INSTANCE;
 | 
								return EmptyFluidHandler.INSTANCE;
 | 
				
			||||||
		return list.get(index).getFirst();
 | 
							return list.get(index).getFirst();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					package dev.xkmc.l2core.capability.conditionals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.xkmc.l2core.capability.player.PlayerCapabilityTemplate;
 | 
				
			||||||
 | 
					import dev.xkmc.l2core.init.L2LibReg;
 | 
				
			||||||
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialClass;
 | 
				
			||||||
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialField;
 | 
				
			||||||
 | 
					import net.minecraft.server.level.ServerPlayer;
 | 
				
			||||||
 | 
					import net.minecraft.world.entity.LivingEntity;
 | 
				
			||||||
 | 
					import net.minecraft.world.entity.player.Player;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.TreeSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@SerialClass
 | 
				
			||||||
 | 
					public class PlayerFlagData extends PlayerCapabilityTemplate<PlayerFlagData> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static void addFlag(LivingEntity entity, String str) {
 | 
				
			||||||
 | 
							if (entity instanceof Player player) {
 | 
				
			||||||
 | 
								L2LibReg.FLAGS.type().get(player).addFlag(str);
 | 
				
			||||||
 | 
								if (player instanceof ServerPlayer sp)
 | 
				
			||||||
 | 
									L2LibReg.FLAGS.type().network.toClient(sp);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								entity.addTag(str);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static boolean hasFlag(LivingEntity entity, String str) {
 | 
				
			||||||
 | 
							if (entity instanceof Player player) {
 | 
				
			||||||
 | 
								return L2LibReg.FLAGS.type().get(player).hasFlag(str);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return entity.getTags().contains(str);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@SerialField
 | 
				
			||||||
 | 
						private final TreeSet<String> flags = new TreeSet<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void addFlag(String str) {
 | 
				
			||||||
 | 
							flags.add(str);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public boolean hasFlag(String flag) {
 | 
				
			||||||
 | 
							return flags.contains(flag);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static void register() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -9,7 +9,7 @@ public record TokenKey<T extends ConditionalToken>(String type, String id) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public ResourceLocation asLocation() {
 | 
						public ResourceLocation asLocation() {
 | 
				
			||||||
		return new ResourceLocation(type, id);
 | 
							return ResourceLocation.fromNamespaceAndPath(type, id);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
package dev.xkmc.l2core.capability.level;
 | 
					package dev.xkmc.l2core.capability.level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.xkmc.l2serial.serialization.SerialClass;
 | 
					 | 
				
			||||||
import dev.xkmc.l2serial.serialization.codec.TagCodec;
 | 
					import dev.xkmc.l2serial.serialization.codec.TagCodec;
 | 
				
			||||||
 | 
					import dev.xkmc.l2serial.serialization.marker.SerialClass;
 | 
				
			||||||
 | 
					import net.minecraft.core.HolderLookup;
 | 
				
			||||||
import net.minecraft.nbt.CompoundTag;
 | 
					import net.minecraft.nbt.CompoundTag;
 | 
				
			||||||
import net.minecraft.world.level.saveddata.SavedData;
 | 
					import net.minecraft.world.level.saveddata.SavedData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9,8 +10,8 @@ import net.minecraft.world.level.saveddata.SavedData;
 | 
				
			|||||||
public class BaseSavedData extends SavedData {
 | 
					public class BaseSavedData extends SavedData {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public CompoundTag save(CompoundTag tag) {
 | 
						public CompoundTag save(CompoundTag tag, HolderLookup.Provider provider) {
 | 
				
			||||||
		TagCodec.toTag(tag, this);
 | 
							new TagCodec(provider).toTag(tag, this);
 | 
				
			||||||
		return tag;
 | 
							return tag;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,5 +21,4 @@ public class BaseSavedData extends SavedData {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.compat.curios;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.resources.ResourceLocation;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public record CurioEntityBuilder(
 | 
					 | 
				
			||||||
		ArrayList<ResourceLocation> entities,
 | 
					 | 
				
			||||||
		ArrayList<String> slots,
 | 
					 | 
				
			||||||
		ArrayList<SlotCondition> conditions) {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,28 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.compat.curios;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import static dev.xkmc.l2core.compat.curios.CurioSlotBuilder.Operation.SET;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public record CurioSlotBuilder(int order, String icon, int size,
 | 
					 | 
				
			||||||
							   Operation operation,
 | 
					 | 
				
			||||||
							   boolean add_cosmetic,
 | 
					 | 
				
			||||||
							   boolean use_native_gui,
 | 
					 | 
				
			||||||
							   boolean render_toggle,
 | 
					 | 
				
			||||||
							   boolean replace, ArrayList<SlotCondition> conditions) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public CurioSlotBuilder(int order, String icon) {
 | 
					 | 
				
			||||||
		this(order, icon, 1, SET);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public CurioSlotBuilder(int order, String icon, int size,
 | 
					 | 
				
			||||||
							Operation operation) {
 | 
					 | 
				
			||||||
		this(order, icon, size, operation,
 | 
					 | 
				
			||||||
				false, true, true, false, SlotCondition.of());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public enum Operation {
 | 
					 | 
				
			||||||
		SET, ADD, REMOVE
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,19 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.compat.curios;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public record SlotCondition(String type, String modid) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static ArrayList<SlotCondition> of(String... ids) {
 | 
					 | 
				
			||||||
		ArrayList<SlotCondition> ans = new ArrayList<>();
 | 
					 | 
				
			||||||
		for (String id : ids) {
 | 
					 | 
				
			||||||
			ans.add(new SlotCondition(id));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return ans;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public SlotCondition(String modid) {
 | 
					 | 
				
			||||||
		this("forge:mod_loaded", modid);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
@MethodsReturnNonnullByDefault
 | 
					 | 
				
			||||||
@ParametersAreNonnullByDefault
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package dev.xkmc.l2core.compat.curios;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
					 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package dev.xkmc.l2core.init.events;
 | 
					package dev.xkmc.l2core.events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.xkmc.l2core.capability.attachment.GeneralCapabilityHolder;
 | 
					import dev.xkmc.l2core.capability.attachment.GeneralCapabilityHolder;
 | 
				
			||||||
import dev.xkmc.l2core.capability.player.PlayerCapabilityHolder;
 | 
					import dev.xkmc.l2core.capability.player.PlayerCapabilityHolder;
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package dev.xkmc.l2core.init.events;
 | 
					package dev.xkmc.l2core.events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.gson.Gson;
 | 
					import com.google.gson.Gson;
 | 
				
			||||||
import com.google.gson.GsonBuilder;
 | 
					import com.google.gson.GsonBuilder;
 | 
				
			||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
package dev.xkmc.l2core.init.events;
 | 
					package dev.xkmc.l2core.events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.mojang.blaze3d.systems.RenderSystem;
 | 
					 | 
				
			||||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
 | 
					import com.mojang.blaze3d.vertex.DefaultVertexFormat;
 | 
				
			||||||
import com.mojang.blaze3d.vertex.PoseStack;
 | 
					import com.mojang.blaze3d.vertex.PoseStack;
 | 
				
			||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
 | 
					import com.mojang.blaze3d.vertex.VertexConsumer;
 | 
				
			||||||
@@ -26,18 +25,15 @@ import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
 | 
				
			|||||||
import net.minecraft.resources.ResourceLocation;
 | 
					import net.minecraft.resources.ResourceLocation;
 | 
				
			||||||
import net.minecraft.util.Mth;
 | 
					import net.minecraft.util.Mth;
 | 
				
			||||||
import net.minecraft.world.effect.MobEffect;
 | 
					import net.minecraft.world.effect.MobEffect;
 | 
				
			||||||
import net.minecraft.world.effect.MobEffectInstance;
 | 
					 | 
				
			||||||
import net.minecraft.world.entity.Entity;
 | 
					import net.minecraft.world.entity.Entity;
 | 
				
			||||||
import net.minecraft.world.entity.LivingEntity;
 | 
					import net.minecraft.world.entity.LivingEntity;
 | 
				
			||||||
import net.minecraft.world.phys.Vec3;
 | 
					import net.minecraft.world.phys.Vec3;
 | 
				
			||||||
import net.neoforged.api.distmarker.Dist;
 | 
					import net.neoforged.api.distmarker.Dist;
 | 
				
			||||||
import net.neoforged.bus.api.SubscribeEvent;
 | 
					import net.neoforged.bus.api.SubscribeEvent;
 | 
				
			||||||
import net.neoforged.fml.common.EventBusSubscriber;
 | 
					import net.neoforged.fml.common.EventBusSubscriber;
 | 
				
			||||||
import net.neoforged.fml.common.Mod;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.client.event.ClientTickEvent;
 | 
					import net.neoforged.neoforge.client.event.ClientTickEvent;
 | 
				
			||||||
import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
 | 
					import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
 | 
				
			||||||
import net.neoforged.neoforge.client.event.RenderLivingEvent;
 | 
					import net.neoforged.neoforge.client.event.RenderLivingEvent;
 | 
				
			||||||
import net.neoforged.neoforge.event.TickEvent;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
@@ -81,11 +77,11 @@ public class ClientEffectRenderEvents {
 | 
				
			|||||||
	public static void onLivingEntityRender(RenderLivingEvent.Post<?, ?> event) {
 | 
						public static void onLivingEntityRender(RenderLivingEvent.Post<?, ?> event) {
 | 
				
			||||||
		LivingEntity entity = event.getEntity();
 | 
							LivingEntity entity = event.getEntity();
 | 
				
			||||||
		if (!L2LibReg.EFFECT.type().isProper(entity)) return;
 | 
							if (!L2LibReg.EFFECT.type().isProper(entity)) return;
 | 
				
			||||||
		if (entity.getTags().contains("ClientOnly")) return;
 | 
							if (entity.getTags().contains("ClientOnly")) return;//TODO
 | 
				
			||||||
		ClientEffectCap cap = L2LibReg.EFFECT.type().get(entity);
 | 
							ClientEffectCap cap = L2LibReg.EFFECT.type().get(entity);
 | 
				
			||||||
		List<Pair<ClientRenderEffect, Integer>> l0 = new ArrayList<>();
 | 
							List<Pair<ClientRenderEffect, Integer>> l0 = new ArrayList<>();
 | 
				
			||||||
		for (Map.Entry<MobEffect, Integer> entry : cap.map.entrySet()) {
 | 
							for (var entry : cap.map.entrySet()) {
 | 
				
			||||||
			if (entry.getKey() instanceof ClientRenderEffect effect) {
 | 
								if (entry.getKey().value() instanceof ClientRenderEffect effect) {
 | 
				
			||||||
				l0.add(Pair.of(effect, entry.getValue()));
 | 
									l0.add(Pair.of(effect, entry.getValue()));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -103,7 +99,6 @@ public class ClientEffectRenderEvents {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
		int n = index;
 | 
							int n = index;
 | 
				
			||||||
		int w = (int) Math.ceil(Math.sqrt(n));
 | 
							int w = (int) Math.ceil(Math.sqrt(n));
 | 
				
			||||||
		int h = (int) Math.ceil(n * 1d / w);
 | 
							int h = (int) Math.ceil(n * 1d / w);
 | 
				
			||||||
@@ -155,10 +150,9 @@ public class ClientEffectRenderEvents {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static void iconVertex(PoseStack.Pose entry, VertexConsumer builder, float x, float y, float u, float v) {
 | 
						private static void iconVertex(PoseStack.Pose entry, VertexConsumer builder, float x, float y, float u, float v) {
 | 
				
			||||||
		builder.vertex(entry.pose(), x, y, 0)
 | 
							builder.addVertex(entry.pose(), x, y, 0)
 | 
				
			||||||
				.uv(u, v)
 | 
									.setUv(u, v)
 | 
				
			||||||
				.normal(entry.normal(), 0.0F, 1.0F, 0.0F)
 | 
									.setNormal(entry, 0.0F, 1.0F, 0.0F);
 | 
				
			||||||
				.endVertex();
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static RenderType get2DIcon(ResourceLocation rl) {
 | 
						public static RenderType get2DIcon(ResourceLocation rl) {
 | 
				
			||||||
@@ -188,5 +182,4 @@ public class ClientEffectRenderEvents {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,26 +1,30 @@
 | 
				
			|||||||
package dev.xkmc.l2core.init.events;
 | 
					package dev.xkmc.l2core.events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.xkmc.l2core.base.effects.EffectToClient;
 | 
					import dev.xkmc.l2core.base.effects.EffectToClient;
 | 
				
			||||||
import dev.xkmc.l2core.init.L2Core;
 | 
					import dev.xkmc.l2core.init.L2Core;
 | 
				
			||||||
 | 
					import net.minecraft.core.Holder;
 | 
				
			||||||
 | 
					import net.minecraft.core.registries.Registries;
 | 
				
			||||||
import net.minecraft.server.level.ServerPlayer;
 | 
					import net.minecraft.server.level.ServerPlayer;
 | 
				
			||||||
 | 
					import net.minecraft.tags.TagKey;
 | 
				
			||||||
import net.minecraft.world.effect.MobEffect;
 | 
					import net.minecraft.world.effect.MobEffect;
 | 
				
			||||||
import net.minecraft.world.entity.LivingEntity;
 | 
					import net.minecraft.world.entity.LivingEntity;
 | 
				
			||||||
import net.neoforged.bus.api.SubscribeEvent;
 | 
					import net.neoforged.bus.api.SubscribeEvent;
 | 
				
			||||||
import net.neoforged.fml.common.Mod;
 | 
					import net.neoforged.fml.common.EventBusSubscriber;
 | 
				
			||||||
import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
 | 
					import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
 | 
				
			||||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
 | 
					import net.neoforged.neoforge.event.entity.player.PlayerEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.HashSet;
 | 
					@EventBusSubscriber(modid = L2Core.MODID, bus = EventBusSubscriber.Bus.GAME)
 | 
				
			||||||
import java.util.Set;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Mod.EventBusSubscriber(modid = L2Core.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE)
 | 
					 | 
				
			||||||
public class EffectSyncEvents {
 | 
					public class EffectSyncEvents {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static final Set<MobEffect> TRACKED = new HashSet<>();
 | 
						public static final TagKey<MobEffect> SYNCED = TagKey.create(Registries.MOB_EFFECT, L2Core.loc("synced"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static boolean isTracked(Holder<MobEffect> eff) {
 | 
				
			||||||
 | 
							return eff.is(SYNCED);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@SubscribeEvent
 | 
						@SubscribeEvent
 | 
				
			||||||
	public static void onPotionAddedEvent(MobEffectEvent.Added event) {
 | 
						public static void onPotionAddedEvent(MobEffectEvent.Added event) {
 | 
				
			||||||
		if (TRACKED.contains(event.getEffectInstance().getEffect())) {
 | 
							if (isTracked(event.getEffectInstance().getEffect())) {
 | 
				
			||||||
			onEffectAppear(event.getEffectInstance().getEffect(), event.getEntity(), event.getEffectInstance().getAmplifier());
 | 
								onEffectAppear(event.getEffectInstance().getEffect(), event.getEntity(), event.getEffectInstance().getAmplifier());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -28,7 +32,7 @@ public class EffectSyncEvents {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	@SubscribeEvent
 | 
						@SubscribeEvent
 | 
				
			||||||
	public static void onPotionRemoveEvent(MobEffectEvent.Remove event) {
 | 
						public static void onPotionRemoveEvent(MobEffectEvent.Remove event) {
 | 
				
			||||||
		if (event.getEffectInstance() != null && TRACKED.contains(event.getEffectInstance().getEffect())) {
 | 
							if (event.getEffectInstance() != null && isTracked(event.getEffectInstance().getEffect())) {
 | 
				
			||||||
			onEffectDisappear(event.getEffectInstance().getEffect(), event.getEntity());
 | 
								onEffectDisappear(event.getEffectInstance().getEffect(), event.getEntity());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -36,17 +40,16 @@ public class EffectSyncEvents {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	@SubscribeEvent
 | 
						@SubscribeEvent
 | 
				
			||||||
	public static void onPotionExpiryEvent(MobEffectEvent.Expired event) {
 | 
						public static void onPotionExpiryEvent(MobEffectEvent.Expired event) {
 | 
				
			||||||
		if (event.getEffectInstance() != null && TRACKED.contains(event.getEffectInstance().getEffect())) {
 | 
							if (event.getEffectInstance() != null && isTracked(event.getEffectInstance().getEffect())) {
 | 
				
			||||||
			onEffectDisappear(event.getEffectInstance().getEffect(), event.getEntity());
 | 
								onEffectDisappear(event.getEffectInstance().getEffect(), event.getEntity());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@SubscribeEvent
 | 
						@SubscribeEvent
 | 
				
			||||||
	public static void onPlayerStartTracking(PlayerEvent.StartTracking event) {
 | 
						public static void onPlayerStartTracking(PlayerEvent.StartTracking event) {
 | 
				
			||||||
		if (!(event.getTarget() instanceof LivingEntity le))
 | 
							if (!(event.getTarget() instanceof LivingEntity le)) return;
 | 
				
			||||||
			return;
 | 
							for (var eff : le.getActiveEffectsMap().keySet()) {
 | 
				
			||||||
		for (MobEffect eff : le.getActiveEffectsMap().keySet()) {
 | 
								if (isTracked(eff)) {
 | 
				
			||||||
			if (TRACKED.contains(eff)) {
 | 
					 | 
				
			||||||
				onEffectAppear(eff, le, le.getActiveEffectsMap().get(eff).getAmplifier());
 | 
									onEffectAppear(eff, le, le.getActiveEffectsMap().get(eff).getAmplifier());
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -54,10 +57,9 @@ public class EffectSyncEvents {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	@SubscribeEvent
 | 
						@SubscribeEvent
 | 
				
			||||||
	public static void onPlayerStopTracking(PlayerEvent.StopTracking event) {
 | 
						public static void onPlayerStopTracking(PlayerEvent.StopTracking event) {
 | 
				
			||||||
		if (!(event.getTarget() instanceof LivingEntity le))
 | 
							if (!(event.getTarget() instanceof LivingEntity le)) return;
 | 
				
			||||||
			return;
 | 
							for (var eff : le.getActiveEffectsMap().keySet()) {
 | 
				
			||||||
		for (MobEffect eff : le.getActiveEffectsMap().keySet()) {
 | 
								if (isTracked(eff)) {
 | 
				
			||||||
			if (TRACKED.contains(eff)) {
 | 
					 | 
				
			||||||
				onEffectDisappear(eff, le);
 | 
									onEffectDisappear(eff, le);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -66,33 +68,31 @@ public class EffectSyncEvents {
 | 
				
			|||||||
	@SubscribeEvent
 | 
						@SubscribeEvent
 | 
				
			||||||
	public static void onServerPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
 | 
						public static void onServerPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
 | 
				
			||||||
		ServerPlayer e = (ServerPlayer) event.getEntity();
 | 
							ServerPlayer e = (ServerPlayer) event.getEntity();
 | 
				
			||||||
		if (e != null) {
 | 
							if (e == null) return;
 | 
				
			||||||
			for (MobEffect eff : e.getActiveEffectsMap().keySet()) {
 | 
							for (var eff : e.getActiveEffectsMap().keySet()) {
 | 
				
			||||||
				if (TRACKED.contains(eff)) {
 | 
								if (isTracked(eff)) {
 | 
				
			||||||
				onEffectAppear(eff, e, e.getActiveEffectsMap().get(eff).getAmplifier());
 | 
									onEffectAppear(eff, e, e.getActiveEffectsMap().get(eff).getAmplifier());
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@SubscribeEvent
 | 
						@SubscribeEvent
 | 
				
			||||||
	public static void onServerPlayerLeave(PlayerEvent.PlayerLoggedOutEvent event) {
 | 
						public static void onServerPlayerLeave(PlayerEvent.PlayerLoggedOutEvent event) {
 | 
				
			||||||
		ServerPlayer e = (ServerPlayer) event.getEntity();
 | 
							ServerPlayer e = (ServerPlayer) event.getEntity();
 | 
				
			||||||
		if (e != null) {
 | 
							if (e == null) return;
 | 
				
			||||||
			for (MobEffect eff : e.getActiveEffectsMap().keySet()) {
 | 
							for (var eff : e.getActiveEffectsMap().keySet()) {
 | 
				
			||||||
				if (TRACKED.contains(eff)) {
 | 
								if (isTracked(eff)) {
 | 
				
			||||||
				onEffectDisappear(eff, e);
 | 
									onEffectDisappear(eff, e);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static void onEffectAppear(MobEffect eff, LivingEntity e, int lv) {
 | 
						private static void onEffectAppear(Holder<MobEffect> eff, LivingEntity e, int lv) {
 | 
				
			||||||
		if (e.level().isClientSide()) return;
 | 
							if (e.level().isClientSide()) return;
 | 
				
			||||||
		L2Core.PACKET_HANDLER.toTrackingPlayers(new EffectToClient(e.getId(), eff, true, lv), e);
 | 
							L2Core.PACKET_HANDLER.toTrackingPlayers(new EffectToClient(e.getId(), eff, true, lv), e);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static void onEffectDisappear(MobEffect eff, LivingEntity e) {
 | 
						private static void onEffectDisappear(Holder<MobEffect> eff, LivingEntity e) {
 | 
				
			||||||
		if (e.level().isClientSide()) return;
 | 
							if (e.level().isClientSide()) return;
 | 
				
			||||||
		L2Core.PACKET_HANDLER.toTrackingPlayers(new EffectToClient(e.getId(), eff, false, 0), e);
 | 
							L2Core.PACKET_HANDLER.toTrackingPlayers(new EffectToClient(e.getId(), eff, false, 0), e);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/main/java/dev/xkmc/l2core/events/SchedulerHandler.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/main/java/dev/xkmc/l2core/events/SchedulerHandler.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					package dev.xkmc.l2core.events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.xkmc.l2core.init.L2Core;
 | 
				
			||||||
 | 
					import net.neoforged.bus.api.SubscribeEvent;
 | 
				
			||||||
 | 
					import net.neoforged.fml.common.EventBusSubscriber;
 | 
				
			||||||
 | 
					import net.neoforged.neoforge.event.tick.ServerTickEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.function.BooleanSupplier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@EventBusSubscriber(modid = L2Core.MODID, bus = EventBusSubscriber.Bus.GAME)
 | 
				
			||||||
 | 
					public class SchedulerHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@SubscribeEvent
 | 
				
			||||||
 | 
						public static void serverTick(ServerTickEvent.Post event) {
 | 
				
			||||||
 | 
							execute();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static List<BooleanSupplier> TASKS = new ArrayList<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static synchronized void schedule(Runnable runnable) {
 | 
				
			||||||
 | 
							TASKS.add(() -> {
 | 
				
			||||||
 | 
								runnable.run();
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static synchronized void schedulePersistent(BooleanSupplier runnable) {
 | 
				
			||||||
 | 
							TASKS.add(runnable);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static synchronized void execute() {
 | 
				
			||||||
 | 
							if (TASKS.isEmpty()) return;
 | 
				
			||||||
 | 
							var temp = TASKS;
 | 
				
			||||||
 | 
							TASKS = new ArrayList<>();
 | 
				
			||||||
 | 
							temp.removeIf(BooleanSupplier::getAsBoolean);
 | 
				
			||||||
 | 
							temp.addAll(TASKS);
 | 
				
			||||||
 | 
							TASKS = temp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
@MethodsReturnNonnullByDefault
 | 
					@MethodsReturnNonnullByDefault
 | 
				
			||||||
@ParametersAreNonnullByDefault
 | 
					@ParametersAreNonnullByDefault
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package dev.xkmc.l2core.util;
 | 
					package dev.xkmc.l2core.events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					import net.minecraft.MethodsReturnNonnullByDefault;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3,9 +3,9 @@ package dev.xkmc.l2core.init;
 | 
				
			|||||||
import dev.xkmc.l2core.base.effects.EffectToClient;
 | 
					import dev.xkmc.l2core.base.effects.EffectToClient;
 | 
				
			||||||
import dev.xkmc.l2core.capability.conditionals.TokenToClient;
 | 
					import dev.xkmc.l2core.capability.conditionals.TokenToClient;
 | 
				
			||||||
import dev.xkmc.l2core.capability.player.PlayerCapToClient;
 | 
					import dev.xkmc.l2core.capability.player.PlayerCapToClient;
 | 
				
			||||||
import dev.xkmc.l2core.serial.config.SyncPacket;
 | 
					 | 
				
			||||||
import dev.xkmc.l2serial.network.PacketHandler;
 | 
					import dev.xkmc.l2serial.network.PacketHandler;
 | 
				
			||||||
import dev.xkmc.l2serial.serialization.custom_handler.Handlers;
 | 
					import dev.xkmc.l2serial.serialization.custom_handler.Handlers;
 | 
				
			||||||
 | 
					import net.minecraft.resources.ResourceLocation;
 | 
				
			||||||
import net.neoforged.bus.api.IEventBus;
 | 
					import net.neoforged.bus.api.IEventBus;
 | 
				
			||||||
import net.neoforged.bus.api.SubscribeEvent;
 | 
					import net.neoforged.bus.api.SubscribeEvent;
 | 
				
			||||||
import net.neoforged.fml.common.EventBusSubscriber;
 | 
					import net.neoforged.fml.common.EventBusSubscriber;
 | 
				
			||||||
@@ -35,6 +35,7 @@ public class L2Core {
 | 
				
			|||||||
	public L2Core(IEventBus bus) {
 | 
						public L2Core(IEventBus bus) {
 | 
				
			||||||
		Handlers.register();
 | 
							Handlers.register();
 | 
				
			||||||
		L2LibReg.register(bus);
 | 
							L2LibReg.register(bus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@SubscribeEvent
 | 
						@SubscribeEvent
 | 
				
			||||||
@@ -42,4 +43,8 @@ public class L2Core {
 | 
				
			|||||||
		PACKET_HANDLER.register(event);
 | 
							PACKET_HANDLER.register(event);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static ResourceLocation loc(String id) {
 | 
				
			||||||
 | 
							return ResourceLocation.fromNamespaceAndPath(MODID, id);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,12 +3,12 @@ package dev.xkmc.l2core.init;
 | 
				
			|||||||
import dev.xkmc.l2core.base.effects.ClientEffectCap;
 | 
					import dev.xkmc.l2core.base.effects.ClientEffectCap;
 | 
				
			||||||
import dev.xkmc.l2core.base.menu.base.MenuLayoutConfig;
 | 
					import dev.xkmc.l2core.base.menu.base.MenuLayoutConfig;
 | 
				
			||||||
import dev.xkmc.l2core.capability.conditionals.ConditionalData;
 | 
					import dev.xkmc.l2core.capability.conditionals.ConditionalData;
 | 
				
			||||||
 | 
					import dev.xkmc.l2core.capability.conditionals.PlayerFlagData;
 | 
				
			||||||
import dev.xkmc.l2core.capability.player.PlayerCapabilityNetworkHandler;
 | 
					import dev.xkmc.l2core.capability.player.PlayerCapabilityNetworkHandler;
 | 
				
			||||||
import dev.xkmc.l2core.init.reg.datapack.DatapackReg;
 | 
					import dev.xkmc.l2core.init.reg.datapack.DatapackReg;
 | 
				
			||||||
import dev.xkmc.l2core.init.reg.simple.*;
 | 
					import dev.xkmc.l2core.init.reg.simple.*;
 | 
				
			||||||
import dev.xkmc.l2core.serial.conditions.*;
 | 
					import dev.xkmc.l2core.serial.conditions.*;
 | 
				
			||||||
import dev.xkmc.l2core.serial.ingredients.EnchantmentIngredient;
 | 
					import dev.xkmc.l2core.serial.ingredients.EnchantmentIngredient;
 | 
				
			||||||
import dev.xkmc.l2core.serial.ingredients.MobEffectIngredient;
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.serial.ingredients.PotionIngredient;
 | 
					import dev.xkmc.l2core.serial.ingredients.PotionIngredient;
 | 
				
			||||||
import net.minecraft.world.entity.LivingEntity;
 | 
					import net.minecraft.world.entity.LivingEntity;
 | 
				
			||||||
import net.neoforged.bus.api.IEventBus;
 | 
					import net.neoforged.bus.api.IEventBus;
 | 
				
			||||||
@@ -23,7 +23,6 @@ public class L2LibReg {
 | 
				
			|||||||
	public static final IngReg INGREDIENT = IngReg.of(REG);
 | 
						public static final IngReg INGREDIENT = IngReg.of(REG);
 | 
				
			||||||
	public static final IngVal<EnchantmentIngredient> ING_ENCH = INGREDIENT.reg("enchantment", EnchantmentIngredient.class);
 | 
						public static final IngVal<EnchantmentIngredient> ING_ENCH = INGREDIENT.reg("enchantment", EnchantmentIngredient.class);
 | 
				
			||||||
	public static final IngVal<PotionIngredient> ING_POTION = INGREDIENT.reg("potion", PotionIngredient.class);
 | 
						public static final IngVal<PotionIngredient> ING_POTION = INGREDIENT.reg("potion", PotionIngredient.class);
 | 
				
			||||||
	public static final IngVal<MobEffectIngredient> ING_EFF = INGREDIENT.reg("mob_effect", MobEffectIngredient.class);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// conditions
 | 
						// conditions
 | 
				
			||||||
	public static final CdcReg<ICondition> CONDITION = CdcReg.of(REG, NeoForgeRegistries.CONDITION_SERIALIZERS);
 | 
						public static final CdcReg<ICondition> CONDITION = CdcReg.of(REG, NeoForgeRegistries.CONDITION_SERIALIZERS);
 | 
				
			||||||
@@ -35,10 +34,13 @@ public class L2LibReg {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// attachments
 | 
						// attachments
 | 
				
			||||||
	public static final AttReg ATTACHMENT = AttReg.of(REG);
 | 
						public static final AttReg ATTACHMENT = AttReg.of(REG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static final AttVal.CapVal<LivingEntity, ClientEffectCap> EFFECT = ATTACHMENT.entity("effect",
 | 
						public static final AttVal.CapVal<LivingEntity, ClientEffectCap> EFFECT = ATTACHMENT.entity("effect",
 | 
				
			||||||
			ClientEffectCap.class, ClientEffectCap::new, LivingEntity.class, e -> e.level().isClientSide());
 | 
								ClientEffectCap.class, ClientEffectCap::new, LivingEntity.class, e -> e.level().isClientSide());
 | 
				
			||||||
	public static final AttVal.PlayerVal<ConditionalData> CONDITIONAL = ATTACHMENT.player("conditionals",
 | 
						public static final AttVal.PlayerVal<ConditionalData> CONDITIONAL = ATTACHMENT.player("conditionals",
 | 
				
			||||||
			ConditionalData.class, ConditionalData::new, PlayerCapabilityNetworkHandler::new);
 | 
								ConditionalData.class, ConditionalData::new, PlayerCapabilityNetworkHandler::new);
 | 
				
			||||||
 | 
						public static final AttVal.PlayerVal<PlayerFlagData> FLAGS = ATTACHMENT.player("flags",
 | 
				
			||||||
 | 
								PlayerFlagData.class, PlayerFlagData::new, PlayerCapabilityNetworkHandler::new);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static final DatapackReg<MenuLayoutConfig> MENU_LAYOUT = REG.dataReg("menu_layout", MenuLayoutConfig.class);
 | 
						public static final DatapackReg<MenuLayoutConfig> MENU_LAYOUT = REG.dataReg("menu_layout", MenuLayoutConfig.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.init.events;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.init.L2Core;
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.util.raytrace.EntityTarget;
 | 
					 | 
				
			||||||
import net.neoforged.api.distmarker.Dist;
 | 
					 | 
				
			||||||
import net.neoforged.bus.api.SubscribeEvent;
 | 
					 | 
				
			||||||
import net.neoforged.fml.common.Mod;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.event.TickEvent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Mod.EventBusSubscriber(value = Dist.CLIENT, modid = L2Core.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE)
 | 
					 | 
				
			||||||
public class ClientGeneralEventHandler {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@SubscribeEvent
 | 
					 | 
				
			||||||
	public static void clientTick(TickEvent.ClientTickEvent event) {
 | 
					 | 
				
			||||||
		if (event.phase != TickEvent.Phase.END) return;
 | 
					 | 
				
			||||||
		for (EntityTarget target : EntityTarget.LIST) {
 | 
					 | 
				
			||||||
			target.tickRender();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,67 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.init.events;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.base.explosion.BaseExplosion;
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.init.L2Core;
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.serial.config.PacketHandlerWithConfig;
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.util.raytrace.RayTraceUtil;
 | 
					 | 
				
			||||||
import net.neoforged.bus.api.SubscribeEvent;
 | 
					 | 
				
			||||||
import net.neoforged.fml.common.Mod;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.event.AddReloadListenerEvent;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.event.OnDatapackSyncEvent;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.event.TickEvent;
 | 
					 | 
				
			||||||
import net.neoforged.neoforge.event.level.ExplosionEvent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.function.BooleanSupplier;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Mod.EventBusSubscriber(modid = L2Core.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE)
 | 
					 | 
				
			||||||
public class GeneralEventHandler {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@SubscribeEvent
 | 
					 | 
				
			||||||
	public static void addReloadListeners(AddReloadListenerEvent event) {
 | 
					 | 
				
			||||||
		PacketHandlerWithConfig.addReloadListeners(event);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@SubscribeEvent
 | 
					 | 
				
			||||||
	public static void onDatapackSync(OnDatapackSyncEvent event) {
 | 
					 | 
				
			||||||
		PacketHandlerWithConfig.onDatapackSync(event);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@SubscribeEvent
 | 
					 | 
				
			||||||
	public static void serverTick(TickEvent.ServerTickEvent event) {
 | 
					 | 
				
			||||||
		if (event.phase != TickEvent.Phase.END) return;
 | 
					 | 
				
			||||||
		RayTraceUtil.serverTick();
 | 
					 | 
				
			||||||
		execute();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@SubscribeEvent
 | 
					 | 
				
			||||||
	public static void onDetonate(ExplosionEvent.Detonate event) {
 | 
					 | 
				
			||||||
		if (event.getExplosion() instanceof BaseExplosion exp) {
 | 
					 | 
				
			||||||
			event.getAffectedEntities().removeIf(e -> !exp.hurtEntity(e));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static List<BooleanSupplier> TASKS = new ArrayList<>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static synchronized void schedule(Runnable runnable) {
 | 
					 | 
				
			||||||
		TASKS.add(() -> {
 | 
					 | 
				
			||||||
			runnable.run();
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static synchronized void schedulePersistent(BooleanSupplier runnable) {
 | 
					 | 
				
			||||||
		TASKS.add(runnable);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static synchronized void execute() {
 | 
					 | 
				
			||||||
		if (TASKS.isEmpty()) return;
 | 
					 | 
				
			||||||
		var temp = TASKS;
 | 
					 | 
				
			||||||
		TASKS = new ArrayList<>();
 | 
					 | 
				
			||||||
		temp.removeIf(BooleanSupplier::getAsBoolean);
 | 
					 | 
				
			||||||
		temp.addAll(TASKS);
 | 
					 | 
				
			||||||
		TASKS = temp;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
@MethodsReturnNonnullByDefault
 | 
					 | 
				
			||||||
@ParametersAreNonnullByDefault
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package dev.xkmc.l2core.init.events;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
					 | 
				
			||||||
@@ -1,166 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.init.reg.registrate;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*TODO
 | 
					 | 
				
			||||||
public class L2Registrate extends AbstractRegistrate<L2Registrate> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public L2Registrate(String modid) {
 | 
					 | 
				
			||||||
		super(modid);
 | 
					 | 
				
			||||||
		registerEventListeners(FMLJavaModLoadingContext.get().getModEventBus());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public <T extends NamedEntry<T>, P extends T> GenericBuilder<T, P> generic(RegistryInstance<T> cls, String id, NonNullSupplier<P> sup) {
 | 
					 | 
				
			||||||
		return entry(id, cb -> new GenericBuilder<>(this, id, cb, cls.key(), sup));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public <T extends Recipe<?>> RegistryEntry<RecipeType<T>> recipe(String id) {
 | 
					 | 
				
			||||||
		return simple(id, ForgeRegistries.Keys.RECIPE_TYPES, () -> new RecipeType<>() {
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Deprecated
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public <T extends Enchantment> EnchantmentBuilder<T, L2Registrate> enchantment(String name, EnchantmentCategory type, EnchantmentBuilder.EnchantmentFactory<T> factory) {
 | 
					 | 
				
			||||||
		return super.enchantment(name, type, factory);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public <T extends Enchantment> EnchantmentBuilder<T, L2Registrate> enchantment(String name, EnchantmentCategory type, EnchantmentBuilder.EnchantmentFactory<T> factory, String desc) {
 | 
					 | 
				
			||||||
		addRawLang("enchantment." + getModid() + "." + name + ".desc", desc);
 | 
					 | 
				
			||||||
		return super.enchantment(name, type, factory);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public <T extends MobEffect> NoConfigBuilder<MobEffect, T, L2Registrate> effect(String name, NonNullSupplier<T> sup, String desc) {
 | 
					 | 
				
			||||||
		addRawLang("effect." + getModid() + "." + name + ".description", desc);
 | 
					 | 
				
			||||||
		return entry(name, cb -> new NoConfigBuilder<>(this, this, name, cb, ForgeRegistries.Keys.MOB_EFFECTS, sup));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@SuppressWarnings({"unchecked", "unsafe"})
 | 
					 | 
				
			||||||
	public <E extends NamedEntry<E>> RegistryInstance<E> newRegistry(String id, Class<?> cls, Consumer<RegistryBuilder<E>> cons) {
 | 
					 | 
				
			||||||
		ResourceKey<Registry<E>> key = makeRegistry(id, () -> {
 | 
					 | 
				
			||||||
			var ans = new RegistryBuilder<E>();
 | 
					 | 
				
			||||||
			ans.onCreate((r, s) -> new RLClassHandler<>((Class<E>) cls, () -> r));
 | 
					 | 
				
			||||||
			cons.accept(ans);
 | 
					 | 
				
			||||||
			return ans;
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
		return new RegistryInstance<>(Suppliers.memoize(() -> RegistryManager.ACTIVE.getRegistry(key)), key);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public <E extends NamedEntry<E>> RegistryInstance<E> newRegistry(String id, Class<?> cls) {
 | 
					 | 
				
			||||||
		return newRegistry(id, cls, e -> {
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public synchronized RegistryEntry<CreativeModeTab> buildModCreativeTab(String name, String def, Consumer<CreativeModeTab.Builder> config) {
 | 
					 | 
				
			||||||
		ResourceLocation id = new ResourceLocation(getModid(), name);
 | 
					 | 
				
			||||||
		defaultCreativeTab(ResourceKey.create(Registries.CREATIVE_MODE_TAB, id));
 | 
					 | 
				
			||||||
		return buildCreativeTabImpl(name, this.addLang("itemGroup", id, def), config);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public synchronized RegistryEntry<CreativeModeTab> buildL2CreativeTab(String name, String def, Consumer<CreativeModeTab.Builder> config) {
 | 
					 | 
				
			||||||
		ResourceLocation id = new ResourceLocation(L2Library.MODID, name);
 | 
					 | 
				
			||||||
		defaultCreativeTab(ResourceKey.create(Registries.CREATIVE_MODE_TAB, id));
 | 
					 | 
				
			||||||
		TabSorter sorter = new TabSorter(getModid() + ":" + name, id);
 | 
					 | 
				
			||||||
		return L2Library.REGISTRATE.buildCreativeTabImpl(name, this.addLang("itemGroup", id, def), b -> {
 | 
					 | 
				
			||||||
			config.accept(b);
 | 
					 | 
				
			||||||
			sorter.sort(b);
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private synchronized RegistryEntry<CreativeModeTab> buildCreativeTabImpl(String name, Component comp, Consumer<CreativeModeTab.Builder> config) {
 | 
					 | 
				
			||||||
		return this.generic(self(), name, Registries.CREATIVE_MODE_TAB, () -> {
 | 
					 | 
				
			||||||
			var builder = CreativeModeTab.builder().title(comp)
 | 
					 | 
				
			||||||
					.withTabsBefore(CreativeModeTabs.SPAWN_EGGS);
 | 
					 | 
				
			||||||
			config.accept(builder);
 | 
					 | 
				
			||||||
			return builder.build();
 | 
					 | 
				
			||||||
		}).register();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public record RegistryInstance<E extends NamedEntry<E>>(Supplier<IForgeRegistry<E>> supplier,
 | 
					 | 
				
			||||||
															ResourceKey<Registry<E>> key) implements Supplier<IForgeRegistry<E>> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		@Override
 | 
					 | 
				
			||||||
		public IForgeRegistry<E> get() {
 | 
					 | 
				
			||||||
			return supplier().get();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static class GenericBuilder<T extends NamedEntry<T>, P extends T> extends AbstractBuilder<T, P, L2Registrate, GenericBuilder<T, P>> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private final NonNullSupplier<P> sup;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		GenericBuilder(L2Registrate parent, String name, BuilderCallback callback, ResourceKey<Registry<T>> registryType, NonNullSupplier<P> sup) {
 | 
					 | 
				
			||||||
			super(parent, parent, name, callback, registryType);
 | 
					 | 
				
			||||||
			this.sup = sup;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		@Override
 | 
					 | 
				
			||||||
		protected @NonnullType @NotNull P createEntry() {
 | 
					 | 
				
			||||||
			return sup.get();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public GenericBuilder<T, P> defaultLang() {
 | 
					 | 
				
			||||||
			return lang(NamedEntry::getDescriptionId, RegistrateLangProvider.toEnglishName(this.getName()));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static class TabSorter {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private static final TreeMap<String, TabSorter> MAP = new TreeMap<>();
 | 
					 | 
				
			||||||
		private static final HashSet<ResourceLocation> SET = new HashSet<>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private final ResourceLocation id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private TabSorter(String str, ResourceLocation id) {
 | 
					 | 
				
			||||||
			MAP.put(str, this);
 | 
					 | 
				
			||||||
			SET.add(id);
 | 
					 | 
				
			||||||
			this.id = id;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public void sort(CreativeModeTab.Builder b) {
 | 
					 | 
				
			||||||
			var list = new ArrayList<>(MAP.values());
 | 
					 | 
				
			||||||
			boolean after = false;
 | 
					 | 
				
			||||||
			ResourceLocation before = null;
 | 
					 | 
				
			||||||
			for (var e : list) {
 | 
					 | 
				
			||||||
				if (e == this) {
 | 
					 | 
				
			||||||
					after = true;
 | 
					 | 
				
			||||||
					if (before != null) {
 | 
					 | 
				
			||||||
						b.withTabsBefore(before);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if (after) {
 | 
					 | 
				
			||||||
					b.withTabsAfter(e.id);
 | 
					 | 
				
			||||||
					return;
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					before = e.id;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			for (var e : BuiltInRegistries.CREATIVE_MODE_TAB.entrySet()) {
 | 
					 | 
				
			||||||
				var id = e.getKey().location();
 | 
					 | 
				
			||||||
				if (known(id) || known(e.getValue())) {
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				b.withTabsAfter(id);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private static boolean known(ResourceLocation id) {
 | 
					 | 
				
			||||||
			if (id.getNamespace().equals("minecraft")) {
 | 
					 | 
				
			||||||
				return true;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return SET.contains(id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private static boolean known(CreativeModeTab tab) {
 | 
					 | 
				
			||||||
			for (var other : tab.tabsAfter) {
 | 
					 | 
				
			||||||
				if (known(other)) {
 | 
					 | 
				
			||||||
					return true;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
@@ -1,40 +0,0 @@
 | 
				
			|||||||
package dev.xkmc.l2core.init.reg.registrate;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*TODO
 | 
					 | 
				
			||||||
public class NamedEntry<T extends NamedEntry<T>> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private final L2Registrate.RegistryInstance<T> registry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private String desc = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public NamedEntry(L2Registrate.RegistryInstance<T> registry) {
 | 
					 | 
				
			||||||
		this.registry = registry;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public @NotNull String getDescriptionId() {
 | 
					 | 
				
			||||||
		if (desc != null)
 | 
					 | 
				
			||||||
			return desc;
 | 
					 | 
				
			||||||
		ResourceLocation rl = getRegistryName();
 | 
					 | 
				
			||||||
		ResourceLocation reg = registry.get().getRegistryName();
 | 
					 | 
				
			||||||
		desc = reg.getPath() + "." + rl.getNamespace() + "." + rl.getPath();
 | 
					 | 
				
			||||||
		return desc;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public MutableComponent getDesc() {
 | 
					 | 
				
			||||||
		return Component.translatable(getDescriptionId());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ResourceLocation getRegistryName() {
 | 
					 | 
				
			||||||
		return Objects.requireNonNull(registry.get().getKey(getThis()));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public String getID() {
 | 
					 | 
				
			||||||
		return getRegistryName().toString();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public T getThis() {
 | 
					 | 
				
			||||||
		return Wrappers.cast(this);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
@MethodsReturnNonnullByDefault
 | 
					 | 
				
			||||||
@ParametersAreNonnullByDefault
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package dev.xkmc.l2core.init.reg.registrate;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
					 | 
				
			||||||
@@ -24,7 +24,7 @@ public record BooleanValueCondition(String path, ArrayList<String> line, boolean
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public MapCodec<? extends ICondition> codec() {
 | 
						public MapCodec<BooleanValueCondition> codec() {
 | 
				
			||||||
		return L2LibReg.CONDITION_BOOL.get();
 | 
							return L2LibReg.CONDITION_BOOL.get();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package dev.xkmc.l2core.serial.conditions;
 | 
					package dev.xkmc.l2core.serial.conditions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.mojang.serialization.Codec;
 | 
					import com.mojang.serialization.MapCodec;
 | 
				
			||||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
					import dev.xkmc.l2core.init.L2LibReg;
 | 
				
			||||||
import net.neoforged.fml.config.ConfigTracker;
 | 
					import net.neoforged.fml.config.ConfigTracker;
 | 
				
			||||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
					import net.neoforged.neoforge.common.ModConfigSpec;
 | 
				
			||||||
@@ -24,7 +24,7 @@ public record DoubleValueCondition(String path, ArrayList<String> line, double l
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public Codec<DoubleValueCondition> codec() {
 | 
						public MapCodec<DoubleValueCondition> codec() {
 | 
				
			||||||
		return L2LibReg.CONDITION_DOUBLE.get();
 | 
							return L2LibReg.CONDITION_DOUBLE.get();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package dev.xkmc.l2core.serial.conditions;
 | 
					package dev.xkmc.l2core.serial.conditions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.mojang.serialization.Codec;
 | 
					import com.mojang.serialization.MapCodec;
 | 
				
			||||||
import dev.xkmc.l2core.init.L2Core;
 | 
					import dev.xkmc.l2core.init.L2Core;
 | 
				
			||||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
					import dev.xkmc.l2core.init.L2LibReg;
 | 
				
			||||||
import net.minecraft.resources.ResourceLocation;
 | 
					import net.minecraft.resources.ResourceLocation;
 | 
				
			||||||
@@ -12,8 +12,6 @@ import java.util.ArrayList;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public record IntValueCondition(String path, ArrayList<String> line, int low, int high) implements ICondition {
 | 
					public record IntValueCondition(String path, ArrayList<String> line, int low, int high) implements ICondition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static final ResourceLocation ID = new ResourceLocation(L2Core.MODID, "int_config");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static IntValueCondition of(String file, ModConfigSpec.ConfigValue<Integer> config, int low, int high) {
 | 
						public static IntValueCondition of(String file, ModConfigSpec.ConfigValue<Integer> config, int low, int high) {
 | 
				
			||||||
		return new IntValueCondition(file, new ArrayList<>(config.getPath()), low, high);
 | 
							return new IntValueCondition(file, new ArrayList<>(config.getPath()), low, high);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -29,7 +27,7 @@ public record IntValueCondition(String path, ArrayList<String> line, int low, in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public Codec<IntValueCondition> codec() {
 | 
						public MapCodec<IntValueCondition> codec() {
 | 
				
			||||||
		return L2LibReg.CONDITION_INT.get();
 | 
							return L2LibReg.CONDITION_INT.get();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
package dev.xkmc.l2core.serial.conditions;
 | 
					package dev.xkmc.l2core.serial.conditions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.mojang.serialization.Codec;
 | 
					import com.mojang.serialization.MapCodec;
 | 
				
			||||||
import dev.xkmc.l2core.init.L2Core;
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
					import dev.xkmc.l2core.init.L2LibReg;
 | 
				
			||||||
import net.minecraft.resources.ResourceLocation;
 | 
					 | 
				
			||||||
import net.neoforged.fml.config.ConfigTracker;
 | 
					import net.neoforged.fml.config.ConfigTracker;
 | 
				
			||||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
					import net.neoforged.neoforge.common.ModConfigSpec;
 | 
				
			||||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
					import net.neoforged.neoforge.common.conditions.ICondition;
 | 
				
			||||||
@@ -13,8 +11,6 @@ import java.util.List;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public record ListStringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
 | 
					public record ListStringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static final ResourceLocation ID = new ResourceLocation(L2Core.MODID, "string_list_config");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static ListStringValueCondition of(String file, ModConfigSpec.ConfigValue<List<String>> config, String key) {
 | 
						public static ListStringValueCondition of(String file, ModConfigSpec.ConfigValue<List<String>> config, String key) {
 | 
				
			||||||
		return new ListStringValueCondition(file, new ArrayList<>(config.getPath()), key);
 | 
							return new ListStringValueCondition(file, new ArrayList<>(config.getPath()), key);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -29,7 +25,7 @@ public record ListStringValueCondition(String path, ArrayList<String> line, Stri
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public Codec<ListStringValueCondition> codec() {
 | 
						public MapCodec<ListStringValueCondition> codec() {
 | 
				
			||||||
		return L2LibReg.CONDITION_LIST_STR.get();
 | 
							return L2LibReg.CONDITION_LIST_STR.get();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
package dev.xkmc.l2core.serial.conditions;
 | 
					package dev.xkmc.l2core.serial.conditions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.mojang.serialization.Codec;
 | 
					import com.mojang.serialization.MapCodec;
 | 
				
			||||||
import dev.xkmc.l2core.init.L2Core;
 | 
					 | 
				
			||||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
					import dev.xkmc.l2core.init.L2LibReg;
 | 
				
			||||||
import net.minecraft.resources.ResourceLocation;
 | 
					 | 
				
			||||||
import net.neoforged.fml.config.ConfigTracker;
 | 
					import net.neoforged.fml.config.ConfigTracker;
 | 
				
			||||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
					import net.neoforged.neoforge.common.ModConfigSpec;
 | 
				
			||||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
					import net.neoforged.neoforge.common.conditions.ICondition;
 | 
				
			||||||
@@ -12,8 +10,6 @@ import java.util.ArrayList;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public record StringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
 | 
					public record StringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static final ResourceLocation ID = new ResourceLocation(L2Core.MODID, "string_config");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static StringValueCondition of(String file, ModConfigSpec.ConfigValue<String> config, String key) {
 | 
						public static StringValueCondition of(String file, ModConfigSpec.ConfigValue<String> config, String key) {
 | 
				
			||||||
		return new StringValueCondition(file, new ArrayList<>(config.getPath()), key);
 | 
							return new StringValueCondition(file, new ArrayList<>(config.getPath()), key);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -28,7 +24,7 @@ public record StringValueCondition(String path, ArrayList<String> line, String k
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public Codec<StringValueCondition> codec() {
 | 
						public MapCodec<StringValueCondition> codec() {
 | 
				
			||||||
		return L2LibReg.CONDITION_STR.get();
 | 
							return L2LibReg.CONDITION_STR.get();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package dev.xkmc.l2core.serial.recipe;
 | 
					package dev.xkmc.l2core.serial.recipe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.minecraft.core.HolderLookup;
 | 
				
			||||||
import net.minecraft.core.RegistryAccess;
 | 
					import net.minecraft.core.RegistryAccess;
 | 
				
			||||||
import net.minecraft.world.Container;
 | 
					import net.minecraft.world.Container;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
@@ -23,13 +24,14 @@ public abstract class BaseRecipe<Rec extends SRec, SRec extends BaseRecipe<?, SR
 | 
				
			|||||||
	public abstract boolean matches(Inv inv, Level world);
 | 
						public abstract boolean matches(Inv inv, Level world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public abstract ItemStack assemble(Inv inv, RegistryAccess access);
 | 
						public abstract ItemStack assemble(Inv inv, HolderLookup.Provider provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public abstract ItemStack getResultItem(HolderLookup.Provider provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public abstract boolean canCraftInDimensions(int r, int c);
 | 
						public abstract boolean canCraftInDimensions(int r, int c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public abstract ItemStack getResultItem(RegistryAccess access);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public final RecipeSerializer<?> getSerializer() {
 | 
						public final RecipeSerializer<?> getSerializer() {
 | 
				
			||||||
		return factory;
 | 
							return factory;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,23 @@
 | 
				
			|||||||
package dev.xkmc.l2core.util;
 | 
					package dev.xkmc.l2core.util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.minecraft.advancements.critereon.EnchantmentPredicate;
 | 
					import net.minecraft.advancements.critereon.EnchantmentPredicate;
 | 
				
			||||||
import net.minecraft.advancements.critereon.ItemPredicate;
 | 
					 | 
				
			||||||
import net.minecraft.advancements.critereon.MinMaxBounds;
 | 
					import net.minecraft.advancements.critereon.MinMaxBounds;
 | 
				
			||||||
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
 | 
					import net.minecraft.advancements.critereon.StatePropertiesPredicate;
 | 
				
			||||||
 | 
					import net.minecraft.core.Holder;
 | 
				
			||||||
import net.minecraft.world.item.Item;
 | 
					import net.minecraft.world.item.Item;
 | 
				
			||||||
import net.minecraft.world.item.enchantment.Enchantment;
 | 
					import net.minecraft.world.item.enchantment.Enchantment;
 | 
				
			||||||
import net.minecraft.world.item.enchantment.Enchantments;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.block.Block;
 | 
					import net.minecraft.world.level.block.Block;
 | 
				
			||||||
import net.minecraft.world.level.block.state.properties.Property;
 | 
					import net.minecraft.world.level.block.state.properties.Property;
 | 
				
			||||||
import net.minecraft.world.level.storage.loot.LootPool;
 | 
					import net.minecraft.world.level.storage.loot.LootPool;
 | 
				
			||||||
import net.minecraft.world.level.storage.loot.LootTable;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.storage.loot.entries.LootItem;
 | 
					import net.minecraft.world.level.storage.loot.entries.LootItem;
 | 
				
			||||||
import net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer;
 | 
					import net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer;
 | 
				
			||||||
import net.minecraft.world.level.storage.loot.functions.ApplyBonusCount;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.storage.loot.functions.LootingEnchantFunction;
 | 
					 | 
				
			||||||
import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction;
 | 
					import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction;
 | 
				
			||||||
import net.minecraft.world.level.storage.loot.predicates.*;
 | 
					import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition;
 | 
				
			||||||
 | 
					import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
 | 
				
			||||||
 | 
					import net.minecraft.world.level.storage.loot.predicates.LootItemKilledByPlayerCondition;
 | 
				
			||||||
 | 
					import net.minecraft.world.level.storage.loot.predicates.LootItemRandomChanceCondition;
 | 
				
			||||||
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
 | 
					import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
 | 
				
			||||||
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
 | 
					import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
 | 
				
			||||||
import net.neoforged.neoforge.common.Tags;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Optional;
 | 
					import java.util.Optional;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,12 +38,6 @@ public class LootTableTemplate {
 | 
				
			|||||||
				.apply(SetItemCountFunction.setCount(UniformGenerator.between(min, max)));
 | 
									.apply(SetItemCountFunction.setCount(UniformGenerator.between(min, max)));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static LootPoolSingletonContainer.Builder<?> getItem(Item item, int min, int max, int add) {
 | 
					 | 
				
			||||||
		return LootItem.lootTableItem(item)
 | 
					 | 
				
			||||||
				.apply(SetItemCountFunction.setCount(UniformGenerator.between(min, max)))
 | 
					 | 
				
			||||||
				.apply(LootingEnchantFunction.lootingMultiplier(UniformGenerator.between(0, add)));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static LootItemCondition.Builder byPlayer() {
 | 
						public static LootItemCondition.Builder byPlayer() {
 | 
				
			||||||
		return LootItemKilledByPlayerCondition.killedByPlayer();
 | 
							return LootItemKilledByPlayerCondition.killedByPlayer();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -54,10 +46,6 @@ public class LootTableTemplate {
 | 
				
			|||||||
		return LootItemRandomChanceCondition.randomChance(chance);
 | 
							return LootItemRandomChanceCondition.randomChance(chance);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static LootItemCondition.Builder chance(float chance, float add) {
 | 
					 | 
				
			||||||
		return LootItemRandomChanceWithLootingCondition.randomChanceAndLootingBoost(chance, add);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static LootItemBlockStatePropertyCondition.Builder withBlockState(Block block, Property<Integer> prop, int low, int high) {
 | 
						public static LootItemBlockStatePropertyCondition.Builder withBlockState(Block block, Property<Integer> prop, int low, int high) {
 | 
				
			||||||
		StatePropertiesPredicate.Builder builder = StatePropertiesPredicate.Builder.properties();
 | 
							StatePropertiesPredicate.Builder builder = StatePropertiesPredicate.Builder.properties();
 | 
				
			||||||
		builder.matchers.add(new StatePropertiesPredicate.PropertyMatcher(prop.getName(),
 | 
							builder.matchers.add(new StatePropertiesPredicate.PropertyMatcher(prop.getName(),
 | 
				
			||||||
@@ -85,42 +73,9 @@ public class LootTableTemplate {
 | 
				
			|||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static LootPoolSingletonContainer.Builder<?> cropDrop(Item item) {
 | 
						public static EnchantmentPredicate hasEnchantment(Holder<Enchantment> enchant, int min) {
 | 
				
			||||||
		return LootItem.lootTableItem(item).apply(ApplyBonusCount
 | 
					 | 
				
			||||||
				.addBonusBinomialDistributionCount(Enchantments.BLOCK_FORTUNE, 0.57f, 3));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static EnchantmentPredicate hasEnchantment(Enchantment enchant, int min) {
 | 
					 | 
				
			||||||
		return new EnchantmentPredicate(enchant, MinMaxBounds.Ints.atLeast(min));
 | 
							return new EnchantmentPredicate(enchant, MinMaxBounds.Ints.atLeast(min));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static LootItemCondition.Builder shearOrSilk(boolean inverted) {
 | 
					 | 
				
			||||||
		var ans = AnyOfCondition.anyOf(
 | 
					 | 
				
			||||||
				MatchTool.toolMatches(ItemPredicate.Builder.item().of(Tags.Items.SHEARS)),
 | 
					 | 
				
			||||||
				MatchTool.toolMatches(ItemPredicate.Builder.item().hasEnchantment(hasEnchantment(Enchantments.SILK_TOUCH, 1)))
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
		return inverted ? ans.invert() : ans;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static LootItemCondition.Builder silk(boolean inverted) {
 | 
					 | 
				
			||||||
		LootItemCondition.Builder ans = MatchTool.toolMatches(ItemPredicate.Builder.item().hasEnchantment(hasEnchantment(Enchantments.SILK_TOUCH, 1)));
 | 
					 | 
				
			||||||
		return inverted ? InvertedLootItemCondition.invert(ans) : ans;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public static LootTable.Builder selfOrOther(Block block, Block base, Item other, int count) {
 | 
					 | 
				
			||||||
		return LootTable.lootTable()
 | 
					 | 
				
			||||||
				.withPool(LootTableTemplate.getPool(1, 0)
 | 
					 | 
				
			||||||
						.add(LootTableTemplate.getItem(base.asItem(), 1))
 | 
					 | 
				
			||||||
						.when(ExplosionCondition.survivesExplosion())
 | 
					 | 
				
			||||||
						.when(LootTableTemplate.silk(true)))
 | 
					 | 
				
			||||||
				.withPool(LootTableTemplate.getPool(1, 0)
 | 
					 | 
				
			||||||
						.add(LootTableTemplate.getItem(other, count))
 | 
					 | 
				
			||||||
						.when(ExplosionCondition.survivesExplosion())
 | 
					 | 
				
			||||||
						.when(LootTableTemplate.silk(true)))
 | 
					 | 
				
			||||||
				.withPool(LootTableTemplate.getPool(1, 0)
 | 
					 | 
				
			||||||
						.add(LootTableTemplate.getItem(block.asItem(), 1))
 | 
					 | 
				
			||||||
						.when(LootTableTemplate.silk(false))
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user