Skip to content

Commit f9be644

Browse files
committed
fix(spell): 修复法术错误处理和参数验证机制
- 添加了详细的法术错误消息和错误类型分类 - 实现了统一的错误处理机制,包括语法错误、参数错误、数学错误和内部错误 - 修复了括号匹配、if语句配对、循环语句配对等语法检查 - 改进了法术参数类型验证和重载匹配逻辑 - 添加了除零检测和存储空值检查 - 优化了法术序列执行中的错误传播机制 - 修复了魔力不足和参数类型不匹配的错误处理 - 更新了法术值类型定义和匹配逻辑 - 改进了魔杖界面和插件相关的错误处理逻辑
1 parent 6e03b85 commit f9be644

File tree

19 files changed

+317
-83
lines changed

19 files changed

+317
-83
lines changed

src/main/java/org/creepebucket/programmable_magic/ModUtils.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.creepebucket.programmable_magic;
22

33
import net.minecraft.core.registries.BuiltInRegistries;
4+
import net.minecraft.ChatFormatting;
45
import net.minecraft.network.chat.Component;
56
import net.minecraft.server.level.ServerPlayer;
67
import net.minecraft.tags.TagKey;
@@ -77,6 +78,15 @@ public static boolean sendErrorMessageToPlayer(Component message, Player player)
7778
return false;
7879
}
7980

81+
public static Component formatSpellError(Component kind, Component detail) {
82+
return Component.translatable("message.programmable_magic.error.spell_error_header")
83+
.withStyle(ChatFormatting.RED)
84+
.append(Component.literal(" "))
85+
.append(kind.copy().withStyle(ChatFormatting.GOLD))
86+
.append(Component.literal("\n"))
87+
.append(detail.copy().withStyle(ChatFormatting.GRAY));
88+
}
89+
8090
/**
8191
* 由插件物品聚合魔杖数值:
8292
* - 遍历每个插件物品,构造插件实例并调用其 adjustWandValues。

src/main/java/org/creepebucket/programmable_magic/entities/SpellEntity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public void tick() {
7676
// 执行法术序列逻辑
7777

7878
if (this.level().isClientSide) { spawnParticles(); return; }
79+
if (this.spellData != null && Boolean.TRUE.equals(this.spellData.getCustomData("spell_error", Boolean.class))) { this.discard(); return; }
7980

8081
// 若已附加“弹丸附加”效果,则先进行严格命中检测并结算伤害(严格:沿速度向量扫掠)
8182
handleProjectileAttachHit();
@@ -239,6 +240,7 @@ private void simplifyPendingExpressions(SpellItemLogic boundary) {
239240
if (start == null || end == null || start == boundary) return; // 空区间或起点即边界,直接跳过
240241
SpellSequence slice = cloneRange(start, end);
241242
SpellSequence simplified = SpellUtils.calculateSpellSequence(caster, spellData, slice);
243+
if (this.spellData != null && Boolean.TRUE.equals(this.spellData.getCustomData("spell_error", Boolean.class))) { this.discard(); return; }
242244
spellSequence.replaceSection(start, end, simplified);
243245
}
244246

src/main/java/org/creepebucket/programmable_magic/gui/wand/WandMenu.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ private void saveWandInvToStack(Player player) {
375375
if (st.isEmpty()) return;
376376
int n = this.wandInv.getContainerSize();
377377
var list = new ArrayList<ItemStack>(n);
378-
for (int i = 0; i < n; i++) if (!this.wandInv.getItem(i).isEmpty()) list.add(this.wandInv.getItem(i));
378+
for (int i = 0; i < n; i++) list.add(this.wandInv.getItem(i).copy());
379379
st.set(ModDataComponents.WAND_STACKS_SMALL.get(), list);
380380
}
381381

@@ -401,7 +401,7 @@ private void saveWandInvToSavedStacks(Player player) {
401401
if (st.isEmpty()) return;
402402
int n = this.wandInv.getContainerSize();
403403
var list = new ArrayList<ItemStack>(n);
404-
for (int i = 0; i < n; i++) if (!this.wandInv.getItem(i).isEmpty()) list.add(this.wandInv.getItem(i).copy());
404+
for (int i = 0; i < n; i++) list.add(this.wandInv.getItem(i).copy());
405405
st.set(ModDataComponents.WAND_SAVED_STACKS.get(), list);
406406
}
407407

@@ -413,6 +413,7 @@ public void removed(Player player) {
413413
super.removed(player);
414414
saveWandInvToStack(player);
415415
savePluginsToStack(player);
416+
if (!player.level().isClientSide) getWandStack().set(ModDataComponents.WAND_LAST_RELEASE_TIME.get(), player.level().getGameTime());
416417
}
417418

418419
@Override

src/main/java/org/creepebucket/programmable_magic/gui/wand/WandScreen.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,22 @@ public int computeStep() {
9696
return 1;
9797
}
9898

99+
private int getVisibleSpellSlots() {
100+
var win = Minecraft.getInstance().getWindow();
101+
int sw = win.getGuiScaledWidth();
102+
return Math.max(1, Math.floorDiv(sw - 200, 16) - 4);
103+
}
104+
99105
/**
100106
* 更新法术偏移并同步给 Menu。
101107
*/
102108
public void updateSpellIndex(int delta) {
103109
int prev = this.spellIndexOffset;
104110
int cap = this.menu.getSpellSlotCapacity();
105-
int next = Mth.clamp(prev + delta, 0, cap);
111+
int visible = getVisibleSpellSlots();
112+
int maxOffset = Math.max(0, cap - visible);
113+
int next = Mth.clamp(prev + delta, 0, maxOffset);
114+
if (next == prev) return;
106115
this.spellIndexOffset = next;
107116
sendMenuData(WandMenu.KEY_SPELL_OFFSET, this.spellIndexOffset);
108117
}

