Add leftover Clans commit to introduce GearManager.

This commit is contained in:
Ty Sayers 2015-05-05 15:34:32 -04:00
parent 7567648312
commit 66c9fefc6e
3 changed files with 344 additions and 249 deletions

View File

@ -1,8 +1,8 @@
package mineplex.game.clans;
import org.bukkit.plugin.java.JavaPlugin;
import net.minecraft.server.v1_7_R4.MinecraftServer;
import net.minecraft.server.v1_7_R4.MinecraftServer;
import mineplex.core.account.CoreClientManager;
import mineplex.core.antihack.AntiHack;
import mineplex.core.blockrestore.BlockRestore;
@ -27,6 +27,7 @@ import mineplex.core.teleport.Teleport;
import mineplex.core.updater.FileUpdater;
import mineplex.core.updater.Updater;
import mineplex.game.clans.clans.ClansManager;
import mineplex.game.clans.items.GearManager;
import mineplex.game.clans.shop.building.BuildingShop;
import mineplex.game.clans.shop.pvp.PvpShop;
@ -91,6 +92,8 @@ public class Clans extends JavaPlugin
new BuildingShop(clans, _clientManager, _donationManager);
new PvpShop(clans, _clientManager, _donationManager);
GearManager customGear = new GearManager(this);
//Updates
getServer().getScheduler().scheduleSyncRepeatingTask(this, new Updater(this), 1, 1);

View File

