/* * Minecraft Forge * Copyright (c) 2016-2018. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package net.minecraftforge.common; import java.io.BufferedReader; import java.io.IOException; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.UUID; import javax.annotation.Nullable; import com.google.common.base.Charsets; import net.minecraftforge.fml.loading.FMLLoader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.google.common.collect.ImmutableMap; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; /** * Caches player's last known usernames *

* Modders should use {@link #getLastKnownUsername(UUID)} to determine a players * last known username.
* For convenience, {@link #getMap()} is provided to get an immutable copy of * the caches underlying map. */ public final class UsernameCache { private static Map map = new HashMap<>(); private static final Path saveFile = FMLLoader.getGamePath().resolve("usernamecache.json"); private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); private static final Logger LOGGER = LogManager.getLogger(UsernameCache.class); private static final Marker USRCACHE = MarkerManager.getMarker("USERNAMECACHE"); private UsernameCache() {} /** * Set a player's current usernamee * * @param uuid * the player's {@link java.util.UUID UUID} * @param username * the player's username */ protected static void setUsername(UUID uuid, String username) { Objects.requireNonNull(uuid); Objects.requireNonNull(username); if (username.equals(map.get(uuid))) return; map.put(uuid, username); save(); } /** * Remove a player's username from the cache * * @param uuid * the player's {@link java.util.UUID UUID} * @return if the cache contained the user */ protected static boolean removeUsername(UUID uuid) { Objects.requireNonNull(uuid); if (map.remove(uuid) != null) { save(); return true; } return false; } /** * Get the player's last known username *

* May be null * * @param uuid * the player's {@link java.util.UUID UUID} * @return the player's last known username, or null if the * cache doesn't have a record of the last username */ @Nullable public static String getLastKnownUsername(UUID uuid) { Objects.requireNonNull(uuid); return map.get(uuid); } /** * Check if the cache contains the given player's username * * @param uuid * the player's {@link java.util.UUID UUID} * @return if the cache contains a username for the given player */ public static boolean containsUUID(UUID uuid) { Objects.requireNonNull(uuid); return map.containsKey(uuid); } /** * Get an immutable copy of the cache's underlying map * * @return the map */ public static Map getMap() { return ImmutableMap.copyOf(map); } /** * Save the cache to file */ protected static void save() { new SaveThread(gson.toJson(map)).start(); } /** * Load the cache from file */ protected static void load() { if (!Files.exists(saveFile)) return; try (final BufferedReader reader = Files.newBufferedReader(saveFile, Charsets.UTF_8)) { @SuppressWarnings("serial") Type type = new TypeToken>(){}.getType(); map = gson.fromJson(reader, type); } catch (JsonSyntaxException | IOException e) { LOGGER.error(USRCACHE,"Could not parse username cache file as valid json, deleting file {}", saveFile, e); try { Files.delete(saveFile); } catch (IOException e1) { LOGGER.error(USRCACHE,"Could not delete file {}", saveFile.toString()); } } finally { // Can sometimes occur when the json file is malformed if (map == null) { map = new HashMap<>(); } } } /** * Used for saving the {@link com.google.gson.Gson#toJson(Object) Gson} * representation of the cache to disk */ private static class SaveThread extends Thread { /** The data that will be saved to disk */ private final String data; public SaveThread(String data) { this.data = data; } @Override public void run() { try { // Make sure we don't save when another thread is still saving synchronized (saveFile) { Files.write(saveFile, data.getBytes(StandardCharsets.UTF_8)); } } catch (IOException e) { LOGGER.error(USRCACHE, "Failed to save username cache to file!", e); } } } }