1+ package com .kd_gaming1 .commands ;
2+
3+ import com .kd_gaming1 .copysystem .ZipArchiver ;
4+ import com .mojang .brigadier .CommandDispatcher ;
5+ import com .mojang .brigadier .arguments .StringArgumentType ;
6+ import com .mojang .brigadier .context .CommandContext ;
7+ import com .mojang .brigadier .exceptions .CommandSyntaxException ;
8+ import net .fabricmc .loader .api .FabricLoader ;
9+ import net .minecraft .server .command .CommandManager ;
10+ import net .minecraft .server .command .ServerCommandSource ;
11+ import net .minecraft .text .Text ;
12+
13+ import java .io .File ;
14+ import java .nio .file .Path ;
15+ import java .util .ArrayList ;
16+ import java .util .List ;
17+ import java .util .concurrent .CompletableFuture ;
18+
19+ /**
20+ * Command to create ZIP archives of selected Minecraft files and folders.
21+ * Usage: /packcore archive <preset|folder_name> [filename]
22+ * Presets: vanilla-configs, mod-configs, all-configs
23+ */
24+ public class ArchiveCommand {
25+
26+ public static void register (CommandDispatcher <ServerCommandSource > dispatcher ) {
27+ dispatcher .register (CommandManager .literal ("packcore" )
28+ .then (CommandManager .literal ("archive" )
29+ .then (CommandManager .argument ("target" , StringArgumentType .word ())
30+ .suggests ((context , builder ) -> {
31+ // Auto-complete suggestions for presets
32+ String [] presets = {"vanilla-configs" , "mod-configs" , "all-configs" };
33+ for (String preset : presets ) {
34+ builder .suggest (preset );
35+ }
36+ // Could also suggest common folder names
37+ String [] commonFolders = {"config" , "resourcepacks" , "shaderpacks" , "screenshots" };
38+ for (String folder : commonFolders ) {
39+ builder .suggest (folder );
40+ }
41+ return builder .buildFuture ();
42+ })
43+ .executes (context -> executeArchive (context , null ))
44+ .then (CommandManager .argument ("filename" , StringArgumentType .greedyString ())
45+ .executes (context -> executeArchive (context ,
46+ StringArgumentType .getString (context , "filename" )))))));
47+ }
48+
49+ private static int executeArchive (CommandContext <ServerCommandSource > context , String customFilename )
50+ throws CommandSyntaxException {
51+
52+ String target = StringArgumentType .getString (context , "target" );
53+ ServerCommandSource source = context .getSource ();
54+
55+ // Send initial message
56+ source .sendFeedback (() -> Text .literal ("§6Starting archive creation for: §e" + target ), false );
57+
58+ // Run archive creation asynchronously to avoid blocking the game thread
59+ CompletableFuture .runAsync (() -> {
60+ try {
61+ createArchive (source , target , customFilename );
62+ } catch (Exception e ) {
63+ source .sendFeedback (() -> Text .literal ("§cError creating archive: " + e .getMessage ()), false );
64+ e .printStackTrace ();
65+ }
66+ });
67+
68+ return 1 ;
69+ }
70+
71+ private static void createArchive (ServerCommandSource source , String target , String customFilename ) {
72+ File minecraftRoot = FabricLoader .getInstance ().getGameDir ().toFile ();
73+ File skyblockFolder = new File (minecraftRoot , "Skyblock Enhanced" );
74+ File customConfigFolder = new File (skyblockFolder , "CustomConfigs" );
75+
76+ // Ensure CustomConfigs folder exists
77+ if (!customConfigFolder .exists ()) {
78+ customConfigFolder .mkdirs ();
79+ }
80+
81+ // Generate filename if not provided
82+ String filename = customFilename != null ? customFilename : generateFilename (target );
83+ if (!filename .endsWith (".zip" )) {
84+ filename += ".zip" ;
85+ }
86+
87+ // Get paths based on target (preset or folder name)
88+ List <Path > pathsToArchive = getPathsForTarget (target , minecraftRoot , source );
89+
90+ if (pathsToArchive .isEmpty ()) {
91+ source .sendFeedback (() -> Text .literal ("§cNo valid paths found for: " + target ), false );
92+ return ;
93+ }
94+
95+ // Create the archive
96+ source .sendFeedback (() -> Text .literal ("§6Creating archive with " + pathsToArchive .size () + " items..." ), false );
97+
98+ boolean success = ZipArchiver .createZipArchive (
99+ filename ,
100+ customConfigFolder .getAbsolutePath (),
101+ pathsToArchive ,
102+ minecraftRoot ,
103+ new ZipArchiver .ArchiveProgressListener () {
104+ private int lastReportedProgress = 0 ;
105+
106+ @ Override
107+ public void onProgress (int percentComplete ) {
108+ // Report progress every 20%
109+ if (percentComplete >= lastReportedProgress + 20 ) {
110+ lastReportedProgress = percentComplete ;
111+ source .sendFeedback (() -> Text .literal ("§6Archive progress: §e" + percentComplete + "%" ), false );
112+ }
113+ }
114+ }
115+ );
116+
117+ if (success ) {
118+ String finalFilename = filename ;
119+ source .sendFeedback (() -> Text .literal ("§aArchive created successfully: §f" + finalFilename ), false );
120+ source .sendFeedback (() -> Text .literal ("§aLocation: §f" + customConfigFolder .getAbsolutePath ()), false );
121+ } else {
122+ source .sendFeedback (() -> Text .literal ("§cFailed to create archive. Check console for errors." ), false );
123+ }
124+ }
125+
126+ private static List <Path > getPathsForTarget (String target , File minecraftRoot , ServerCommandSource source ) {
127+ List <Path > paths = new ArrayList <>();
128+ Path rootPath = minecraftRoot .toPath ();
129+
130+ switch (target .toLowerCase ()) {
131+ case "vanilla-configs" :
132+ // Vanilla Minecraft configuration files
133+ addIfExists (paths , rootPath .resolve ("options.txt" ), source );
134+ addIfExists (paths , rootPath .resolve ("servers.dat" ), source );
135+ break ;
136+
137+ case "mod-configs" :
138+ // Only the config folder (mod configurations)
139+ addIfExists (paths , rootPath .resolve ("config" ), source );
140+ break ;
141+
142+ case "all-configs" :
143+ // Both vanilla and mod configs
144+ addIfExists (paths , rootPath .resolve ("options.txt" ), source );
145+ addIfExists (paths , rootPath .resolve ("servers.dat" ), source );
146+ addIfExists (paths , rootPath .resolve ("config" ), source );
147+ break ;
148+
149+ default :
150+ // Treat as folder name
151+ Path targetPath = rootPath .resolve (target );
152+ if (targetPath .toFile ().exists ()) {
153+ paths .add (targetPath );
154+ source .sendFeedback (() -> Text .literal ("§6Found folder: §e" + target ), false );
155+ } else {
156+ source .sendFeedback (() -> Text .literal ("§cFolder not found: §e" + target ), false );
157+ }
158+ break ;
159+ }
160+
161+ return paths ;
162+ }
163+
164+ private static void addIfExists (List <Path > paths , Path path , ServerCommandSource source ) {
165+ if (path .toFile ().exists ()) {
166+ paths .add (path );
167+ source .sendFeedback (() -> Text .literal ("§6Found: §e" + path .getFileName ()), false );
168+ } else {
169+ source .sendFeedback (() -> Text .literal ("§7Skipped (not found): §e" + path .getFileName ()), false );
170+ }
171+ }
172+
173+ private static String generateFilename (String target ) {
174+ String timestamp = String .valueOf (System .currentTimeMillis ());
175+ return target .replace ("-" , "_" ) + "_backup_" + timestamp ;
176+ }
177+ }
0 commit comments