Crop and reorder skull textures to eliminate unused space

Should reduce memory & storage usage for Bedrock clients
This commit is contained in:
davchoo 2022-07-27 22:32:18 -04:00
parent 8244afa8c7
commit 15fd5353e1
No known key found for this signature in database
GPG key ID: A0168C8E45799B7D
5 changed files with 127 additions and 32 deletions

View file

@ -53,7 +53,7 @@ import java.util.zip.ZipOutputStream;
public class SkullResourcePackManager { public class SkullResourcePackManager {
private static final long RESOURCE_PACK_VERSION = 6; private static final long RESOURCE_PACK_VERSION = 9;
private static final Path SKULL_SKIN_CACHE_PATH = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("player_skulls"); private static final Path SKULL_SKIN_CACHE_PATH = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("player_skulls");
@ -112,21 +112,24 @@ public class SkullResourcePackManager {
} }
BufferedImage image = SkinProvider.requestImage(skinUrl, null); BufferedImage image = SkinProvider.requestImage(skinUrl, null);
if (image.getHeight() != 64) { // Resize skins to 48x16 to save on space and memory
// We have to resize legacy skins to 64x64 for them to be displayed properly BufferedImage skullTexture = new BufferedImage(48, 16, image.getType());
BufferedImage modernSkin = new BufferedImage(64, 64, image.getType()); // Reorder skin parts to fit into the space
// Right, Front, Left, Back, Top, Bottom - head
// Right, Front, Left, Back, Top, Bottom - hat
Graphics g = skullTexture.createGraphics();
// Right, Front, Left, Back of the head
g.drawImage(image, 0, 0, 32, 8, 0, 8, 32, 16, null);
// Right, Front, Left, Back of the hat
g.drawImage(image, 0, 8, 32, 16, 32, 8, 64, 16, null);
// Top and bottom of the head
g.drawImage(image, 32, 0, 48, 8, 8, 0, 24, 8, null);
// Top and bottom of the hat
g.drawImage(image, 32, 8, 48, 16, 40, 0, 56, 8, null);
g.dispose();
image.flush();
Graphics g = modernSkin.createGraphics(); ImageIO.write(skullTexture, "png", skinPath.toFile());
g.drawImage(image, 0, 0, null);
g.setColor(new Color(0, 0, 0, 0));
g.fillRect(0, 32, 64, 32);
g.dispose();
image.flush();
image = modernSkin;
}
ImageIO.write(image, "png", skinPath.toFile());
SKULL_SKINS.put(skinHash, skinPath); SKULL_SKINS.put(skinHash, skinPath);
GeyserImpl.getInstance().getLogger().debug("Cached player skull to " + skinPath + " for " + skinHash); GeyserImpl.getInstance().getLogger().debug("Cached player skull to " + skinPath + " for " + skinHash);
} }

View file

@ -4,8 +4,8 @@
{ {
"description": { "description": {
"identifier": "geometry.geyser.player_skull", "identifier": "geometry.geyser.player_skull",
"texture_width": 64, "texture_width": 48,
"texture_height": 64 "texture_height": 16
}, },
"bones": [ "bones": [
{ {
@ -33,7 +33,18 @@
"parent": "root_z", "parent": "root_z",
"pivot": [0, 24, 0], "pivot": [0, 24, 0],
"cubes": [ "cubes": [
{"origin": [-4, 8, -4], "size": [8, 8, 8], "uv": [0, 0]} {
"origin": [-4, 8, -4],
"size": [8, 8, 8],
"uv": {
"north": {"uv": [8, 0], "uv_size": [8, 8]},
"east": {"uv": [0, 0], "uv_size": [8, 8]},
"south": {"uv": [24, 0], "uv_size": [8, 8]},
"west": {"uv": [16, 0], "uv_size": [8, 8]},
"up": {"uv": [32, 0], "uv_size": [8, 8]},
"down": {"uv": [40, 8], "uv_size": [8, -8]}
}
}
] ]
}, },
{ {
@ -41,10 +52,22 @@
"parent": "player_skull", "parent": "player_skull",
"pivot": [0, 24, 0], "pivot": [0, 24, 0],
"cubes": [ "cubes": [
{"origin": [-4, 8, -4], "size": [8, 8, 8], "uv": [32, 0], "inflate": 0.25} {
"origin": [-4, 8, -4],
"size": [8, 8, 8],
"inflate": 0.25,
"uv": {
"north": {"uv": [8, 8], "uv_size": [8, 8]},
"east": {"uv": [0, 8], "uv_size": [8, 8]},
"south": {"uv": [24, 8], "uv_size": [8, 8]},
"west": {"uv": [16, 8], "uv_size": [8, 8]},
"up": {"uv": [32, 8], "uv_size": [8, 8]},
"down": {"uv": [40, 16], "uv_size": [8, -8]}
}
}
] ]
} }
] ]
} }
] ]
} }

View file

