package in.twizmwaz.cardinal.repository; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import in.twizmwaz.cardinal.Cardinal; import in.twizmwaz.cardinal.GameHandler; import in.twizmwaz.cardinal.match.Match; import in.twizmwaz.cardinal.module.modules.header.HeaderModule; import in.twizmwaz.cardinal.repository.exception.RotationLoadException; import in.twizmwaz.cardinal.repository.repositories.DefaultRepository; import in.twizmwaz.cardinal.repository.repositories.FileRepository; import in.twizmwaz.cardinal.repository.repositories.GitRepository; import in.twizmwaz.cardinal.repository.repositories.Repository; import in.twizmwaz.cardinal.util.CollectionUtils; import in.twizmwaz.cardinal.util.Config; import in.twizmwaz.cardinal.util.Contributor; import in.twizmwaz.cardinal.util.MojangUtil; import in.twizmwaz.cardinal.util.Strings; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.ConcurrentModificationException; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; public class RepositoryManager { private Rotation rotation = new Rotation(); private List<Repository> repos = Lists.newArrayList(); public void setupRotation() throws RotationLoadException { try { refreshRepos(); } catch (IOException e) { throw new RotationLoadException("Could not access the repository. Make sure java has sufficient read and write privileges."); } refreshRotation(); } /** * Refreshes the maps in the repository and the data associated with them * * @throws RotationLoadException */ public void refreshRepos() throws RotationLoadException, IOException { List<Repository> newRepos = Lists.newArrayList(new DefaultRepository()); for (String repo : Config.repos) { if (repo.startsWith("git:")) { newRepos.add(GitRepository.fromURL(repo.replaceFirst("git:", ""))); } else { newRepos.add(new FileRepository(repo)); } } repos = CollectionUtils.update(repos, newRepos).collect(Collectors.toList()); // Reload maps inside the repos for (Repository repo : repos) repo.refreshRepo(); updatePlayers(); if (!getLoadedStream().findFirst().isPresent()) throw new RotationLoadException("No maps were loaded. Are there any maps in the repositories?"); } /** * Refreshes the plugin's default rotation */ public void refreshRotation() throws RotationLoadException { try { rotation.refreshRotation(getLoadedStream()); } catch (RotationLoadException | IOException e) { Bukkit.getLogger().log(Level.WARNING, e.getMessage()); Bukkit.getLogger().log(Level.WARNING, "Failed to load rotation file, using a temporary rotation instead."); rotation.add(getLoadedStream().findFirst().get()); } } public static RepositoryManager get() { return GameHandler.getGameHandler().getRepositoryManager(); } /** * @return Returns the rotation */ public Rotation getRotation() { return rotation; } public Iterable<LoadedMap> getLoadedIterable() { return () -> getLoadedStream().iterator(); } public Stream<LoadedMap> getLoadedStream() { return repos.stream().flatMap(repository -> repository.getLoaded().stream()); } public List<Repository> getRepos() { return repos; } public int getMapSize() { return repos.stream().mapToInt(repo -> repo.getLoaded().size()).sum(); } public Repository getRepo(LoadedMap map) { return repos.stream().filter(repository -> repository.getLoaded().contains(map)).findFirst().orElse(null); } /** * @param string The name of map to be searched for * @return The map */ public List<LoadedMap> getMap(String string) { return getLoadedStream().filter(map -> Strings.matchString(map.getName(), string)).collect(Collectors.toList()); } /** * @param id The id of map to be searched for * @return The map */ public LoadedMap getMap(int id) { return getLoadedStream().filter(map -> map.getId() == id).findFirst().orElse(null); } /*public class LoadedMapIterator implements Iterator<LoadedMap> { private final Queue<Repository> repoQueue = new LinkedList<>(repos); private Iterator<LoadedMap> currIter = null; private LoadedMap nextMap = null; @Override public boolean hasNext() { return this.nextMap != null || setNext(); } @Override public LoadedMap next() { if (!hasNext()) { throw new NoSuchElementException(); } LoadedMap next = this.nextMap; this.nextMap = null; setNext(); return next; } private boolean setNext() { while (true) { if (currIter == null) { if (repoQueue.isEmpty()) return false; if (!repoQueue.isEmpty()) currIter = repoQueue.poll().getLoaded().iterator(); } else if (currIter.hasNext()) { this.nextMap = currIter.next(); return true; } else if (!repoQueue.isEmpty()) { currIter = repoQueue.poll().getLoaded().iterator(); } else { currIter = null; } } } @Override public void remove() { throw new UnsupportedOperationException(); } }*/ private void updatePlayers() { Bukkit.getScheduler().runTaskAsynchronously(Cardinal.getInstance(), new PlayerNameUpdater()); } private class PlayerNameUpdater implements Runnable { @Override public void run() { try { Bukkit.getLogger().log(Level.INFO, "Setting known map author names."); Map<UUID, String> names; try { names = (Map<UUID, String>) new ObjectInputStream(new FileInputStream(new File(Cardinal.getInstance().getDataFolder().getPath() + "/.names.ser"))).readObject(); } catch (FileNotFoundException | ClassCastException e) { names = Maps.newHashMap(); } for (LoadedMap map : getLoadedIterable()) { List<Contributor> contributors = new ArrayList<>(); contributors.addAll(map.getAuthors()); contributors.addAll(map.getContributors()); for (Contributor contributor : contributors) { if (contributor.getName() == null && contributor.getUniqueId() != null) { if (!names.containsKey(contributor.getUniqueId())) names.put(contributor.getUniqueId(), "Unknown"); contributor.setName(names.get(contributor.getUniqueId())); } } } Bukkit.getLogger().log(Level.INFO, "Updating map author names."); List<UUID> requested = Lists.newArrayList(); for (LoadedMap map : getLoadedIterable()) { List<Contributor> contributors = new ArrayList<>(); contributors.addAll(map.getAuthors()); contributors.addAll(map.getContributors()); for (Contributor contributor : contributors) { if (contributor.getUniqueId() == null) continue; if (requested.contains(contributor.getUniqueId())) { contributor.setName(names.get(contributor.getUniqueId())); } else { OfflinePlayer player = Bukkit.getOfflinePlayer(contributor.getUniqueId()); if (player != null && player.getLastPlayed() + 180000 > System.currentTimeMillis()) { names.put(contributor.getUniqueId(), player.getName()); } else { String name = MojangUtil.getName(contributor.getUniqueId()); if (name != null) { names.put(contributor.getUniqueId(), name); requested.add(contributor.getUniqueId()); } } contributor.setName(names.get(contributor.getUniqueId())); } } Match match = GameHandler.getGameHandler().getMatch(); if (match != null && map.equals(match.getLoadedMap())) match.getModules().getModule(HeaderModule.class).updateAll(HeaderModule.HeaderPart.HEADER); } ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(Cardinal.getInstance().getDataFolder().getPath() + "/.names.ser"))); out.writeObject(names); out.close(); Bukkit.getLogger().log(Level.INFO, "Finished updating map author names."); } catch (IOException | ClassNotFoundException | ConcurrentModificationException e) { e.printStackTrace(); } } } }