77import org .bukkit .event .Listener ;
88import org .bukkit .event .player .AsyncPlayerChatEvent ;
99
10+ import java .text .NumberFormat ;
11+ import java .text .ParsePosition ;
12+ import java .util .Locale ;
13+
1014import static me .w41k3r .shopkeepersAddon .ShopkeepersAddon .*;
1115
1216public class SetPriceTask implements Listener {
@@ -30,28 +34,72 @@ public void onEditPrice(AsyncPlayerChatEvent event) {
3034 return ;
3135 }
3236
33- try {
34- if (event .getMessage ().equalsIgnoreCase ("cancel" )) {
35- sendPlayerMessage (player , config .getString ("messages.priceChangeCancelled" ));
36- event .setCancelled (true );
37- HandlerList .unregisterAll (this );
38- return ;
39- }
40- double price = Double .parseDouble (event .getMessage ());
37+ String message = event .getMessage ().trim ();
4138
39+ // cancel keyword
40+ if (message .equalsIgnoreCase ("cancel" )) {
4241 event .setCancelled (true );
43-
4442 Bukkit .getScheduler ().runTask (plugin , () -> {
45- callback . onPriceSet ( price , slot );
43+ sendPlayerMessage ( player , config . getString ( "messages.priceChangeCancelled" ) );
4644 HandlerList .unregisterAll (this );
4745 });
46+ return ;
47+ }
4848
49- HandlerList .unregisterAll (this );
50-
49+ double price ;
50+ try {
51+ price = parsePrice (message );
5152 } catch (NumberFormatException e ) {
5253 event .setCancelled (true );
5354 sendPlayerMessage (player , config .getString ("messages.invalidPrice" ));
55+ return ;
56+ }
57+
58+ final double finalPrice = price ;
59+ event .setCancelled (true );
60+ Bukkit .getScheduler ().runTask (plugin , () -> {
61+ callback .onPriceSet (finalPrice , slot );
62+ HandlerList .unregisterAll (this );
63+ });
64+ }
65+
66+ /**
67+ * Parse a user input price robustly:
68+ * - strips non numeric / separator characters,
69+ * - tries dot-normalized parse,
70+ * - then tries NumberFormat for common locales (US, FR).
71+ */
72+ private double parsePrice (String input ) throws NumberFormatException {
73+ if (input == null ) throw new NumberFormatException ("null input" );
74+
75+ String orig = input .trim ();
76+
77+ // Keep only digits, comma, dot and minus sign (removes € $ letters § color codes, spaces, etc.)
78+ String sanitized = orig .replaceAll ("[^0-9,\\ .-]" , "" );
79+
80+ if (sanitized .isEmpty ()) throw new NumberFormatException ("empty after sanitize" );
81+
82+ // 1) quick try: replace comma with dot (accept "10", "10.00", "10,00")
83+ try {
84+ return Double .parseDouble (sanitized .replace (',' , '.' ));
85+ } catch (NumberFormatException ignored ) {
86+ }
87+
88+ // 2) try parsing with NumberFormat for common locales and ensure full consumption
89+ NumberFormat [] formats = new NumberFormat []{
90+ NumberFormat .getInstance (Locale .US ), // 1,234.56
91+ NumberFormat .getInstance (Locale .FRANCE ) // 1.234,56
92+ };
93+
94+ for (NumberFormat nf : formats ) {
95+ ParsePosition pos = new ParsePosition (0 );
96+ Number num = nf .parse (sanitized , pos );
97+ if (num != null && pos .getIndex () == sanitized .length ()) {
98+ return num .doubleValue ();
99+ }
54100 }
55101
102+ // nothing matched
103+ throw new NumberFormatException ("Invalid number: " + input );
56104 }
57- }
105+ }
0 commit comments