@ -4,8 +4,8 @@
{ {
"description": { "description": {
"identifier": "geometry.geyser.player_skull_floor_${quadrant}", "identifier": "geometry.geyser.player_skull_floor_${quadrant}",
"texture_width": 64, "texture_width": 48,
"texture_height": 64 "texture_height": 16
}, },
"bones": [ "bones": [
{ {
@ -13,7 +13,18 @@
"pivot": [0, 24, 0], "pivot": [0, 24, 0],
"rotation": [0, ${y_rotation}, 0], "rotation": [0, ${y_rotation}, 0],
"cubes": [ "cubes": [
{"origin": [-4, 0.5, -4], "size": [8, 8, 8], "uv": [0, 0]} {
"origin": [-4, 0.5, -4],
"size": [8, 8, 8],
"uv": {
"north": {"uv": [8, 0], "uv_size": [8, 8]},
"east": {"uv": [0, 0], "uv_size": [8, 8]},
"south": {"uv": [24, 0], "uv_size": [8, 8]},
"west": {"uv": [16, 0], "uv_size": [8, 8]},
"up": {"uv": [32, 0], "uv_size": [8, 8]},
"down": {"uv": [40, 8], "uv_size": [8, -8]}
}
}
] ]
}, },
{ {
@ -21,7 +32,19 @@
"parent": "head", "parent": "head",
"pivot": [0, 24, 0], "pivot": [0, 24, 0],
"cubes": [ "cubes": [
{"origin": [-4, 0.5, -4], "size": [8, 8, 8], "uv": [32, 0], "inflate": 0.5} {
"origin": [-4, 0.5, -4],
"size": [8, 8, 8],
"inflate": 0.5,
"uv": {
"north": {"uv": [8, 8], "uv_size": [8, 8]},
"east": {"uv": [0, 8], "uv_size": [8, 8]},
"south": {"uv": [24, 8], "uv_size": [8, 8]},
"west": {"uv": [16, 8], "uv_size": [8, 8]},
"up": {"uv": [32, 8], "uv_size": [8, 8]},
"down": {"uv": [40, 16], "uv_size": [8, -8]}
}
}
] ]
} }
] ]

View file

@ -4,15 +4,26 @@
{ {
"description": { "description": {
"identifier": "geometry.geyser.player_skull_hand", "identifier": "geometry.geyser.player_skull_hand",
"texture_width": 64, "texture_width": 48,
"texture_height": 64 "texture_height": 16
}, },
"bones": [ "bones": [
{ {
"name": "head", "name": "head",
"pivot": [0, 24, 0], "pivot": [0, 24, 0],
"cubes": [ "cubes": [
{"origin": [-4, 4, -4], "size": [8, 8, 8], "uv": [0, 0]} {
"origin": [-4, 4, -4],
"size": [8, 8, 8],
"uv": {
"north": {"uv": [8, 0], "uv_size": [8, 8]},
"east": {"uv": [0, 0], "uv_size": [8, 8]},
"south": {"uv": [24, 0], "uv_size": [8, 8]},
"west": {"uv": [16, 0], "uv_size": [8, 8]},
"up": {"uv": [32, 0], "uv_size": [8, 8]},
"down": {"uv": [40, 8], "uv_size": [8, -8]}
}
}
] ]
}, },
{ {
@ -20,7 +31,19 @@
"parent": "head", "parent": "head",
"pivot": [0, 24, 0], "pivot": [0, 24, 0],
"cubes": [ "cubes": [
{"origin": [-4, 4, -4], "size": [8, 8, 8], "uv": [32, 0], "inflate": 0.5} {
"origin": [-4, 4, -4],
"size": [8, 8, 8],
"inflate": 0.5,
"uv": {
"north": {"uv": [8, 8], "uv_size": [8, 8]},
"east": {"uv": [0, 8], "uv_size": [8, 8]},
"south": {"uv": [24, 8], "uv_size": [8, 8]},
"west": {"uv": [16, 8], "uv_size": [8, 8]},
"up": {"uv": [32, 8], "uv_size": [8, 8]},
"down": {"uv": [40, 16], "uv_size": [8, -8]}
}
}
] ]
} }
] ]

View file

@ -4,15 +4,26 @@
{ {
"description": { "description": {
"identifier": "geometry.geyser.player_skull_wall", "identifier": "geometry.geyser.player_skull_wall",
"texture_width": 64, "texture_width": 48,
"texture_height": 64 "texture_height": 16
}, },
"bones": [ "bones": [
{ {
"name": "head", "name": "head",
"pivot": [0, 24, 0], "pivot": [0, 24, 0],
"cubes": [ "cubes": [
{"origin": [-4, 4, -0.5], "size": [8, 8, 8], "uv": [0, 0]} {
"origin": [-4, 4, -0.5],
"size": [8, 8, 8],
"uv": {
"north": {"uv": [8, 0], "uv_size": [8, 8]},
"east": {"uv": [0, 0], "uv_size": [8, 8]},
"south": {"uv": [24, 0], "uv_size": [8, 8]},
"west": {"uv": [16, 0], "uv_size": [8, 8]},
"up": {"uv": [32, 0], "uv_size": [8, 8]},
"down": {"uv": [40, 8], "uv_size": [8, -8]}
}
}
] ]
}, },
{ {
@ -20,7 +31,19 @@
"parent": "head", "parent": "head",
"pivot": [0, 24, 0], "pivot": [0, 24, 0],
"cubes": [ "cubes": [
{"origin": [-4, 4, -0.5], "size": [8, 8, 8], "uv": [32, 0], "inflate": 0.5} {
"origin": [-4, 4, -0.5],
"size": [8, 8, 8],
"inflate": 0.5,
"uv": {
"north": {"uv": [8, 8], "uv_size": [8, 8]},
"east": {"uv": [0, 8], "uv_size": [8, 8]},
"south": {"uv": [24, 8], "uv_size": [8, 8]},
"west": {"uv": [16, 8], "uv_size": [8, 8]},
"up": {"uv": [32, 8], "uv_size": [8, 8]},
"down": {"uv": [40, 16], "uv_size": [8, -8]}
}
}
] ]
} }
] ]