Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
f17a776
提取IPacket与SimpleRecipeSerializer
westernat Nov 11, 2025
8ec65fb
渲染部分功能拆分,一堆灯笼,矿透小改(线框剔除),星星瓶可与绳子相连
Lazy-Pillow-Minecraft Nov 16, 2025
b1980e5
修了点渲染bug,给祭坛加上物品显示
Lazy-Pillow-Minecraft Nov 17, 2025
7990c1c
心灯和星星瓶能旋转,正确发光,红气球和气球和河豚鱼防摔增加一格
MagicHarp Nov 21, 2025
b13ed57
拆分暴击mixin
voila1106 Dec 23, 2025
2725112
加点注释
voila1106 Dec 24, 2025
907f8d9
确定缺少的翻译键
westernat Dec 30, 2025
844f88e
剑类剑气,回旋镖,剑横扫吃岩浆石加成
westernat Dec 31, 2025
c36cffa
灵雾合成改成检查方块或玩家在灵雾中
westernat Dec 31, 2025
84425fe
修复爆破专家把自己和其它NPC炸死的问题
westernat Dec 31, 2025
9e4be8b
巨鹿生成
westernat Jan 1, 2026
3161af1
露西斧功能
westernat Jan 2, 2026
ca58b76
修复GlobalCloakData重复修复的问题
westernat Jan 6, 2026
57f5261
update lib
westernat Jan 7, 2026
af2a0ec
分离ItemStackedOnOtherEvent
westernat Jan 8, 2026
47d183f
提取简单的client item extensions
westernat Jan 9, 2026
b778185
将TaskScheduler从TerraEntity模块迁移到Lib模块
Wang-Xiao-Jing Jan 10, 2026
c9af1e6
注释
Wang-Xiao-Jing Jan 10, 2026
9ba0a79
重构了LivingEntityDelayRun现在类名为DelayTaskHolder
Wang-Xiao-Jing Jan 10, 2026
8783b61
重构了LivingEntityDelayRun现在类名为DelayTaskHolder
Wang-Xiao-Jing Jan 10, 2026
a935155
修改注释
Wang-Xiao-Jing Jan 10, 2026
1ca5864
微调
westernat Jan 10, 2026
e21b8ff
重写HUD房屋选择器,并加上区域边框
westernat Jan 10, 2026
6ea81c4
连弩基本代码
Wang-Xiao-Jing Jan 12, 2026
0901edf
稀里糊涂跑起来了
Wang-Xiao-Jing Jan 12, 2026
cb68a78
一些优化和处理,不保证比上次好,需要检查
Wang-Xiao-Jing Jan 13, 2026
66cecd5
有事件存在时不自然生成boss
westernat Jan 13, 2026
7217530
Boss接口移到lib
westernat Jan 13, 2026
e866087
升级neoforge到21.1.215
westernat Jan 13, 2026
96a211e
优化一下DelayTaskHolder的判断
Wang-Xiao-Jing Jan 14, 2026
108df8e
重写水蜡烛相关
westernat Jan 16, 2026
a430c06
测试最新的史莱姆雨
westernat Jan 16, 2026
877e086
重写血月事件
westernat Jan 17, 2026
ba9e5aa
史莱姆雨效果
westernat Jan 17, 2026
e3a30f6
修改史莱姆雨特效
westernat Jan 18, 2026
0f85c1e
调整流星雨与史莱姆雨的渲染
westernat Jan 18, 2026
f12e49c
移除三个事件模块
westernat Jan 19, 2026
80b886f
调整代码
westernat Jan 19, 2026
84554a1
元宵节自动触发灯笼夜事件
westernat Jan 20, 2026
a23fae3
为油漆工具去掉dyed标签
westernat Jan 21, 2026
a1ee2cb
将DPSMeter移到lib
westernat Jan 21, 2026
57381bb
短剑现在有戳戳的动画
westernat Jan 23, 2026
981760d
boss相关语言键移到lib
westernat Jan 23, 2026
8047fe0
增强动物保护指南
westernat Jan 24, 2026
9b828d9
修高级战利品信息显示兼容
westernat Jan 31, 2026
f17a2f6
修一些问题
westernat Jan 31, 2026
0bbf626
删掉一些被标记为待移除的代码
westernat Feb 1, 2026
dcab3d8
更新版本号
cooobird Feb 2, 2026
aee4196
重写敌怪旗
westernat Feb 3, 2026
7273923
特殊月亮
westernat Feb 4, 2026
95383b6
修复、优化与调整
westernat Feb 5, 2026
b55e503
队伍功能与同步(差GUI)
westernat Feb 5, 2026
bb32fcd
魔法飞刀
westernat Feb 6, 2026
64b8c55
键位显示
westernat Feb 7, 2026
a9919bd
0.0.5
westernat Feb 7, 2026
30fbfb4
更好的树叶更新方法,完全修复的松树
Lazy-Pillow-Minecraft Feb 7, 2026
b1fcf70
refactor: 优化松树生成算法和叶子更新逻辑
cooobird Feb 8, 2026
e0491dc
perf: 优化松树生成性能使用快速集合
cooobird Feb 8, 2026
d077f26
fix: 多人模式仅某个玩家重生会使附近BOSS消失
MakerTechno Feb 9, 2026
0a35f6e
展台优化
Lazy-Pillow-Minecraft Feb 9, 2026
f418c72
背景
westernat Feb 10, 2026
ca8d110
idfixer懒加载
westernat Feb 11, 2026
4123121
Going Oldschool成就
westernat Feb 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,17 @@ idea {
tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' }

tasks.register('runLangMerger', JavaExec) {
group = 'mod development'
group = 'mod development/internal'
description = 'Language Merger'
classpath = sourceSets.main.runtimeClasspath
mainClass = 'org.confluence.lib.util.LangMerger'
mainClass = 'org.confluence.lib.util.lang.LangMerger'
args "../"
}

tasks.register('runLangDistinctor', JavaExec) {
group = 'mod development/internal'
description = 'Language Distinctor'
classpath = sourceSets.main.runtimeClasspath
mainClass = 'org.confluence.lib.util.lang.LangDistinctor'
args "../"
}
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ minecraft_version=1.21.1
# as they do not follow standard versioning conventions.
minecraft_version_range=[1.21.1,1.22)
# The Neo version must agree with the Minecraft version to get a valid artifact
neo_version=21.1.209
neo_version=21.1.218
# The Neo version range can use any version of Neo as bounds
neo_version_range=[21,)
# The loader version range can only use the major version of FML as bounds
Expand All @@ -30,7 +30,7 @@ mod_name=Confluence Magic Lib
mod_license=MIT
# The mod version. See https://semver.org/
###### remove '-SNAPSHOT' when merge to main branch ######
mod_version=0.0.2f-SNAPSHOT
mod_version=0.0.6
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
Expand Down
31 changes: 14 additions & 17 deletions src/main/java/org/confluence/lib/ConfluenceMagicLib.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.ModList;
import net.neoforged.fml.common.Mod;
import net.neoforged.neoforge.attachment.AttachmentType;
import net.neoforged.neoforge.common.crafting.IngredientType;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
Expand All @@ -27,31 +28,32 @@
import org.confluence.lib.common.recipe.AmountIngredient;
import org.confluence.lib.common.worldgen.structure.GridPiece;
import org.confluence.lib.common.worldgen.structure.SimpleTemplatePiece;
import org.confluence.lib.util.NaturalSpawnerUtil;
import org.jetbrains.annotations.ApiStatus;
import org.confluence.lib.util.DelayTaskHolder;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Supplier;

@Mod(ConfluenceMagicLib.LIB_ID)
public class ConfluenceMagicLib {
public final class ConfluenceMagicLib {
public static final String LIB_ID = "confluence_magic_lib";
public static final String CONFLUENCE_ID = "confluence";
public static final Logger LOGGER = LoggerFactory.getLogger("Confluence Magic Lib");
public static final Supplier<Boolean> IS_CONFLUENCE_LOADED = Suppliers.memoize(() -> ModList.get().isLoaded(CONFLUENCE_ID));

//region 数据附件
private static final DeferredRegister<AttachmentType<?>> ATTACHMENT_TYPE = DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, LIB_ID);

public static final Supplier<AttachmentType<DelayTaskHolder>> DELAY_TASK_HOLDER = ATTACHMENT_TYPE.register("delay_task_holder", () -> AttachmentType.builder(DelayTaskHolder::new).build());
//endregion

// region 属性
private static final DeferredRegister<Attribute> ATTRIBUTES = DeferredRegister.create(Registries.ATTRIBUTE, LIB_ID);
/**
* 玩家怪物生成速度系数
*/
public static final DeferredHolder<Attribute, RangedAttribute> MOB_SPAWN_SPEED_MULTIPLIER = registerRangedAttribute("player.mob_spawn_speed_multiplier", NaturalSpawnerUtil.DEFAULT_MULTIPLIER, 0, 1024, false, Attribute.Sentiment.NEUTRAL);
/**
* 玩家怪物生成数量系数
*/
public static final DeferredHolder<Attribute, RangedAttribute> MOB_SPAWN_COUNT_MULTIPLIER = registerRangedAttribute("player.mob_spawn_count_multiplier", NaturalSpawnerUtil.DEFAULT_MULTIPLIER, 0, 1024, false, Attribute.Sentiment.NEUTRAL);
/// 玩家怪物生成速度系数
public static final DeferredHolder<Attribute, RangedAttribute> MOB_SPAWN_SPEED_MULTIPLIER = registerRangedAttribute("player.mob_spawn_speed_multiplier", 1, 0, 1024, false, Attribute.Sentiment.NEUTRAL);
/// 玩家怪物生成数量系数
public static final DeferredHolder<Attribute, RangedAttribute> MOB_SPAWN_COUNT_MULTIPLIER = registerRangedAttribute("player.mob_spawn_count_multiplier", 1, 0, 1024, false, Attribute.Sentiment.NEUTRAL);

private static DeferredHolder<Attribute, RangedAttribute> registerRangedAttribute(String name, double defaultValue, double min, double max, boolean syncable, Attribute.Sentiment sentiment) {
return ATTRIBUTES.register(name, () -> {
Expand Down Expand Up @@ -99,6 +101,7 @@ public StreamCodec<? super RegistryFriendlyByteBuf, CrossDustParticleOptions> st

public ConfluenceMagicLib(IEventBus modEventBus, ModContainer modContainer) {
StartupConfig.register(modContainer);
ATTACHMENT_TYPE.register(modEventBus);
ATTRIBUTES.register(modEventBus);
INGREDIENT_TYPES.register(modEventBus);
PIECE_TYPES.register(modEventBus);
Expand All @@ -109,10 +112,4 @@ public ConfluenceMagicLib(IEventBus modEventBus, ModContainer modContainer) {
public static ResourceLocation asResource(String path) {
return ResourceLocation.fromNamespaceAndPath(LIB_ID, path);
}

@Deprecated(since = "1.2.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "1.3.0")
public static boolean isConfluenceLoaded() {
return IS_CONFLUENCE_LOADED.get();
}
}
67 changes: 67 additions & 0 deletions src/main/java/org/confluence/lib/api/entity/Boss.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.confluence.lib.api.entity;

import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import org.apache.commons.lang3.stream.Streams;
import org.confluence.lib.color.GlobalColors;

/// All bosses should implement this interface
///
/// 所有boss都应该实现这个接口
public interface Boss extends Enemy, IDiscardWhenRespawnEntity {
default boolean shouldShowMessage() {
return isMainBody();
}

default boolean isMainBody() {
return true;
}

default boolean shouldEnhanceMultiplayer() {
return true;
}

interface BossPart extends Boss {
@Override
default boolean isMainBody() {
return false;
}
}

static void sendBossSpawnMessage(Entity entity) {
Level level = entity.level();
if (!level.isClientSide && entity instanceof Boss boss) {
if (boss.shouldShowMessage()) {
Component mes = Component.translatable("message.confluence.boss_spawn",
entity.getDisplayName()).withColor(GlobalColors.EVENT.get()).withStyle(ChatFormatting.BOLD);

for (Player player : level.players()) {
player.sendSystemMessage(mes);
}
}
}
}

static void sendBossDeathMessage(Entity entity) {
Level level = entity.level();
if (!level.isClientSide && entity instanceof Boss boss) {
if (boss.shouldShowMessage()) {
Component mes = Component.translatable("message.confluence.boss_leave",
entity.getDisplayName()).withColor(GlobalColors.EVENT.get()).withStyle(ChatFormatting.BOLD);

for (Player player : level.players()) {
player.sendSystemMessage(mes);
}
}
}
}

static boolean noBossInWorld(ServerLevel level) {
return Streams.of(level.getAllEntities()).noneMatch(entity -> entity instanceof Boss);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.confluence.lib.api.entity;

import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;

import java.util.List;

/// 当玩家重生时,若附近没有存活的玩家,实现该接口的实体会消失,以实现出生保护
public interface IDiscardWhenRespawnEntity {
default boolean shouldDiscard(boolean hasNearbyPlayer) {
return !hasNearbyPlayer;
}

static void process(ServerPlayer player) {
List<Entity> entities = player.level().getEntities(player, player.getBoundingBox().inflate(32));
boolean hasPlayer = entities.stream().anyMatch(e -> e instanceof Player);
entities.stream().filter(e -> e instanceof IDiscardWhenRespawnEntity entity && entity.shouldDiscard(hasPlayer)).forEach(Entity::discard);
}
}
40 changes: 40 additions & 0 deletions src/main/java/org/confluence/lib/client/DPSMeter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.confluence.lib.client;

public final class DPSMeter {
private static boolean dpsStarted;
private static long dpsLastHit;
private static float dpsDamage;
private static long dpsStart;
private static long dpsEnd;

public static void addDPS(float dmg, long currentTime) {
if (dpsStarted) {
dpsLastHit = currentTime;
dpsDamage += dmg;
dpsEnd = currentTime;
} else {
dpsStarted = true;
dpsStart = currentTime;
dpsEnd = currentTime;
dpsLastHit = currentTime;
dpsDamage = dmg;
}
}

public static void checkDPSTime(long currentTime) {
if (dpsStarted && currentTime - dpsLastHit >= 30) {
dpsStarted = false;
}
}

public static float getDPS(long currentTime) {
float num = (dpsEnd - dpsStart) / 20.0F;
if (num >= 3.0F) {
dpsStart = currentTime - 20;
dpsDamage = dpsDamage / num;
num = (dpsEnd - dpsStart) / 20.0F;
}
if (num < 1.0F) num = 1.0F;
return dpsDamage / num;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.mojang.datafixers.util.Either;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FormattedText;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
Expand All @@ -13,6 +15,7 @@
import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.client.event.RenderTooltipEvent;
import org.confluence.lib.ConfluenceMagicLib;
import org.confluence.lib.client.DPSMeter;
import org.confluence.lib.client.animate.ExpertColorAnimation;
import org.confluence.lib.client.animate.MasterColorAnimation;
import org.confluence.lib.common.LibTags;
Expand All @@ -27,6 +30,10 @@ public final class LibGameEvents {
public static void clientTick$Post(ClientTickEvent.Pre event) {
ExpertColorAnimation.INSTANCE.updateColor();
MasterColorAnimation.INSTANCE.updateColor();
LocalPlayer player = Minecraft.getInstance().player;
if (player != null) {
DPSMeter.checkDPSTime(player.level().getGameTime());
}
}

@SubscribeEvent(priority = EventPriority.HIGHEST)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
@EventBusSubscriber(modid = ConfluenceMagicLib.LIB_ID, value = Dist.CLIENT)
public final class LibModEvents {
@SubscribeEvent
public static void registerParticles(RegisterParticleProvidersEvent event) {
public static void registerParticleProviders(RegisterParticleProvidersEvent event) {
event.registerSpriteSet(ConfluenceMagicLib.CROSS_DUST_PARTICLE.get(), CrossDustParticle.Provider::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.confluence.lib.client.render.item;

import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
import org.jetbrains.annotations.Nullable;

public class SimpleClientItemExtensions implements IClientItemExtensions {
protected RenderByItemCallback renderByItemCallback = (minecraft, stack, displayContext, poseStack, buffer, packedLight, packedOverlay) -> renderSimpleItem(minecraft, stack, poseStack, buffer, packedLight, packedOverlay);
protected BlockEntityWithoutLevelRenderer renderer;
protected HandTransformPredicate handTransformPredicate = IClientItemExtensions.super::applyForgeHandTransform;
protected ArmPoseGetter armPoseGetter = IClientItemExtensions.super::getArmPose;

public SimpleClientItemExtensions noRenderer() {
this.renderByItemCallback = (minecraft, stack, displayContext, poseStack, buffer, packedLight, packedOverlay) -> {};
return this;
}

public SimpleClientItemExtensions customRenderer(RenderByItemCallback callback) {
this.renderByItemCallback = callback;
return this;
}

public SimpleClientItemExtensions handTransform(boolean force) {
this.handTransformPredicate = (poseStack, player, arm, itemInHand, partialTick, equipProcess, swingProcess) -> force;
return this;
}

public SimpleClientItemExtensions handTransform(HandTransformPredicate predicate) {
this.handTransformPredicate = predicate;
return this;
}

public SimpleClientItemExtensions armPose(HumanoidModel.ArmPose armPose) {
this.armPoseGetter = (living, hand, itemStack) -> armPose;
return this;
}

public SimpleClientItemExtensions armPose(ArmPoseGetter getter) {
this.armPoseGetter = getter;
return this;
}

@Override
public BlockEntityWithoutLevelRenderer getCustomRenderer() {
if (renderer == null) {
Minecraft minecraft = Minecraft.getInstance();
this.renderer = new BlockEntityWithoutLevelRenderer(minecraft.getBlockEntityRenderDispatcher(), minecraft.getEntityModels()) {
@Override
public void renderByItem(ItemStack stack, ItemDisplayContext displayContext, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) {
renderByItemCallback.render(minecraft, stack, displayContext, poseStack, buffer, packedLight, packedOverlay);
}
};
}
return renderer;
}

@Override
public boolean applyForgeHandTransform(PoseStack poseStack, LocalPlayer player, HumanoidArm arm, ItemStack itemInHand, float partialTick, float equipProcess, float swingProcess) {
return handTransformPredicate.force(poseStack, player, arm, itemInHand, partialTick, equipProcess, swingProcess);
}

@Override
public HumanoidModel.@Nullable ArmPose getArmPose(LivingEntity entityLiving, InteractionHand hand, ItemStack itemStack) {
return armPoseGetter.get(entityLiving, hand, itemStack);
}

public static void renderSimpleItem(Minecraft minecraft, ItemStack stack, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) {
minecraft.getItemRenderer().renderModelLists(
minecraft.getItemRenderer().getModel(stack, minecraft.level, null, 260109),
stack, packedLight, packedOverlay, poseStack,
ItemRenderer.getFoilBufferDirect(buffer, Sheets.translucentCullBlockSheet(), true, stack.hasFoil())
);
}

@FunctionalInterface
public interface RenderByItemCallback {
void render(Minecraft minecraft, ItemStack stack, ItemDisplayContext displayContext, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay);
}

@FunctionalInterface
public interface HandTransformPredicate {
boolean force(PoseStack poseStack, LocalPlayer player, HumanoidArm arm, ItemStack itemInHand, float partialTick, float equipProcess, float swingProcess);
}

@FunctionalInterface
public interface ArmPoseGetter {
@Nullable HumanoidModel.ArmPose get(LivingEntity living, InteractionHand hand, ItemStack itemStack);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
package org.confluence.lib.client.render.item;

import net.minecraft.MethodsReturnNonnullByDefault;

import javax.annotation.ParametersAreNonnullByDefault;
Loading
Loading