Bulk query and fix double join bug

This commit is contained in:
Sam 2018-06-28 23:49:10 +01:00 committed by Alexander Meech
parent 4d0ac23b45
commit 29a1619011
7 changed files with 126 additions and 82 deletions

View File

@ -116,7 +116,7 @@ public class MissionContext<T> implements Mission<T>
private T _data;
private LevelReward[] _rewards;
private int _minX, _maxX;
private int _minX = 1, _maxX = 1;
private int _minY, _maxY;
private boolean _eventMission;
@ -139,7 +139,6 @@ public class MissionContext<T> implements Mission<T>
return this;
}
public MissionBuilder<T> games(GameDisplay... games)
{
_games = games;

View File

@ -32,9 +32,9 @@ public enum MissionLength
_calendarField = calendarField;
}
public <T> PlayerMission<T> createFromContext(MissionContext<T> context, double rankBonus)
public <T> PlayerMission<T> createFromContext(MissionContext<T> context)
{
return new PlayerMission<>(context, this, context.getRandomX(), context.getRandomY(), 0, rankBonus);
return new PlayerMission<>(context, this, context.getRandomX(), context.getRandomY(), 0, true);
}
public String getName()

View File

@ -19,6 +19,8 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Slime;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
import mineplex.core.MiniDbClientPlugin;
import mineplex.core.ReflectivelyCreateMiniPlugin;
@ -31,7 +33,6 @@ import mineplex.core.common.util.UtilAlg;
import mineplex.core.common.util.UtilServer;
import mineplex.core.donation.DonationManager;
import mineplex.core.game.GameDisplay;
import mineplex.core.mission.MissionRepository.MissionQuery;
import mineplex.core.mission.commands.DebugMissionCommand;
import mineplex.core.mission.commands.ViewMissionsCommand;
import mineplex.core.mission.ui.MissionShop;
@ -51,6 +52,10 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
DEBUG_MISSION_COMMAND
}
private static final int MAX_DAILY = 5;
private static final int MAX_WEEKLY = 3;
private static final int MAX_TOTAL = MAX_DAILY + MAX_WEEKLY;
private static final String NPC_METADATA = "MISSION_NPC";
private static final String NPC_NAME = C.cGreenB + "Sam The Slime";
@ -137,6 +142,7 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
MissionClient client = Get(uuid);
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar now = Calendar.getInstance(utc);
int nonEventMissions = 0;
while (resultSet.next())
{
@ -149,12 +155,22 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
continue;
}
// Here we attempt to fix a duplication bug caused by players joining US and EU at the same time.
// How? well we know that players can have a maximum of 8 (non-event) missions total. So in that case
// when they join a server with more than they should we'll clear everything from their 9th mission
// onwards.
if (!context.isEventMission() && ++nonEventMissions > MAX_TOTAL)
{
runAsync(() -> _repository.clearMission(accountId, missionId));
continue;
}
int progress = resultSet.getInt("progress");
int length = resultSet.getInt("length");
int x = resultSet.getInt("x");
int y = resultSet.getInt("y");
long startTime = resultSet.getLong("startTime");
PlayerMission mission = new PlayerMission<>(context, MissionLength.values()[length], x, y, progress, getRankBonus(uuid));
PlayerMission mission = new PlayerMission<>(context, MissionLength.values()[length], x, y, progress, false);
Calendar start = Calendar.getInstance(utc);
start.setTimeInMillis(startTime);
@ -162,7 +178,7 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
if (lengthField != -1 && now.get(lengthField) != start.get(lengthField))
{
runAsync(() -> _repository.clearProgress(accountId, missionId));
runAsync(() -> _repository.clearMission(accountId, missionId));
}
else
{
@ -183,19 +199,26 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
return "SELECT * FROM accountMissions WHERE accountId=" + accountId + ";";
}
@EventHandler(priority = EventPriority.LOW)
public void playerJoin(PlayerJoinEvent event)
{
Player player = event.getPlayer();
double rankBonus = getRankBonus(player);
for (PlayerMission mission : Get(player).getMissions())
{
mission.createRewards(rankBonus);
}
selectNewMissions(player);
}
public void startMission(Player player, PlayerMission mission)
{
MissionClient client = Get(player);
client.startMission(mission);
runAsync(() ->
{
if (!_repository.startMission(ClientManager.getAccountId(player), mission.getId(), mission.getLength().ordinal(), mission.getRequiredProgress(), mission.getY()))
{
client.getMissions().remove(mission);
player.sendMessage(F.main(getName(), "Something went wrong when trying to start " + F.name(mission.getName()) + "."));
}
});
_repository.addQueryToQueue(MissionRepository.startMission(ClientManager.getAccountId(player), () -> mission.createRewards(getRankBonus(player)), mission));
}
private void completeMission(Player player, PlayerMission<?> mission)
@ -221,7 +244,7 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
player.sendMessage("");
player.playSound(player.getLocation(), Sound.LEVEL_UP, 1, (float) Math.random());
runAsync(() -> _repository.completeQuest(ClientManager.getAccountId(player), mission.getId()));
runAsync(() -> _repository.completeMission(ClientManager.getAccountId(player), mission.getId()));
}
@SuppressWarnings("unchecked")
@ -249,7 +272,6 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
{
for (Player player : UtilServer.getPlayersCollection())
{
selectNewMissions(player);
saveProgress(player);
}
@ -271,7 +293,7 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
continue;
}
startMission(player, MissionLength.EVENT.createFromContext(context, getRankBonus(player)));
startMission(player, MissionLength.EVENT.createFromContext(context));
started++;
}
@ -294,7 +316,7 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
missions.removeIf(client::has);
int started = 0;
for (int i = current; i <= max; i++)
for (int i = current; i < max; i++)
{
MissionContext<?> context = UtilAlg.Random(missions);
@ -304,7 +326,7 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
}
missions.remove(context);
startMission(player, length.createFromContext(context, getRankBonus(player)));
startMission(player, length.createFromContext(context));
started++;
}
@ -344,13 +366,13 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
{
boolean complete = mission.isComplete();
_repository.incrementProgress(new MissionQuery(accountId, mission, progress, () ->
_repository.addQueryToQueue(MissionRepository.incrementProgress(accountId, () ->
{
if (complete)
{
runSync(() -> completeMission(player, mission));
}
}));
}, progress, mission));
});
}
@ -363,11 +385,6 @@ public class MissionManager extends MiniDbClientPlugin<MissionClient>
}
private double getRankBonus(Player player)
{
return getRankBonus(player.getUniqueId());
}
private double getRankBonus(UUID player)
{
switch (ClientManager.Get(player).getPrimaryGroup())
{

View File

@ -5,6 +5,7 @@ import org.bukkit.Material;
import mineplex.core.achievement.leveling.rewards.LevelCurrencyReward;
import mineplex.core.achievement.leveling.rewards.LevelExperienceReward;
import mineplex.core.common.currency.GlobalCurrency;
import mineplex.core.game.GameDisplay;
import static mineplex.core.mission.MissionTrackerType.*;
@ -107,6 +108,7 @@ public class MissionPopulator
MissionContext.<Material>newBuilder(manager, 100)
.name("Enthusiast")
.description("Play %s games.")
.games(GameDisplay.values())
.xRange(10, 50)
.tracker(GAME_PLAY)
.rewards(
@ -119,6 +121,7 @@ public class MissionPopulator
MissionContext.<Material>newBuilder(manager, 101)
.name("Winner")
.description("Win %s games.")
.games(GameDisplay.values())
.xRange(2, 10)
.tracker(GAME_WIN)
.rewards(
@ -131,6 +134,7 @@ public class MissionPopulator
MissionContext.<Material>newBuilder(manager, 102)
.name("Killer")
.description("Kill %s players in game.")
.games(GameDisplay.values())
.xRange(10, 50)
.tracker(GAME_KILL)
.rewards(
@ -143,6 +147,7 @@ public class MissionPopulator
MissionContext.<Material>newBuilder(manager, 103)
.name("I Shall Taunt You A Second Time")
.description("Taunt %s times in game.")
.games(GameDisplay.values())
.xRange(2, 20)
.tracker(GAME_TAUNT)
.rewards(

View File

@ -4,20 +4,49 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import mineplex.core.common.util.EnclosedObject;
import mineplex.serverdata.database.DBPool;
import mineplex.serverdata.database.RepositoryBase;
import mineplex.serverdata.database.column.ColumnByte;
import mineplex.serverdata.database.column.ColumnInt;
import mineplex.serverdata.database.column.ColumnLong;
public class MissionRepository extends RepositoryBase
{
private static final String START_QUEST = "INSERT INTO accountMissions (accountId, missionId, length, x, y, startTime) VALUES (?,?,?,?,?,?);";
private static final String START_MISSION = "INSERT INTO accountMissions (accountId, missionId, length, x, y, startTime) VALUES ({0},{1},{2},{3},{4},{5});";
private static final String INCREMENT_PROGRESS = "UPDATE accountMissions SET progress=progress+{0} WHERE accountId={1} AND missionId={2};";
private static final String COMPLETE_QUEST = "UPDATE accountMissions SET complete=1 WHERE accountId=? AND missionId=?;";
private static final String IS_MISSION_COMPLETE = "SELECT complete FROM accountMissions WHERE accountId=? AND missionId=?;";
private static final String COMPLETE_MISSION = "UPDATE accountMissions SET complete=1 WHERE accountId=? AND missionId=?;";
private static final String CLEAR_PROGRESS = "DELETE FROM accountMissions WHERE accountId=? AND missionId=?;";
static MissionQuery startMission(int accountId, Runnable callback, PlayerMission mission)
{
return new MissionQuery(START_MISSION, accountId, callback, accountId, mission.getId(), mission.getLength().ordinal(), mission.getRequiredProgress(), mission.getY(), System.currentTimeMillis());
}
static MissionQuery incrementProgress(int accountId, Runnable callback, int progress, Mission mission)
{
return new MissionQuery(INCREMENT_PROGRESS, accountId, callback, progress, accountId, mission.getId());
}
static class MissionQuery
{
private final String _query;
private final int _accountId;
private final Runnable _callback;
MissionQuery(String query, int accountId, Runnable callback, Object... args)
{
for (int i = 0; i < args.length; i++)
{
query = query.replace("{" + i + "}", String.valueOf(args[i]));
}
_query = query;
_accountId = accountId;
_callback = callback;
}
}
private final List<MissionQuery> _queries;
MissionRepository()
@ -27,19 +56,7 @@ public class MissionRepository extends RepositoryBase
_queries = new ArrayList<>();
}
public boolean startMission(int accountId, int missionId, int lengthId, int x, int y)
{
return accountId != -1 && executeInsert(START_QUEST, null,
new ColumnInt("accountId", accountId),
new ColumnInt("missionId", missionId),
new ColumnByte("length", (byte) lengthId),
new ColumnInt("x", x),
new ColumnInt("y", y),
new ColumnLong("startTime", System.currentTimeMillis())
) > 0;
}
public void incrementProgress(MissionQuery query)
public void addQueryToQueue(MissionQuery query)
{
if (query._accountId == -1)
{
@ -68,36 +85,39 @@ public class MissionRepository extends RepositoryBase
_queries.clear();
}
public boolean completeQuest(int accountId, int missionId)
public boolean completeMission(int accountId, int missionId)
{
return accountId != -1 && executeUpdate(COMPLETE_QUEST,
new ColumnInt("accountId", accountId),
new ColumnInt("missionId", missionId)
) > 0;
return !isComplete(accountId, missionId) && executeUpdate(COMPLETE_MISSION, new ColumnInt("accountId", accountId), new ColumnInt("missionId", missionId)) > 0;
}
public boolean clearProgress(int accountId, int missionId)
public boolean isComplete(int accountId, int missionId)
{
if (accountId == -1)
{
return false;
}
EnclosedObject<Boolean> complete = new EnclosedObject<>(false);
executeQuery(IS_MISSION_COMPLETE, resultSet ->
{
while (resultSet.next())
{
complete.Set(resultSet.getBoolean("complete"));
}
},
new ColumnInt("accountId", accountId),
new ColumnInt("missionId", missionId)
);
return complete.Get();
}
public boolean clearMission(int accountId, int missionId)
{
return accountId != -1 && executeUpdate(CLEAR_PROGRESS,
new ColumnInt("accountId", accountId),
new ColumnInt("missionId", missionId)
) > 0;
}
static class MissionQuery
{
private final String _query;
private final int _accountId;
private final Runnable _callback;
MissionQuery(int accountId, Mission mission, int progress, Runnable callback)
{
_query = INCREMENT_PROGRESS
.replace("{0}", String.valueOf(progress))
.replace("{1}", String.valueOf(accountId))
.replace("{2}", String.valueOf(mission.getId()));
_accountId = accountId;
_callback = callback;
}
}
}

View File

@ -15,35 +15,40 @@ public class PlayerMission<T> implements Mission<T>
private final MissionLength _length;
private final int _x;
private final int _y;
private final LevelReward[] _rewards;
private LevelReward[] _rewards;
private int _currentProgress, _unsavedProgress;
private boolean _rewarded;
PlayerMission(MissionContext<T> context, MissionLength length, int x, int y, int currentProgress, double rankBonus)
PlayerMission(MissionContext<T> context, MissionLength length, int x, int y, int currentProgress, boolean fromContext)
{
_context = context;
_length = length;
_x = x * length.getxScale();
_x = fromContext && x > 1 ? x * length.getxScale() : x;
_y = y;
if (_x == 0)
{
_description = String.format(context.getDescription(), _x, y);
}
else
if (x == 1)
{
_description = String.format(context.getDescription(), y);
}
else
{
_description = String.format(context.getDescription(), _x, y);
}
_currentProgress = currentProgress;
}
public void createRewards(double rankBonus)
{
if (_x != 1 || rankBonus > 0)
{
_rewards = new LevelReward[context.getRewards().length];
_rewards = new LevelReward[_context.getRewards().length];
for (int i = 0; i < _rewards.length; i++)
{
LevelReward reward = context.getRewards()[i];
LevelReward reward = _context.getRewards()[i];
if (reward instanceof ScalableLevelReward)
{
@ -64,10 +69,8 @@ public class PlayerMission<T> implements Mission<T>
}
else
{
_rewards = context.getRewards();
_rewards = _context.getRewards();
}
_currentProgress = currentProgress;
}
@Override

View File

@ -122,10 +122,10 @@ public class MissionMainPage extends ShopPageBase<MissionManager, MissionShop>
if (lastLength == null || lastLength != mission.getLength())
{
lastLength = mission.getLength();
column++;
column = 0;
}
addButtonNoAction(getSlot(row, column++), builder.build());
addButtonNoAction(getSlot(row, ++column), builder.build());
}
if (getItem(19) == null)