From 451d6b9fa298eec78d8a1a79f74e3760326e18ad Mon Sep 17 00:00:00 2001 From: carm Date: Mon, 5 May 2025 08:15:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(time):=20=E4=BF=AE=E5=A4=8D=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E5=87=BA=E7=8E=B0=E7=9A=84=E6=97=B6=E9=97=B4=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cc/carm/plugin/timereward/Main.java | 3 + .../plugin/timereward/conf/PluginConfig.java | 9 ++- .../plugin/timereward/data/IntervalType.java | 71 ++++++++++-------- .../plugin/timereward/data/TimeRecord.java | 34 +-------- .../storage/database/DatabaseTables.java | 2 +- .../plugin/timereward/util/DateTimeUtils.java | 73 +++++++++++++++++++ src/test/java/TimeTest.java | 57 --------------- .../java/cc/carm/plugin/tests/DataTest.java | 52 +++++++++++++ .../java/cc/carm/plugin/tests/TimeTest.java | 41 +++++++++++ 9 files changed, 221 insertions(+), 121 deletions(-) create mode 100644 src/main/java/cc/carm/plugin/timereward/util/DateTimeUtils.java delete mode 100644 src/test/java/TimeTest.java create mode 100644 src/test/java/cc/carm/plugin/tests/DataTest.java create mode 100644 src/test/java/cc/carm/plugin/tests/TimeTest.java diff --git a/src/main/java/cc/carm/plugin/timereward/Main.java b/src/main/java/cc/carm/plugin/timereward/Main.java index ec15168..2bdf209 100644 --- a/src/main/java/cc/carm/plugin/timereward/Main.java +++ b/src/main/java/cc/carm/plugin/timereward/Main.java @@ -14,6 +14,7 @@ import cc.carm.plugin.timereward.listener.UserListener; import cc.carm.plugin.timereward.manager.RewardManager; import cc.carm.plugin.timereward.manager.UserManager; import cc.carm.plugin.timereward.storage.database.MySQLStorage; +import cc.carm.plugin.timereward.util.DateTimeUtils; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.entity.Entity; @@ -49,6 +50,8 @@ public class Main extends EasyPlugin { this.rewardProvider = BukkitConfigFactory.from(new File(getDataFolder(), "rewards.yml")).build(); this.rewardProvider.initialize(RewardsConfig.class); + + DateTimeUtils.WEEK_START_DAY = PluginConfig.WEEK_FIRST_DAY::resolve; } @Override diff --git a/src/main/java/cc/carm/plugin/timereward/conf/PluginConfig.java b/src/main/java/cc/carm/plugin/timereward/conf/PluginConfig.java index 63a8788..640a700 100644 --- a/src/main/java/cc/carm/plugin/timereward/conf/PluginConfig.java +++ b/src/main/java/cc/carm/plugin/timereward/conf/PluginConfig.java @@ -25,7 +25,7 @@ public interface PluginConfig extends Configuration { "检查更新为异步操作,绝不会影响性能与使用体验。" }) ConfiguredValue CHECK_UPDATE = ConfiguredValue.of(Boolean.class, true); - + @HeaderComments({ "自动保存设定,用于设置自动保存的时间间隔,单位为秒(小于等于0则关闭)。", "一般来说,玩家会在退出游戏时进行保存。", @@ -33,6 +33,13 @@ public interface PluginConfig extends Configuration { }) ConfiguredValue AUTO_SAVE = ConfiguredValue.of(Long.class, 60L); + @HeaderComments({ + "是否在保存时优先使用数据库中的数据。", + "若启用,则会在保存数据时在数据库中重新读取数据计算时间,以确利用最新数据;", + "若关闭,则保存时会直接采用进入服务器时所加载的数据进行计算。" + }) + ConfiguredValue USE_STORAGE_DATA = ConfiguredValue.of(Boolean.class, true); + @HeaderComments("周起始日,用于判断周度奖励的结算日期。") ConfiguredValue WEEK_FIRST_DAY = ConfiguredValue.builderOf(DayOfWeek.class) .from(Integer.class) diff --git a/src/main/java/cc/carm/plugin/timereward/data/IntervalType.java b/src/main/java/cc/carm/plugin/timereward/data/IntervalType.java index e9620b0..9198e1a 100644 --- a/src/main/java/cc/carm/plugin/timereward/data/IntervalType.java +++ b/src/main/java/cc/carm/plugin/timereward/data/IntervalType.java @@ -1,5 +1,6 @@ package cc.carm.plugin.timereward.data; +import cc.carm.plugin.timereward.util.DateTimeUtils; import org.jetbrains.annotations.NotNull; import java.time.Duration; @@ -11,62 +12,64 @@ import java.util.function.Predicate; public enum IntervalType { TOTAL( - 0, time -> false, + 0, Duration.ofSeconds(4294967295L), time -> false, (timeRecord, join) -> Duration.between(join, LocalDateTime.now()).plus(timeRecord.getTotalTime()) ), DAILY( - 1, time -> time.isBefore(TimeRecord.getTodayStart()), + 1, Duration.ofDays(1), time -> DateTimeUtils.sameDay(time.toLocalDate()), (timeRecord, join) -> { LocalDateTime now = LocalDateTime.now(); - if (now.toLocalDate().isEqual(timeRecord.getDate())) { - // 和记录还在同一天 - return Duration.between(join, now).plus(timeRecord.getDailyTime()); - } else if (now.toLocalDate().isEqual(join.toLocalDate())) { - // 加入的时间和现在的时间在同一天 - return Duration.between(join, now); - } else { + if (!now.toLocalDate().isEqual(join.toLocalDate())) { // 加入的时间和现在的时间不在同一天 - return Duration.between(TimeRecord.getTodayStart(), now); + return Duration.between(DateTimeUtils.todayStartTime(), now); } + if (now.toLocalDate().isEqual(timeRecord.getDate())) { // 和记录还在同一天 + return Duration.between(join, now).plus(timeRecord.getDailyTime()); + } + return Duration.between(join, now); // 加入的时间和现在的时间在同一天 } ), WEEKLY( - 2, time -> time.isBefore(TimeRecord.getThisWeekStart()), - (timeRecord, join) -> { + 2, Duration.ofDays(7), + time -> !DateTimeUtils.sameWeek(time), + (r, join) -> { LocalDateTime now = LocalDateTime.now(); - if (TimeRecord.isSameWeek(timeRecord.getDate(), now)) { - return Duration.between(join, now).plus(timeRecord.getWeeklyTime()); - } else if (TimeRecord.isSameWeek(join, now)) { - return Duration.between(join, now); - } else { - return Duration.between(TimeRecord.getThisWeekStart(), now); + if (!DateTimeUtils.sameWeek(join, now)) { + return Duration.between(DateTimeUtils.currentWeekStartTime(), now); } + if (DateTimeUtils.sameWeek(r.getDate(), now)) { + return Duration.between(join, now).plus(r.getWeeklyTime()); + } + return Duration.between(join, now); } ), MONTHLY( - 3, time -> time.isBefore(TimeRecord.getThisMonthStart()), - (timeRecord, join) -> { + 3, Duration.ofDays(31), + time -> !DateTimeUtils.sameMonth(time.toLocalDate()), + (r, join) -> { LocalDateTime now = LocalDateTime.now(); - if (TimeRecord.isSameMonth(timeRecord.getDate(), now.toLocalDate())) { - return Duration.between(join, now).plus(timeRecord.getMonthlyTime()); - } else if (TimeRecord.isSameMonth(join.toLocalDate(), now.toLocalDate())) { - return Duration.between(join, now); - } else { - return Duration.between(TimeRecord.getThisMonthStart(), now); + if (!DateTimeUtils.sameMonth(join.toLocalDate(), now.toLocalDate())) { + return Duration.between(DateTimeUtils.currentMonthStartTime(), now); } + if (DateTimeUtils.sameMonth(r.getDate(), now.toLocalDate())) { + return Duration.between(join, now).plus(r.getMonthlyTime()); + } + return Duration.between(join, now); } ); private final int id; + private final @NotNull Duration maxDuration; private final @NotNull Predicate periodChangePredicate; private final @NotNull BiFunction calculator; - IntervalType(int id, + IntervalType(int id, @NotNull Duration maxDuration, @NotNull Predicate periodChangePredicate, @NotNull BiFunction calculator) { this.id = id; + this.maxDuration = maxDuration; this.periodChangePredicate = periodChangePredicate; this.calculator = calculator; } @@ -75,20 +78,26 @@ public enum IntervalType { return id; } - public @NotNull BiFunction getCalculator() { + public @NotNull Duration getMaxDuration() { + return maxDuration; + } + + public @NotNull BiFunction calculator() { return calculator; } - public @NotNull Predicate getPreiodChangePredicate() { + public @NotNull Predicate changePredicator() { return periodChangePredicate; } public Duration calculate(@NotNull TimeRecord timeRecord, @NotNull LocalDateTime joinTime) { - return calculator.apply(timeRecord, joinTime); + Duration result = calculator.apply(timeRecord, joinTime); + // 如果超过最大值,则返回最大值 + return result.compareTo(maxDuration) > 0 ? maxDuration : result; } public boolean isPeriodChanged(@NotNull LocalDateTime claimedDate) { - return periodChangePredicate.test(claimedDate); + return changePredicator().test(claimedDate); } public static IntervalType parse(String input) { diff --git a/src/main/java/cc/carm/plugin/timereward/data/TimeRecord.java b/src/main/java/cc/carm/plugin/timereward/data/TimeRecord.java index 30755b3..6cdce49 100644 --- a/src/main/java/cc/carm/plugin/timereward/data/TimeRecord.java +++ b/src/main/java/cc/carm/plugin/timereward/data/TimeRecord.java @@ -1,14 +1,10 @@ package cc.carm.plugin.timereward.data; -import cc.carm.plugin.timereward.conf.PluginConfig; +import cc.carm.plugin.timereward.util.DateTimeUtils; import org.jetbrains.annotations.NotNull; import java.time.Duration; import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalField; -import java.time.temporal.WeekFields; public class TimeRecord { @@ -16,7 +12,6 @@ public class TimeRecord { return new TimeRecord(LocalDate.now(), 0, 0, 0, 0); } - protected final @NotNull LocalDate date; protected final @NotNull Duration daily; @@ -68,37 +63,14 @@ public class TimeRecord { public boolean isWeekUpdated() { if (!isDayUpdated()) return false; // Same day always same week - return !isSameWeek(LocalDate.now(), getDate()); + return !DateTimeUtils.sameWeek(LocalDate.now(), getDate()); } public boolean isMonthUpdated() { if (!isDayUpdated()) return false; // Same day always same month - - // Predicate current month is after the month of the date - return LocalDate.now().getMonth().compareTo(getDate().getMonth()) > 0; + return !DateTimeUtils.sameMonth(LocalDate.now(), getDate()); } - public static boolean isSameWeek(Temporal a, Temporal b) { - TemporalField woy = WeekFields.of(PluginConfig.WEEK_FIRST_DAY.getNotNull(), 4).weekOfWeekBasedYear(); - return a.get(woy) == b.get(woy); - } - - public static boolean isSameMonth(LocalDate a, LocalDate b) { - return a.getMonth().equals(b.getMonth()); - } - - public static LocalDateTime getTodayStart() { - return LocalDate.now().atTime(0, 0); - } - - public static LocalDateTime getThisWeekStart() { - TemporalField woy = WeekFields.of(PluginConfig.WEEK_FIRST_DAY.getNotNull(), 4).weekOfWeekBasedYear(); - return LocalDate.now().with(woy, 1).atTime(0, 0); - } - - public static LocalDateTime getThisMonthStart() { - return LocalDate.now().withDayOfMonth(1).atTime(0, 0); - } @Override public String toString() { diff --git a/src/main/java/cc/carm/plugin/timereward/storage/database/DatabaseTables.java b/src/main/java/cc/carm/plugin/timereward/storage/database/DatabaseTables.java index 8ff346a..57a9d76 100644 --- a/src/main/java/cc/carm/plugin/timereward/storage/database/DatabaseTables.java +++ b/src/main/java/cc/carm/plugin/timereward/storage/database/DatabaseTables.java @@ -22,7 +22,7 @@ public enum DatabaseTables implements SQLTable { table.addColumn("daily_time", "MEDIUMINT UNSIGNED NOT NULL DEFAULT 0"); // 用户日在线时间(秒) table.addColumn("weekly_time", "MEDIUMINT UNSIGNED NOT NULL DEFAULT 0"); // 用户周在线时间(秒) - table.addColumn("monthly_time", "INT UNSIGNED NOT NULL DEFAULT 0"); // 用户月在线时间(秒) + table.addColumn("monthly_time", "MEDIUMINT UNSIGNED NOT NULL DEFAULT 0"); // 用户月在线时间(秒) table.addColumn("total_time", "INT UNSIGNED NOT NULL DEFAULT 0"); // 用户总在线时间(秒) table.addColumn("update", diff --git a/src/main/java/cc/carm/plugin/timereward/util/DateTimeUtils.java b/src/main/java/cc/carm/plugin/timereward/util/DateTimeUtils.java new file mode 100644 index 0000000..a49172a --- /dev/null +++ b/src/main/java/cc/carm/plugin/timereward/util/DateTimeUtils.java @@ -0,0 +1,73 @@ +package cc.carm.plugin.timereward.util; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAdjusters; +import java.time.temporal.TemporalField; +import java.time.temporal.WeekFields; +import java.util.function.Supplier; + +public class DateTimeUtils { + + public static Supplier WEEK_START_DAY = () -> DayOfWeek.MONDAY; + + public static boolean sameDay(LocalDate a) { + return sameDay(a, LocalDate.now()); + } + + public static boolean sameDay(LocalDate a, LocalDate b) { + return a.getDayOfYear() == b.getDayOfYear() && a.getYear() == b.getYear(); + } + + public static boolean sameWeek(Temporal a) { + return sameWeek(WEEK_START_DAY.get(), a, LocalDate.now()); + } + + public static boolean sameWeek(DayOfWeek weekStart, Temporal a) { + return sameWeek(weekStart, a, LocalDate.now()); + } + + public static boolean sameWeek(Temporal a, Temporal b) { + return sameWeek(WEEK_START_DAY.get(), a, b); + } + + public static boolean sameWeek(DayOfWeek weekStart, Temporal a, Temporal b) { + TemporalField woy = WeekFields.of(weekStart, 4).weekOfWeekBasedYear(); + return a.get(woy) == b.get(woy); + } + + public static boolean sameMonth(LocalDate a) { + return sameMonth(a, LocalDate.now()); + } + + public static boolean sameMonth(LocalDate a, LocalDate b) { + return a.getMonth().equals(b.getMonth()); + } + + public static LocalDateTime todayStartTime() { + return LocalDate.now().atTime(0, 0); + } + + public static LocalDate currentWeekStartDay(DayOfWeek weekStart) { + return LocalDate.now().with(TemporalAdjusters.previousOrSame(weekStart)); + } + + public static LocalDate currentWeekStartDay() { + return currentWeekStartDay(WEEK_START_DAY.get()); + } + + public static LocalDateTime currentWeekStartTime(DayOfWeek weekStart) { + return currentWeekStartDay(weekStart).atTime(0, 0); + } + + public static LocalDateTime currentWeekStartTime() { + return currentWeekStartTime(WEEK_START_DAY.get()); + } + + public static LocalDateTime currentMonthStartTime() { + return LocalDate.now().withDayOfMonth(1).atTime(0, 0); + } + +} diff --git a/src/test/java/TimeTest.java b/src/test/java/TimeTest.java deleted file mode 100644 index 74b0674..0000000 --- a/src/test/java/TimeTest.java +++ /dev/null @@ -1,57 +0,0 @@ -import org.jetbrains.annotations.NotNull; -import org.junit.Test; - -import java.time.DayOfWeek; -import java.time.LocalDate; -import java.time.temporal.TemporalField; -import java.time.temporal.WeekFields; - -public class TimeTest { - - LocalDate date = LocalDate.of(2023, 8, 30); - - @Test - public void test() { - - LocalDate date1 = LocalDate.of(2023, 9, 2); - LocalDate date2 = LocalDate.of(2023, 8, 28); - LocalDate date3 = LocalDate.of(2023, 8, 27); - - System.out.println(isDayUpdated(date1)); - System.out.println(isWeekUpdated(date1)); - System.out.println(isMonthUpdated(date1)); - - System.out.println(isDayUpdated(date2)); - System.out.println(isWeekUpdated(date2)); - System.out.println(isMonthUpdated(date2)); - - System.out.println(isDayUpdated(date3)); - System.out.println(isWeekUpdated(date3)); - System.out.println(isMonthUpdated(date3)); - - System.out.println(isDayUpdated(date)); - - } - - public @NotNull LocalDate getDate() { - return date; - } - - public boolean isDayUpdated(LocalDate d) { - return !d.equals(getDate()); - } - - public boolean isWeekUpdated(LocalDate d) { - if (!isDayUpdated(d)) return false; // Same day always same week - - TemporalField woy = WeekFields.of(DayOfWeek.MONDAY, 4).weekOfWeekBasedYear(); - return getDate().get(woy) != d.get(woy); - } - - public boolean isMonthUpdated(LocalDate d) { - if (!isDayUpdated(d)) return false; // Same day always same month - - // Predicate current month is after the month of the date - return d.getMonth().compareTo(getDate().getMonth()) > 0; - } -} diff --git a/src/test/java/cc/carm/plugin/tests/DataTest.java b/src/test/java/cc/carm/plugin/tests/DataTest.java new file mode 100644 index 0000000..84befde --- /dev/null +++ b/src/test/java/cc/carm/plugin/tests/DataTest.java @@ -0,0 +1,52 @@ +package cc.carm.plugin.tests; + +import cc.carm.plugin.timereward.data.IntervalType; +import cc.carm.plugin.timereward.data.TimeRecord; +import cc.carm.plugin.timereward.user.UserRewardData; +import cc.carm.plugin.timereward.util.DateTimeUtils; +import org.junit.Test; + +import java.time.DayOfWeek; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.UUID; + +public class DataTest { + + DateTimeFormatter DATETIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Test + public void test() { + + LocalDate date = LocalDate.of(2025, 5, 1); + LocalDateTime dateTime = LocalDateTime.now().minusHours(10).minusSeconds(600); + + System.out.println("-----------------------------------------"); + System.out.println(" DURATION: " + Duration.between(dateTime, LocalDateTime.now()).getSeconds()); + System.out.println("TODAY START: " + DATETIME.format(DateTimeUtils.todayStartTime())); + System.out.println("WEEK START: " + DATETIME.format(DateTimeUtils.currentWeekStartTime())); + System.out.println("MONTH START: " + DATETIME.format(DateTimeUtils.currentMonthStartTime())); + System.out.println("-----------------------------------------"); + System.out.println("RECORD DATE: " + DateTimeFormatter.ofPattern("yyyy-MM-dd").format(date)); + System.out.println(" JOIN TIME: " + DATETIME.format(dateTime)); + System.out.println("-----------------------------------------"); + + UserRewardData data = createData(date, dateTime); + for (IntervalType value : IntervalType.values()) { + System.out.println(value.name() + " = " + data.getOnlineDuration(value).getSeconds()); + } + + } + + static UserRewardData createData(LocalDate date, LocalDateTime join) { + return new UserRewardData( + UUID.randomUUID(), new HashMap<>(), + new TimeRecord(date, 0, 0, 0, 0), + join + ); + } + +} diff --git a/src/test/java/cc/carm/plugin/tests/TimeTest.java b/src/test/java/cc/carm/plugin/tests/TimeTest.java new file mode 100644 index 0000000..811a846 --- /dev/null +++ b/src/test/java/cc/carm/plugin/tests/TimeTest.java @@ -0,0 +1,41 @@ +package cc.carm.plugin.tests; + +import cc.carm.plugin.timereward.data.IntervalType; +import cc.carm.plugin.timereward.data.TimeRecord; +import org.junit.Test; + +import java.time.LocalDate; + +public class TimeTest { + + LocalDate date = LocalDate.of(2023, 8, 30); + + @Test + public void test() { + + TimeRecord record1 = new TimeRecord(LocalDate.now().minusMonths(1), 0, 0, 0, 0); + TimeRecord record2 = new TimeRecord(LocalDate.now().minusWeeks(1), 0, 0, 0, 0); + TimeRecord record3 = new TimeRecord(LocalDate.now().minusDays(1), 0, 0, 0, 0); + + System.out.println(record1.isDayUpdated()); + System.out.println(record1.isWeekUpdated()); + System.out.println(record1.isMonthUpdated()); + + System.out.println(record2.isDayUpdated()); + System.out.println(record2.isWeekUpdated()); + System.out.println(record2.isMonthUpdated()); + + System.out.println(record3.isDayUpdated()); + System.out.println(record3.isWeekUpdated()); + System.out.println(record3.isMonthUpdated()); + + } + + @Test + public void durationTest() { + for (IntervalType value : IntervalType.values()) { + System.out.println(value.name() + " = = " + value.getMaxDuration().getSeconds()); + } + } + +}