Skip to content

Commit

Permalink
Support caching of skins to disk based on configuration variable
Browse files Browse the repository at this point in the history
If a skin is downloaded it will be saved to `cache/skins` using a base64 encoded filename of the textureUrl, if allowed by setting a non 0 value for the configuration variable `cache-skins`

When reading a skin we try load it from a cache file first before trying to download it.

We don't yet expire them but do update their last modification so we know which ones have been accessed.
  • Loading branch information
bundabrg committed Jun 3, 2020
1 parent af7fd9e commit e1fe62d
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,4 @@ config.yml
logs/
public-key.pem
locales/
cache/
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ public boolean isCacheChunks() {
return true; // We override this as with Bukkit, we have direct access to the server implementation
}

@Override
public int getCacheSkins() {
return config.getInt("cache-skins", 0);
}

@Override
public boolean isAboveBedrockNetherBuilding() {
return config.getBoolean("above-bedrock-nether-building", false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ public boolean isCacheChunks() {
return config.getBoolean("cache-chunks", false);
}

@Override
public int getCacheSkins() {
return config.getInt("cache-skins", 0);
}

@Override
public boolean isAboveBedrockNetherBuilding() {
return config.getBoolean("above-bedrock-nether-building", false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ public boolean isCacheChunks() {
return node.getNode("cache-chunks").getBoolean(false);
}

@Override
public int getCacheSkins() {
return node.getNode("cache-skins").getInt(0);
}

@Override
public boolean isAboveBedrockNetherBuilding() {
return node.getNode("above-bedrock-nether-building").getBoolean(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration {
@JsonProperty("cache-chunks")
private boolean cacheChunks;

@JsonProperty(value = "cache-skins", defaultValue = "0")
private int cacheSkins;

@JsonProperty("above-bedrock-nether-building")
private boolean isAboveBedrockNetherBuilding;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,12 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration {
@JsonProperty("default-locale")
private String defaultLocale;

@JsonProperty("cache-chunks")
@JsonProperty(value = "cache-chunks")
private boolean cacheChunks;

@JsonProperty(value = "cache-skins", defaultValue = "0")
private int cacheSkins;

@JsonProperty("above-bedrock-nether-building")
private boolean aboveBedrockNetherBuilding;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ public interface GeyserConfiguration {

boolean isCacheChunks();

int getCacheSkins();

IMetricsInfo getMetrics();

interface IBedrockConfiguration {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;
Expand Down Expand Up @@ -285,11 +289,33 @@ public static void storeEarGeometry(UUID playerID, boolean isSlim) {
}

private static Skin supplySkin(UUID uuid, String textureUrl) {
byte[] skin = EMPTY_SKIN.getSkinData();
// First see if we have a cached file
Path skinFile = Paths.get("cache", "skins", Base64.getEncoder().encodeToString(textureUrl.getBytes()));
try {
skin = requestImage(textureUrl, null);
Files.setLastModifiedTime(skinFile, FileTime.fromMillis(System.currentTimeMillis()));
GeyserConnector.getInstance().getLogger().debug("Reading cached skin from file " + skinFile.toString() + " for " + textureUrl);
return new Skin(uuid, textureUrl, Files.readAllBytes(skinFile), System.currentTimeMillis(), false, false);
} catch (IOException ignored) {}

try {
byte[] skin = requestImage(textureUrl, null);

// Write cache if we are allowed
if (GeyserConnector.getInstance().getConfig().getCacheSkins() > 0) {
//noinspection ResultOfMethodCallIgnored
skinFile.getParent().toFile().mkdirs();
try {
Files.write(skinFile, skin);
GeyserConnector.getInstance().getLogger().debug("Writing cached skin to file " + skinFile.toString() + " for " + textureUrl);
} catch (IOException e) {
GeyserConnector.getInstance().getLogger().error("Failed to write cached skin to file " + skinFile.toString() + " for " + textureUrl);
}
}

return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false, false);
} catch (Exception ignored) {} // just ignore I guess
return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false, false);

return new Skin(uuid, "empty", EMPTY_SKIN.getSkinData(), System.currentTimeMillis(), false, false);
}

private static Cape supplyCape(String capeUrl, CapeProvider provider) {
Expand Down

0 comments on commit e1fe62d

Please sign in to comment.