Java游戏新玩家在线1小时动作限制逻辑实现问题求助
现有代码核心逻辑问题
- 时间类型选择错误:
LocalTime仅表示当日的时分秒,跨天场景下计算时间差会出现异常,且无法正确记录跨天的在线时长 - 字段设计错误:你不需要
startedTime/currentTime/finishTime三个时间点字段,核心应该记录历史累计在线时长 + 本次登录的起始时间即可 - 计时逻辑写反:
count和logout方法中使用minus减少时长的操作完全错误,你应该累加玩家的在线时长 - 没有持久化累计时长:现有字段如果重启服务或者玩家重新登录,所有计时都会重置,需要把累计在线时长做序列化持久化
修正后完整代码
package com.rs.game.player; import com.rs.utils.Utils; import java.io.Serializable; import java.time.Duration; import java.time.Instant; public class AccountRestriction implements Serializable { public enum RestrictionType { TRADING,DROPPING_ITEMS,PVP } private transient Player player; // 持久化存储:历史累计在线时长 private Duration totalOnlineDuration = Duration.ZERO; // transient不持久化:本次登录的开始时间,每次登录重新赋值 private transient Instant loginStartTime; // 新玩家限制阈值:累计在线满1小时解除 private static final Duration RESTRICT_THRESHOLD = Duration.ofHours(1); public void setPlayer(Player player) { this.player = player; // 登录绑定玩家实例时,记录本次登录开始时间 this.loginStartTime = Instant.now(); } /** * 每tick(600ms)更新玩家累计在线时长 */ public void count() { Instant now = Instant.now(); // 累加本次计时周期的在线时长 Duration delta = Duration.between(loginStartTime, now); totalOnlineDuration = totalOnlineDuration.plus(delta); // 更新计时起始点,避免重复累加 loginStartTime = now; System.out.println("累计在线时长:" + totalOnlineDuration.toMinutes() + "分钟"); } /** * 玩家登出时结算本次在线时长 */ public void logout() { Instant now = Instant.now(); Duration delta = Duration.between(loginStartTime, now); totalOnlineDuration = totalOnlineDuration.plus(delta); } /** * 构造方法 * @param player 玩家实例 */ public AccountRestriction(Player player) { this.player = player; this.loginStartTime = Instant.now(); } /** * 检查账号是否处于限制状态 * @return 处于限制状态返回{@code true},否则返回{@code false} */ public boolean isRestricted(RestrictionType type) { // 累计在线时长满1小时直接解除限制 if (totalOnlineDuration.compareTo(RESTRICT_THRESHOLD) >= 0) { return false; } player.sm(getRestriction(type)); return true; } /** * 获取限制提示文案 * @param type 限制类型 * @return 限制提示字符串 */ public String getRestriction(RestrictionType type) { long timeLeft = RESTRICT_THRESHOLD.minus(totalOnlineDuration).toMinutes(); String timeText; if (timeLeft >= 60) { timeText = "1</col> 小时"; } else if (timeLeft > 1) { timeText = timeLeft + "</col> 分钟"; } else if (timeLeft == 1) { timeText = "1</col> 分钟"; } else { timeText = "不到1</col> 分钟"; } return "你还有 <col=ff0000>" + timeText + " 的新玩家限制,无法使用功能:<col=ff0000>" + Utils.formatPlayerNameForDisplay(type.name()) + "</col>!"; } public Duration getTotalOnlineDuration() { return totalOnlineDuration; } }
逻辑说明
- 所有时间计算改用
Instant,不受时区、跨天影响,计算更准确 - 每次登录、每tick、登出三个节点都正确累加在线时长,离线不会产生时长增量
- 限制判断直接对比累计在线时长和1小时的阈值即可,逻辑清晰没有歧义
- 累计时长做了序列化持久化,重启服务、玩家重新登录都不会丢失计时数据
内容的提问来源于stack exchange,提问作者wyvern800
相关产品推荐
相关产品推荐

