configs
This commit is contained in:
		@@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.neoforged.neoforge.attachment.IAttachmentHolder;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.concurrent.ConcurrentHashMap;
 | 
			
		||||
import java.util.function.Predicate;
 | 
			
		||||
import java.util.function.Supplier;
 | 
			
		||||
@@ -14,32 +15,36 @@ import java.util.function.Supplier;
 | 
			
		||||
 */
 | 
			
		||||
public class GeneralCapabilityHolder<E extends IAttachmentHolder, T extends GeneralCapabilityTemplate<E, T>> extends AttachmentDef<T> {
 | 
			
		||||
 | 
			
		||||
	public static final Map<ResourceLocation, GeneralCapabilityHolder<?, ?>> INTERNAL_MAP = new ConcurrentHashMap<>();
 | 
			
		||||
    public static final Map<ResourceLocation, GeneralCapabilityHolder<?, ?>> INTERNAL_MAP = new ConcurrentHashMap<>();
 | 
			
		||||
 | 
			
		||||
	public final ResourceLocation id;
 | 
			
		||||
	public final Class<E> entity_class;
 | 
			
		||||
	private final Predicate<E> pred;
 | 
			
		||||
    public final ResourceLocation id;
 | 
			
		||||
    public final Class<E> entity_class;
 | 
			
		||||
    private final Predicate<E> pred;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public GeneralCapabilityHolder(ResourceLocation id, Class<T> holder_class, Supplier<T> sup,
 | 
			
		||||
								   Class<E> entity_class, Predicate<E> pred) {
 | 
			
		||||
		super(holder_class, sup);
 | 
			
		||||
		this.id = id;
 | 
			
		||||
		this.entity_class = entity_class;
 | 
			
		||||
		this.pred = pred;
 | 
			
		||||
		INTERNAL_MAP.put(id, this);
 | 
			
		||||
	}
 | 
			
