fix(buff): 배속 상태에서 버프 시간이 배속을 따라가는 버그 수정
Some checks failed
CI / analyze-and-test (push) Has been cancelled
Some checks failed
CI / analyze-and-test (push) Has been cancelled
- speedBoostEndMs: elapsedMs(게임 시간) → DateTime.now()(실제 시간) - autoReviveEndMs: elapsedMs → DateTime.now() - MonetizationState: isAutoReviveActive/isSpeedBoostActive 실제 시간 기준 - 5배속에서 5분 버프가 1분에 만료되던 문제 해결 - bossLevelingEndTime은 이미 DateTime.now() 기준 (변경 불필요)
This commit is contained in:
@@ -69,18 +69,18 @@ class MonetizationState with _$MonetizationState {
|
|||||||
/// 무료 사용자 여부
|
/// 무료 사용자 여부
|
||||||
bool get isFreeUser => !adRemovalPurchased;
|
bool get isFreeUser => !adRemovalPurchased;
|
||||||
|
|
||||||
/// 자동부활 버프 활성 여부 (elapsedMs 기준)
|
/// 자동부활 버프 활성 여부 (실제 시간 기준)
|
||||||
bool isAutoReviveActive(int elapsedMs) {
|
bool isAutoReviveActive([int? _]) {
|
||||||
if (autoReviveEndMs == null) return false;
|
if (autoReviveEndMs == null) return false;
|
||||||
return elapsedMs < autoReviveEndMs!;
|
return DateTime.now().millisecondsSinceEpoch < autoReviveEndMs!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 5배속 버프 활성 여부 (elapsedMs 기준)
|
/// 5배속 버프 활성 여부 (실제 시간 기준)
|
||||||
/// 유료 사용자는 항상 활성
|
/// 유료 사용자는 항상 활성
|
||||||
bool isSpeedBoostActive(int elapsedMs) {
|
bool isSpeedBoostActive([int? _]) {
|
||||||
if (isPaidUser) return true;
|
if (isPaidUser) return true;
|
||||||
if (speedBoostEndMs == null) return false;
|
if (speedBoostEndMs == null) return false;
|
||||||
return elapsedMs < speedBoostEndMs!;
|
return DateTime.now().millisecondsSinceEpoch < speedBoostEndMs!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 행운의 부적 버프 활성 여부 (elapsedMs 기준)
|
/// 행운의 부적 버프 활성 여부 (elapsedMs 기준)
|
||||||
|
|||||||
@@ -136,10 +136,8 @@ class GameSessionController extends ChangeNotifier {
|
|||||||
int get speedBoostMultiplier => _speedBoostManager.speedBoostMultiplier;
|
int get speedBoostMultiplier => _speedBoostManager.speedBoostMultiplier;
|
||||||
int get speedBoostDuration => _speedBoostManager.speedBoostDuration;
|
int get speedBoostDuration => _speedBoostManager.speedBoostDuration;
|
||||||
|
|
||||||
int get speedBoostRemainingSeconds => _speedBoostManager.getRemainingSeconds(
|
int get speedBoostRemainingSeconds =>
|
||||||
_monetization,
|
_speedBoostManager.getRemainingSeconds(_monetization);
|
||||||
_state?.skillSystem.elapsedMs ?? 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
int get currentSpeedMultiplier =>
|
int get currentSpeedMultiplier =>
|
||||||
_speedBoostManager.getCurrentSpeedMultiplier(_loop);
|
_speedBoostManager.getCurrentSpeedMultiplier(_loop);
|
||||||
@@ -242,7 +240,6 @@ class GameSessionController extends ChangeNotifier {
|
|||||||
void _checkBuffExpiries(int elapsedMs) {
|
void _checkBuffExpiries(int elapsedMs) {
|
||||||
// 속도 부스트 만료 체크
|
// 속도 부스트 만료 체크
|
||||||
final boostEnded = _speedBoostManager.checkExpiry(
|
final boostEnded = _speedBoostManager.checkExpiry(
|
||||||
elapsedMs: elapsedMs,
|
|
||||||
monetization: _monetization,
|
monetization: _monetization,
|
||||||
loop: _loop,
|
loop: _loop,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ class ResurrectionManager {
|
|||||||
void processRevive() {
|
void processRevive() {
|
||||||
revivedState = resurrectionService.processAdRevive(state);
|
revivedState = resurrectionService.processAdRevive(state);
|
||||||
|
|
||||||
// 10분 자동부활 버프 활성화 (elapsedMs 기준)
|
// 10분 자동부활 버프 활성화 (실제 시간 기준, 배속 영향 받지 않음)
|
||||||
final buffEndMs =
|
final buffEndMs =
|
||||||
revivedState!.skillSystem.elapsedMs + 600000; // 10분 = 600,000ms
|
DateTime.now().millisecondsSinceEpoch + 600000; // 10분 = 600,000ms
|
||||||
updatedMonetization = monetization.copyWith(autoReviveEndMs: buffEndMs);
|
updatedMonetization = monetization.copyWith(autoReviveEndMs: buffEndMs);
|
||||||
|
|
||||||
debugPrint(
|
debugPrint(
|
||||||
|
|||||||
@@ -51,15 +51,12 @@ class SpeedBoostManager {
|
|||||||
/// 속도 부스트 지속 시간 (초)
|
/// 속도 부스트 지속 시간 (초)
|
||||||
int get speedBoostDuration => _speedBoostDuration;
|
int get speedBoostDuration => _speedBoostDuration;
|
||||||
|
|
||||||
/// 속도 부스트 남은 시간 (초) - 게임 시간(elapsedMs) 기준 계산
|
/// 속도 부스트 남은 시간 (초) - 실제 시간(wall clock) 기준 계산
|
||||||
int getRemainingSeconds(
|
int getRemainingSeconds(MonetizationState monetization) {
|
||||||
MonetizationState monetization,
|
|
||||||
int currentElapsedMs,
|
|
||||||
) {
|
|
||||||
if (!_isSpeedBoostActive) return 0;
|
if (!_isSpeedBoostActive) return 0;
|
||||||
final endMs = monetization.speedBoostEndMs;
|
final endMs = monetization.speedBoostEndMs;
|
||||||
if (endMs == null) return 0;
|
if (endMs == null) return 0;
|
||||||
final remainingMs = endMs - currentElapsedMs;
|
final remainingMs = endMs - DateTime.now().millisecondsSinceEpoch;
|
||||||
return remainingMs > 0 ? (remainingMs / 1000).ceil() : 0;
|
return remainingMs > 0 ? (remainingMs / 1000).ceil() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,8 +133,9 @@ class SpeedBoostManager {
|
|||||||
loop.updateAvailableSpeeds([speedBoostMultiplier]);
|
loop.updateAvailableSpeeds([speedBoostMultiplier]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 종료 시점 저장 (게임 시간 기준)
|
// 종료 시점 저장 (실제 시간 기준, 배속 영향 받지 않음)
|
||||||
final endMs = currentElapsedMs + (_speedBoostDuration * 1000);
|
final endMs =
|
||||||
|
DateTime.now().millisecondsSinceEpoch + (_speedBoostDuration * 1000);
|
||||||
final updatedMonetization = monetization.copyWith(speedBoostEndMs: endMs);
|
final updatedMonetization = monetization.copyWith(speedBoostEndMs: endMs);
|
||||||
|
|
||||||
debugPrint('[SpeedBoost] Started, ends at $endMs ms');
|
debugPrint('[SpeedBoost] Started, ends at $endMs ms');
|
||||||
@@ -150,14 +148,14 @@ class SpeedBoostManager {
|
|||||||
///
|
///
|
||||||
/// Returns: 부스트가 종료되었으면 true
|
/// Returns: 부스트가 종료되었으면 true
|
||||||
bool checkExpiry({
|
bool checkExpiry({
|
||||||
required int elapsedMs,
|
|
||||||
required MonetizationState monetization,
|
required MonetizationState monetization,
|
||||||
required ProgressLoop? loop,
|
required ProgressLoop? loop,
|
||||||
}) {
|
}) {
|
||||||
if (!_isSpeedBoostActive) return false;
|
if (!_isSpeedBoostActive) return false;
|
||||||
|
|
||||||
final endMs = monetization.speedBoostEndMs;
|
final endMs = monetization.speedBoostEndMs;
|
||||||
if (endMs != null && elapsedMs >= endMs) {
|
final now = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
if (endMs != null && now >= endMs) {
|
||||||
endSpeedBoost(loop: loop);
|
endSpeedBoost(loop: loop);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,31 +56,36 @@ void main() {
|
|||||||
test('autoReviveEndMs가 null이면 false 반환', () {
|
test('autoReviveEndMs가 null이면 false 반환', () {
|
||||||
final state = MonetizationState.initial();
|
final state = MonetizationState.initial();
|
||||||
|
|
||||||
expect(state.isAutoReviveActive(1000), isFalse);
|
expect(state.isAutoReviveActive(), isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('elapsedMs가 종료 시점 이내면 true 반환', () {
|
test('종료 시점이 미래면 true 반환', () {
|
||||||
|
final futureMs =
|
||||||
|
DateTime.now().millisecondsSinceEpoch + 60000; // 1분 후
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
autoReviveEndMs: 5000,
|
autoReviveEndMs: futureMs,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(state.isAutoReviveActive(3000), isTrue);
|
expect(state.isAutoReviveActive(), isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('elapsedMs가 종료 시점을 초과하면 false 반환', () {
|
test('종료 시점이 과거면 false 반환', () {
|
||||||
|
final pastMs =
|
||||||
|
DateTime.now().millisecondsSinceEpoch - 1000; // 1초 전
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
autoReviveEndMs: 5000,
|
autoReviveEndMs: pastMs,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(state.isAutoReviveActive(6000), isFalse);
|
expect(state.isAutoReviveActive(), isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('elapsedMs가 종료 시점과 정확히 같으면 false 반환 (경계값)', () {
|
test('종료 시점이 현재와 거의 같으면 false 반환 (경계값)', () {
|
||||||
|
final nowMs = DateTime.now().millisecondsSinceEpoch - 1;
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
autoReviveEndMs: 5000,
|
autoReviveEndMs: nowMs,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(state.isAutoReviveActive(5000), isFalse);
|
expect(state.isAutoReviveActive(), isFalse);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -93,30 +98,33 @@ void main() {
|
|||||||
final state = MonetizationState.initial(isPaidUser: true);
|
final state = MonetizationState.initial(isPaidUser: true);
|
||||||
|
|
||||||
// speedBoostEndMs가 null이어도 유료 사용자는 항상 활성
|
// speedBoostEndMs가 null이어도 유료 사용자는 항상 활성
|
||||||
expect(state.isSpeedBoostActive(0), isTrue);
|
expect(state.isSpeedBoostActive(), isTrue);
|
||||||
expect(state.isSpeedBoostActive(999999), isTrue);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('무료 사용자 - 종료 시점 이내면 true 반환', () {
|
test('무료 사용자 - 종료 시점이 미래면 true 반환', () {
|
||||||
|
final futureMs =
|
||||||
|
DateTime.now().millisecondsSinceEpoch + 60000;
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
speedBoostEndMs: 10000,
|
speedBoostEndMs: futureMs,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(state.isSpeedBoostActive(5000), isTrue);
|
expect(state.isSpeedBoostActive(), isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('무료 사용자 - 종료 시점 초과 시 false 반환', () {
|
test('무료 사용자 - 종료 시점이 과거면 false 반환', () {
|
||||||
|
final pastMs =
|
||||||
|
DateTime.now().millisecondsSinceEpoch - 1000;
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
speedBoostEndMs: 10000,
|
speedBoostEndMs: pastMs,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(state.isSpeedBoostActive(15000), isFalse);
|
expect(state.isSpeedBoostActive(), isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('무료 사용자 - speedBoostEndMs가 null이면 false 반환', () {
|
test('무료 사용자 - speedBoostEndMs가 null이면 false 반환', () {
|
||||||
final state = MonetizationState.initial();
|
final state = MonetizationState.initial();
|
||||||
|
|
||||||
expect(state.isSpeedBoostActive(1000), isFalse);
|
expect(state.isSpeedBoostActive(), isFalse);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user