33import com .google .common .collect .ImmutableMap ;
44import com .mojang .brigadier .Command ;
55import com .mojang .brigadier .CommandDispatcher ;
6+ import com .mojang .brigadier .arguments .DoubleArgumentType ;
67import com .mojang .brigadier .arguments .StringArgumentType ;
8+ import com .mojang .brigadier .builder .RequiredArgumentBuilder ;
79import com .mojang .brigadier .builder .LiteralArgumentBuilder ;
8- import com .mojang .brigadier .arguments .DoubleArgumentType ;
910import com .mojang .brigadier .context .CommandContext ;
1011import com .mojang .brigadier .exceptions .CommandSyntaxException ;
1112import com .mojang .brigadier .exceptions .DynamicCommandExceptionType ;
1718import dev .xpple .seedmapper .config .Configs ;
1819import dev .xpple .seedmapper .render .RenderManager ;
1920import dev .xpple .seedmapper .render .esp .EspStyle ;
20- import dev .xpple .seedmapper .seedmap .SeedMapScreen ;
2121import net .fabricmc .fabric .api .client .command .v2 .FabricClientCommandSource ;
22- import net .minecraft .client .Minecraft ;
2322import net .minecraft .commands .SharedSuggestionProvider ;
2423import net .minecraft .network .chat .Component ;
2524
@@ -48,48 +47,49 @@ private EspConfigCommand() {
4847 private static final SimpleCommandExceptionType INVALID_COLOR = new SimpleCommandExceptionType (Component .literal ("Invalid color. Use hex, e.g. #RRGGBB or #AARRGGBB." ));
4948 private static final DynamicCommandExceptionType UNKNOWN_PROPERTY = new DynamicCommandExceptionType (value -> Component .literal ("Unknown ESP property \" " + value + "\" ." ));
5049 private static final DynamicCommandExceptionType UNKNOWN_TARGET = new DynamicCommandExceptionType (value -> Component .literal ("Unknown ESP target \" " + value + "\" ." ));
51- private static final SimpleCommandExceptionType MAP_SIZE_UNAVAILABLE = new SimpleCommandExceptionType ( Component . literal ( "Unable to determine seed map size. Make sure the game window is open." )) ;
50+ private static final double DEFAULT_ESP_TIMEOUT_MINUTES = 5.0D ;
5251 private static final List <String > PROPERTY_SUGGESTIONS = Arrays .stream (EspProperty .values ())
5352 .map (EspProperty ::displayName )
5453 .toList ();
55- private static final double MIN_ZOOM_BLOCKS = 128.0D ;
56- private static final double MAX_ZOOM_BLOCKS = 100_000.0D ;
5754
5855 public static void register (CommandDispatcher <FabricClientCommandSource > dispatcher ) {
5956 CommandNode <FabricClientCommandSource > cconfigRoot = dispatcher .getRoot ().getChild ("cconfig" );
6057 if (cconfigRoot == null ) {
61- // If the BetterConfig client command isn't present, register a direct sm:config fallback
58+ // BetterConfig client command not present: register direct fallback.
6259 registerDirectSmConfig (dispatcher );
6360 return ;
6461 }
62+
6563 CommandNode <FabricClientCommandSource > modRoot = cconfigRoot .getChild (SeedMapper .MOD_ID );
6664 if (modRoot == null ) {
67- // fallback to direct registration if mod -specific cconfig node missing
65+ // Mod -specific cconfig node missing: register direct fallback.
6866 registerDirectSmConfig (dispatcher );
6967 return ;
7068 }
7169
72- // Use a single target argument that accepts any case but suggests TitleCase names
73- com .mojang .brigadier .builder .RequiredArgumentBuilder <FabricClientCommandSource , String > targetArgNode = argument ("target" , StringArgumentType .word ())
74- .suggests (EspConfigCommand ::suggestTargets );
75- targetArgNode .then (literal ("get" )
76- .executes (ctx -> executeGet (ctx , getTargetArgument (ctx , "target" ), null ))
77- .then (argument ("property" , StringArgumentType .word ())
78- .suggests (EspConfigCommand ::suggestProperties )
79- .executes (ctx -> executeGet (ctx , getTargetArgument (ctx , "target" ), getPropertyArgument (ctx , "property" )))));
80- targetArgNode .then (literal ("set" )
81- .then (argument ("pairs" , StringArgumentType .greedyString ())
82- .executes (ctx -> executeSet (ctx , getTargetArgument (ctx , "target" )))));
83- targetArgNode .then (literal ("reset" )
84- .executes (ctx -> executeReset (ctx , getTargetArgument (ctx , "target" ))));
85- modRoot .addChild (targetArgNode .build ());
86- modRoot .addChild (buildZoomLiteral ("Zoom" ).build ());
70+ modRoot .addChild (buildEspLiteral ("ESP" ).build ());
71+ ZoomConfigCommand .register (modRoot );
8772 }
8873
8974 private static void registerDirectSmConfig (CommandDispatcher <FabricClientCommandSource > dispatcher ) {
9075 LiteralArgumentBuilder <FabricClientCommandSource > smRoot = literal ("sm:config" );
91- // single target argument for sm:config that suggests TitleCase but accepts any case when typed
92- com .mojang .brigadier .builder .RequiredArgumentBuilder <FabricClientCommandSource , String > targetArgNode = argument ("target" , StringArgumentType .word ())
76+ smRoot .then (buildEspLiteral ("ESP" ));
77+ ZoomConfigCommand .register (smRoot );
78+ dispatcher .register (smRoot );
79+ }
80+
81+ private static LiteralArgumentBuilder <FabricClientCommandSource > buildEspLiteral (String literalName ) {
82+ LiteralArgumentBuilder <FabricClientCommandSource > espLiteral = literal (literalName );
83+ espLiteral .then (literal ("Timeout" )
84+ .then (literal ("get" )
85+ .executes (EspConfigCommand ::executeTimeoutGet ))
86+ .then (literal ("set" )
87+ .then (argument ("minutes" , DoubleArgumentType .doubleArg (0.0 ))
88+ .executes (ctx -> executeTimeoutSet (ctx , DoubleArgumentType .getDouble (ctx , "minutes" )))))
89+ .then (literal ("reset" )
90+ .executes (ctx -> executeTimeoutSet (ctx , DEFAULT_ESP_TIMEOUT_MINUTES ))));
91+
92+ RequiredArgumentBuilder <FabricClientCommandSource , String > targetArgNode = argument ("target" , StringArgumentType .word ())
9393 .suggests (EspConfigCommand ::suggestTargets );
9494 targetArgNode .then (literal ("get" )
9595 .executes (ctx -> executeGet (ctx , getTargetArgument (ctx , "target" ), null ))
@@ -101,95 +101,24 @@ private static void registerDirectSmConfig(CommandDispatcher<FabricClientCommand
101101 .executes (ctx -> executeSet (ctx , getTargetArgument (ctx , "target" )))));
102102 targetArgNode .then (literal ("reset" )
103103 .executes (ctx -> executeReset (ctx , getTargetArgument (ctx , "target" ))));
104- smRoot .then (targetArgNode );
105- smRoot .then (buildZoomLiteral ("Zoom" ));
106- // esptimeout top-level alias
107- smRoot .then (literal ("esptimeout" )
108- .executes (ctx -> {
109- CustomClientCommandSource source = CustomClientCommandSource .of (ctx .getSource ());
110- source .sendFeedback (Component .literal ("EspTimeoutMinutes = " + Configs .EspTimeoutMinutes ));
111- return 1 ;
112- })
113- .then (argument ("minutes" , DoubleArgumentType .doubleArg (0.0 ))
114- .executes (ctx -> {
115- double minutes = DoubleArgumentType .getDouble (ctx , "minutes" );
116- Configs .EspTimeoutMinutes = minutes ;
117- Configs .save ();
118- RenderManager .setHighlightTimeout (Configs .EspTimeoutMinutes );
119- CustomClientCommandSource .of (ctx .getSource ()).sendFeedback (Component .literal ("Updated EspTimeoutMinutes = " + minutes ));
120- return 1 ;
121- })));
122- dispatcher .register (smRoot );
104+ espLiteral .then (targetArgNode );
105+ return espLiteral ;
123106 }
124107
125- private static LiteralArgumentBuilder <FabricClientCommandSource > buildZoomLiteral (String literalName ) {
126- LiteralArgumentBuilder <FabricClientCommandSource > zoom = literal (literalName );
127- zoom .then (literal ("get" )
128- .executes (EspConfigCommand ::executeZoomGet ));
129- zoom .then (literal ("set" )
130- .then (argument ("blocks" , DoubleArgumentType .doubleArg (MIN_ZOOM_BLOCKS , MAX_ZOOM_BLOCKS ))
131- .executes (ctx -> executeZoomSet (ctx , DoubleArgumentType .getDouble (ctx , "blocks" )))));
132- zoom .then (literal ("default" )
133- .executes (EspConfigCommand ::executeZoomDefault ));
134- return zoom ;
135- }
136-
137- private static int executeZoomGet (CommandContext <FabricClientCommandSource > ctx ) throws CommandSyntaxException {
108+ private static int executeTimeoutGet (CommandContext <FabricClientCommandSource > ctx ) {
138109 CustomClientCommandSource source = CustomClientCommandSource .of (ctx .getSource ());
139- double minPixels = Math .max (SeedMapScreen .MIN_PIXELS_PER_BIOME , Configs .SeedMapMinPixelsPerBiome );
140- double blocks = computeBlocksForMinPixels (minPixels );
141- source .sendFeedback (Component .literal (String .format (Locale .ROOT , "Max zoom-out ≈ %,.0f blocks at current GUI scale (min pixels per biome %.4f)." , blocks , minPixels )));
110+ source .sendFeedback (Component .literal ("ESP.timeout = " + Configs .EspTimeoutMinutes ));
142111 return Command .SINGLE_SUCCESS ;
143112 }
144113
145- private static int executeZoomSet (CommandContext <FabricClientCommandSource > ctx , double requestedBlocks ) throws CommandSyntaxException {
146- CustomClientCommandSource source = CustomClientCommandSource .of (ctx .getSource ());
147- double minPixels = convertBlocksToMinPixels (requestedBlocks );
148- double clamped = Math .clamp (minPixels , SeedMapScreen .MIN_PIXELS_PER_BIOME , SeedMapScreen .MAX_PIXELS_PER_BIOME );
149- Configs .SeedMapMinPixelsPerBiome = clamped ;
150- Configs .PixelsPerBiome = Math .max (Configs .PixelsPerBiome , clamped );
114+ private static int executeTimeoutSet (CommandContext <FabricClientCommandSource > ctx , double minutes ) {
115+ Configs .EspTimeoutMinutes = minutes ;
151116 Configs .save ();
152- double blocks = computeBlocksForMinPixels ( clamped );
153- source . sendFeedback ( Component . literal ( String . format ( Locale . ROOT , "Max zoom-out updated to ≈ %,.0f blocks at current GUI scale (min pixels per biome %.4f)." , blocks , clamped ) ));
117+ RenderManager . setHighlightTimeout ( Configs . EspTimeoutMinutes );
118+ CustomClientCommandSource . of ( ctx . getSource ()). sendFeedback ( Component . literal ( "Updated ESP.timeout = " + minutes ));
154119 return Command .SINGLE_SUCCESS ;
155120 }
156121
157- private static int executeZoomDefault (CommandContext <FabricClientCommandSource > ctx ) throws CommandSyntaxException {
158- CustomClientCommandSource source = CustomClientCommandSource .of (ctx .getSource ());
159- double defaultMin = SeedMapScreen .DEFAULT_MIN_PIXELS_PER_BIOME ;
160- Configs .SeedMapMinPixelsPerBiome = defaultMin ;
161- Configs .PixelsPerBiome = Math .max (Configs .PixelsPerBiome , defaultMin );
162- Configs .save ();
163- double blocks = computeBlocksForMinPixels (defaultMin );
164- source .sendFeedback (Component .literal (String .format (Locale .ROOT , "Max zoom-out reset to ≈ %,.0f blocks at current GUI scale (min pixels per biome %.4f)." , blocks , defaultMin )));
165- return Command .SINGLE_SUCCESS ;
166- }
167-
168- private static double convertBlocksToMinPixels (double blocks ) throws CommandSyntaxException {
169- int widthPixels = currentSeedMapWidthPixels ();
170- if (widthPixels <= 0 ) {
171- throw MAP_SIZE_UNAVAILABLE .create ();
172- }
173- return (widthPixels * SeedMapScreen .BIOME_SCALE ) / blocks ;
174- }
175-
176- private static double computeBlocksForMinPixels (double minPixelsPerBiome ) throws CommandSyntaxException {
177- int widthPixels = currentSeedMapWidthPixels ();
178- if (widthPixels <= 0 ) {
179- throw MAP_SIZE_UNAVAILABLE .create ();
180- }
181- double safeMin = Math .max (minPixelsPerBiome , SeedMapScreen .MIN_PIXELS_PER_BIOME );
182- return (widthPixels * SeedMapScreen .BIOME_SCALE ) / safeMin ;
183- }
184-
185- private static int currentSeedMapWidthPixels () {
186- Minecraft minecraft = Minecraft .getInstance ();
187- if (minecraft == null || minecraft .getWindow () == null ) {
188- return 0 ;
189- }
190- return SeedMapScreen .computeSeedMapWidth (minecraft .getWindow ().getGuiScaledWidth ());
191- }
192-
193122 private static int executeGet (CommandContext <FabricClientCommandSource > ctx , EspTarget target , EspProperty property ) {
194123 CustomClientCommandSource source = CustomClientCommandSource .of (ctx .getSource ());
195124 EspStyle style = target .style ();
0 commit comments