style(format): dart format 자동 포맷 적용
Some checks are pending
CI / analyze-and-test (push) Waiting to run
Some checks are pending
CI / analyze-and-test (push) Waiting to run
- combat_tick_service, error_logger, save_integrity: 줄바꿈/정렬 - monetization_state_test, save_integrity_test: 포맷 정리 - macos/Podfile.lock: flutter pub get 반영
This commit is contained in:
@@ -179,12 +179,14 @@ class CombatTickService {
|
|||||||
if (monsterStats.isAlive &&
|
if (monsterStats.isAlive &&
|
||||||
monsterAccumulator >= monsterStats.attackDelayMs) {
|
monsterAccumulator >= monsterStats.attackDelayMs) {
|
||||||
// 방어력/회피율 버프 적용
|
// 방어력/회피율 버프 적용
|
||||||
final buffedPlayerForDefense = (buffMods.defMod != 0 ||
|
final buffedPlayerForDefense =
|
||||||
buffMods.evasionMod != 0)
|
(buffMods.defMod != 0 || buffMods.evasionMod != 0)
|
||||||
? playerStats.copyWith(
|
? playerStats.copyWith(
|
||||||
def: (playerStats.def * (1.0 + buffMods.defMod)).round(),
|
def: (playerStats.def * (1.0 + buffMods.defMod)).round(),
|
||||||
evasion: (playerStats.evasion + buffMods.evasionMod)
|
evasion: (playerStats.evasion + buffMods.evasionMod).clamp(
|
||||||
.clamp(0.0, 1.0),
|
0.0,
|
||||||
|
1.0,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: playerStats;
|
: playerStats;
|
||||||
|
|
||||||
|
|||||||
@@ -122,8 +122,7 @@ class ErrorLogger {
|
|||||||
if (size <= maxLogBytes) return;
|
if (size <= maxLogBytes) return;
|
||||||
|
|
||||||
final dir = file.parent.path;
|
final dir = file.parent.path;
|
||||||
final baseName =
|
final baseName = _logFileName.replaceAll('.jsonl', '');
|
||||||
_logFileName.replaceAll('.jsonl', '');
|
|
||||||
|
|
||||||
// 가장 오래된 백업 삭제
|
// 가장 오래된 백업 삭제
|
||||||
final oldest = File('$dir/$baseName.$maxBackupCount.jsonl');
|
final oldest = File('$dir/$baseName.$maxBackupCount.jsonl');
|
||||||
|
|||||||
@@ -21,18 +21,60 @@ class SaveIntegrity {
|
|||||||
static List<int> get _hmacKey {
|
static List<int> get _hmacKey {
|
||||||
// 파트 A: 원본 키의 전반부
|
// 파트 A: 원본 키의 전반부
|
||||||
const partA = <int>[
|
const partA = <int>[
|
||||||
0x41, 0x73, 0x63, 0x69, 0x69, 0x4e, 0x65, 0x76,
|
0x41,
|
||||||
0x65, 0x72, 0x44, 0x69, 0x65, 0x53, 0x61, 0x76,
|
0x73,
|
||||||
|
0x63,
|
||||||
|
0x69,
|
||||||
|
0x69,
|
||||||
|
0x4e,
|
||||||
|
0x65,
|
||||||
|
0x76,
|
||||||
|
0x65,
|
||||||
|
0x72,
|
||||||
|
0x44,
|
||||||
|
0x69,
|
||||||
|
0x65,
|
||||||
|
0x53,
|
||||||
|
0x61,
|
||||||
|
0x76,
|
||||||
];
|
];
|
||||||
// 파트 B: XOR 마스크(mask)
|
// 파트 B: XOR 마스크(mask)
|
||||||
const mask = <int>[
|
const mask = <int>[
|
||||||
0x7a, 0x1c, 0x0f, 0x05, 0x0d, 0x22, 0x09, 0x1a,
|
0x7a,
|
||||||
0x09, 0x1e, 0x28, 0x05, 0x09, 0x3f, 0x0d, 0x1a,
|
0x1c,
|
||||||
|
0x0f,
|
||||||
|
0x05,
|
||||||
|
0x0d,
|
||||||
|
0x22,
|
||||||
|
0x09,
|
||||||
|
0x1a,
|
||||||
|
0x09,
|
||||||
|
0x1e,
|
||||||
|
0x28,
|
||||||
|
0x05,
|
||||||
|
0x09,
|
||||||
|
0x3f,
|
||||||
|
0x0d,
|
||||||
|
0x1a,
|
||||||
];
|
];
|
||||||
// 파트 C: partA XOR mask 결과 (키 후반부)
|
// 파트 C: partA XOR mask 결과 (키 후반부)
|
||||||
const partC = <int>[
|
const partC = <int>[
|
||||||
0x3b, 0x6f, 0x6c, 0x6c, 0x64, 0x6c, 0x6c, 0x6c,
|
0x3b,
|
||||||
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
|
0x6f,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x64,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
|
0x6c,
|
||||||
];
|
];
|
||||||
|
|
||||||
// 전반부(partA) + 후반부(partC XOR mask)로 32바이트 키 생성
|
// 전반부(partA) + 후반부(partC XOR mask)로 32바이트 키 생성
|
||||||
@@ -107,10 +149,7 @@ class SaveIntegrity {
|
|||||||
|
|
||||||
/// HMAC 검증 결과(result)
|
/// HMAC 검증 결과(result)
|
||||||
class SaveIntegrityResult {
|
class SaveIntegrityResult {
|
||||||
const SaveIntegrityResult({
|
const SaveIntegrityResult({required this.gzipBytes, required this.isLegacy});
|
||||||
required this.gzipBytes,
|
|
||||||
required this.isLegacy,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// HMAC을 제외한 순수 GZip 데이터
|
/// HMAC을 제외한 순수 GZip 데이터
|
||||||
final Uint8List gzipBytes;
|
final Uint8List gzipBytes;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- audio_session (0.0.1):
|
- audio_session (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- flutter_secure_storage_macos (6.1.3):
|
||||||
|
- FlutterMacOS
|
||||||
- FlutterMacOS (1.0.0)
|
- FlutterMacOS (1.0.0)
|
||||||
- in_app_purchase_storekit (0.0.1):
|
- in_app_purchase_storekit (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -22,6 +24,7 @@ PODS:
|
|||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
|
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
|
||||||
|
- flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
|
||||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
- in_app_purchase_storekit (from `Flutter/ephemeral/.symlinks/plugins/in_app_purchase_storekit/darwin`)
|
- in_app_purchase_storekit (from `Flutter/ephemeral/.symlinks/plugins/in_app_purchase_storekit/darwin`)
|
||||||
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/darwin`)
|
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/darwin`)
|
||||||
@@ -33,6 +36,8 @@ DEPENDENCIES:
|
|||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
audio_session:
|
audio_session:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos
|
||||||
|
flutter_secure_storage_macos:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
|
||||||
FlutterMacOS:
|
FlutterMacOS:
|
||||||
:path: Flutter/ephemeral
|
:path: Flutter/ephemeral
|
||||||
in_app_purchase_storekit:
|
in_app_purchase_storekit:
|
||||||
@@ -50,6 +55,7 @@ EXTERNAL SOURCES:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
audio_session: 728ae3823d914f809c485d390274861a24b0904e
|
audio_session: 728ae3823d914f809c485d390274861a24b0904e
|
||||||
|
flutter_secure_storage_macos: c2754d3483d20bb207bb9e5a14f1b8e771abcdb9
|
||||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||||
in_app_purchase_storekit: 2342c0a5da86593124d08dd13d920f39a52b273a
|
in_app_purchase_storekit: 2342c0a5da86593124d08dd13d920f39a52b273a
|
||||||
just_audio: a42c63806f16995daf5b219ae1d679deb76e6a79
|
just_audio: a42c63806f16995daf5b219ae1d679deb76e6a79
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('종료 시점이 미래면 true 반환', () {
|
test('종료 시점이 미래면 true 반환', () {
|
||||||
final futureMs =
|
final futureMs = DateTime.now().millisecondsSinceEpoch + 60000; // 1분 후
|
||||||
DateTime.now().millisecondsSinceEpoch + 60000; // 1분 후
|
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
autoReviveEndMs: futureMs,
|
autoReviveEndMs: futureMs,
|
||||||
);
|
);
|
||||||
@@ -70,8 +69,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('종료 시점이 과거면 false 반환', () {
|
test('종료 시점이 과거면 false 반환', () {
|
||||||
final pastMs =
|
final pastMs = DateTime.now().millisecondsSinceEpoch - 1000; // 1초 전
|
||||||
DateTime.now().millisecondsSinceEpoch - 1000; // 1초 전
|
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
autoReviveEndMs: pastMs,
|
autoReviveEndMs: pastMs,
|
||||||
);
|
);
|
||||||
@@ -102,8 +100,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('무료 사용자 - 종료 시점이 미래면 true 반환', () {
|
test('무료 사용자 - 종료 시점이 미래면 true 반환', () {
|
||||||
final futureMs =
|
final futureMs = DateTime.now().millisecondsSinceEpoch + 60000;
|
||||||
DateTime.now().millisecondsSinceEpoch + 60000;
|
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
speedBoostEndMs: futureMs,
|
speedBoostEndMs: futureMs,
|
||||||
);
|
);
|
||||||
@@ -112,8 +109,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('무료 사용자 - 종료 시점이 과거면 false 반환', () {
|
test('무료 사용자 - 종료 시점이 과거면 false 반환', () {
|
||||||
final pastMs =
|
final pastMs = DateTime.now().millisecondsSinceEpoch - 1000;
|
||||||
DateTime.now().millisecondsSinceEpoch - 1000;
|
|
||||||
final state = MonetizationState.initial().copyWith(
|
final state = MonetizationState.initial().copyWith(
|
||||||
speedBoostEndMs: pastMs,
|
speedBoostEndMs: pastMs,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ void main() {
|
|||||||
final signed = SaveIntegrity.sign(original);
|
final signed = SaveIntegrity.sign(original);
|
||||||
|
|
||||||
// 서명된 데이터 = HMAC(32바이트) + 원본
|
// 서명된 데이터 = HMAC(32바이트) + 원본
|
||||||
expect(signed.length, equals(SaveIntegrity.hmacLength + original.length));
|
expect(
|
||||||
|
signed.length,
|
||||||
|
equals(SaveIntegrity.hmacLength + original.length),
|
||||||
|
);
|
||||||
|
|
||||||
final result = SaveIntegrity.verify(signed);
|
final result = SaveIntegrity.verify(signed);
|
||||||
|
|
||||||
@@ -101,7 +104,9 @@ void main() {
|
|||||||
test('레거시 포맷은 HMAC 검증을 건너뛰고 원본 데이터 반환', () {
|
test('레거시 포맷은 HMAC 검증을 건너뛰고 원본 데이터 반환', () {
|
||||||
// GZip 매직 바이트로 시작하는 큰 데이터
|
// GZip 매직 바이트로 시작하는 큰 데이터
|
||||||
final legacyData = Uint8List.fromList([
|
final legacyData = Uint8List.fromList([
|
||||||
0x1f, 0x8b, ...List.generate(100, (i) => i % 256),
|
0x1f,
|
||||||
|
0x8b,
|
||||||
|
...List.generate(100, (i) => i % 256),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
final result = SaveIntegrity.verify(legacyData);
|
final result = SaveIntegrity.verify(legacyData);
|
||||||
|
|||||||
Reference in New Issue
Block a user