77import java .util .List ;
88import java .util .Map ;
99import java .util .Optional ;
10+ import java .util .regex .Matcher ;
11+ import java .util .regex .Pattern ;
1012
1113import org .apache .commons .lang .WordUtils ;
1214import org .bukkit .Bukkit ;
@@ -261,6 +263,9 @@ public StationFeedback craft(Player p, Double forcedQualityPercent) {
261263 return f ;
262264 }
263265
266+ // skill(amount), e.g. crafter(2.0)
267+ private static final Pattern XP_FORMAT = Pattern .compile ("([A-Za-z0-9_-]+)\\ ((\\ d+(?:\\ .\\ d+)?)\\ )" );
268+
264269 private void giveXP (Player p ) {
265270 // Map of skill name -> total XP to give
266271 Map <String , Double > xpBySkill = new HashMap <>();
@@ -271,26 +276,31 @@ private void giveXP(Player p) {
271276 String mId = split [1 ];
272277 int amount = currentMaterials .get (s );
273278
274- double xpPerUnit = 0.0 ;
275- String skill = null ;
279+ String raw = null ;
276280
277281 if (type .equalsIgnoreCase ("ingredient" )) {
278282 Ingredient ingredient = IngredientLoader .getByString (mId ); // Assuming you have a method like this
279283 if (ingredient != null && ingredient .getIngredientData ().hasXP ()) {
280- String raw = ingredient .getIngredientData ().getXP ();
281- xpPerUnit = parseXPAmount (raw );
282- skill = raw .split ("\\ (" )[0 ]; // Assuming you store "agriculturist" here
284+ raw = ingredient .getIngredientData ().getXP ();
283285 }
284286 } else if (type .equalsIgnoreCase ("alloy" )) {
285287 Alloy alloy = AlloyManager .getAlloyById (mId ); // Likewise for alloy
286288 if (alloy != null && alloy .getData ().hasXP ()) {
287- String raw = alloy .getData ().getXP ();
288- xpPerUnit = parseXPAmount (raw );
289- skill = raw .split ("\\ (" )[0 ]; // Assuming you store "agriculturist" here
289+ raw = alloy .getData ().getXP ();
290290 }
291291 }
292+ if (raw == null ) continue ;
293+
294+ // XP is paid after the item drops, so a bad value must be skipped rather than throw and leave the station uncleared.
295+ Matcher m = XP_FORMAT .matcher (raw .trim ());
296+ if (!m .matches ()) {
297+ Bukkit .getLogger ().warning ("AC: Invalid xp value '" + raw + "', expected skill(amount)" );
298+ continue ;
299+ }
300+ String skill = m .group (1 );
301+ double xpPerUnit = Double .parseDouble (m .group (2 ));
292302
293- if (skill != null && xpPerUnit > 0 ) {
303+ if (xpPerUnit > 0 ) {
294304 double totalXP = xpPerUnit * amount ;
295305 xpBySkill .put (skill , xpBySkill .getOrDefault (skill , 0.0 ) + totalXP );
296306 }
@@ -307,16 +317,6 @@ private void giveXP(Player p) {
307317 }
308318
309319
310- // XP is paid after the item drops, so a bad value must not throw and leave the station uncleared.
311- private double parseXPAmount (String raw ) {
312- try {
313- return Double .parseDouble (raw .split ("\\ (" )[1 ].replace (")" , "" ));
314- } catch (RuntimeException e ) {
315- Bukkit .getLogger ().warning ("AC: Invalid xp value '" + raw + "', expected skill(amount)" );
316- return 0.0 ;
317- }
318- }
319-
320320 private boolean checkItems (Player p ) {
321321 boolean complete = true ;
322322 for (IngredientType t : types .keySet ()) {
0 commit comments