Java tutorial
/* * Copyright (C) 2017 The MC-Prison Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package tech.mcprison.prison.ranks.data; import com.google.gson.internal.LinkedTreeMap; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import tech.mcprison.prison.ranks.PrisonRanks; import tech.mcprison.prison.ranks.RankUtil; import tech.mcprison.prison.store.Document; /** * A certain sequence that rank-ups will follow. There may be multiple rank ladders on the server at * a time, and one rank may be a part of multiple ladders. * * @author Faizaan A. Datoo */ public class RankLadder { /* * Fields & Constants */ public int id; public String name; public List<PositionRank> ranks; public int maxPrestige; /* * Document-related */ public RankLadder() { } public RankLadder(Document document) { this.id = RankUtil.doubleToInt(document.get("id")); this.name = (String) document.get("name"); List<LinkedTreeMap<String, Object>> ranksLocal = (List<LinkedTreeMap<String, Object>>) document .get("ranks"); this.ranks = new ArrayList<>(); for (LinkedTreeMap<String, Object> rank : ranksLocal) { ranks.add(new PositionRank(RankUtil.doubleToInt(rank.get("position")), RankUtil.doubleToInt((rank.get("rankId"))))); } } public Document toDocument() { Document ret = new Document(); ret.put("id", this.id); ret.put("name", this.name); ret.put("ranks", this.ranks); ret.put("maxPrestige", this.maxPrestige); return ret; } /* * Methods */ /** * Add a rank to this ladder. * * @param position The place in line to put this rank, beginning at 0. The player will be taken * through each rank by order of their positions in the ladder. * @param rank The {@link Rank} to add. */ public void addRank(int position, Rank rank) { position = Math.min(position, ranks.size() + 1); // Make sure to cap it off at the upper limit or else problems int finalPosition = position; ranks.stream().filter(positionRank -> positionRank.getPosition() >= finalPosition) .forEach(positionRank -> positionRank.setPosition(positionRank.getPosition() + 1)); ranks.add(new PositionRank(position, rank.id)); } /** * Add a rank to this ladder. The rank's position will be set to the next available position * (i.e. at the end of the ladder). * * @param rank The {@link Rank} to add. */ public void addRank(Rank rank) { ranks.add(new PositionRank(getNextAvailablePosition(), rank.id)); } /** * Removes a rank from this ladder. * * @param position The position of the rank to be removed. The positions of the rest of the * ranks will be downshifted to fill the gap. */ public void removeRank(int position) { ranks.stream().filter(positionRank -> positionRank.getPosition() > position) .forEach(positionRank -> positionRank.setPosition(positionRank.getPosition() - 1)); Iterator<PositionRank> iter = ranks.iterator(); while (iter.hasNext()) { PositionRank rank = iter.next(); if (rank.getPosition() == position) { iter.remove(); break; } } } /** * Orders the ranks in the rank list of this ladder by their position, in ascending order. */ public void orderRanksByPosition() { ranks.sort(Comparator.comparingInt(PositionRank::getPosition)); } /* * Getters & Setters */ /** * Returns true if this ladder contains a rank with a specified ID. * * @param rankId The ID of the rank to search for. * @return True if the rank was found, false otherwise. */ public boolean containsRank(int rankId) { return ranks.stream().anyMatch(rank -> rank.getRankId() == rankId); } /** * Returns the position of the specified {@link Rank} in this ladder. * * @param rank The {@link Rank} to retrieve the position of. * @return The position of the rank, or -1 if the rank was not found. */ public int getPositionOfRank(Rank rank) { for (PositionRank rankEntry : ranks) { if (rankEntry.getRankId() == rank.id) { return rankEntry.getPosition(); } } return -1; } /** * Returns the next highest rank in the ladder. * * @param after The position of the current rank. * @return An optional containing either the rank if there is a next rank in the ladder, or * empty if there isn't or if the rank does not exist anymore. */ public Optional<Rank> getNext(int after) { List<Integer> positions = ranks.stream().map(PositionRank::getPosition).sorted() .collect(Collectors.toList()); int newIndex = positions.indexOf(after) + 1; if (newIndex >= positions.size()) { return Optional.empty(); } int nextPosition = positions.get(newIndex); return getByPosition(nextPosition); } /** * Returns the next lowest rank in the ladder. * * @param before The position of the current rank. * @return An optional containing either the rank if there is a previous rank in the ladder, or * empty if there isn't or if the rank does not exist anymore. */ public Optional<Rank> getPrevious(int before) { List<Integer> positions = ranks.stream().map(PositionRank::getPosition).sorted() .collect(Collectors.toList()); int newIndex = positions.indexOf(before) - 1; if (newIndex >= positions.size()) { return Optional.empty(); } int previousPosition = positions.get(newIndex); return getByPosition(previousPosition); } /** * Searches for and returns a rank in the ladder, depending on the position in the ladder. * * @param position The position to search for. * @return An optional containing the rank if it was found, or empty if it wasn't. */ public Optional<Rank> getByPosition(int position) { for (PositionRank posRank : ranks) { if (posRank.getPosition() == position) { return PrisonRanks.getInstance().getRankManager().getRank(posRank.getRankId()); } } return Optional.empty(); } // This next method is sort of precautionary. Sure, positions start at 0, but if the user decides to be crazy // and alters the position within the data files, we need to make sure we adjust accordingly. Never trust // editable data! /** * Finds the lowest rank present in this ladder. It does so by checking to see which position is the lowest. * * @return The rank option, or an empty optional if there are no ranks in this ladder. */ public Optional<Rank> getLowestRank() { if (ranks.isEmpty()) return Optional.empty(); PositionRank lowest = ranks.get(0); for (PositionRank posRank : ranks) { if (posRank.getPosition() < lowest.getPosition()) { lowest = posRank; } } return PrisonRanks.getInstance().getRankManager().getRank(lowest.getRankId()); } /** * Returns the next available position for a rank, by finding the highest one. * * @return The open position. */ private int getNextAvailablePosition() { if (ranks.size() == 0) { return 0; // obviously, if it's empty, we want to start at the bottom } orderRanksByPosition(); return ranks.get(ranks.size() - 1).getPosition() + 1; } /* * equals() and hashCode() */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof RankLadder)) { return false; } RankLadder that = (RankLadder) o; return id == that.id && name.equals(that.name); } @Override public int hashCode() { int result = id; result = 31 * result + name.hashCode(); return result; } public class PositionRank { private int position; private int rankId; public PositionRank(int position, int rankId) { this.position = position; this.rankId = rankId; } public int getPosition() { return position; } public void setPosition(int position) { this.position = position; } public int getRankId() { return rankId; } public void setRankId(int rankId) { this.rankId = rankId; } } }