Skip to content

Commit

Permalink
Merge pull request #291 from Goosius1/t266b
Browse files Browse the repository at this point in the history
T266 - Improvements to battle session scheduler
  • Loading branch information
Goosius1 authored Jun 22, 2021
2 parents 346f235 + ea8cdd7 commit 3661b8f
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 82 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.gmail.goosius</groupId>
<artifactId>SiegeWar</artifactId>
<version>0.3.9</version>
<version>0.3.10</version>
<name>siegewar</name> <!-- Leave lower-cased -->

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import com.palmergames.util.TimeMgmt;
import org.jetbrains.annotations.Nullable;

/**
* This class represents a "Battle Session".
Expand Down Expand Up @@ -33,11 +34,13 @@ public class BattleSession {

private static BattleSession battleSession = null; //The singleton instance
private boolean active; //Is the session active, or is it on break ?
private long scheduledEndTIme; //The time this battle session is scheduled to end
private long scheduledEndTime; //The time this battle session is scheduled to end
private Long scheduledStartTime; //The time this battle session is scheduled to start

public BattleSession() {
active = false;
scheduledEndTIme = 0;
scheduledEndTime = 0;
scheduledStartTime = null;
}

//Singleton
Expand All @@ -57,23 +60,32 @@ public void setActive(boolean active) {
}

public long getScheduledEndTime() {
return scheduledEndTIme;
return scheduledEndTime;
}

public void setScheduledEndTime(long t) {
scheduledEndTIme = t;
scheduledEndTime = t;
}

public String getFormattedTimeRemainingUntilBattleSessionEnds() {
return TimeMgmt.getFormattedTimeValue(getTimeRemainingUntilBattleSessionEnds());
}

public long getTimeRemainingUntilBattleSessionEnds() {
long timeLeftMillis = scheduledEndTIme - System.currentTimeMillis();
long timeLeftMillis = scheduledEndTime - System.currentTimeMillis();
if (timeLeftMillis > 0) {
return timeLeftMillis;
} else {
return 0;
}
}

@Nullable
public Long getScheduledStartTime() {
return scheduledStartTime;
}

public void setScheduledStartTime(Long scheduledStartTime) {
this.scheduledStartTime = scheduledStartTime;
}
}
37 changes: 26 additions & 11 deletions src/main/java/com/gmail/goosius/siegewar/settings/ConfigNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -388,17 +388,32 @@ public enum ConfigNodes {
"# 4. In this example, the siege attacker will not get any points boosts."),

//Battle Sessions
WAR_SIEGE_BATTLE_SESSIONS_START_TIMES_UTC(
"war.siege.battle_session.start_times_utc",
"0:10,1:10,2:10,3:10,4:10,5:10,6:10,7:10,8:10,9:10,10:10,11:10,12:10,13:10,14:10,15:10,16:10,17:10,18:10,19:10,20:10,21:10,22:10,23:10",
"# This value determines the times (in UTC) when each battle session will start.",
"# Integers can be used to signify hours, and minutes are used as follows: 4:20,5:20,6:35 etc.",
"# The default is every hour, at ten past the hour.",
"# The ten-past is so the critical point of the battle (the final minutes), will fall on the hour.",
"# In addition to controlling routine battle session start times,",
"# this config can also be used to prevent afk sieging at unusual times e.g. night-time sieges.",
"# But be careful with this, as it also restricts sieging by cross-timezone players."),
WAR_SIEGE_BATTLE_SESSIONS_DURATION_MINUTES(
WAR_SIEGE_BATTLE_SESSION(
"war.siege.battle_session",
"",
"",
"############################################################",
"# +------------------------------------------------------+ #",
"# | Battle Session settings | #",
"# +------------------------------------------------------+ #",
"############################################################"),
WAR_SIEGE_BATTLE_SESSION_WEEKDAY_START_TIMES_UTC(
"war.siege.battle_session.weekday_start_times_utc",
"19:10,21:10",
"",
"# This value determines the UTC weekday times when each battle session will start.",
"# This setting applies to Monday, Tuesday, Wednesday, Thursday, and Friday.",
"# The format is HOUR:MINUTE.",
"# The default values are all at ten past the hour, so that the critical point of the battle (the final minutes), will fall on the hour."),
WAR_SIEGE_BATTLE_SESSION_WEEKEND_START_TIMES_UTC(
"war.siege.battle_session.weekend_start_times_utc",
"12:10,14:10,16:10,18:10,20:10",
"",
"# This value determines the UTC weekend times when each battle session will start.",
"# This setting applies to Saturday and Sunday.",
"# The format is HOUR:MINUTE.",
"# The default values are all at ten past the hour, so that the critical point of the battle (the final minutes), will fall on the hour."),
WAR_SIEGE_BATTLE_SESSION_DURATION_MINUTES(
"war.siege.battle_session.duration_minutes",
"50",
"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static boolean loadSettingsAndLang() {

//Schedule next battle session
try {
SiegeWarBattleSessionUtil.scheduleNextBattleSession();
SiegeWarBattleSessionUtil.attemptToScheduleNextBattleSession();
} catch (Exception e) {
e.printStackTrace();
System.err.println(SiegeWar.prefix + "Problem Scheduling Battle Session! Disabling!");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.gmail.goosius.siegewar.settings;

import java.time.*;
import java.util.ArrayList;
import java.util.List;

import org.bukkit.Bukkit;
import org.bukkit.Material;

import com.gmail.goosius.siegewar.objects.HeldItemsCombination;
import org.jetbrains.annotations.Nullable;

public class SiegeWarSettings {

Expand Down Expand Up @@ -272,17 +274,59 @@ public static double getWarSiegeCounterattackBoosterExtraDeathPointsPerPlayerPer
return Settings.getDouble(ConfigNodes.WAR_SIEGE_COUNTERATTACK_BOOSTER_EXTRA_DEATH_POINTS_PER_PLAYER_PERCENTAGE);
}

public static List<String> getWarSiegeBattleSessionsStartTimesUtc() {
List<String> timesAsList = new ArrayList<>();
String timesAsString = Settings.getString(ConfigNodes.WAR_SIEGE_BATTLE_SESSIONS_START_TIMES_UTC);
for(String time: timesAsString.split(",")) {
timesAsList.add(time.trim());
public static List<LocalDateTime> getAllBattleSessionStartTimesForTodayUtc() {
LocalDate today = OffsetDateTime.now(ZoneOffset.UTC).toLocalDate();
return getAllBattleSessionStartTimesForDayUtc(today);
}

@Nullable
public static LocalDateTime getFirstBattleSessionStartTimeForTomorrowUtc() {
LocalDate tomorrow = OffsetDateTime.now(ZoneOffset.UTC).plusDays(1).toLocalDate();
List<LocalDateTime> allBattleSessionStartTimesForTomorrow = getAllBattleSessionStartTimesForDayUtc(tomorrow);
if(allBattleSessionStartTimesForTomorrow.size() != 0) {
return allBattleSessionStartTimesForTomorrow.get(0);
} else {
return null;
}
}

private static List<LocalDateTime> getAllBattleSessionStartTimesForDayUtc(LocalDate day) {
//Determine if the given day is on the weekend
boolean isWeekend = day.getDayOfWeek() == DayOfWeek.SATURDAY || day.getDayOfWeek() == DayOfWeek.SUNDAY;

//Get the start times from the config file, in the form of a single string.
String startTimesAsString = isWeekend ?
getWarSiegeBattleSessionWeekendStartTimesUtc() :
getWarSiegeBattleSessionWeekdayStartTimesUtc();

//Transform the config file strings into a list of LocalDateTime objects
List<LocalDateTime> startTimesAsList = new ArrayList<>();
if(startTimesAsString.length() > 0) {
String[] startTimeAsHourMinutePair;
LocalDateTime startTime;
for(String startTimeAsString: startTimesAsString.split(",")) {
if (startTimeAsString.contains(":")) {
startTimeAsHourMinutePair = startTimeAsString.split(":");
startTime = LocalDateTime.of(day, LocalTime.of(Integer.parseInt(startTimeAsHourMinutePair[0]), Integer.parseInt(startTimeAsHourMinutePair[1])));
} else {
startTime = LocalDateTime.of(day, LocalTime.of(Integer.parseInt(startTimeAsString), 0));
}
startTimesAsList.add(startTime);
}
return timesAsList;
}
return startTimesAsList;
}

public static String getWarSiegeBattleSessionWeekdayStartTimesUtc() {
return Settings.getString(ConfigNodes.WAR_SIEGE_BATTLE_SESSION_WEEKDAY_START_TIMES_UTC);
}

public static String getWarSiegeBattleSessionWeekendStartTimesUtc() {
return Settings.getString(ConfigNodes.WAR_SIEGE_BATTLE_SESSION_WEEKEND_START_TIMES_UTC);
}

public static int getWarSiegeBattleSessionsDurationMinutes() {
return Settings.getInt(ConfigNodes.WAR_SIEGE_BATTLE_SESSIONS_DURATION_MINUTES);
public static int getWarSiegeBattleSessionDurationMinutes() {
return Settings.getInt(ConfigNodes.WAR_SIEGE_BATTLE_SESSION_DURATION_MINUTES);
}

public static boolean isWarSiegeZoneBlockPlacementRestrictionsEnabled() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private static String siegeWarUserGuide(String text) {
/*
* Local variables
*/
String activeSession = TimeMgmt.getFormattedTimeValue(SiegeWarSettings.getWarSiegeBattleSessionsDurationMinutes() * TimeMgmt.ONE_MINUTE_IN_MILLIS);
String activeSession = TimeMgmt.getFormattedTimeValue(SiegeWarSettings.getWarSiegeBattleSessionDurationMinutes() * TimeMgmt.ONE_MINUTE_IN_MILLIS);
String maxSiege = TimeMgmt.getFormattedTimeValue(SiegeWarSettings.getWarSiegeMaxHoldoutTimeHours() * TimeMgmt.ONE_HOUR_IN_MILLIS);
double counterPercent = SiegeWarSettings.getWarSiegeCounterattackBoosterExtraDeathPointsPerPlayerPercentage();
boolean bankruptcy = TownySettings.isTownBankruptcyEnabled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,19 @@
import java.util.Map;