@ -9,208 +9,55 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import mineplex.serverdata.Region;
import mineplex.serverdata.commands.ServerTransfer;
import mineplex.serverdata.commands.TransferCommand;
import mineplex.serverdata.data.DedicatedServer;
import mineplex.serverdata.data.ServerGroup;
import mineplex.serverdata.servers.ConnectionData;
import mineplex.serverdata.servers.ServerManager;
import mineplex.serverdata.servers.ServerRepository;
import mineplex.serverprocesses.GenericRunnable;
import mineplex.serverprocesses.ProcessManager;
import mineplex.serverprocesses.ProcessRunner;
public class Queuer
{
public static final int MIN_QUEUE_WAIT = 0; // The number of seconds required in queue before creating a new match for a party.
private static QueueRepository _repo;
private static ServerRepository _serverRepository;
private static Set<Match> _pendingMatches; // Set of all matches awaiting players
private static int _matchId = 0;
private static int _matchesMade = 0;
private static int _updates = 0;
private static int _partyId = 0;
private static int _serverId = 0;
public static void main (String args[])
{
Region region = (!new File("eu.dat").exists()) ? Region.US : Region.EU;
_serverRepository = ServerManager.getServerRepository(region);
_repo = new QueueRepository(region);
HashMap<Integer, Integer> playerVarianceMap = new HashMap<Integer, Integer>();
HashMap<Integer, Match> playerPrepMatchMap = new HashMap<Integer, Match>();
Set<Match> matches = new HashSet<Match>();
QueuePartySorter partySorter = new QueuePartySorter();
int matchId = 1;
_pendingMatches = new HashSet<Match>();
while (true)
{
int matchesMade = 0;
matchId %= 1500;
{
_updates++;
updateQueuer();
ProcessManager.getInstance().updateProcesses();
List<Integer> assignedMatchIdChecked = new ArrayList<Integer>();
Map<Integer, QueueParty> queueParties = _repo.getMappedQueueParties();
int matchPlayerCount = 2;
System.out.println("Checking " + queueParties.size() + " queues...");
for (QueueParty queueParty : queueParties.values())
{
int partyId = queueParty.getId();
int variance = playerVarianceMap.containsKey(partyId) ? playerVarianceMap.get(partyId) : 0;
variance += 25;
playerVarianceMap.put(partyId, variance);
if (queueParty.hasAssignedMatch())
{
for (Match match : matches)
{
if (Math.abs(match.getAverageElo() - queueParty.getAverageElo()) <= variance)
{
if (playerPrepMatchMap.containsKey(partyId))
{
if (playerPrepMatchMap.get(partyId) == match)
break;
playerPrepMatchMap.get(partyId).quitQueueParty(queueParty);
}
match.joinQueueParty(queueParty);
playerPrepMatchMap.put(partyId, match);
log("Found prep match for '" + queueParty.getId() + "'");
break;
}
}
if (!playerPrepMatchMap.containsKey(partyId))
{
Match match = new Match(matchId++, queueParty.getAverageElo(), queueParty);
playerPrepMatchMap.put(partyId, match);
matches.add(match);
}
}
else if (!assignedMatchIdChecked.contains(queueParty.getAssignedMatch()))
{
int assignedMatchId = queueParty.getAssignedMatch();
log("Checking if match '" + assignedMatchId + "' is ready.");
//List<String> matchStatuses = _repo.getMatchStatuses(queueRecord.AssignedMatch);
Collection<QueueParty> joinedParties = _repo.getJoinedQueueParties(assignedMatchId);
boolean matchReady = true;
boolean matchDeny = false;
for (QueueParty joinedParty : joinedParties)
{
String partyState = joinedParty.getState();
if (partyState.equalsIgnoreCase("Deny"))
{
matchDeny = true;
matchReady = false;
break;
}
else if (!partyState.equalsIgnoreCase("Ready"))
{
matchReady = false;
}
}
if (matchReady)
{
_repo.startMatch(assignedMatchId);
_repo.deleteAssignedParties(assignedMatchId);
System.out.println("Starting match '" + assignedMatchId + "'");
}
else if (matchDeny)
{
_repo.deleteMatch(assignedMatchId);
}
assignedMatchIdChecked.add(assignedMatchId);
}
}
System.out.println("Checking " + matches.size() + " matches...");
// Check for and kick off invites for ready matches
for (Iterator<Match> matchIterator = matches.iterator(); matchIterator.hasNext();)
{
Match match = matchIterator.next();
// Don't give me crap about not using iterator...can't cuz of stupid thing.
Set<QueueParty> partiesToRemove = new HashSet<QueueParty>();
for (QueueParty queueParty : match.getParties())
{
if (!queueParties.containsKey(queueParty.getId()))
{
log("Removing matchStatus : " + queueParty.getId());
partiesToRemove.add(queueParty);
if (match.isWaitingForInvites())
{
_repo.deleteMatch(match.getId());
match.setWaitingForInvites(false);
}
}
}
for (QueueParty party : partiesToRemove)
{
match.quitQueueParty(party);
}
if (match.isWaitingForInvites())
{
if ((match.getWaitDuration()) > 15000)
{
for (QueueParty queueParty : match.getParties())
{
if (!queueParty.getState().equalsIgnoreCase("Ready"))
{
_repo.deleteQueueParty(queueParty.getId());
}
}
_repo.deleteMatch(match.getId());
match.setWaitingForInvites(false);
}
continue;
}
if (match.getPlayerCount() >= matchPlayerCount)
{
List<QueueParty> partyList = new ArrayList<QueueParty>(match.getParties());
Collections.sort(partyList, partySorter);
int playerCount = 0;
for (QueueParty party : partyList)
{
if (playerCount + party.getPlayerCount() > matchPlayerCount)
{
match.quitQueueParty(party);
playerPrepMatchMap.remove(party.getId());
log("Oops hit player cap, can't fit you in this match.");
continue;
}
playerCount += party.getPlayerCount();
}
if (playerCount == matchPlayerCount)
{
log("Sent match invites for '" + match.getId() + "'");
for (QueueParty party : match.getParties())
{
playerPrepMatchMap.remove(party.getId());
_repo.assignMatch(party, match);
}
match.setWaitingForInvites(true);
matchesMade++;
}
}
else if (match.getPlayerCount() == 0)
{
matchIterator.remove();
}
}
log("Total pending matches after update: " + _pendingMatches.size());
log("Total queued parties after update: " + _repo.getQueueParties().size());
try
{
if (matchesMade > 0)
System.out.println("Made " + matchesMade + " matches.");
if (_matchesMade > 0)
System.out.println("Made " + _matchesMade + " matches.");
Thread.sleep(1000);
}
@ -222,6 +69,305 @@ public class Queuer
}
/**
* Tick & update the Queuer as a whole, making one whole pass through all queued players and pending matches to
* assign matches to parties and start matches.
*/
private static void updateQueuer()
{
// Update the status of each queue party, searching for best matchings and assigning matches to parties.
for (QueueParty queueParty : _repo.getQueueParties())
{
updateParty(queueParty);
}
// Update all matches, and remove pending matches if they are finished.
Iterator<Match> iterator = _pendingMatches.iterator();
while (iterator.hasNext())
{
Match match = iterator.next();
boolean matchFinished = updateMatch(match);
// Remove match if it is completed/finished
if (matchFinished) iterator.remove();
}
}
/**
* Update the status of a {@link QueueParty} by attempting to locate the best resulting
* {@code Match} available, or creating a new one if required.
* @param queueParty - the queue party to be updated for matchmaking purposes.
*/
private static void updateParty(QueueParty queueParty)
{
int queueDuration = (int) queueParty.getQueueDuration() / 1000; // Queue duration in seconds
Match bestMatch = getBestMatch(queueParty);
if (queueParty.hasAssignedMatch())
{
// TODO: If player has been waiting too long in current game and there is a better match, join that!
}
else
{
if (bestMatch != null) // Assign party into best match!
{
bestMatch.joinQueueParty(queueParty);
_repo.assignMatch(queueParty, bestMatch);
}
else if (queueDuration >= MIN_QUEUE_WAIT) // Create a new match for others to join!
{
Match match = new Match(_matchId++, queueParty.getServerGroup(), queueParty);
_pendingMatches.add(match);
_repo.assignMatch(queueParty, match);
}
}
}
/**
* Update a {@link Match} by verifying it's player statuses, sending out invites
* and managing a Match from creation to deletion.
* @param match - the match to be updated.
* @return true, if the match is no longer required (successful or otherwise) and should be removed, false otherwise.
*/
private static boolean updateMatch(Match match)
{
// Remove queued parties that have left queue/match
// Don't give me crap about not using iterator...can't cuz of stupid thing.
Set<QueueParty> partiesToRemove = new HashSet<QueueParty>();
for (QueueParty queueParty : match.getParties())
{
int partyId = queueParty.getId();
if (!_repo.queuePartyExists(partyId))
{
log("Removing matchStatus : " + queueParty.getId());
partiesToRemove.add(queueParty);
if (match.isWaitingForInvites())
{
_repo.deleteMatch(match.getId());
match.setWaitingForInvites(false);
}
}
}
for (QueueParty party : partiesToRemove)
{
match.quitQueueParty(party);
}
// If match took too long to find players, or is empty, quit match.
if (match.getPlayerCount() == 0)
{
return true; // Match is empty, remove from pending matches.
}
// If match sent invites and is waiting for too long (15 seconds), kick players who didn't
// accept and keep looking
// Otherwise if everyone accepted, start game!
if (match.isWaitingForInvites())
{
boolean matchReady = true;
for (QueueParty party : _repo.getJoinedQueueParties(match.getId()))
{
if (!party.isReady())
{
matchReady = false;
}
}
if (!matchReady && match.getWaitDuration() > 500)
{
matchReady = true;
}
if (match.isReady()) // Invites accepted, MinecraftServer started, and players transferred.
{
return true;
}
else if (matchReady) // Players accepted invites, start match!
{
startMatch(match);
return false;
}
else if (match.getWaitDuration() > 15000)
{
for (QueueParty queueParty : match.getParties())
{
if (!queueParty.isReady())
{
_repo.deleteQueueParty(queueParty.getId());
}
}
_repo.deleteMatch(match.getId());
match.setWaitingForInvites(false);
}
return false;
}
// Match has filled up, send out invites!
if (match.getOpenSlots() == 0)
{
for (QueueParty party : match.getParties())
{
_repo.sendInvite(party);
}
match.setWaitingForInvites(true);
}
return false;
}
/**
* @param queueParty - the party for whom a match is being searched.
* @return the best matching {@link Match} for the {@code queueParty}, if an acceptable {@link Match}
* could be found, null otherwise.
*/
private static Match getBestMatch(QueueParty queueParty)
{
Match best = null;
int minEloDelta = 0;
int variance = getSearchVariance(queueParty);
for (Match match : _pendingMatches)
{
if (match.getOpenSlots() >= queueParty.getPlayerCount())
{
int eloDelta = getEloDelta(queueParty, match);
if (eloDelta <= variance && (eloDelta < minEloDelta || best == null))
{
best = match;
minEloDelta = eloDelta;
}
}
}
return best;
}
/**
* @param r1
* @param r2
* @return the ELO point delta (difference) between two {@link Ranked} objects.
*/
private static int getEloDelta(Ranked r1, Ranked r2)
{
return Math.abs(r1.getElo() - r2.getElo());
}
public static boolean startMatch(Match match)
{
ServerGroup group = match.getServerGroup();
DedicatedServer bestServer = getBestDedicatedServer(group);
startServer(bestServer, group, match);
return true;
}
/**
* Transfer all players queue'd into a {@link Match} to one server.
* @param match - the match whose queue'd players are to be transferred
* @param serverName - the name of the server to transfer the players to
*/
public static void transferPlayers(Match match, String serverName)
{
// Transfer players to the server
for (QueueParty queueParty : _repo.getJoinedQueueParties(match.getId()))
{
for (String playerName : queueParty.getPlayers())
{
// Execute a transfer command
ServerTransfer serverTransfer = new ServerTransfer(playerName, serverName);
TransferCommand transferCommand = new TransferCommand(serverTransfer);
transferCommand.publish();
}
}
// Server transfers sent out, match has started!
_matchesMade++;
// Delete queue parties for players who've been matched
for (QueueParty queueParty : match.getParties())
{
if (!queueParty.isReady())
{
_repo.deleteQueueParty(queueParty.getId());
}
}
match.setReady(true); // Ready to be deleted/removed
}
/**
* @return newly generated unique server id.
*/
public static int generateServerId()
{
return _serverId++;
}
private static void startServer(final DedicatedServer serverSpace, final ServerGroup serverGroup, final Match match)
{
String cmd = "/home/mineplex/easyRemoteStartServerCustom.sh";
final String groupPrefix = serverGroup.getPrefix();
final String serverName = serverSpace.getName();
final String serverAddress = serverSpace.getPublicAddress();
final int serverId = generateServerId();
ProcessRunner pr = new ProcessRunner(new String[] {"/bin/sh", cmd, serverAddress, serverSpace.getPrivateAddress(), (serverGroup.getPortSection() + serverId) + "", serverGroup.getRequiredRam() + "", serverGroup.getWorldZip(), serverGroup.getPlugin(), serverGroup.getConfigPath(), serverGroup.getName(), serverGroup.getPrefix() + "-" + serverId, serverSpace.isUsRegion() ? "true" : "false", serverGroup.getAddNoCheat() + "" });
pr.start(new GenericRunnable<Boolean>()
{
public void run(Boolean error)
{
if (!error)
{
// Successfully started server, now transfer players
transferPlayers(match, serverName);
}
else
{
// TODO: Error in starting server for ELO match, try again or disband queued match?
log("[" + serverName + ":" + serverAddress + " Free Resources; CPU " + serverSpace.getAvailableCpu() + " RAM " + serverSpace.getAvailableRam() + "MB] Errored " + serverName + "(" + groupPrefix+ "-" + serverId + ")");
}
}
});
ProcessManager.getInstance().addProcess(pr);
serverSpace.incrementServerCount(serverGroup);
}
private static DedicatedServer getBestDedicatedServer(ServerGroup serverGroup)
{
Collection<DedicatedServer> dedicatedServers = _serverRepository.getDedicatedServers();
DedicatedServer bestServer = null;
for (DedicatedServer serverData : dedicatedServers)
{
if (serverData.getAvailableRam() > serverGroup.getRequiredRam()
&& serverData.getAvailableCpu() > serverGroup.getRequiredCpu())
{
if (bestServer == null || serverData.getServerCount(serverGroup) < bestServer.getServerCount(serverGroup))
{
bestServer = serverData;
}
}
}
return bestServer;
}
/**
* @param party - the party whose ELO search variance is being fetched.
* @return the variance in ELO search parameters for {@code party}.
* I.E: Queuer searches for potential matches in [party.elo - variance, party.elo + variance] ELO range.
*/
private static int getSearchVariance(QueueParty party)
{
int seconds = (int) party.getQueueDuration() / 1000; // Duration of queue in seconds
return seconds * 10; // 5 ELO variance for every second in queue
}
private static void log(String message)
{

View File

@ -29,13 +29,15 @@ import mineplex.serverdata.data.ServerGroup;
import mineplex.serverdata.servers.DedicatedServerSorter;
import mineplex.serverdata.servers.ServerManager;
import mineplex.serverdata.servers.ServerRepository;
import mineplex.serverprocesses.GenericRunnable;
import mineplex.serverprocesses.ProcessManager;
import mineplex.serverprocesses.ProcessRunner;
public class ServerMonitor
{
private static ServerRepository _repository = null;
private static StatusHistoryRepository _historyRepository = null;
private static int _count = 0;
private static HashSet<ProcessRunner> _processes = new HashSet<ProcessRunner>();
private static HashMap<String, Boolean> _badServers = new HashMap<String, Boolean>();
private static Collection<MinecraftServer> _serverStatuses = null;
private static Collection<ServerGroup> _serverGroups = null;
@ -54,18 +56,6 @@ public class ServerMonitor
public static void main (String args[])
{
/*
MinecraftPingReply data = null;
try
{
data = new MinecraftPing().getPing(new MinecraftPingOptions().setHostname("127.0.0.1").setPort(25565));
}
catch (IOException e2)
{
e2.printStackTrace();
}
System.out.println(data.getDescription() + " " + data.getPlayers().getOnline());
*/
_region = !new File("eu.dat").exists() ? Region.US : Region.EU;
_debug = new File("debug.dat").exists();
_repository = ServerManager.getServerRepository(_region); // Fetches and connects to server repo
@ -283,55 +273,7 @@ public class ServerMonitor
}
}
int processWaits = 0;
while (_processes.size() > 0)
{
for (Iterator<ProcessRunner> iterator = _processes.iterator(); iterator.hasNext();)
{
ProcessRunner pr = iterator.next();
try
{
pr.join(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
if (pr.isDone())
iterator.remove();
}
if (_processes.size() > 0)
{
try
{
log("Sleeping while processes run...");
Thread.sleep(6000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
if (processWaits >= 10)
{
log("Killing stale processes.");
for (Iterator<ProcessRunner> iterator = _processes.iterator(); iterator.hasNext();)
{
iterator.next().abort();
iterator.remove();
}
}
processWaits++;
}
processWaits = 0;
ProcessManager.getInstance().updateProcesses();
try
{
@ -565,7 +507,9 @@ public class ServerMonitor
if (!pr.isDone())
_processes.add(pr);
{
ProcessManager.getInstance().addProcess(pr);
}
}
private static boolean isServerOffline(DedicatedServer serverData)
@ -666,7 +610,9 @@ public class ServerMonitor
serverSpace.incrementServerCount(serverGroup);
if (!pr.isDone())
_processes.add(pr);
{
ProcessManager.getInstance().addProcess(pr);
}
}
private static void log(String message)