/******************************************************************************* * Copyright 2014 Tobias Welther * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package de.tobiyas.racesandclasses.datacontainer.traitholdercontainer; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.bukkit.Bukkit; import de.tobiyas.racesandclasses.RacesAndClasses; import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.exceptions.HolderConfigParseException; import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.exceptions.HolderParsingException; import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.exceptions.HolderTraitParseException; import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.permissionsettings.PermissionRegisterer; import de.tobiyas.racesandclasses.eventprocessing.events.holderevent.HolderSelectedEvent; import de.tobiyas.racesandclasses.playermanagement.player.RaCPlayer; import de.tobiyas.racesandclasses.saving.PlayerSavingData; import de.tobiyas.racesandclasses.saving.PlayerSavingManager; import de.tobiyas.racesandclasses.traitcontainer.interfaces.markerinterfaces.Trait; import de.tobiyas.util.config.YAMLConfigExtended; import de.tobiyas.util.file.FileUtils; public abstract class AbstractHolderManager { /** * The Map of Members Member -> Container. */ protected Map<RaCPlayer, AbstractTraitHolder> memberList; /** * The Set of all Known Trait Holders. */ protected Set<AbstractTraitHolder> traitHolderList; /** * The old file to convert from. */ protected final File oldFile; /** * The Folder for the Holder (lol it ryms :D) */ protected final File folder; /** * The plugin to use. */ protected final RacesAndClasses plugin; /** * Creation of the holders with it's paths to save / load from / to * * @param memberPath * @param traitHolderConfigPath */ public AbstractHolderManager(String traitHolderConfigPath, String folderName){ plugin = RacesAndClasses.getPlugin(); this.folder = new File(RacesAndClasses.getPlugin().getDataFolder(), folderName); this.oldFile = new File(traitHolderConfigPath); memberList = new HashMap<RaCPlayer, AbstractTraitHolder>(); traitHolderList = new HashSet<AbstractTraitHolder>(); } /** * Initializes the Manager */ public void init(){ clearOldTraitholders(); readTraitHolderList(); initDefaultHolder(); setupPermissions(); } /** * Clears the Old Trait-Holders */ private void clearOldTraitholders() { Set<Trait> toDeinit = new HashSet<Trait>(); for(AbstractTraitHolder holder : traitHolderList)toDeinit.addAll(holder.getTraits()); for(Trait trait : toDeinit) trait.deInit(); traitHolderList.clear(); } /** * Here the default holders that the manager always has (without config) should be added. */ protected abstract void initDefaultHolder(); /** * Reads the current Trait Holder list. * This is the corresponding yml file to the TraitHolder. */ protected void readTraitHolderList(){ readTraitHolderListStep1(); readTraitHolderListStep2(); readTraitHolderListStep3(); } protected void readTraitHolderListStep1(){ traitHolderList.clear(); Set<File> files = FileUtils.getAllFiles(folder); if(files.isEmpty()) return; //1st step. Load basic structure. for(File file : files){ YAMLConfigExtended config = new YAMLConfigExtended(file).load(); //check if we have a valid load. if(!config.getValidLoad()){ plugin.log("Could not load " + getConfigPrefix() + " file: " + file.getName() + " because the Synthax is broken."); continue; } for(String holderName : config.getRootChildren()){ AbstractTraitHolder container = generateTraitHolder(config, holderName); if(container != null){ traitHolderList.add(container); } } } } protected void readTraitHolderListStep2(){ //2nd step. load Holder. for(AbstractTraitHolder holder : traitHolderList){ try{ holder.load(); } catch (HolderParsingException exp) { String errorMessage = "Error: "; if(exp instanceof HolderConfigParseException){ errorMessage += "ConfigTotal of: " + holder.getConfigNodeName() + " is mal formated. Please relook synthax!"; }else if(exp instanceof HolderTraitParseException){ HolderTraitParseException rtpe = (HolderTraitParseException) exp; errorMessage = rtpe.getLocalizedMessage(); } plugin.log(errorMessage); } } } protected void readTraitHolderListStep3(){ //3rd step. Read parents. for(AbstractTraitHolder holder : traitHolderList){ holder.readParents(); } } /** * Generates the correct {@link AbstractTraitHolder} for the config and the name. * * @param traitHolderConfig * @param configNodeName * @return */ protected abstract AbstractTraitHolder generateTraitHolder(YAMLConfigExtended traitHolderConfig, String holderName); /** * Returns the name of the correct Holder. * * @param container * @return */ protected abstract String getCorrectFieldFromDBHolder(PlayerHolderAssociation container); /** * Adds a player name to the member list. * Any previous holders is overwritten. * True is returned, if it worked. * If the holders name does not exist, false is returned. * * @param player to add * @param potentialHolder to add the player to * @return if it worked */ public boolean addPlayerToHolder(RaCPlayer player, String potentialHolder, boolean callAfterEvent){ AbstractTraitHolder container = getHolderByName(potentialHolder); if(container == null) return false; memberList.put(player, container); //setting permission group afterwards String groupName = container.getPermissions().getGroupIdentificationName(); PermissionRegisterer.addPlayer(player, groupName); resetPlayerMovementSpeed(player); saveToContainer(player.getPlayerSaveData(), container); if(callAfterEvent){ HolderSelectedEvent event = generateAfterSelectEvent(player, container); plugin.fireEventToBukkit(event); } //Do not forget to do a rescan after Changing Holder! plugin.getPlayerManager().getContainer(player).rescan(); return true; } /** * Saves the Data of the Holder to the Data. * @param data to use. * @param holder to use. */ protected abstract void saveToContainer(PlayerSavingData data, AbstractTraitHolder holder); /** * Generates an Event with the Player that Selected the New TraitHolder. * * @param player that selected * @param newHolder that was selected * * @return the Event */ protected abstract HolderSelectedEvent generateAfterSelectEvent(RaCPlayer player, AbstractTraitHolder newHolder); /** * Generates an Event with the Player that changed from a TraitHolder to a new one. * * @param player that selected * @param newHolder that was selected * @param oldHolder that was changed from * * @return the Event */ protected abstract HolderSelectedEvent generateAfterChangeEvent(RaCPlayer player, AbstractTraitHolder newHolder, AbstractTraitHolder oldHolder); /** * Saves the Holder name to the correct field. * * @param container * @param name */ protected abstract void saveContainerToDBField(PlayerHolderAssociation container, String name); /** * Resets the movement speed of a Player. * The Player is identified by the name. * * @param player to set the speed */ private void resetPlayerMovementSpeed(RaCPlayer player){ if(player != null && player.isOnline()){ player.getPlayer().setWalkSpeed(0.2f); } } /** * Gets the {@link AbstractTraitHolder} for the name passed. * * Null if none found. * * @param configNodeName * @return */ public AbstractTraitHolder getHolderByName(String holderName){ if(holderName == null) return getDefaultHolder(); for(AbstractTraitHolder holder : traitHolderList){ if(holder.getDisplayName().equalsIgnoreCase(holderName) || holder.getConfigNodeName().equals(holderName)){ return holder; } } return null; } /** * This prefix is needed to store / load data to the correct place. * @return */ protected abstract String getConfigPrefix(); /** * Changes the Holder of a player * false is returned if the Holder does not exist. * * @param player to change * @param potentialClass to change to * @param callEvent true if an Changed event chall be called afterwards. * * @return true if worked, false otherwise */ public boolean changePlayerHolder(RaCPlayer player, String newHolderName, boolean callEvent){ if(getHolderByName(newHolderName) == null) return false; AbstractTraitHolder oldHolder = getHolderOfPlayer(player); PermissionRegisterer.removePlayer(player, getContainerTypeAsString()); memberList.remove(player); boolean worked = addPlayerToHolder(player, newHolderName, false); if(callEvent){ AbstractTraitHolder newHolder = getHolderOfPlayer(player); HolderSelectedEvent event = generateAfterChangeEvent(player, newHolder, oldHolder); plugin.fireEventToBukkit(event); } return worked; } /** * Returns the Holder that is associated to a player. * * If the player is not registered, a defaultHolder is returned. * The Player gets the default holders linked if he has none. * * @see #getDefaultHolder() * * @param player * @return */ public AbstractTraitHolder getHolderOfPlayer(RaCPlayer player){ if(player == null) return null; AbstractTraitHolder holder = memberList.get(player); if(holder == null){ PlayerSavingData data = PlayerSavingManager.get().getPlayerData(player.getUniqueId()); holder = getHolder(data); if(holder == null) holder = getDefaultHolder(); memberList.put(player, holder); } return holder; } /** * Gets the holder from the Data. * @param data to use * @return to get. */ protected abstract AbstractTraitHolder getHolder(PlayerSavingData data); /** * This method gets starting Holder. * <br>This is the one specified in the ConfigTotal or the Default TraitHolder. * * @return The holders put into (can be null) */ protected abstract AbstractTraitHolder getStartingHolder(); /** * Returns the default holders for the Manager * * @return */ public abstract AbstractTraitHolder getDefaultHolder(); /** * Returns all names of the holders contained * * @return */ public List<String> getAllHolderNames(){ List<String> holderNameList = new LinkedList<String>(); for(AbstractTraitHolder holder : traitHolderList){ holderNameList.add(holder.getDisplayName()); } return holderNameList; } /** * Returns all players of a holders * * if null is passed, an empty list is returnemd is returned. * * @param configNodeName * @return */ public List<RaCPlayer> getAllPlayersOfHolder(AbstractTraitHolder holder) { if(holder == null){ return new LinkedList<RaCPlayer>(); } List<RaCPlayer> holderMemberList = new LinkedList<RaCPlayer>(); for(RaCPlayer playerUUID : memberList.keySet()){ AbstractTraitHolder toCheckAgainst = memberList.get(playerUUID); if(holder.equals(toCheckAgainst)){ holderMemberList.add(playerUUID); } } return holderMemberList; } /** * Returns all Holders except for the default holders. * * @return */ public List<String> listAllVisibleHolders() { ArrayList<String> holderList = new ArrayList<String>(); for (AbstractTraitHolder container : traitHolderList) { if (!container.equals(getDefaultHolder())) { holderList.add(container.getDisplayName()); } } return holderList; } /** * sets up the Permissions if we have Vault. */ private void setupPermissions() { if(!isVaultUsed()) return; //We need to schedule this to be sure Vault is up and running after startup. Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new PermissionRegisterer(this.traitHolderList, this.memberList, getContainerTypeAsString()), 1); } /** * checks if Vault is used as Permissions system * @return */ private boolean isVaultUsed() { return plugin.getPermissionManager().getPermissionsName().equalsIgnoreCase("Vault"); } /** * Returns the Type of the Container as Name. * This is mostly the word: 'race' or 'class'. */ public abstract String getContainerTypeAsString(); }