Skip to content

Commit 571d50d

Browse files
XxFran10xXclaude
andcommitted
Keep a join sweep going past a broken item and ignore malformed model paths
A recorded craft whose MMOItems data is gone threw in the stat refresh and stopped the whole join sweep on TFMCDev01, so the rest of that inventory was not refreshed or migrated. CraftRefreshListener now logs the item and carries on. A v.<material>.<model> path with a non-numeric model no longer throws in the look migration; it simply does not match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 83a9684 commit 571d50d

4 files changed

Lines changed: 41 additions & 2 deletions

File tree

‎src/main/java/net/tfminecraft/advancedcrafting/managers/CraftRefreshListener.java‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,14 @@ private void tryRefresh(ItemStack item, ItemConsumer writer) {
126126
if (item == null || item.getType().isAir() || !AcItemRefresher.isManaged(item)) {
127127
return;
128128
}
129-
ItemStack refreshed = AcItemRefresher.refreshIfOutdated(item);
129+
ItemStack refreshed;
130+
try {
131+
refreshed = AcItemRefresher.refreshIfOutdated(item);
132+
} catch (RuntimeException e) {
133+
// One broken item (e.g. a recorded craft whose MMOItems data is gone) must not stop the rest of a sweep.
134+
AdvancedCrafting.plugin.getLogger().warning("Could not refresh " + item.getType() + ": " + e);
135+
return;
136+
}
130137
if (refreshed == item) {
131138
return;
132139
}

‎src/main/java/net/tfminecraft/advancedcrafting/utils/ArmourLookMigrator.java‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,12 @@ static boolean wears(ItemStack item, String path) {
9797
|| !item.getType().name().equalsIgnoreCase(parts[1])) {
9898
return false;
9999
}
100-
int model = Integer.parseInt(parts[2]);
100+
int model;
101+
try {
102+
model = Integer.parseInt(parts[2]);
103+
} catch (NumberFormatException e) {
104+
return false;
105+
}
101106
ItemMeta meta = item.getItemMeta();
102107
int current = LegacyModelData.has(meta) ? LegacyModelData.get(meta) : 0;
103108
return current == model;

‎src/test/java/net/tfminecraft/advancedcrafting/ArmourLookMigratorTest.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ void looksAreMatchedAndDescribedByTheirSchemePath() throws Exception {
305305

306306
assertTrue((boolean) wears.invoke(null, plain, "v.chainmail_helmet.0"));
307307
assertFalse((boolean) wears.invoke(null, plain, "v.chainmail_helmet"));
308+
assertFalse((boolean) wears.invoke(null, plain, "v.chainmail_helmet.x"), "a malformed model never matches");
308309
assertFalse((boolean) wears.invoke(null, plain, "m.helmets.light_custom_helmet"));
309310
assertFalse((boolean) wears.invoke(null, plain, "ia.tfmc_armor:iron_light_helmet"));
310311
assertEquals("v.chainmail_helmet.0", describe.invoke(null, plain));

‎src/test/java/net/tfminecraft/advancedcrafting/RefreshListenerCoverageTest.java‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,32 @@ void joinSweepRefreshesInventoryArmourOffhandAndEnderChestOneTickLater() throws
158158
verify(gone, never()).getInventory();
159159
}
160160

161+
@Test
162+
void aBrokenItemIsLoggedAndTheSweepCarriesOn() {
163+
when(plugin.isEnabled()).thenReturn(true);
164+
var p = server.addPlayer();
165+
var broken = new ItemStack(Material.IRON_HELMET);
166+
var next = new ItemStack(Material.IRON_BOOTS);
167+
var refreshed = new ItemStack(Material.LEATHER_BOOTS);
168+
p.getInventory().setItem(0, broken);
169+
p.getInventory().setItem(1, next);
170+
try (var refresher = mockStatic(AcItemRefresher.class)) {
171+
refresher.when(() -> AcItemRefresher.isManaged(any())).thenReturn(true);
172+
refresher
173+
.when(() -> AcItemRefresher.refreshIfOutdated(argThat(i -> i != null && i.getType() == Material.IRON_HELMET)))
174+
.thenThrow(new NullPointerException("no MMOItems type"));
175+
refresher
176+
.when(() -> AcItemRefresher.refreshIfOutdated(argThat(i -> i != null && i.getType() == Material.IRON_BOOTS)))
177+
.thenReturn(refreshed);
178+
var join = mock(PlayerJoinEvent.class);
179+
when(join.getPlayer()).thenReturn(p);
180+
new CraftRefreshListener().onJoin(join);
181+
server.getScheduler().performOneTick();
182+
}
183+
assertEquals(Material.IRON_HELMET, p.getInventory().getItem(0).getType());
184+
assertEquals(Material.LEATHER_BOOTS, p.getInventory().getItem(1).getType());
185+
}
186+
161187
@Test
162188
void openSweepOnlyTouchesWorldStorageAfterTheEvent() throws Exception {
163189
when(plugin.isEnabled()).thenReturn(true);

0 commit comments

Comments
 (0)