1414import dev .objz .commandbridge .net .proto .MessageType ;
1515import dev .objz .commandbridge .scripting .model .enums .ArgType ;
1616import dev .objz .commandbridge .scripting .model .records .mapping .ArgMapping ;
17+
1718import java .util .ArrayList ;
19+ import java .util .Collection ;
1820import java .util .List ;
19- import org .bukkit .command .BlockCommandSender ;
20- import org .bukkit .command .CommandSender ;
21- import org .bukkit .command .ConsoleCommandSender ;
22- import org .bukkit .entity .Player ;
21+ import java .util .Objects ;
22+ import java .util .UUID ;
2323
2424public final class InvokedCommandEvent extends OutboundHandler <InvokedCommandContext > {
2525
2626 @ Override
2727 public SendOperation accept (InvokedCommandContext ctx ) {
28- CommandSender sender = ctx .sender ;
29- SenderContext senderCtx ;
30- if (sender instanceof Player p ) {
31- senderCtx = new SenderContext .Player (p .getName (), p .getUniqueId ().toString ());
32- } else if (sender instanceof ConsoleCommandSender ) {
33- senderCtx = new SenderContext .Console ();
34- } else if (sender instanceof BlockCommandSender b ) {
35- var l = b .getBlock ().getLocation ();
36- senderCtx = new SenderContext .Block (
37- new Location3D (
38- l .getWorld ().getName (),
39- l .getX (),
40- l .getY (),
41- l .getZ ()));
42- } else {
43- senderCtx = new SenderContext .Other (sender .getClass ().getSimpleName ());
44- }
28+ SenderContext senderCtx = mapSender (ctx .sender );
4529
4630 List <InvokedCommand .TypedArgument > typedArgs = new ArrayList <>();
4731 CommandStub stub = ctx .stub ;
4832 CommandArguments args = ctx .args ;
4933
5034 if (stub .args () != null && !stub .args ().isEmpty ()) {
51- for (ArgMapping m : stub .args ()) {
52- String name = m .name ();
53- ArgType type = m .type ();
54- Object raw = args .getOptional (name ).orElse (null );
55-
56- Object value = switch (type ) {
57- case STRING , TEXT , GREEDY_STRING -> (raw != null ? raw .toString () : null );
58-
59- case INTEGER , TIME -> (raw != null ? ((Number ) raw ).intValue () : 0 );
60-
61- case DOUBLE -> (raw != null ? ((Number ) raw ).doubleValue () : 0.0 );
62-
63- case BOOLEAN -> (raw instanceof Boolean b ? b
64- : raw != null && Boolean .TRUE .equals (raw ));
65-
66- case LOCATION -> {
67- org .bukkit .Location l = (org .bukkit .Location ) raw ;
68- yield (l == null ) ? null
69- : new Location3D (
70- l .getWorld ().getName (),
71- l .getX (),
72- l .getY (),
73- l .getZ ());
74- }
75-
76- case LOCATION_2D -> {
77- org .bukkit .Location l = (org .bukkit .Location ) raw ;
78- yield (l == null ) ? null
79- : new Location2D (
80- l .getWorld ().getName (),
81- l .getX (),
82- l .getZ ());
83- }
84-
85- case PLAYERS , ENTITIES -> {
86- var list = ((raw instanceof java .util .Collection <?>)
87- ? (java .util .Collection <?>) raw
88- : List .of ())
89- .stream ()
90- .filter (o -> o instanceof org .bukkit .entity .Entity )
91- .map (o -> {
92- var e = (org .bukkit .entity .Entity ) o ;
93- return new EntityRef (
94- e .getType ().name (),
95- e .getUniqueId ().toString (),
96- e .getName ());
97- })
98- .toList ();
99- yield list ; // List<EntityRef>
100- }
101-
102- case ENTITY_TYPE -> (raw != null ? raw .toString () : null );
103-
104- case OFFLINE_PLAYER -> (raw != null ? raw .toString () : null );
105-
106- case RANGE -> (raw != null ? raw .toString () : null );
107-
108- case WORLD , ANGLE , ROTATION , ITEM_STACK , ENCHANTMENT , POTION_EFFECT ,
109- SOUND , BIOME , SERVER ->
110- (raw != null ? raw .toString () : null );
111- };
112-
35+ for (ArgMapping mapping : stub .args ()) {
36+ ArgType type = mapping .type ();
37+ Object raw = args .getOptional (mapping .name ()).orElse (null );
38+ Object value = mapArgument (type , raw );
11339 typedArgs .add (new InvokedCommand .TypedArgument (type , value ));
11440 }
11541 }
@@ -127,4 +53,239 @@ public SendOperation accept(InvokedCommandContext ctx) {
12753 op .dispatch ();
12854 return op ;
12955 }
56+
57+ private SenderContext mapSender (Object sender ) {
58+ if (sender == null ) {
59+ return new SenderContext .Other ("null" );
60+ }
61+
62+ SenderContext .Player player = asPlayerSender (sender );
63+ if (player != null ) {
64+ return player ;
65+ }
66+
67+ if (isConsoleSender (sender )) {
68+ return new SenderContext .Console ();
69+ }
70+
71+ Location3D block = extractBlockLocation (sender );
72+ if (block != null ) {
73+ return new SenderContext .Block (block );
74+ }
75+
76+ return new SenderContext .Other (sender .getClass ().getSimpleName ());
77+ }
78+
79+ private SenderContext .Player asPlayerSender (Object sender ) {
80+ UUID uuid = invokeUuid (sender , "getUniqueId" );
81+ if (uuid == null ) {
82+ return null ;
83+ }
84+
85+ String name = invokeString (sender , "getUsername" );
86+ if (name == null || name .isBlank ()) {
87+ name = invokeString (sender , "getName" );
88+ }
89+ if (name == null || name .isBlank ()) {
90+ name = sender .getClass ().getSimpleName ();
91+ }
92+
93+ return new SenderContext .Player (name , uuid .toString ());
94+ }
95+
96+ private boolean isConsoleSender (Object sender ) {
97+ String className = sender .getClass ().getName ();
98+ return className .endsWith ("ConsoleCommandSender" )
99+ || className .endsWith ("ConsoleCommandSource" );
100+ }
101+
102+ private Location3D extractBlockLocation (Object sender ) {
103+ Object block = invoke (sender , "getBlock" );
104+ if (block == null ) {
105+ return null ;
106+ }
107+ Object location = invoke (block , "getLocation" );
108+ return toLocation3D (location );
109+ }
110+
111+ private Object mapArgument (ArgType type , Object raw ) {
112+ return switch (type ) {
113+ case STRING , TEXT , GREEDY_STRING , ENTITY_TYPE , OFFLINE_PLAYER , RANGE ,
114+ WORLD , ANGLE , ROTATION , ITEM_STACK , ENCHANTMENT , POTION_EFFECT ,
115+ SOUND , BIOME , SERVER -> raw != null ? raw .toString () : null ;
116+
117+ case INTEGER , TIME -> toInt (raw );
118+
119+ case DOUBLE -> toDouble (raw );
120+
121+ case BOOLEAN -> toBoolean (raw );
122+
123+ case LOCATION -> toLocation3D (raw );
124+
125+ case LOCATION_2D -> toLocation2D (raw );
126+
127+ case PLAYERS , ENTITIES -> toEntityRefs (raw );
128+ };
129+ }
130+
131+ private int toInt (Object raw ) {
132+ if (raw instanceof Number number ) {
133+ return number .intValue ();
134+ }
135+ if (raw == null ) {
136+ return 0 ;
137+ }
138+ try {
139+ return Integer .parseInt (raw .toString ());
140+ } catch (NumberFormatException ignored ) {
141+ return 0 ;
142+ }
143+ }
144+
145+ private double toDouble (Object raw ) {
146+ if (raw instanceof Number number ) {
147+ return number .doubleValue ();
148+ }
149+ if (raw == null ) {
150+ return 0.0 ;
151+ }
152+ try {
153+ return Double .parseDouble (raw .toString ());
154+ } catch (NumberFormatException ignored ) {
155+ return 0.0 ;
156+ }
157+ }
158+
159+ private boolean toBoolean (Object raw ) {
160+ if (raw instanceof Boolean value ) {
161+ return value ;
162+ }
163+ return raw != null && Boolean .parseBoolean (raw .toString ());
164+ }
165+
166+ private Location3D toLocation3D (Object raw ) {
167+ if (raw == null ) {
168+ return null ;
169+ }
170+
171+ Double x = invokeDouble (raw , "getX" );
172+ Double y = invokeDouble (raw , "getY" );
173+ Double z = invokeDouble (raw , "getZ" );
174+ if (x == null || y == null || z == null ) {
175+ return null ;
176+ }
177+
178+ return new Location3D (resolveWorldName (raw ), x , y , z );
179+ }
180+
181+ private Location2D toLocation2D (Object raw ) {
182+ if (raw == null ) {
183+ return null ;
184+ }
185+
186+ Double x = invokeDouble (raw , "getX" );
187+ Double z = invokeDouble (raw , "getZ" );
188+ if (x == null || z == null ) {
189+ return null ;
190+ }
191+
192+ return new Location2D (resolveWorldName (raw ), x , z );
193+ }
194+
195+ private String resolveWorldName (Object location ) {
196+ Object world = invoke (location , "getWorld" );
197+ String worldName = invokeString (world , "getName" );
198+ if (worldName == null || worldName .isBlank ()) {
199+ worldName = invokeString (location , "getWorldName" );
200+ }
201+ return (worldName == null || worldName .isBlank ()) ? "unknown" : worldName ;
202+ }
203+
204+ private List <EntityRef > toEntityRefs (Object raw ) {
205+ if (!(raw instanceof Collection <?> collection )) {
206+ return List .of ();
207+ }
208+
209+ return collection .stream ()
210+ .map (this ::toEntityRef )
211+ .filter (Objects ::nonNull )
212+ .toList ();
213+ }
214+
215+ private EntityRef toEntityRef (Object entity ) {
216+ if (entity == null ) {
217+ return null ;
218+ }
219+
220+ if (entity instanceof String name && !name .isBlank ()) {
221+ return new EntityRef ("PLAYER" , null , name );
222+ }
223+
224+ String uuid = null ;
225+ UUID parsedUuid = invokeUuid (entity , "getUniqueId" );
226+ if (parsedUuid != null ) {
227+ uuid = parsedUuid .toString ();
228+ }
229+
230+ String name = invokeString (entity , "getName" );
231+
232+ Object typeObj = invoke (entity , "getType" );
233+ String type = invokeString (typeObj , "name" );
234+ if (type == null || type .isBlank ()) {
235+ type = typeObj != null ? typeObj .toString () : "UNKNOWN" ;
236+ }
237+
238+ if ((name == null || name .isBlank ()) && uuid == null ) {
239+ return null ;
240+ }
241+
242+ return new EntityRef (type , uuid , name );
243+ }
244+
245+ private Object invoke (Object target , String method ) {
246+ if (target == null ) {
247+ return null ;
248+ }
249+
250+ try {
251+ return target .getClass ().getMethod (method ).invoke (target );
252+ } catch (ReflectiveOperationException ignored ) {
253+ return null ;
254+ }
255+ }
256+
257+ private String invokeString (Object target , String method ) {
258+ Object value = invoke (target , method );
259+ return value != null ? value .toString () : null ;
260+ }
261+
262+ private UUID invokeUuid (Object target , String method ) {
263+ Object value = invoke (target , method );
264+ if (value instanceof UUID uuid ) {
265+ return uuid ;
266+ }
267+ if (value instanceof String str ) {
268+ try {
269+ return UUID .fromString (str );
270+ } catch (IllegalArgumentException ignored ) {
271+ return null ;
272+ }
273+ }
274+ return null ;
275+ }
276+
277+ private Double invokeDouble (Object target , String method ) {
278+ Object value = invoke (target , method );
279+ if (value instanceof Number number ) {
280+ return number .doubleValue ();
281+ }
282+ if (value instanceof String str ) {
283+ try {
284+ return Double .parseDouble (str );
285+ } catch (NumberFormatException ignored ) {
286+ return null ;
287+ }
288+ }
289+ return null ;
290+ }
130291}
0 commit comments