Skip to content

Commit e129e13

Browse files
committed
Update heads support to 1.20.6
1 parent aba41bf commit e129e13

File tree

2 files changed

+60
-39
lines changed

2 files changed

+60
-39
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,5 +267,10 @@
267267
<artifactId>commons-lang3</artifactId>
268268
<version>3.14.0</version>
269269
</dependency>
270+
<dependency>
271+
<groupId>com.googlecode.json-simple</groupId>
272+
<artifactId>json-simple</artifactId>
273+
<version>1.1.1</version>
274+
</dependency>
270275
</dependencies>
271276
</project>

src/main/java/dev/espi/protectionstones/utils/BlockUtil.java

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,17 @@
2727
import org.bukkit.entity.Entity;
2828
import org.bukkit.inventory.ItemStack;
2929
import org.bukkit.inventory.meta.SkullMeta;
30+
import org.bukkit.profile.PlayerProfile;
31+
import org.bukkit.profile.PlayerTextures;
3032

33+
import java.net.MalformedURLException;
34+
import java.net.URL;
3135
import java.util.HashMap;
3236
import java.util.UUID;
37+
import java.util.Base64;
38+
import org.json.simple.JSONObject;
39+
import org.json.simple.parser.JSONParser;
40+
import org.json.simple.parser.ParseException;
3341

3442
public class BlockUtil {
3543
static final int MAX_USERNAME_LENGTH = 16;
@@ -117,19 +125,54 @@ public static void setHeadType(String psType, Block b) {
117125
}
118126
}
119127

128+
public static PlayerProfile getProfile(String uuid, String base64) {
129+
String name = uuid.substring(0, 16);
130+
PlayerProfile profile = Bukkit.getServer().createPlayerProfile(UUID.fromString(uuid), name);
131+
PlayerTextures textures = profile.getTextures();
132+
133+
// decode base64 to URL
134+
byte[] decodedBytes = Base64.getDecoder().decode(base64);
135+
String decodedString = new String(decodedBytes);
136+
137+
// read decoded string as JSON object
138+
// sample: {"textures":{"SKIN":{"url":"http://textures.minecraft.net/texture/..."}}}
139+
String url = "";
140+
try {
141+
JSONParser parser = new JSONParser();
142+
JSONObject object = (JSONObject) parser.parse(decodedString);
143+
JSONObject jsonTextures = (JSONObject) object.get("textures");
144+
JSONObject jsonSkin = (JSONObject) jsonTextures.get("SKIN");
145+
url = (String) jsonSkin.get("url");
146+
} catch (ParseException exception) {
147+
throw new RuntimeException("Invalid JSON retrieved from base64 " + decodedString, exception);
148+
}
149+
150+
URL urlObject;
151+
try {
152+
urlObject = new URL(url);
153+
} catch (MalformedURLException exception) {
154+
throw new RuntimeException("Invalid decoded URL from head data: " + url, exception);
155+
}
156+
157+
textures.setSkin(urlObject);
158+
profile.setTextures(textures);
159+
return profile;
160+
}
161+
120162
public static ItemStack setHeadType(String psType, ItemStack item) {
121163
String name = psType.split(":")[1];
122164
if (name.length() > MAX_USERNAME_LENGTH) { // base 64 head
123165
String uuid = name;
124166

125-
// if 1.16 or above, use new uuid format
126-
if (Integer.parseInt(MiscUtil.getVersionString().split("\\.")[1]) >= 16 || !MiscUtil.getVersionString().split("\\.")[0].equals("1")) {
127-
uuid = MiscUtil.getUniqueIdIntArray(UUID.fromString(uuid));
128-
} else { // quotes are needed for pre 1.16 uuids
129-
uuid = "\"" + uuid + "\"";
130-
}
167+
// decode base64 to URL
168+
String base64 = uuidToBase64Head.get(name);
169+
PlayerProfile profile = getProfile(uuid, base64);
170+
171+
SkullMeta meta = (SkullMeta) item.getItemMeta();
172+
meta.setOwnerProfile(profile);
173+
item.setItemMeta(meta);
131174

132-
return Bukkit.getUnsafe().modifyItemStack(item, "{SkullOwner:{Name:\"" + name + "\",Id:" + uuid + ",Properties:{textures:[{Value:\"" + uuidToBase64Head.get(name) + "\"}]}}}");
175+
return item;
133176
} else { // normal name head
134177
SkullMeta sm = (SkullMeta) item.getItemMeta();
135178
sm.setOwningPlayer(Bukkit.getOfflinePlayer(name));
@@ -138,40 +181,13 @@ public static ItemStack setHeadType(String psType, ItemStack item) {
138181
}
139182
}
140183

141-
// Note: this code is really weird
142184
private static void blockWithBase64(Block block, String uuid) {
143-
String base64 = uuidToBase64Head.get(uuid), args;
144-
145-
// if 1.16 or above, use new uuid format
146-
if (Integer.parseInt(MiscUtil.getVersionString().split("\\.")[1]) >= 16 || !MiscUtil.getVersionString().split("\\.")[0].equals("1")) {
147-
uuid = MiscUtil.getUniqueIdIntArray(UUID.fromString(uuid));
148-
args = String.format(
149-
"%d %d %d %s",
150-
block.getX(),
151-
block.getY(),
152-
block.getZ(),
153-
"{SkullOwner:{Name:\"" + uuid + "\",Id:" + uuid + ",Properties:{textures:[{Value:\"" + base64 + "\"}]}}}"
154-
);
155-
} else { // tag was different pre 1.16
156-
args = String.format(
157-
"%d %d %d %s",
158-
block.getX(),
159-
block.getY(),
160-
block.getZ(),
161-
"{Owner:{Name:\"" + uuid + "\",Id:\"" + uuid + "\",Properties:{textures:[{Value:\"" + base64 + "\"}]}}}"
162-
);
163-
}
164-
165-
// fake entity to run command at its location
166-
Entity e = block.getWorld().spawn(new Location(block.getWorld(), 0, 0, 0), ArmorStand.class, ent -> {
167-
ent.setCustomName("mrpig");
168-
ent.setInvulnerable(true);
169-
ent.setVisible(false);
170-
});
185+
String base64 = uuidToBase64Head.get(uuid);
186+
PlayerProfile profile = getProfile(uuid, base64);
171187

172-
// run data command to change block using the pig's world
173-
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "execute at @e[type=armor_stand,nbt={CustomName:'{\"extra\":[{\"text\":\"" + e.getName() + "\"}],\"text\":\"\"}'}] run data merge block " + args);
174-
e.remove();
188+
Skull skull = (Skull) block.getState();
189+
skull.setOwnerProfile(profile);
190+
skull.update(false);
175191
}
176192

177193
public static boolean isBase64PSHead(String type) {

0 commit comments

Comments
 (0)