1212import com .mojang .brigadier .exceptions .SimpleCommandExceptionType ;
1313import com .mojang .brigadier .suggestion .Suggestions ;
1414import com .mojang .brigadier .tree .CommandNode ;
15+ import dev .xpple .seedmapper .SeedMapper ;
1516import dev .xpple .seedmapper .command .CustomClientCommandSource ;
1617import dev .xpple .seedmapper .config .Configs ;
17- import dev .xpple .seedmapper .render .esp .EspStyle ;
1818import dev .xpple .seedmapper .render .RenderManager ;
19- import dev .xpple .seedmapper .SeedMapper ;
19+ import dev .xpple .seedmapper .render .esp .EspStyle ;
20+ import dev .xpple .seedmapper .seedmap .SeedMapScreen ;
2021import net .fabricmc .fabric .api .client .command .v2 .FabricClientCommandSource ;
22+ import net .minecraft .client .Minecraft ;
2123import net .minecraft .commands .SharedSuggestionProvider ;
2224import net .minecraft .network .chat .Component ;
2325
@@ -46,9 +48,12 @@ private EspConfigCommand() {
4648 private static final SimpleCommandExceptionType INVALID_COLOR = new SimpleCommandExceptionType (Component .literal ("Invalid color. Use hex, e.g. #RRGGBB or #AARRGGBB." ));
4749 private static final DynamicCommandExceptionType UNKNOWN_PROPERTY = new DynamicCommandExceptionType (value -> Component .literal ("Unknown ESP property \" " + value + "\" ." ));
4850 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." ));
4952 private static final List <String > PROPERTY_SUGGESTIONS = Arrays .stream (EspProperty .values ())
5053 .map (EspProperty ::displayName )
5154 .toList ();
55+ private static final double MIN_ZOOM_BLOCKS = 128.0D ;
56+ private static final double MAX_ZOOM_BLOCKS = 100_000.0D ;
5257
5358 public static void register (CommandDispatcher <FabricClientCommandSource > dispatcher ) {
5459 CommandNode <FabricClientCommandSource > cconfigRoot = dispatcher .getRoot ().getChild ("cconfig" );
@@ -78,6 +83,7 @@ public static void register(CommandDispatcher<FabricClientCommandSource> dispatc
7883 targetArgNode .then (literal ("reset" )
7984 .executes (ctx -> executeReset (ctx , getTargetArgument (ctx , "target" ))));
8085 modRoot .addChild (targetArgNode .build ());
86+ modRoot .addChild (buildZoomLiteral ().build ());
8187 }
8288
8389 private static void registerDirectSmConfig (CommandDispatcher <FabricClientCommandSource > dispatcher ) {
@@ -96,6 +102,7 @@ private static void registerDirectSmConfig(CommandDispatcher<FabricClientCommand
96102 targetArgNode .then (literal ("reset" )
97103 .executes (ctx -> executeReset (ctx , getTargetArgument (ctx , "target" ))));
98104 smRoot .then (targetArgNode );
105+ smRoot .then (buildZoomLiteral ());
99106 // esptimeout top-level alias
100107 smRoot .then (literal ("esptimeout" )
101108 .executes (ctx -> {
@@ -115,6 +122,74 @@ private static void registerDirectSmConfig(CommandDispatcher<FabricClientCommand
115122 dispatcher .register (smRoot );
116123 }
117124
125+ private static LiteralArgumentBuilder <FabricClientCommandSource > buildZoomLiteral () {
126+ LiteralArgumentBuilder <FabricClientCommandSource > zoom = literal ("Zoom" );
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 {
138+ 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 )));
142+ return Command .SINGLE_SUCCESS ;
143+ }
144+
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 );
151+ 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 )));
154+ return Command .SINGLE_SUCCESS ;
155+ }
156+
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+
118193 private static int executeGet (CommandContext <FabricClientCommandSource > ctx , EspTarget target , EspProperty property ) {
119194 CustomClientCommandSource source = CustomClientCommandSource .of (ctx .getSource ());
120195 EspStyle style = target .style ();
0 commit comments