-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathRecipeLoader.java
More file actions
224 lines (200 loc) · 7.49 KB
/
RecipeLoader.java
File metadata and controls
224 lines (200 loc) · 7.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package fr.traqueur.recipes.api;
import fr.traqueur.recipes.impl.domains.ItemRecipe;
import fr.traqueur.recipes.impl.domains.recipes.RecipeConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.stream.Stream;
/**
* RecipeLoader allows you to load recipes from multiple sources
* using a fluent API.
*/
public class RecipeLoader {
/**
* The plugin instance
*/
private final Plugin plugin;
/**
* The API instance to register recipes
*/
private final RecipesAPI api;
/**
* List of folders to load recipes from
*/
private final List<File> folders = new ArrayList<>();
/**
* List of individual files to load
*/
private final List<File> files = new ArrayList<>();
/**
* Create a new RecipeLoader
* Can be instantiated via RecipesAPI.createLoader()
* @param plugin The plugin instance
* @param api The RecipesAPI instance
*/
protected RecipeLoader(Plugin plugin, RecipesAPI api) {
this.plugin = plugin;
this.api = api;
}
/**
* Add a folder to load recipes from (recursive)
* The path is relative to the plugin's data folder
* If the folder doesn't exist, it will automatically extract default recipes from the JAR
* @param path The path to the folder
* @return This RecipeLoader instance for chaining
*/
public RecipeLoader addFolder(String path) {
File folder = new File(plugin.getDataFolder(), path);
// If folder doesn't exist, extract defaults from JAR
if (!folder.exists()) {
// Create folder if extraction didn't create it
if (!folder.mkdirs()) {
plugin.getLogger().warning("Could not create folder: " + path);
return this;
}
extractDefaultsFromJar(path);
}
if (!folder.isDirectory()) {
plugin.getLogger().warning("Path is not a folder: " + path);
return this;
}
this.folders.add(folder);
return this;
}
/**
* Add a file to load a recipe from
* The path is relative to the plugin's data folder
* @param path The path to the file
* @return This RecipeLoader instance for chaining
*/
public RecipeLoader addFile(String path) {
File file = new File(plugin.getDataFolder(), path);
if (!file.exists()) {
plugin.getLogger().warning("File does not exist: " + path);
return this;
}
if (!file.isFile()) {
plugin.getLogger().warning("Path is not a file: " + path);
return this;
}
if (!file.getName().endsWith(".yml")) {
plugin.getLogger().warning("File is not a YAML file: " + path);
return this;
}
this.files.add(file);
return this;
}
/**
* Extract default recipes from the JAR to the data folder
* This will scan for .yml files in the specified JAR path and extract them
* if they don't already exist in the data folder
* @param jarPath The path inside the JAR to scan for recipes (e.g., "recipes/")
*/
private void extractDefaultsFromJar(String jarPath) {
if (!jarPath.endsWith("/")) {
jarPath += "/";
}
try {
CodeSource src = plugin.getClass().getProtectionDomain().getCodeSource();
if (src != null) {
URL jar = src.getLocation();
try (JarInputStream jarStream = new JarInputStream(jar.openStream())) {
JarEntry entry;
while ((entry = jarStream.getNextJarEntry()) != null) {
if (entry.getName().startsWith(jarPath) && entry.getName().endsWith(".yml")) {
File outFile = new File(plugin.getDataFolder(), entry.getName());
File parentDir = outFile.getParentFile();
if (parentDir != null && !parentDir.exists() && !parentDir.mkdirs()) {
plugin.getLogger().warning("Could not create directory: " + parentDir.getAbsolutePath());
continue;
}
if (!outFile.exists()) {
plugin.saveResource(entry.getName(), false);
}
}
}
}
}
} catch (IOException e) {
plugin.getLogger().severe("Could not extract default recipes from JAR: " + e.getMessage());
}
}
/**
* Load all recipes from the configured folders and files
* @return The number of recipes loaded
*/
public int load() {
List<ItemRecipe> recipes = new ArrayList<>();
// Load from folders
for (File folder : folders) {
loadFromFolder(folder, recipes);
}
// Load from individual files
for (File file : files) {
loadRecipe(file, recipes);
}
// Sort recipes by priority (higher priority first)
recipes.sort((r1, r2) -> Integer.compare(r2.priority(), r1.priority()));
// Register sorted recipes
for (ItemRecipe recipe : recipes) {
api.addRecipe(recipe);
}
plugin.getLogger().info("Loaded " + recipes.size() + " recipes via RecipeLoader.");
return recipes.size();
}
/**
* Reload all recipes from the configured folders and files
* This will unregister all existing recipes and reload them
* @return The number of recipes loaded
*/
public int reload() {
api.unregisterRecipes();
return load();
}
/**
* Load all recipes from a folder (recursive)
* @param folder The folder to load recipes from
* @param recipes The list to add loaded recipes to
*/
private void loadFromFolder(File folder, List<ItemRecipe> recipes) {
try (Stream<Path> stream = Files.walk(folder.toPath())) {
List<File> ymlFiles = stream.map(Path::toFile)
.filter(File::isFile)
.filter(f -> f.getName().endsWith(".yml"))
.toList();
for (File file : ymlFiles) {
loadRecipe(file, recipes);
}
} catch (IOException exception) {
plugin.getLogger().severe("Could not load recipes from folder " + folder.getAbsolutePath() + ": " + exception.getMessage());
}
}
/**
* Load a recipe from a file
* @param file The file to load the recipe from
* @param recipes The list to add the loaded recipe to
*/
private void loadRecipe(File file, List<ItemRecipe> recipes) {
try {
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file);
ItemRecipe recipe = new RecipeConfiguration(file.getName().replace(".yml", ""), configuration)
.build();
recipes.add(recipe);
} catch (Exception e) {
plugin.getLogger().severe("Could not load recipe from file " + file.getAbsolutePath() + ": " + e.getMessage());
if (api.isDebug()) {
e.printStackTrace();
}
}
}
}