public class SiegeWarBattleSessionUtil {
private static long scheduledStartTimeOfNextBattleSession;

public static void scheduleNextBattleSession() {
scheduledStartTimeOfNextBattleSession = System.currentTimeMillis() + getTimeUntilNextBattleSessionMillis();
}

/**
* Attempt to schedule the next battle session
* 1. If there is a battle session configured to start later today, or tomorrow,
* this method will successfully set the battleSessions.scheduledStartTime variable.
* 2. If there are no battle sessions configured to start later today, or tomorrow,
* this method will set the battleSessions.scheduledStartTime variable to null.
*/
public static void attemptToScheduleNextBattleSession() {
Long startTimeOfNextSession = getConfiguredStartTimeOfNextBattleSession();
BattleSession.getBattleSession().setScheduledStartTime(startTimeOfNextSession);
}

public static void evaluateBattleSessions() {
BattleSession battleSession = BattleSession.getBattleSession();

Expand All @@ -37,9 +44,6 @@ public static void evaluateBattleSessions() {
//Finish battle session
battleSession.setActive(false);

//Schedule next session
scheduleNextBattleSession();

/*
* Gather the results of all battles
* End any active battles
Expand Down Expand Up @@ -112,16 +116,25 @@ public void run() {
}

} else {
/*
* Battle session is inactive. Check to see if it starts
* If the time remaining is less than a minute, start it
*/
if (System.currentTimeMillis() > scheduledStartTimeOfNextBattleSession) {
//Start battle session
battleSession.setActive(true);
battleSession.setScheduledEndTime(System.currentTimeMillis() + (SiegeWarSettings.getWarSiegeBattleSessionsDurationMinutes() * 60000));
//Send global message to let the server know that "it is on"
Messaging.sendGlobalMessage(Translation.of("msg_war_siege_battle_session_started"));
//Battle session is inactive.

//If there is no battle session scheduled, attempt to schedule session now.
if(battleSession.getScheduledStartTime() == null) {
attemptToScheduleNextBattleSession();
}

//If a battle session is scheduled, start it if we hit the scheduled time
if(battleSession.getScheduledStartTime() != null) {
if (System.currentTimeMillis() > battleSession.getScheduledStartTime()) {
//Activate the session
battleSession.setActive(true);
//Set the scheduled end time
battleSession.setScheduledEndTime(System.currentTimeMillis() + (SiegeWarSettings.getWarSiegeBattleSessionDurationMinutes() * 60000));
//Clear the scheduled start time
battleSession.setScheduledStartTime(null);
//Send global message to let the server know that the battle session started
Messaging.sendGlobalMessage(Translation.of("msg_war_siege_battle_session_started"));
}
}
}
}
Expand Down Expand Up @@ -163,49 +176,52 @@ private static void sendBattleSessionEndedMessage(Map<Siege, Integer> battleResu
//Send message
Messaging.sendGlobalMessage(header, lines);
}

public static String getFormattedTimeUntilNextBattleSessionStarts() {
long timeRemaining = scheduledStartTimeOfNextBattleSession - System.currentTimeMillis();
if(timeRemaining > 0) {
return TimeMgmt.getFormattedTimeValue(timeRemaining);
Long startTimeOfTodaysNextBattleSession = BattleSession.getBattleSession().getScheduledStartTime();
if(startTimeOfTodaysNextBattleSession == null) {
return "?"; // Rarely needed but can happen if a server configures only weekday/weekend sessions
} else {
return "0";
}
}

private static long getTimeUntilNextBattleSessionMillis() {
LocalDateTime currentDateTime = LocalDateTime.now(Clock.systemUTC());
Duration closestDuration = null;
Duration candidateDuration;
LocalTime candidateTime;
LocalDate candidateDate;
LocalDateTime candidateDateTime;
String[] startTimeHourMinutePair;
for (String startTime : SiegeWarSettings.getWarSiegeBattleSessionsStartTimesUtc()) {
if (startTime.contains(":")) {
startTimeHourMinutePair = startTime.split(":");
candidateTime = LocalTime.of(Integer.parseInt(startTimeHourMinutePair[0]), Integer.parseInt(startTimeHourMinutePair[1]));
long timeRemaining = startTimeOfTodaysNextBattleSession - System.currentTimeMillis();
if(timeRemaining > 0) {
return TimeMgmt.getFormattedTimeValue(timeRemaining);
} else {
candidateTime = LocalTime.of(Integer.parseInt(startTime), 0);
}
return "0";
}
}
}

//Convert candidate to local date time
if (candidateTime.isAfter(currentDateTime.toLocalTime())) {
candidateDate = LocalDate.now(Clock.systemUTC());
} else {
candidateDate = LocalDate.now(Clock.systemUTC()).plusDays(1);
/**
* Get the configured start time, in millis, of the next battle session.
*
* This method will only find the start time if it is later today or tomorrow.
* If there are no start times later today or tomorrow, then this method will return null
*
* @return configured start time, in millis.
*/
private static Long getConfiguredStartTimeOfNextBattleSession() {
LocalDateTime currentTime = LocalDateTime.now(Clock.systemUTC());
LocalDateTime nextStartDateTime = null;

//Look for next configured-start-time for today
for (LocalDateTime candidateStartTimeUtc : SiegeWarSettings.getAllBattleSessionStartTimesForTodayUtc()) {
if(candidateStartTimeUtc.isAfter(currentTime)) {
nextStartDateTime = candidateStartTimeUtc;
break;
}
candidateDateTime = LocalDateTime.of(candidateDate, candidateTime);

//Make this candidate our favourite if it is closer
candidateDuration = Duration.between(currentDateTime, candidateDateTime);
if (closestDuration == null) {
closestDuration = candidateDuration;
} else if (candidateDuration.getSeconds() < closestDuration.getSeconds())
closestDuration = candidateDuration;
}

//Return closest duration
return closestDuration.getSeconds() * 1000;
//If no configured-start-time was found, look for the first configured time for tomorrow
if(nextStartDateTime == null) {
nextStartDateTime = SiegeWarSettings.getFirstBattleSessionStartTimeForTomorrowUtc();
}

//If nextStartTime is still null, return null, else transform it to millis and return
if(nextStartDateTime != null) {
ZonedDateTime zdt = ZonedDateTime.of(nextStartDateTime, ZoneOffset.UTC);
return zdt.toInstant().toEpochMilli();
} else {
return null;
}
}
}

0 comments on commit 3661b8f

Please sign in to comment.