src/main/java/org/creepebucket/programmable_magic/gui/wand/slots/OffsetSlot.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ private boolean inRange(int idx) {
3737
return idx >= 0 && idx < inv.getContainerSize();
3838
}
3939

40+
@Override
41+
public boolean isActive() {
42+
return inRange(targetIndex());
43+
}
44+
4045
@Override
4146
public boolean hasItem() {
4247
int idx = targetIndex();

src/main/java/org/creepebucket/programmable_magic/items/Wand.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ public class Wand extends BowItem implements IItemExtension {
3232
private final int slots;
3333
private final int pluginSlots;
3434

35+
private static boolean hasAutoChargePlugin(ItemStack stack) {
36+
java.util.List<ItemStack> plugins = stack.get(ModDataComponents.WAND_PLUGINS.get());
37+
if (plugins == null) return false;
38+
for (ItemStack it : plugins) {
39+
if (it == null || it.isEmpty()) continue;
40+
var id = BuiltInRegistries.ITEM.getKey(it.getItem());
41+
if (id != null && "wand_plugin_auto_charge".equals(id.getPath())) return true;
42+
}
43+
return false;
44+
}
45+
3546
/**
3647
* 构造一个魔杖实例。
3748
* @param properties 物品属性
@@ -59,6 +70,8 @@ public Wand(Properties properties, int slots, int pluginSlots) {
5970
*/
6071
public InteractionResult use(Level level, Player player, InteractionHand hand) {
6172
if (player.isShiftKeyDown()) {
73+
ItemStack stack = player.getItemInHand(hand);
74+
stack.set(ModDataComponents.WAND_LAST_RELEASE_TIME.get(), level.getGameTime());
6275
if (!level.isClientSide && player instanceof ServerPlayer serverPlayer) {
6376
serverPlayer.openMenu(
6477
new SimpleMenuProvider(
@@ -72,6 +85,8 @@ public InteractionResult use(Level level, Player player, InteractionHand hand) {
7285
}
7386

7487
// 非潜行:进入“使用”态(按住右键充能,松手释放)
88+
ItemStack stack = player.getItemInHand(hand);
89+
if (!hasAutoChargePlugin(stack)) stack.set(ModDataComponents.WAND_LAST_RELEASE_TIME.get(), level.getGameTime());
7590
player.startUsingItem(hand);
7691
return InteractionResult.SUCCESS;
7792
}
@@ -174,17 +189,10 @@ public void inventoryTick(ItemStack stack, ServerLevel level, Entity entity, @Nu
174189
if (!isHeld) return;
175190

176191
java.util.List<ItemStack> plugins = stack.get(ModDataComponents.WAND_PLUGINS.get());
177-
boolean hasAuto = false;
178-
if (plugins != null) {
179-
for (ItemStack it : plugins) {
180-
if (it == null || it.isEmpty()) continue;
181-
var id = BuiltInRegistries.ITEM.getKey(it.getItem());
182-
if (id != null && "wand_plugin_auto_charge".equals(id.getPath())) { hasAuto = true; break; }
183-
}
184-
}
185-
if (!hasAuto) return;
192+
if (!hasAutoChargePlugin(stack)) return;
186193

187194
if (level.isClientSide) {
195+
if (player.containerMenu instanceof WandMenu) return;
188196
boolean using = player.isUsingItem() && (player.getUseItem() == stack);
189197
if (using) return; // 按住使用时由 onUseTick 负责 HUD
190198

src/main/java/org/creepebucket/programmable_magic/registries/ModDataComponents.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,18 @@ public class ModDataComponents {
3838
// 直接存储完整 ItemStack(含数据组件/自定义状态)
3939
public static final DeferredHolder<DataComponentType<?>, DataComponentType<List<ItemStack>>> WAND_STACKS_BIG =
4040
DATA_COMPONENTS.registerComponentType("wand_stacks_big", builder -> builder
41-
.persistent(Codec.list(ItemStack.CODEC))
41+
.persistent(Codec.list(ItemStack.OPTIONAL_CODEC))
4242
.networkSynchronized(ByteBufCodecs.collection(ArrayList::new, ItemStack.OPTIONAL_STREAM_CODEC)));
4343

4444
public static final DeferredHolder<DataComponentType<?>, DataComponentType<List<ItemStack>>> WAND_STACKS_SMALL =
4545
DATA_COMPONENTS.registerComponentType("wand_stacks_small", builder -> builder
46-
.persistent(Codec.list(ItemStack.CODEC))
46+
.persistent(Codec.list(ItemStack.OPTIONAL_CODEC))
4747
.networkSynchronized(ByteBufCodecs.collection(ArrayList::new, ItemStack.OPTIONAL_STREAM_CODEC)));
4848

4949
// 隐藏保存:供左键释放读取
5050
public static final DeferredHolder<DataComponentType<?>, DataComponentType<List<ItemStack>>> WAND_SAVED_STACKS =
5151
DATA_COMPONENTS.registerComponentType("wand_saved_stacks", builder -> builder
52-
.persistent(Codec.list(ItemStack.CODEC))
52+
.persistent(Codec.list(ItemStack.OPTIONAL_CODEC))
5353
.networkSynchronized(ByteBufCodecs.collection(ArrayList::new, ItemStack.OPTIONAL_STREAM_CODEC)));
5454

5555

src/main/java/org/creepebucket/programmable_magic/spells/SpellLogic.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.List;
2121

2222
import static org.creepebucket.programmable_magic.ModUtils.sendErrorMessageToPlayer;
23+
import static org.creepebucket.programmable_magic.ModUtils.formatSpellError;
2324
import static org.creepebucket.programmable_magic.spells.SpellUtils.getSeps;
2425
import static org.creepebucket.programmable_magic.spells.SpellValueType.NUMBER;
2526

@@ -93,7 +94,10 @@ public void execute() {
9394
boolean r = consumePendingItemsFromInventory();
9495
if (!r) {
9596
// 未能按预期扣除物品
96-
sendErrorMessageToPlayer(Component.translatable("message.programmable_magic.error.wand.placeholder_consume_failed"), player);
97+
sendErrorMessageToPlayer(formatSpellError(
98+
Component.translatable("message.programmable_magic.error.kind.param"),
99+
Component.translatable("message.programmable_magic.error.wand.placeholder_consume_failed")
100+
), player);
97101
return;
98102
}
99103
// 4. 创建法术实体

0 commit comments

Comments
 (0)