- Progress Quest 6.4 Flutter 포팅 프로젝트 - 게임 루프, 상태 관리, UI 구현 - 캐릭터 생성, 인벤토리, 장비, 주문 시스템 - 시장/판매/구매 메커니즘
146 lines
4.0 KiB
Dart
146 lines
4.0 KiB
Dart
// Extracts TMemo Lines.Strings from example/pq/Config.dfm into a Dart const map.
|
|
// Usage:
|
|
// dart run tool/dfm_extract.dart [input_dfm] [output_dart]
|
|
// Defaults:
|
|
// input_dfm: example/pq/Config.dfm
|
|
// output_dart: lib/data/pq_config_data.dart
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
void main(List<String> args) {
|
|
final inputPath = args.isNotEmpty ? args[0] : 'example/pq/Config.dfm';
|
|
final outputPath = args.length > 1 ? args[1] : 'lib/data/pq_config_data.dart';
|
|
|
|
final file = File(inputPath);
|
|
if (!file.existsSync()) {
|
|
stderr.writeln('Input file not found: $inputPath');
|
|
exitCode = 1;
|
|
return;
|
|
}
|
|
|
|
final lines = file.readAsLinesSync();
|
|
final data = _parseMemos(lines);
|
|
_writeDart(outputPath, data);
|
|
_printSummary(outputPath, data);
|
|
}
|
|
|
|
Map<String, List<String>> _parseMemos(List<String> lines) {
|
|
final result = <String, List<String>>{};
|
|
String? currentMemo;
|
|
bool inLines = false;
|
|
|
|
for (final rawLine in lines) {
|
|
final line = rawLine.trimRight();
|
|
final trimmed = line.trimLeft();
|
|
|
|
// Detect TMemo object names.
|
|
if (trimmed.startsWith('object ') && trimmed.contains(': TMemo')) {
|
|
final token = trimmed.split(' ')[1];
|
|
currentMemo = token.contains(':') ? token.split(':').first : token;
|
|
inLines = false;
|
|
continue;
|
|
}
|
|
|
|
// Detect start of Lines.Strings block.
|
|
if (trimmed.contains('Lines.Strings')) {
|
|
if (currentMemo == null) continue;
|
|
inLines = true;
|
|
result[currentMemo] = <String>[];
|
|
continue;
|
|
}
|
|
|
|
if (!inLines || currentMemo == null) {
|
|
continue;
|
|
}
|
|
|
|
// End of block.
|
|
if (trimmed == ')') {
|
|
inLines = false;
|
|
continue;
|
|
}
|
|
|
|
// Extract string literal line (may end with "')" on last item).
|
|
final hasClosing = trimmed.endsWith(')');
|
|
final value = _decodeDelphiLiteral(line, stripTrailingParen: hasClosing);
|
|
if (value.isNotEmpty) {
|
|
result[currentMemo]!.add(value);
|
|
}
|
|
|
|
// Handle closing parenthesis on same line.
|
|
if (hasClosing) {
|
|
inLines = false;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
String _decodeDelphiLiteral(String line, {required bool stripTrailingParen}) {
|
|
// Remove trailing ')' only when it denotes end-of-block.
|
|
var work = line;
|
|
if (stripTrailingParen && work.trimRight().endsWith(')')) {
|
|
work = work.substring(0, work.lastIndexOf(')'));
|
|
}
|
|
|
|
final buffer = StringBuffer();
|
|
var i = 0;
|
|
while (i < work.length) {
|
|
final ch = work[i];
|
|
if (ch == '\'') {
|
|
// Quoted segment.
|
|
i++;
|
|
final start = i;
|
|
while (i < work.length && work[i] != '\'') {
|
|
i++;
|
|
}
|
|
buffer.write(work.substring(start, i));
|
|
i++; // Skip closing quote.
|
|
} else if (ch == '#') {
|
|
// Numeric char code segment.
|
|
i++;
|
|
final start = i;
|
|
while (i < work.length && _isDigit(work.codeUnitAt(i))) {
|
|
i++;
|
|
}
|
|
final code = int.parse(work.substring(start, i));
|
|
buffer.write(String.fromCharCode(code));
|
|
} else {
|
|
i++; // Ignore other characters between tokens.
|
|
}
|
|
}
|
|
return buffer.toString();
|
|
}
|
|
|
|
bool _isDigit(int charCode) => charCode >= 48 && charCode <= 57;
|
|
|
|
void _writeDart(String outputPath, Map<String, List<String>> data) {
|
|
final buffer = StringBuffer()
|
|
..writeln('// GENERATED CODE - DO NOT EDIT BY HAND.')
|
|
..writeln(
|
|
'// Generated by tool/dfm_extract.dart from example/pq/Config.dfm',
|
|
)
|
|
..writeln('')
|
|
..writeln('const Map<String, List<String>> pqConfigData = {');
|
|
|
|
final sortedKeys = data.keys.toList()..sort();
|
|
for (final key in sortedKeys) {
|
|
final encodedKey = jsonEncode(key);
|
|
final encodedList = jsonEncode(data[key]);
|
|
buffer.writeln(' $encodedKey: $encodedList,');
|
|
}
|
|
|
|
buffer.writeln('};');
|
|
|
|
File(outputPath)
|
|
..createSync(recursive: true)
|
|
..writeAsStringSync(buffer.toString());
|
|
}
|
|
|
|
void _printSummary(String outputPath, Map<String, List<String>> data) {
|
|
stdout.writeln('Wrote $outputPath');
|
|
for (final entry in data.entries) {
|
|
stdout.writeln(' - ${entry.key}: ${entry.value.length} items');
|
|
}
|
|
}
|