-
Notifications
You must be signed in to change notification settings - Fork 0
/
SkinManager.java
271 lines (239 loc) · 10.1 KB
/
SkinManager.java
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
package com.github.mafelp.minecraft.skins;
import com.github.mafelp.utils.Logging;
import com.github.mafelp.utils.Settings;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.entity.Player;
import javax.imageio.ImageIO;
import javax.net.ssl.HttpsURLConnection;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.Base64;
import static com.github.mafelp.utils.Logging.info;
import static com.github.mafelp.utils.Settings.debug;
/**
* Skin Manager used for managing getting skins from Mojang, saving them and getting head
* images for the user avatar in Discord Messages.
*/
public class SkinManager {
/**
* Sets the file extension for skin files to .png
*/
private static final String fileExtension = ".png";
/**
* Checks the skin and head directories and creates them if they don't exist
* @return return success state, if all directories are present
*/
private static boolean checkDirectories() {
// Checks if main directory exists
if (!Settings.getConfigurationFileDirectory().exists()) {
boolean success = Settings.getConfigurationFileDirectory().mkdirs();
// Processes the result of the making of the directories
if (success)
Settings.minecraftServer.getLogger().info(Settings.prefix +
"Successfully created directory " + Settings.getConfigurationFileDirectory().getAbsolutePath());
else {
Settings.minecraftServer.getLogger().warning(Settings.prefix +
"Could not create directory " + Settings.getConfigurationFileDirectory().getAbsolutePath());
return false;
}
}
File headsDirectory = new File(Settings.getConfigurationFileDirectory(), "heads/");
File skinsDirectory = new File(Settings.getConfigurationFileDirectory(), "skins/");
// Check directory for head images
if (!checkSubFolder(headsDirectory)) return false;
// Check and return directory for skin images
return checkSubFolder(skinsDirectory);
}
/**
* Checks if a folder exists and if not creates it. - Only used in checkDirectories()
* @param directoryToCheck The File of the directory which to check and create
* @return the present state of the directory
*/
private static boolean checkSubFolder(File directoryToCheck) {
// When the directory does not exists
if (!directoryToCheck.exists()) {
boolean success = directoryToCheck.mkdirs();
// Processes the result of the making of the directories
if (success) {
Settings.minecraftServer.getLogger().info(Settings.prefix +
"Successfully created directory " + directoryToCheck.getAbsolutePath());
return true;
}
else {
Settings.minecraftServer.getLogger().warning(Settings.prefix +
"Could not create directory " + directoryToCheck.getAbsolutePath());
return false;
}
}
return true;
}
/**
* Create a new BufferedImage in the boundaries of the head of a Minecraft Skin
* @param inputImage the image to crop
* @return a sub-image with boundaries (x=8, y=8, width=8, height=8)
*/
protected static BufferedImage getHead(BufferedImage inputImage) {
return inputImage.getSubimage(8, 8, 8, 8);
}
/**
* Returns the image of a file
* @param skinFile The file from which the image to get
* @return The image of the input file
*/
protected static BufferedImage getSkinFromFile(File skinFile) {
// Check the directories
if (!checkDirectories()) {
Settings.minecraftServer.getLogger().warning(Settings.prefix + "Error while checking skin directories");
return null;
}
// Returns the image of an error
try {
return ImageIO.read(skinFile);
} catch (IOException ioException) {
Logging.logIOException(ioException, "Something went wrong whilst trying to load th skin.");
}
return null;
}
/**
* Gets the according skin from the Mojang libraries - this should only be used by Skin.java!
* - this should only be used by Skin.java!
* @param player The player to get the skin of
* @return the skin
*/
protected static BufferedImage getSkinFromMojang(Player player) {
// Check the directories before downloading the image from Mojang
if (!checkDirectories()) {
Settings.minecraftServer.getLogger().warning(Settings.prefix + "Error while checking skin directories");
return null;
}
// Try to download the skin
try {
if (debug)
info("Getting the URL for player " + player.getDisplayName());
URL skinUrl = new URL(getSkinUrl(player.getUniqueId().toString()));
// Read the skin from the URL and return he image
if (debug)
info("Reading the skin file in.");
return ImageIO.read(skinUrl);
} catch (IOException e) {
Logging.logIOException(e, "Something went wrong whilst trying to download th skin.");
}
return null;
}
/**
* Saves an image to a folder
* @param image The image to save to a file
* @param folder the folder in which the image should be saved
* @param imageName the name of the image
* @return Returns the file in which the image was saved
*/
protected static File saveImage(BufferedImage image, File folder, String imageName) {
// Check the directories before saving
if (!checkDirectories()) {
Settings.minecraftServer.getLogger().warning(Settings.prefix + "Error while checking skin directories");
return null;
}
// Try to save the file
try {
// Creates the skin file to return in the end
File skinFile = new File(folder, imageName + fileExtension);
if (debug)
info("Creating skin file" + skinFile.getAbsolutePath());
if (debug)
info("Writing the skin to the file.");
// Write the image to the file
ImageIO.write(image, "png", skinFile);
// Return the file
return skinFile;
} catch (IOException e) {
Logging.logIOException(e, "Error while trying to save skin image.");
return null;
}
}
/**
* Gets the JSON Data from an URL
* @param link the link to get the data from
* @return the data
*/
private static String getContent(String link) {
try {
if (debug)
info("Establishing a connection to Mojang's servers");
// Creates a URL from String
URL url = new URL(link);
// Establishes a https connection
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// Create the reader to read the information from given URL
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder outputLine = new StringBuilder();
if (debug)
info("Reading response");
String inputLine;
// read all the lines Mojang's API responded
while ((inputLine = br.readLine()) != null) {
outputLine.append(inputLine);
}
// After reading everything, close the reader
br.close();
if (debug)
info("Response is: " + outputLine.toString());
// Return the JSON Data
return outputLine.toString();
} catch (IOException e) {
Logging.logIOException(e, "Error while trying to save skin image.");
return null;
}
}
/**
* JSON Parser used to interpret JSOn Data
*/
private static final JsonParser parser = new JsonParser();
/**
* Gets the URL of a minecraft player UUID
* @param uuid the UUID to get the URL from
* @return the url as a String
*/
private static String getSkinUrl(String uuid) {
// Gets the Data of the profile
String json = getContent("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid);
assert json != null;
JsonObject o = parser.parse(json).getAsJsonObject();
// Decoding field "value" of the JSON data
if (debug)
info("Decoding field \"value\"...");
// Get the value data
String jsonBase64 = o.get("properties").getAsJsonArray().get(0).getAsJsonObject().get("value").getAsString();
// Decode it and write it to bytes
byte[] decodedBytes = Base64.getDecoder().decode(jsonBase64);
// Create a new string from the bytes
String decoded = new String(decodedBytes);
if (debug)
info("Decoded content is: " + decoded);
// Get the decoded data (also JSON) as a JSON object
o = parser.parse(decoded).getAsJsonObject();
// Gets the value of the field "textures.SKIN.url"
String out = o.get("textures").getAsJsonObject().get("SKIN").getAsJsonObject().get("url").getAsString();
if (debug)
info("Skin url is: " + out);
// Returns the skin URL
return out;
}
/**
* Gets the File with the corresponding player skin in it
* @param player The player whose skin to grab
* @return The file which contains the player's skin
*/
protected static File getSkinFile(Player player) {
return new File(Settings.getConfigurationFileDirectory(), "skins/" + player.getDisplayName() + fileExtension);
}
/**
* Gets the file with the player's head in it
* @param player The player to grab the head of.
* @return The file which contains the player's head
*/
protected static File getHeadFile(Player player) {
return new File(Settings.getConfigurationFileDirectory(), "heads/" + player.getDisplayName() + fileExtension);
}
}