		||||
    public GeneralCapabilityHolder(ResourceLocation id, Class<T> holder_class, Supplier<T> sup,
 | 
			
		||||
                                   Class<E> entity_class, Predicate<E> pred) {
 | 
			
		||||
        super(holder_class, sup);
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        this.entity_class = entity_class;
 | 
			
		||||
        this.pred = pred;
 | 
			
		||||
        INTERNAL_MAP.put(id, this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public T get(E e) {
 | 
			
		||||
		return e.getData(type());
 | 
			
		||||
	}
 | 
			
		||||
    public T getOrCreate(E e) {
 | 
			
		||||
        return e.getData(type());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public boolean isFor(IAttachmentHolder holder) {
 | 
			
		||||
		return entity_class.isInstance(holder) && isProper(Wrappers.cast(holder));
 | 
			
		||||
	}
 | 
			
		||||
    public Optional<T> getExisting(E e) {
 | 
			
		||||
        return e.getExistingData(type());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public boolean isProper(E entity) {
 | 
			
		||||
		return pred.test(entity);
 | 
			
		||||
	}
 | 
			
		||||
    public boolean isFor(IAttachmentHolder holder) {
 | 
			
		||||
        return entity_class.isInstance(holder) && isProper(Wrappers.cast(holder));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isProper(E entity) {
 | 
			
		||||
        return pred.test(entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ public class ClientDataHandler {
 | 
			
		||||
	public static <T extends ConditionalToken> void handle(TokenKey<T> key, T token) {
 | 
			
		||||
		Player player = Proxy.getClientPlayer();
 | 
			
		||||
		if (player == null) return;
 | 
			
		||||
		ConditionalToken old = L2LibReg.CONDITIONAL.type().get(player).data.put(key, token);
 | 
			
		||||
		ConditionalToken old = L2LibReg.CONDITIONAL.type().getOrCreate(player).data.put(key, token);
 | 
			
		||||
		if (token instanceof NetworkSensitiveToken<?> t) {
 | 
			
		||||
			t.onSync(Wrappers.cast(old), player);
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,37 +13,37 @@ 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 void addFlag(LivingEntity entity, String str) {
 | 
			
		||||
        if (entity instanceof Player player) {
 | 
			
		||||
            L2LibReg.FLAGS.type().getOrCreate(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);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
    public static boolean hasFlag(LivingEntity entity, String str) {
 | 
			
		||||
        if (entity instanceof Player player) {
 | 
			
		||||
            return L2LibReg.FLAGS.type().getExisting(player).map(e -> e.hasFlag(str)).orElse(false);
 | 
			
		||||
        } else {
 | 
			
		||||
            return entity.getTags().contains(str);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	@SerialField
 | 
			
		||||
	private final TreeSet<String> flags = new TreeSet<>();
 | 
			
		||||
    @SerialField
 | 
			
		||||
    private final TreeSet<String> flags = new TreeSet<>();
 | 
			
		||||
 | 
			
		||||
	public void addFlag(String str) {
 | 
			
		||||
		flags.add(str);
 | 
			
		||||
	}
 | 
			
		||||
    public void addFlag(String str) {
 | 
			
		||||
        flags.add(str);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public boolean hasFlag(String flag) {
 | 
			
		||||
		return flags.contains(flag);
 | 
			
		||||
	}
 | 
			
		||||
    public boolean hasFlag(String flag) {
 | 
			
		||||
        return flags.contains(flag);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public static void register() {
 | 
			
		||||
    public static void register() {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,22 +5,25 @@ import net.minecraft.server.level.ServerPlayer;
 | 
			
		||||
 | 
			
		||||
public class PlayerCapabilityNetworkHandler<T extends PlayerCapabilityTemplate<T>> {
 | 
			
		||||
 | 
			
		||||
	public final PlayerCapabilityHolder<T> holder;
 | 
			
		||||
    public final PlayerCapabilityHolder<T> holder;
 | 
			
		||||
 | 
			
		||||
	public PlayerCapabilityNetworkHandler(PlayerCapabilityHolder<T> holder) {
 | 
			
		||||
		this.holder = holder;
 | 
			
		||||
	}
 | 
			
		||||
    public PlayerCapabilityNetworkHandler(PlayerCapabilityHolder<T> holder) {
 | 
			
		||||
        this.holder = holder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public void toClient(ServerPlayer e) {
 | 
			
		||||
		L2Core.PACKET_HANDLER.toClientPlayer(PlayerCapToClient.of(e, PlayerCapToClient.Action.CLIENT, holder, holder.get(e)), e);
 | 
			
		||||
	}
 | 
			
		||||
    public void toClient(ServerPlayer e) {
 | 
			
		||||
        holder.getExisting(e).ifPresent(x -> L2Core.PACKET_HANDLER.toClientPlayer(
 | 
			
		||||
            PlayerCapToClient.of(e, PlayerCapToClient.Action.CLIENT, holder, x), e));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public void toTracking(ServerPlayer e) {
 | 
			
		||||
		L2Core.PACKET_HANDLER.toTrackingOnly(PlayerCapToClient.of(e, PlayerCapToClient.Action.TRACK, holder, holder.get(e)), e);
 | 
			
		||||
	}
 | 
			
		||||
    public void toTracking(ServerPlayer e) {
 | 
			
		||||
        holder.getExisting(e).ifPresent(x -> L2Core.PACKET_HANDLER.toTrackingOnly(
 | 
			
		||||
            PlayerCapToClient.of(e, PlayerCapToClient.Action.TRACK, holder, x), e));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public void startTracking(ServerPlayer tracker, ServerPlayer target) {
 | 
			
		||||
		L2Core.PACKET_HANDLER.toClientPlayer(PlayerCapToClient.of(target, PlayerCapToClient.Action.TRACK, holder, holder.get(target)), tracker);
 | 
			
		||||
	}
 | 
			
		||||
    public void startTracking(ServerPlayer tracker, ServerPlayer target) {
 | 
			
		||||
        holder.getExisting(target).ifPresent(x -> L2Core.PACKET_HANDLER.toClientPlayer(
 | 
			
		||||
            PlayerCapToClient.of(target, PlayerCapToClient.Action.TRACK, holder, x), tracker));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ public class BaseCapabilityEvents {
 | 
			
		||||
		if (event.getEntity() instanceof LivingEntity le && le.isAlive()) {
 | 
			
		||||
			for (GeneralCapabilityHolder<?, ?> holder : GeneralCapabilityHolder.INTERNAL_MAP.values()) {
 | 
			
		||||
				if (holder.isFor(event.getEntity()))
 | 
			
		||||
					holder.get(Wrappers.cast(event.getEntity())).tick(Wrappers.cast(event.getEntity()));
 | 
			
		||||
					holder.getOrCreate(Wrappers.cast(event.getEntity())).tick(Wrappers.cast(event.getEntity()));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -29,7 +29,7 @@ public class BaseCapabilityEvents {
 | 
			
		||||
	public static void onPlayerClone(PlayerEvent.Clone event) {
 | 
			
		||||
		for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
 | 
			
		||||
			ServerPlayer e = (ServerPlayer) event.getEntity();
 | 
			
		||||
			holder.get(e).onClone(e, event.isWasDeath());
 | 
			
		||||
			holder.getOrCreate(e).onClone(e, event.isWasDeath());
 | 
			
		||||
			holder.network.toClient(e);
 | 
			
		||||
			holder.network.toTracking(e);
 | 
			
		||||
		}
 | 
			
		||||
@@ -40,7 +40,7 @@ public class BaseCapabilityEvents {
 | 
			
		||||
		ServerPlayer e = (ServerPlayer) event.getEntity();
 | 
			
		||||
		if (e == null) return;
 | 
			
		||||
		for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
 | 
			
		||||
			holder.get(e).init(e);
 | 
			
		||||
			holder.getOrCreate(e).init(e);
 | 
			
		||||
			holder.network.toClient(e);
 | 
			
		||||
			holder.network.toTracking(e);
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,6 @@ import net.minecraft.client.renderer.RenderType;
 | 
			
		||||
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.util.Mth;
 | 
			
		||||
import net.minecraft.world.effect.MobEffect;
 | 
			
		||||
import net.minecraft.world.entity.Entity;
 | 
			
		||||
import net.minecraft.world.entity.LivingEntity;
 | 
			
		||||
import net.minecraft.world.phys.Vec3;
 | 
			
		||||
@@ -37,149 +36,148 @@ import net.neoforged.neoforge.client.event.RenderLivingEvent;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@EventBusSubscriber(value = Dist.CLIENT, modid = L2Core.MODID, bus = EventBusSubscriber.Bus.GAME)
 | 
			
		||||
public class ClientEffectRenderEvents {
 | 
			
		||||
 | 
			
		||||
	private static final ArrayList<DelayedEntityRender> ICONS = new ArrayList<>();
 | 
			
		||||
    private static final ArrayList<DelayedEntityRender> ICONS = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
	@SubscribeEvent
 | 
			
		||||
	public static void clientTick(ClientTickEvent.Post event) {
 | 
			
		||||
		AbstractClientPlayer player = Proxy.getClientPlayer();
 | 
			
		||||
		if (player != null) {
 | 
			
		||||
			for (var entry : player.getActiveEffectsMap().entrySet()) {
 | 
			
		||||
				if (entry.getKey() instanceof FirstPlayerRenderEffect effect) {
 | 
			
		||||
					effect.onClientLevelRender(player, entry.getValue());
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
    @SubscribeEvent
 | 
			
		||||
    public static void clientTick(ClientTickEvent.Post event) {
 | 
			
		||||
        AbstractClientPlayer player = Proxy.getClientPlayer();
 | 
			
		||||
        if (player != null) {
 | 
			
		||||
            for (var entry : player.getActiveEffectsMap().entrySet()) {
 | 
			
		||||
                if (entry.getKey() instanceof FirstPlayerRenderEffect effect) {
 | 
			
		||||
                    effect.onClientLevelRender(player, entry.getValue());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	@SubscribeEvent
 | 
			
		||||
	public static void levelRenderLast(RenderLevelStageEvent event) {
 | 
			
		||||
		if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER) return;
 | 
			
		||||
		LevelRenderer renderer = event.getLevelRenderer();
 | 
			
		||||
		MultiBufferSource.BufferSource buffers = Minecraft.getInstance().renderBuffers().bufferSource();
 | 
			
		||||
		Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
 | 
			
		||||
		PoseStack stack = event.getPoseStack();
 | 
			
		||||
    @SubscribeEvent
 | 
			
		||||
    public static void levelRenderLast(RenderLevelStageEvent event) {
 | 
			
		||||
        if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER) return;
 | 
			
		||||
        LevelRenderer renderer = event.getLevelRenderer();
 | 
			
		||||
        MultiBufferSource.BufferSource buffers = Minecraft.getInstance().renderBuffers().bufferSource();
 | 
			
		||||
        Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
 | 
			
		||||
        PoseStack stack = event.getPoseStack();
 | 
			
		||||
 | 
			
		||||
		// cache the previous handler
 | 
			
		||||
		for (DelayedEntityRender icon : ICONS) {
 | 
			
		||||
			renderIcon(stack, buffers, icon, event.getPartialTick().getGameTimeDeltaTicks(), camera, renderer.entityRenderDispatcher);
 | 
			
		||||
		}
 | 
			
		||||
		buffers.endBatch();
 | 
			
		||||
        // cache the previous handler
 | 
			
		||||
        for (DelayedEntityRender icon : ICONS) {
 | 
			
		||||
            renderIcon(stack, buffers, icon, event.getPartialTick().getGameTimeDeltaTicks(), camera, renderer.entityRenderDispatcher);
 | 
			
		||||
        }
 | 
			
		||||
        buffers.endBatch();
 | 
			
		||||
 | 
			
		||||
		ICONS.clear();
 | 
			
		||||
	}
 | 
			
		||||
        ICONS.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	@SubscribeEvent
 | 
			
		||||
	public static void onLivingEntityRender(RenderLivingEvent.Post<?, ?> event) {
 | 
			
		||||
		LivingEntity entity = event.getEntity();
 | 
			
		||||
		if (!L2LibReg.EFFECT.type().isProper(entity)) return;
 | 
			
		||||
		if (entity.getTags().contains("ClientOnly")) return;//TODO
 | 
			
		||||
		ClientEffectCap cap = L2LibReg.EFFECT.type().get(entity);
 | 
			
		||||
		List<Pair<ClientRenderEffect, Integer>> l0 = new ArrayList<>();
 | 
			
		||||
		for (var entry : cap.map.entrySet()) {
 | 
			
		||||
			if (entry.getKey().value() instanceof ClientRenderEffect effect) {
 | 
			
		||||
				l0.add(Pair.of(effect, entry.getValue()));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (l0.isEmpty()) return;
 | 
			
		||||
		List<Pair<Integer, DelayedEntityRender>> l1 = new ArrayList<>();
 | 
			
		||||
		int index = 0;
 | 
			
		||||
    @SubscribeEvent
 | 
			
		||||
    public static void onLivingEntityRender(RenderLivingEvent.Post<?, ?> event) {
 | 
			
		||||
        LivingEntity entity = event.getEntity();
 | 
			
		||||
        if (!L2LibReg.EFFECT.type().isProper(entity)) return;
 | 
			
		||||
        if (entity.getTags().contains("ClientOnly")) return;//TODO
 | 
			
		||||
        ClientEffectCap cap = L2LibReg.EFFECT.type().getOrCreate(entity);
 | 
			
		||||
        List<Pair<ClientRenderEffect, Integer>> l0 = new ArrayList<>();
 | 
			
		||||
        for (var entry : cap.map.entrySet()) {
 | 
			
		||||
            if (entry.getKey().value() instanceof ClientRenderEffect effect) {
 | 
			
		||||
                l0.add(Pair.of(effect, entry.getValue()));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (l0.isEmpty()) return;
 | 
			
		||||
        List<Pair<Integer, DelayedEntityRender>> l1 = new ArrayList<>();
 | 
			
		||||
        int index = 0;
 | 
			
		||||
 | 
			
		||||
		for (var e : l0) {
 | 
			
		||||
			int lv = e.getSecond();
 | 
			
		||||
			int size = l1.size();
 | 
			
		||||
			int I = index;
 | 
			
		||||
			e.getFirst().render(entity, lv, x -> l1.add(Pair.of(I, x)));
 | 
			
		||||
			if (l1.size() > size) {
 | 
			
		||||
				index++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
        for (var e : l0) {
 | 
			
		||||
            int lv = e.getSecond();
 | 
			
		||||
            int size = l1.size();
 | 
			
		||||
            int I = index;
 | 
			
		||||
            e.getFirst().render(entity, lv, x -> l1.add(Pair.of(I, x)));
 | 
			
		||||
            if (l1.size() > size) {
 | 
			
		||||
                index++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		int n = index;
 | 
			
		||||
		int w = (int) Math.ceil(Math.sqrt(n));
 | 
			
		||||
		int h = (int) Math.ceil(n * 1d / w);
 | 
			
		||||
        int n = index;
 | 
			
		||||
        int w = (int) Math.ceil(Math.sqrt(n));
 | 
			
		||||
        int h = (int) Math.ceil(n * 1d / w);
 | 
			
		||||
 | 
			
		||||
		for (var e : l1) {
 | 
			
		||||
			int i = e.getFirst();
 | 
			
		||||
			int iy = i / w;
 | 
			
		||||
			int iw = Math.min(w, n - iy * w);
 | 
			
		||||
			int ix = i - iy * w;
 | 
			
		||||
			ICONS.add(e.getSecond().resize(IconRenderRegion.of(w, ix, iy, iw, h)));
 | 
			
		||||
		}
 | 
			
		||||
        for (var e : l1) {
 | 
			
		||||
            int i = e.getFirst();
 | 
			
		||||
            int iy = i / w;
 | 
			
		||||
            int iw = Math.min(w, n - iy * w);
 | 
			
		||||
            int ix = i - iy * w;
 | 
			
		||||
            ICONS.add(e.getSecond().resize(IconRenderRegion.of(w, ix, iy, iw, h)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	private static void renderIcon(PoseStack pose, MultiBufferSource buffer, DelayedEntityRender icon,
 | 
			
		||||
								   float partial, Camera camera, EntityRenderDispatcher dispatcher) {
 | 
			
		||||
		LivingEntity entity = icon.entity();
 | 
			
		||||
		float f = entity.getBbHeight() / 2;
 | 
			
		||||
    private static void renderIcon(PoseStack pose, MultiBufferSource buffer, DelayedEntityRender icon,
 | 
			
		||||
                                   float partial, Camera camera, EntityRenderDispatcher dispatcher) {
 | 
			
		||||
        LivingEntity entity = icon.entity();
 | 
			
		||||
        float f = entity.getBbHeight() / 2;
 | 
			
		||||
 | 
			
		||||
		double x0 = Mth.lerp(partial, entity.xOld, entity.getX());
 | 
			
		||||
		double y0 = Mth.lerp(partial, entity.yOld, entity.getY());
 | 
			
		||||
		double z0 = Mth.lerp(partial, entity.zOld, entity.getZ());
 | 
			
		||||
		Vec3 offset = dispatcher.getRenderer(entity).getRenderOffset(entity, partial);
 | 
			
		||||
		Vec3 cam_pos = camera.getPosition();
 | 
			
		||||
		double d2 = x0 - cam_pos.x + offset.x();
 | 
			
		||||
		double d3 = y0 - cam_pos.y + offset.y();
 | 
			
		||||
		double d0 = z0 - cam_pos.z + offset.z();
 | 
			
		||||
        double x0 = Mth.lerp(partial, entity.xOld, entity.getX());
 | 
			
		||||
        double y0 = Mth.lerp(partial, entity.yOld, entity.getY());
 | 
			
		||||
        double z0 = Mth.lerp(partial, entity.zOld, entity.getZ());
 | 
			
		||||
        Vec3 offset = dispatcher.getRenderer(entity).getRenderOffset(entity, partial);
 | 
			
		||||
        Vec3 cam_pos = camera.getPosition();
 | 
			
		||||
        double d2 = x0 - cam_pos.x + offset.x();
 | 
			
		||||
        double d3 = y0 - cam_pos.y + offset.y();
 | 
			
		||||
        double d0 = z0 - cam_pos.z + offset.z();
 | 
			
		||||
 | 
			
		||||
		pose.pushPose();
 | 
			
		||||
		pose.translate(d2, d3 + f, d0);
 | 
			
		||||
		pose.mulPose(camera.rotation());
 | 
			
		||||
		PoseStack.Pose entry = pose.last();
 | 
			
		||||
		VertexConsumer ivertexbuilder = buffer.getBuffer(get2DIcon(icon.rl()));
 | 
			
		||||
        pose.pushPose();
 | 
			
		||||
        pose.translate(d2, d3 + f, d0);
 | 
			
		||||
        pose.mulPose(camera.rotation());
 | 
			
		||||
        PoseStack.Pose entry = pose.last();
 | 
			
		||||
        VertexConsumer ivertexbuilder = buffer.getBuffer(get2DIcon(icon.rl()));
 | 
			
		||||
 | 
			
		||||
		float ix0 = -0.5f + icon.region().x();
 | 
			
		||||
		float ix1 = ix0 + icon.region().scale();
 | 
			
		||||
		float iy0 = -0.5f + icon.region().y();
 | 
			
		||||
		float iy1 = iy0 + icon.region().scale();
 | 
			
		||||
		float u0 = icon.tx();
 | 
			
		||||
		float v0 = icon.ty();
 | 
			
		||||
		float u1 = icon.tx() + icon.tw();
 | 
			
		||||
		float v1 = icon.ty() + icon.th();
 | 
			
		||||
        float ix0 = -0.5f + icon.region().x();
 | 
			
		||||
        float ix1 = ix0 + icon.region().scale();
 | 
			
		||||
        float iy0 = -0.5f + icon.region().y();
 | 
			
		||||
        float iy1 = iy0 + icon.region().scale();
 | 
			
		||||
        float u0 = icon.tx();
 | 
			
		||||
        float v0 = icon.ty();
 | 
			
		||||
        float u1 = icon.tx() + icon.tw();
 | 
			
		||||
        float v1 = icon.ty() + icon.th();
 | 
			
		||||
 | 
			
		||||
		iconVertex(entry, ivertexbuilder, ix1, iy0, u0, v1);
 | 
			
		||||
		iconVertex(entry, ivertexbuilder, ix0, iy0, u1, v1);
 | 
			
		||||
		iconVertex(entry, ivertexbuilder, ix0, iy1, u1, v0);
 | 
			
		||||
		iconVertex(entry, ivertexbuilder, ix1, iy1, u0, v0);
 | 
			
		||||
		pose.popPose();
 | 
			
		||||
	}
 | 
			
		||||
        iconVertex(entry, ivertexbuilder, ix1, iy0, u0, v1);
 | 
			
		||||
        iconVertex(entry, ivertexbuilder, ix0, iy0, u1, v1);
 | 
			
		||||
        iconVertex(entry, ivertexbuilder, ix0, iy1, u1, v0);
 | 
			
		||||
        iconVertex(entry, ivertexbuilder, ix1, iy1, u0, v0);
 | 
			
		||||
        pose.popPose();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	private static void iconVertex(PoseStack.Pose entry, VertexConsumer builder, float x, float y, float u, float v) {
 | 
			
		||||
		builder.addVertex(entry.pose(), x, y, 0)
 | 
			
		||||
				.setUv(u, v)
 | 
			
		||||
				.setNormal(entry, 0.0F, 1.0F, 0.0F);
 | 
			
		||||
	}
 | 
			
		||||
    private static void iconVertex(PoseStack.Pose entry, VertexConsumer builder, float x, float y, float u, float v) {
 | 
			
		||||
        builder.addVertex(entry.pose(), x, y, 0)
 | 
			
		||||
            .setUv(u, v)
 | 
			
		||||
            .setNormal(entry, 0.0F, 1.0F, 0.0F);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public static RenderType get2DIcon(ResourceLocation rl) {
 | 
			
		||||
		return RenderType.create(
 | 
			
		||||
				"entity_body_icon",
 | 
			
		||||
				DefaultVertexFormat.POSITION_TEX,
 | 
			
		||||
				VertexFormat.Mode.QUADS, 256, false, true,
 | 
			
		||||
				RenderType.CompositeState.builder()
 | 
			
		||||
						.setShaderState(RenderStateShard.RENDERTYPE_ENTITY_GLINT_SHADER)
 | 
			
		||||
						.setTextureState(new RenderStateShard.TextureStateShard(rl, false, false))
 | 
			
		||||
						.setTransparencyState(RenderStateShard.ADDITIVE_TRANSPARENCY)
 | 
			
		||||
						.setDepthTestState(RenderStateShard.NO_DEPTH_TEST)
 | 
			
		||||
						.createCompositeState(false)
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
    public static RenderType get2DIcon(ResourceLocation rl) {
 | 
			
		||||
        return RenderType.create(
 | 
			
		||||
            "entity_body_icon",
 | 
			
		||||
            DefaultVertexFormat.POSITION_TEX,
 | 
			
		||||
            VertexFormat.Mode.QUADS, 256, false, true,
 | 
			
		||||
            RenderType.CompositeState.builder()
 | 
			
		||||
                .setShaderState(RenderStateShard.RENDERTYPE_ENTITY_GLINT_SHADER)
 | 
			
		||||
                .setTextureState(new RenderStateShard.TextureStateShard(rl, false, false))
 | 
			
		||||
                .setTransparencyState(RenderStateShard.ADDITIVE_TRANSPARENCY)
 | 
			
		||||
                .setDepthTestState(RenderStateShard.NO_DEPTH_TEST)
 | 
			
		||||
                .createCompositeState(false)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public static void sync(EffectToClient eff) {
 | 
			
		||||
		if (Minecraft.getInstance().level == null) return;
 | 
			
		||||
		Entity e = Minecraft.getInstance().level.getEntity(eff.entity());
 | 
			
		||||
		if (!(e instanceof LivingEntity le)) return;
 | 
			
		||||
		if (!L2LibReg.EFFECT.type().isProper(le)) return;
 | 
			
		||||
		ClientEffectCap cap = L2LibReg.EFFECT.type().get(le);
 | 
			
		||||
		if (eff.exist()) {
 | 
			
		||||
			cap.map.put(eff.effect(), eff.level());
 | 
			
		||||
		} else {
 | 
			
		||||
			cap.map.remove(eff.effect());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
    public static void sync(EffectToClient eff) {
 | 
			
		||||
        if (Minecraft.getInstance().level == null) return;
 | 
			
		||||
        Entity e = Minecraft.getInstance().level.getEntity(eff.entity());
 | 
			
		||||
        if (!(e instanceof LivingEntity le)) return;
 | 
			
		||||
        if (!L2LibReg.EFFECT.type().isProper(le)) return;
 | 
			
		||||
        ClientEffectCap cap = L2LibReg.EFFECT.type().getOrCreate(le);
 | 
			
		||||
        if (eff.exist()) {
 | 
			
		||||
            cap.map.put(eff.effect(), eff.level());
 | 
			
		||||
        } else {
 | 
			
		||||
            cap.map.remove(eff.effect());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,45 +7,62 @@ import dev.xkmc.l2core.capability.conditionals.PlayerFlagData;
 | 
			
		||||
import dev.xkmc.l2core.capability.player.PlayerCapabilityNetworkHandler;
 | 
			
		||||
import dev.xkmc.l2core.init.reg.datapack.DatapackReg;
 | 
			
		||||
import dev.xkmc.l2core.init.reg.simple.*;
 | 
			
		||||
import dev.xkmc.l2core.serial.conditions.*;
 | 
			
		||||
import dev.xkmc.l2core.serial.configval.*;
 | 
			
		||||
import dev.xkmc.l2core.serial.ingredients.EnchantmentIngredient;
 | 
			
		||||
import dev.xkmc.l2core.serial.ingredients.PotionIngredient;
 | 
			
		||||
import dev.xkmc.l2core.serial.loot.AddItemModifier;
 | 
			
		||||
import dev.xkmc.l2core.serial.loot.AddLootTableModifier;
 | 
			
		||||
import dev.xkmc.l2core.serial.loot.PlayerFlagCondition;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.codec.MapCodecAdaptor;
 | 
			
		||||
import net.minecraft.core.registries.BuiltInRegistries;
 | 
			
		||||
import net.minecraft.world.entity.LivingEntity;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
 | 
			
		||||
import net.neoforged.bus.api.IEventBus;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
import net.neoforged.neoforge.common.loot.IGlobalLootModifier;
 | 
			
		||||
import net.neoforged.neoforge.registries.NeoForgeRegistries;
 | 
			
		||||
 | 
			
		||||
public class L2LibReg {
 | 
			
		||||
 | 
			
		||||
	public static final Reg REG = new Reg(L2Core.MODID);
 | 
			
		||||
    public static final Reg REG = new Reg(L2Core.MODID);
 | 
			
		||||
 | 
			
		||||
	// ingredients
 | 
			
		||||
	public static final IngReg INGREDIENT = IngReg.of(REG);
 | 
			
		||||
	public static final IngVal<EnchantmentIngredient> ING_ENCH = INGREDIENT.reg("enchantment", EnchantmentIngredient.class);
 | 
			
		||||
	public static final IngVal<PotionIngredient> ING_POTION = INGREDIENT.reg("potion", PotionIngredient.class);
 | 
			
		||||
    // ingredients
 | 
			
		||||
    public static final IngReg INGREDIENT = IngReg.of(REG);
 | 
			
		||||
    public static final IngVal<EnchantmentIngredient> ING_ENCH = INGREDIENT.reg("enchantment", EnchantmentIngredient.class);
 | 
			
		||||
    public static final IngVal<PotionIngredient> ING_POTION = INGREDIENT.reg("potion", PotionIngredient.class);
 | 
			
		||||
 | 
			
		||||
	// conditions
 | 
			
		||||
	public static final CdcReg<ICondition> CONDITION = CdcReg.of(REG, NeoForgeRegistries.CONDITION_SERIALIZERS);
 | 
			
		||||
	public static final CdcVal<BooleanValueCondition> CONDITION_BOOL = CONDITION.reg("bool_config", BooleanValueCondition.class);
 | 
			
		||||
	public static final CdcVal<IntValueCondition> CONDITION_INT = CONDITION.reg("int_config", IntValueCondition.class);
 | 
			
		||||
	public static final CdcVal<DoubleValueCondition> CONDITION_DOUBLE = CONDITION.reg("double_config", DoubleValueCondition.class);
 | 
			
		||||
	public static final CdcVal<StringValueCondition> CONDITION_STR = CONDITION.reg("string_config", StringValueCondition.class);
 | 
			
		||||
	public static final CdcVal<ListStringValueCondition> CONDITION_LIST_STR = CONDITION.reg("string_list_config", ListStringValueCondition.class);
 | 
			
		||||
    // conditions
 | 
			
		||||
    public static final CdcReg<ICondition> CONDITION = CdcReg.of(REG, NeoForgeRegistries.CONDITION_SERIALIZERS);
 | 
			
		||||
    public static final CdcVal<BooleanValueCondition> CONDITION_BOOL = CONDITION.reg("bool_config", BooleanValueCondition.class);
 | 
			
		||||
    public static final CdcVal<IntValueCondition> CONDITION_INT = CONDITION.reg("int_config", IntValueCondition.class);
 | 
			
		||||
    public static final CdcVal<DoubleValueCondition> CONDITION_DOUBLE = CONDITION.reg("double_config", DoubleValueCondition.class);
 | 
			
		||||
    public static final CdcVal<StringValueCondition> CONDITION_STR = CONDITION.reg("string_config", StringValueCondition.class);
 | 
			
		||||
    public static final CdcVal<ListStringValueCondition> CONDITION_LIST_STR = CONDITION.reg("string_list_config", ListStringValueCondition.class);
 | 
			
		||||
 | 
			
		||||
	// attachments
 | 
			
		||||
	public static final AttReg ATTACHMENT = AttReg.of(REG);
 | 
			
		||||
    // attachments
 | 
			
		||||
    public static final AttReg ATTACHMENT = AttReg.of(REG);
 | 
			
		||||
 | 
			
		||||
	public static final AttVal.CapVal<LivingEntity, ClientEffectCap> EFFECT = ATTACHMENT.entity("effect",
 | 
			
		||||
			ClientEffectCap.class, ClientEffectCap::new, LivingEntity.class, e -> e.level().isClientSide());
 | 
			
		||||
	public static final AttVal.PlayerVal<ConditionalData> CONDITIONAL = ATTACHMENT.player("conditionals",
 | 
			
		||||
			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 AttVal.CapVal<LivingEntity, ClientEffectCap> EFFECT = ATTACHMENT.entity("effect",
 | 
			
		||||
        ClientEffectCap.class, ClientEffectCap::new, LivingEntity.class, e -> e.level().isClientSide());
 | 
			
		||||
    public static final AttVal.PlayerVal<ConditionalData> CONDITIONAL = ATTACHMENT.player("conditionals",
 | 
			
		||||
        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);
 | 
			
		||||
    // loot modifiers
 | 
			
		||||
    public static final CdcReg<IGlobalLootModifier> GLM = CdcReg.of(REG, NeoForgeRegistries.GLOBAL_LOOT_MODIFIER_SERIALIZERS);
 | 
			
		||||
    public static final CdcVal<AddItemModifier> ADD_ITEM = GLM.reg("add_item", AddItemModifier.MAP_CODEC);
 | 
			
		||||
    public static final CdcVal<AddLootTableModifier> ADD_TABLE = GLM.reg("add_table", AddLootTableModifier.MAP_CODEC);
 | 
			
		||||
 | 
			
		||||
	public static void register(IEventBus bus) {
 | 
			
		||||
		REG.register(bus);
 | 
			
		||||
	}
 | 
			
		||||
    // loot conditions
 | 
			
		||||
    public static final SR<LootItemConditionType> LIC = SR.of(REG, BuiltInRegistries.LOOT_CONDITION_TYPE);
 | 
			
		||||
    public static final Val<LootItemConditionType> LIC_FLAG = LIC.reg("player_flag", () -> new LootItemConditionType(MapCodecAdaptor.of(PlayerFlagCondition.class)));
 | 
			
		||||
 | 
			
		||||
    // datapack
 | 
			
		||||
    public static final DatapackReg<MenuLayoutConfig> MENU_LAYOUT = REG.dataReg("menu_layout", MenuLayoutConfig.class);
 | 
			
		||||
 | 
			
		||||
    public static void register(IEventBus bus) {
 | 
			
		||||
        REG.register(bus);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.conditions;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.neoforged.fml.config.ConfigTracker;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
public record BooleanValueCondition(String path, ArrayList<String> line, boolean expected) implements ICondition {
 | 
			
		||||
 | 
			
		||||
	public static BooleanValueCondition of(String file, ModConfigSpec.ConfigValue<Boolean> config, boolean value) {
 | 
			
		||||
		return new BooleanValueCondition(file, new ArrayList<>(config.getPath()), value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean test(IContext context) {
 | 
			
		||||
		var file = ConfigTracker.INSTANCE.fileMap().get(path);
 | 
			
		||||
		if (file == null) return false;
 | 
			
		||||
		var line = file.getConfigData().get(line());
 | 
			
		||||
		if (line == null) return false;
 | 
			
		||||
		return line instanceof Boolean bool && bool == expected;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public MapCodec<BooleanValueCondition> codec() {
 | 
			
		||||
		return L2LibReg.CONDITION_BOOL.get();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.conditions;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.neoforged.fml.config.ConfigTracker;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
public record DoubleValueCondition(String path, ArrayList<String> line, double low, double high) implements ICondition {
 | 
			
		||||
 | 
			
		||||
	public static DoubleValueCondition of(String file, ModConfigSpec.ConfigValue<Double> config, double low, double high) {
 | 
			
		||||
		return new DoubleValueCondition(file, new ArrayList<>(config.getPath()), low, high);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean test(IContext context) {
 | 
			
		||||
		var file = ConfigTracker.INSTANCE.fileMap().get(path);
 | 
			
		||||
		if (file == null) return false;
 | 
			
		||||
		var line = file.getConfigData().get(line());
 | 
			
		||||
		if (line == null) return false;
 | 
			
		||||
		return line instanceof Double val && low <= val && val <= high;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public MapCodec<DoubleValueCondition> codec() {
 | 
			
		||||
		return L2LibReg.CONDITION_DOUBLE.get();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.conditions;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.neoforged.fml.config.ConfigTracker;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public record ListStringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
 | 
			
		||||
 | 
			
		||||
	public static ListStringValueCondition of(String file, ModConfigSpec.ConfigValue<List<String>> config, String key) {
 | 
			
		||||
		return new ListStringValueCondition(file, new ArrayList<>(config.getPath()), key);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean test(IContext context) {
 | 
			
		||||
		var file = ConfigTracker.INSTANCE.fileMap().get(path);
 | 
			
		||||
		if (file == null) return false;
 | 
			
		||||
		var line = file.getConfigData().get(line());
 | 
			
		||||
		if (line == null) return false;
 | 
			
		||||
		return line instanceof List<?> val && val.contains(key);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public MapCodec<ListStringValueCondition> codec() {
 | 
			
		||||
		return L2LibReg.CONDITION_LIST_STR.get();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.conditions;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.neoforged.fml.config.ConfigTracker;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
public record StringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
 | 
			
		||||
 | 
			
		||||
	public static StringValueCondition of(String file, ModConfigSpec.ConfigValue<String> config, String key) {
 | 
			
		||||
		return new StringValueCondition(file, new ArrayList<>(config.getPath()), key);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean test(IContext context) {
 | 
			
		||||
		var file = ConfigTracker.INSTANCE.fileMap().get(path);
 | 
			
		||||
		if (file == null) return false;
 | 
			
		||||
		var line = file.getConfigData().get(line());
 | 
			
		||||
		if (line == null) return false;
 | 
			
		||||
		return line instanceof String val && val.equals(key);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public MapCodec<StringValueCondition> codec() {
 | 
			
		||||
		return L2LibReg.CONDITION_STR.get();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import net.neoforged.fml.config.ConfigTracker;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
public class AbstractConfigParser {
 | 
			
		||||
 | 
			
		||||
    public static Optional<Object> parse(String path, List<String> line) {
 | 
			
		||||
        return Optional.ofNullable(ConfigTracker.INSTANCE.fileMap().get(path))
 | 
			
		||||
            .map(file -> file.getConfigData().get(line));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import com.mojang.datafixers.util.Either;
 | 
			
		||||
import com.mojang.serialization.Codec;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.function.BooleanSupplier;
 | 
			
		||||
 | 
			
		||||
public record BooleanConfigValue(String path, List<String> line) implements BooleanSupplier {
 | 
			
		||||
 | 
			
		||||
    public static BooleanConfigValue of(String file, ModConfigSpec.ConfigValue<Double> config) {
 | 
			
		||||
        return new BooleanConfigValue(file, config.getPath());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static BooleanConfigValue of(String data) {
 | 
			
		||||
        int last = data.lastIndexOf('/');
 | 
			
		||||
        var line = data.substring(last + 1).split("\\.");
 | 
			
		||||
        return new BooleanConfigValue(data.substring(0, last), List.of(line));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Codec<BooleanSupplier> CODEC = Codec.either(Codec.BOOL, Codec.STRING)
 | 
			
		||||
        .xmap(e -> e.map(x -> (BooleanSupplier) (() -> x), BooleanConfigValue::of),
 | 
			
		||||
            e -> e instanceof BooleanConfigValue val ?
 | 
			
		||||
                Either.right(val.toData()) :
 | 
			
		||||
                Either.left(e.getAsBoolean()));
 | 
			
		||||
 | 
			
		||||
    public boolean getAsBoolean() {
 | 
			
		||||
        return AbstractConfigParser.parse(path, line)
 | 
			
		||||
            .map(e -> e instanceof Boolean val ? val : false)
 | 
			
		||||
            .orElse(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String toData() {
 | 
			
		||||
        StringBuilder lines = new StringBuilder();
 | 
			
		||||
        for (var e : line) {
 | 
			
		||||
            if (!lines.isEmpty()) {
 | 
			
		||||
                lines.append(".");
 | 
			
		||||
            }
 | 
			
		||||
            lines.append(e);
 | 
			
		||||
        }
 | 
			
		||||
        return path + "/" + lines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
public record BooleanValueCondition(String path, ArrayList<String> line, boolean expected) implements ICondition {
 | 
			
		||||
 | 
			
		||||
    public static BooleanValueCondition of(String file, ModConfigSpec.ConfigValue<Boolean> config, boolean value) {
 | 
			
		||||
        return new BooleanValueCondition(file, new ArrayList<>(config.getPath()), value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean test(IContext context) {
 | 
			
		||||
        return AbstractConfigParser.parse(path, line)
 | 
			
		||||
            .map(e -> e instanceof Boolean bool && bool == expected).orElse(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MapCodec<BooleanValueCondition> codec() {
 | 
			
		||||
        return L2LibReg.CONDITION_BOOL.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import com.mojang.datafixers.util.Either;
 | 
			
		||||
import com.mojang.serialization.Codec;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.function.DoubleSupplier;
 | 
			
		||||
 | 
			
		||||
public record DoubleConfigValue(String path, List<String> line) implements DoubleSupplier {
 | 
			
		||||
 | 
			
		||||
    public static DoubleConfigValue of(String file, ModConfigSpec.ConfigValue<Double> config) {
 | 
			
		||||
        return new DoubleConfigValue(file, config.getPath());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static DoubleConfigValue of(String data) {
 | 
			
		||||
        int last = data.lastIndexOf('/');
 | 
			
		||||
        var line = data.substring(last + 1).split("\\.");
 | 
			
		||||
        return new DoubleConfigValue(data.substring(0, last), List.of(line));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Codec<DoubleSupplier> CODEC = Codec.either(Codec.DOUBLE, Codec.STRING)
 | 
			
		||||
        .xmap(e -> e.map(x -> (DoubleSupplier) (() -> x), DoubleConfigValue::of),
 | 
			
		||||
            e -> e instanceof DoubleConfigValue val ?
 | 
			
		||||
                Either.right(val.toData()) :
 | 
			
		||||
                Either.left(e.getAsDouble()));
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public double getAsDouble() {
 | 
			
		||||
        return AbstractConfigParser.parse(path, line)
 | 
			
		||||
            .map(e -> e instanceof Number val ? val.doubleValue() : 0d)
 | 
			
		||||
            .orElse(0d);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String toData() {
 | 
			
		||||
        StringBuilder lines = new StringBuilder();
 | 
			
		||||
        for (var e : line) {
 | 
			
		||||
            if (!lines.isEmpty()) {
 | 
			
		||||
                lines.append(".");
 | 
			
		||||
            }
 | 
			
		||||
            lines.append(e);
 | 
			
		||||
        }
 | 
			
		||||
        return path + "/" + lines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
public record DoubleValueCondition(String path, ArrayList<String> line, double low, double high) implements ICondition {
 | 
			
		||||
 | 
			
		||||
    public static DoubleValueCondition of(String file, ModConfigSpec.ConfigValue<Double> config, double low, double high) {
 | 
			
		||||
        return new DoubleValueCondition(file, new ArrayList<>(config.getPath()), low, high);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean test(IContext context) {
 | 
			
		||||
        return AbstractConfigParser.parse(path, line)
 | 
			
		||||
            .map(e -> e instanceof Double val && low <= val && val <= high).orElse(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MapCodec<DoubleValueCondition> codec() {
 | 
			
		||||
        return L2LibReg.CONDITION_DOUBLE.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import com.mojang.datafixers.util.Either;
 | 
			
		||||
import com.mojang.serialization.Codec;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.function.IntSupplier;
 | 
			
		||||
 | 
			
		||||
public record IntConfigValue(String path, List<String> line) implements IntSupplier {
 | 
			
		||||
 | 
			
		||||
    public static IntConfigValue of(String file, ModConfigSpec.ConfigValue<Integer> config) {
 | 
			
		||||
        return new IntConfigValue(file, config.getPath());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IntConfigValue of(String data) {
 | 
			
		||||
        int last = data.lastIndexOf('/');
 | 
			
		||||
        var line = data.substring(last + 1).split("\\.");
 | 
			
		||||
        return new IntConfigValue(data.substring(0, last), List.of(line));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Codec<IntSupplier> CODEC = Codec.either(Codec.INT, Codec.STRING)
 | 
			
		||||
        .xmap(e -> e.map(x -> (IntSupplier) (() -> x), IntConfigValue::of),
 | 
			
		||||
            e -> e instanceof IntConfigValue val ?
 | 
			
		||||
                Either.right(val.toData()) :
 | 
			
		||||
                Either.left(e.getAsInt()));
 | 
			
		||||
 | 
			
		||||
    public int getAsInt() {
 | 
			
		||||
        return AbstractConfigParser.parse(path, line)
 | 
			
		||||
            .map(e -> e instanceof Number val ? val.intValue() : 0)
 | 
			
		||||
            .orElse(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String toData() {
 | 
			
		||||
        StringBuilder lines = new StringBuilder();
 | 
			
		||||
        for (var e : line) {
 | 
			
		||||
            if (!lines.isEmpty()) {
 | 
			
		||||
                lines.append(".");
 | 
			
		||||
            }
 | 
			
		||||
            lines.append(e);
 | 
			
		||||
        }
 | 
			
		||||
        return path + "/" + lines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,7 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.conditions;
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2Core;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.neoforged.fml.config.ConfigTracker;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
@@ -18,11 +15,8 @@ public record IntValueCondition(String path, ArrayList<String> line, int low, in
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean test(IContext context) {
 | 
			
		||||
		var file = ConfigTracker.INSTANCE.fileMap().get(path);
 | 
			
		||||
		if (file == null) return false;
 | 
			
		||||
		var line = file.getConfigData().get(line());
 | 
			
		||||
		if (line == null) return false;
 | 
			
		||||
		return line instanceof Integer val && low <= val && val <= high;
 | 
			
		||||
		return AbstractConfigParser.parse(path, line)
 | 
			
		||||
			.map(e -> e instanceof Integer val && low <= val && val <= high).orElse(false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public record ListStringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
 | 
			
		||||
 | 
			
		||||
    public static ListStringValueCondition of(String file, ModConfigSpec.ConfigValue<List<String>> config, String key) {
 | 
			
		||||
        return new ListStringValueCondition(file, new ArrayList<>(config.getPath()), key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean test(IContext context) {
 | 
			
		||||
        return AbstractConfigParser.parse(path, line)
 | 
			
		||||
            .map(e -> e instanceof List<?> val && val.contains(key)).orElse(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MapCodec<ListStringValueCondition> codec() {
 | 
			
		||||
        return L2LibReg.CONDITION_LIST_STR.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import net.neoforged.neoforge.common.ModConfigSpec;
 | 
			
		||||
import net.neoforged.neoforge.common.conditions.ICondition;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
public record StringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
 | 
			
		||||
 | 
			
		||||
    public static StringValueCondition of(String file, ModConfigSpec.ConfigValue<String> config, String key) {
 | 
			
		||||
        return new StringValueCondition(file, new ArrayList<>(config.getPath()), key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean test(IContext context) {
 | 
			
		||||
        return AbstractConfigParser.parse(path, line)
 | 
			
		||||
            .map(e -> e instanceof String val && val.equals(key)).orElse(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MapCodec<StringValueCondition> codec() {
 | 
			
		||||
        return L2LibReg.CONDITION_STR.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
@MethodsReturnNonnullByDefault
 | 
			
		||||
@ParametersAreNonnullByDefault
 | 
			
		||||
 | 
			
		||||
package dev.xkmc.l2core.serial.conditions;
 | 
			
		||||
package dev.xkmc.l2core.serial.configval;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,74 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.loot;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.Codec;
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
 | 
			
		||||
import dev.xkmc.l2core.serial.configval.DoubleConfigValue;
 | 
			
		||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
 | 
			
		||||
import net.minecraft.core.registries.BuiltInRegistries;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.item.Items;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.LootContext;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
 | 
			
		||||
import net.neoforged.neoforge.common.loot.LootModifier;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.function.DoubleSupplier;
 | 
			
		||||
 | 
			
		||||
public class AddItemModifier extends LootModifier {
 | 
			
		||||
 | 
			
		||||
    public static final Codec<AddItemModifier> CODEC = RecordCodecBuilder.create(i -> LootModifier.codecStart(i).and(i.group(
 | 
			
		||||
        BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter(m -> m.item),
 | 
			
		||||
        BuiltInRegistries.ITEM.byNameCodec().optionalFieldOf("fail").forGetter(m -> m.fail == Items.AIR ? Optional.<Item>empty() : Optional.of(m.fail)),
 | 
			
		||||
        DoubleConfigValue.CODEC.optionalFieldOf("chance")
 | 
			
		||||
            .forGetter(m -> Optional.ofNullable(m.chance))
 | 
			
		||||
    )).apply(i, AddItemModifier::new));
 | 
			
		||||
 | 
			
		||||
    public static final MapCodec<AddItemModifier> MAP_CODEC = CODEC.dispatchMap(e -> e, AddItemModifier::codec);
 | 
			
		||||
 | 
			
		||||
    public final Item item, fail;
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public final DoubleSupplier chance;
 | 
			
		||||
 | 
			
		||||
    protected AddItemModifier(LootItemCondition[] conditionsIn, Item item, Optional<Item> fail, Optional<DoubleSupplier> chance) {
 | 
			
		||||
        super(conditionsIn);
 | 
			
		||||
        this.item = item;
 | 
			
		||||
        this.fail = fail.orElse(Items.AIR);
 | 
			
		||||
        this.chance = chance.orElse(null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AddItemModifier(Item item, @Nullable DoubleConfigValue chance, LootItemCondition... conditionsIn) {
 | 
			
		||||
        this(item, Items.AIR, chance, conditionsIn);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AddItemModifier(Item item, Item fail, @Nullable DoubleConfigValue chance, LootItemCondition... conditionsIn) {
 | 
			
		||||
        super(conditionsIn);
 | 
			
		||||
        this.item = item;
 | 
			
		||||
        this.fail = fail;
 | 
			
		||||
        this.chance = chance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected @NotNull ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
 | 
			
		||||
        if (!context.hasParam(LootContextParams.DAMAGE_SOURCE)) {
 | 
			
		||||
            return generatedLoot;
 | 
			
		||||
        }
 | 
			
		||||
        if (chance == null || context.getRandom().nextDouble() <= chance.getAsDouble()) {
 | 
			
		||||
            generatedLoot.add(new ItemStack(item));
 | 
			
		||||
        } else if (fail != Items.AIR) {
 | 
			
		||||
            generatedLoot.add(new ItemStack(fail));
 | 
			
		||||
        }
 | 
			
		||||
        return generatedLoot;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MapCodec<AddItemModifier> codec() {
 | 
			
		||||
        return MAP_CODEC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.loot;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.Codec;
 | 
			
		||||
import com.mojang.serialization.MapCodec;
 | 
			
		||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
 | 
			
		||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
 | 
			
		||||
import net.minecraft.core.registries.Registries;
 | 
			
		||||
import net.minecraft.resources.ResourceKey;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.LootContext;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
 | 
			
		||||
import net.neoforged.neoforge.common.loot.LootModifier;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
 | 
			
		||||
import static net.minecraft.world.level.storage.loot.LootTable.createStackSplitter;
 | 
			
		||||
 | 
			
		||||
public class AddLootTableModifier extends LootModifier {
 | 
			
		||||
 | 
			
		||||
    public static final Codec<AddLootTableModifier> CODEC = RecordCodecBuilder.create(inst -> codecStart(inst)
 | 
			
		||||
        .and(ResourceLocation.CODEC.fieldOf("lootTable").forGetter((m) -> m.lootTable))
 | 
			
		||||
        .apply(inst, AddLootTableModifier::new));
 | 
			
		||||
 | 
			
		||||
    public static final MapCodec<AddLootTableModifier> MAP_CODEC = CODEC.dispatchMap(e -> e, AddLootTableModifier::codec);
 | 
			
		||||
 | 
			
		||||
    private final ResourceLocation lootTable;
 | 
			
		||||
 | 
			
		||||
    protected AddLootTableModifier(LootItemCondition[] conditionsIn, ResourceLocation lootTable) {
 | 
			
		||||
        super(conditionsIn);
 | 
			
		||||
        this.lootTable = lootTable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AddLootTableModifier(ResourceLocation lootTable, LootItemCondition... conditionsIn) {
 | 
			
		||||
        super(conditionsIn);
 | 
			
		||||
        this.lootTable = lootTable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    protected ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
 | 
			
		||||
        var extraTable = context.getResolver().lookupOrThrow(Registries.LOOT_TABLE)
 | 
			
		||||
            .getOrThrow(ResourceKey.create(Registries.LOOT_TABLE, this.lootTable)).value();
 | 
			
		||||
        extraTable.getRandomItemsRaw(context, createStackSplitter(context.getLevel(), generatedLoot::add));
 | 
			
		||||
        return generatedLoot;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MapCodec<AddLootTableModifier> codec() {
 | 
			
		||||
        return MAP_CODEC;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
package dev.xkmc.l2core.serial.loot;
 | 
			
		||||
 | 
			
		||||
import dev.xkmc.l2core.init.L2LibReg;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.marker.SerialClass;
 | 
			
		||||
import dev.xkmc.l2serial.serialization.marker.SerialField;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.LootContext;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
 | 
			
		||||
 | 
			
		||||
@SerialClass
 | 
			
		||||
public class PlayerFlagCondition implements LootItemCondition {
 | 
			
		||||
 | 
			
		||||
    @SerialField
 | 
			
		||||
    public String flag;
 | 
			
		||||
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    public PlayerFlagCondition() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public PlayerFlagCondition(String flag) {
 | 
			
		||||
        this.flag = flag;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public LootItemConditionType getType() {
 | 
			
		||||
        return L2LibReg.LIC_FLAG.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean test(LootContext ctx) {
 | 
			
		||||
        if (!ctx.hasParam(LootContextParams.LAST_DAMAGE_PLAYER)) return false;
 | 
			
		||||
        var player = ctx.getParam(LootContextParams.LAST_DAMAGE_PLAYER);
 | 
			
		||||
        return L2LibReg.FLAGS.type().getExisting(player).map(e -> e.hasFlag(flag)).orElse(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
@MethodsReturnNonnullByDefault
 | 
			
		||||
@ParametersAreNonnullByDefault
 | 
			
		||||
 | 
			
		||||
package dev.xkmc.l2core.serial.loot;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.MethodsReturnNonnullByDefault;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
			
		||||
		Reference in New Issue
	
	Block a user