warcrafty 1.0.1 copy "warcrafty: ^1.0.1" to clipboard
warcrafty: ^1.0.1 copied to clipboard

A high-performance Dart library for reading and writing World of Warcraft DBC files.

example/warcrafty_example.dart

/// DBC 文件读写完整示例
///
/// 演示如何使用 warcrafty 库读取、写入和处理 DBC 文件。
// ignore_for_file: unused_local_variable, non_constant_identifier_names

library;

import 'dart:io';
import 'package:warcrafty/warcrafty.dart';

void main() async {
  print('=' * 80);
  print('WARCRAFTY DBC 库使用示例');
  print('=' * 80);

  // 示例 1: 使用预定义的结构
  print('\n=== 示例 1: 使用预定义结构 ===');
  await example1_PredefinedSchemas();

  // 示例 2: 读取 DBC 文件
  print('\n=== 示例 2: 读取 DBC 文件 ===');
  await example2_ReadingDbcFiles();

  // 示例 3: 写入 DBC 文件
  print('\n=== 示例 3: 写入 DBC 文件 ===');
  await example3_WritingDbcFiles();

  // 示例 4: 使用索引快速查找
  print('\n=== 示例 4: 使用索引 ===');
  await example4_UsingIndexes();

  // 示例 5: 从字节数据加载
  print('\n=== 示例 5: 从字节数据加载 ===');
  await example5_LoadingFromBytes();

  // 示例 6: 复制并修改现有文件
  print('\n=== 示例 6: 复制并修改文件 ===');
  await example6_CopyAndModify();

  // 示例 7: 创建自定义结构
  print('\n=== 示例 7: 自定义结构 ===');
  await example7_CustomSchema();

  // 示例 8: 错误处理
  print('\n=== 示例 8: 错误处理 ===');
  await example8_ErrorHandling();

  // 示例 9: 处理本地化字段
  print('\n=== 示例 9: 本地化字段 ===');
  await example9_LocalizedFields();

  print('\n${'=' * 80}');
  print('所有示例完成!');
  print('=' * 80);
}

/// 示例 1: 使用预定义结构
Future<void> example1_PredefinedSchemas() async {
  print('ChrRaces 结构名: ${Definitions.chrRaces.name}');
  print('ChrRaces 格式: ${Definitions.chrRaces.format}');
  print('ChrRaces 字段数: ${Definitions.chrRaces.fieldCount}');
  print('ChrRaces 记录大小: ${Definitions.chrRaces.recordSize} 字节');

  // 查找特定字段
  final idField = Definitions.chrRaces.getFieldByName('ID');
  if (idField != null) {
    print(
      '找到 ID 字段: ${idField.name} (索引: ${idField.index}, 类型: ${idField.type})',
    );
  }

  print('可用的预定义结构超过 200 个,涵盖所有主要 DBC 文件');
}

/// 示例 2: 读取 DBC 文件
Future<void> example2_ReadingDbcFiles() async {
  // 注意: 需要实际的 DBC 文件路径才能运行此示例
  const dbcPath = 'ChrRaces.dbc';

  if (!File(dbcPath).existsSync()) {
    print('文件不存在: $dbcPath');
    print('跳过此示例 - 请提供实际的 DBC 文件路径');
    return;
  }

  // 使用预定义格式加载
  final loader = DbcLoader(dbcPath, Definitions.chrRaces.format);

  print('文件: $dbcPath');
  print('记录数: ${loader.recordCount}');
  print('字段数: ${loader.fieldCount}');

  // 读取第一条记录
  if (loader.recordCount > 0) {
    final firstRecord = loader.getRecord(0);
    final id = firstRecord.getInt(0);
    print('第一条记录 ID: $id');

    // 尝试读取名称字段
    try {
      final name = firstRecord.getString(14); // Name_lang 字段
      print('第一条记录名称: $name');
    } catch (e) {
      print('无法读取名称字段: $e');
    }
  }

  // 遍历所有记录(前 5 条)
  print('\n前 5 条记录:');
  final count = loader.recordCount > 5 ? 5 : loader.recordCount;
  for (int i = 0; i < count; i++) {
    final record = loader.getRecord(i);
    final id = record.getInt(0);
    print('  记录 $i: ID = $id');
  }

  // 将所有记录转换为 Map
  print('\n转换为 Map 列表 (前 3 条):');
  final maps = loader.toMapList();
  for (int i = 0; i < (maps.length > 3 ? 3 : maps.length); i++) {
    print('  Map $i: ${maps[i]}');
  }
}

/// 示例 3: 写入 DBC 文件
Future<void> example3_WritingDbcFiles() async {
  final outputPath = 'example_output.dbc';

  // 创建测试数据
  final records = [
    [1, 0, 84, 0, 0, 'Human', 'Human'], // 简单格式
    [2, 1, 74, 0, 0, 'Orc', 'Orc'],
    [3, 2, 69, 0, 0, 'Night Elf', 'Night Elf'],
  ];

  print('准备写入 $records.length 条记录到: $outputPath');

  // 同步写入
  DbcWriter.writeToPath(outputPath, 'niiiiss', records);
  print('同步写入完成');

  // 验证文件是否创建
  if (File(outputPath).existsSync()) {
    print('文件已创建: ${File(outputPath).lengthSync()} 字节');

    // 读取验证
    final loader = DbcLoader(outputPath, 'niiiiss');
    print('验证读取: ${loader.recordCount} 条记录');

    // 清理测试文件
    File(outputPath).deleteSync();
    print('已清理测试文件');
  }
}

/// 示例 4: 使用索引
Future<void> example4_UsingIndexes() async {
  const dbcPath = 'ChrRaces.dbc';

  if (!File(dbcPath).existsSync()) {
    print('文件不存在: $dbcPath,跳过索引示例');
    return;
  }

  final loader = DbcLoader(dbcPath, Definitions.chrRaces.format);

  // 创建索引(从加载器)
  final index = DbcIndex.fromLoader(loader, (record) => record.toMap());

  print('索引创建完成');
  print('索引记录数: ${index.count}');
  print('索引字段: ${index.indexField}');

  // 获取所有 ID
  final allIds = index.allIds;
  print(
    '所有 ID: ${allIds.take(10).join(', ')}${allIds.length > 10 ? '...' : ''}',
  );

  // 快速查找
  if (allIds.isNotEmpty) {
    final firstId = allIds.first;
    final record = index.lookup(firstId);
    print('查找 ID $firstId: ${record != null ? "找到" : "未找到"}');
  }

  // 使用 contains 检查
  final testId = 1;
  if (index.contains(testId)) {
    print('索引包含 ID $testId');
  } else {
    print('索引不包含 ID $testId');
  }

  // 使用索引器
  final record = index[testId];
  if (record != null) {
    print('通过索引器找到 ID $testId: $record');
  }
}

/// 示例 5: 从字节数据加载
Future<void> example5_LoadingFromBytes() async {
  const dbcPath = 'ChrRaces.dbc';

  if (!File(dbcPath).existsSync()) {
    print('文件不存在: $dbcPath,跳过字节加载示例');
    return;
  }

  // 读取文件为字节
  final bytes = File(dbcPath).readAsBytesSync();
  print('读取文件为字节: ${bytes.length} 字节');

  // 从字节加载
  final loader = DbcLoader.fromBytes(bytes, Definitions.chrRaces.format);
  print('从字节加载完成: ${loader.recordCount} 条记录');

  // 比较:验证内容相同
  final fileLoader = DbcLoader(dbcPath, Definitions.chrRaces.format);
  print('文件加载验证: ${fileLoader.recordCount} 条记录');
  print('字节加载与文件加载结果相同: ${loader.recordCount == fileLoader.recordCount}');
}

/// 示例 6: 复制并修改文件
Future<void> example6_CopyAndModify() async {
  const inputPath = 'ChrRaces.dbc';
  const outputPath = 'example_modified.dbc';

  if (!File(inputPath).existsSync()) {
    print('文件不存在: $inputPath,跳过复制修改示例');
    return;
  }

  print('从 $inputPath 复制并修改到 $outputPath');

  DbcWriter.copyWithModify(inputPath, Definitions.chrRaces.format, outputPath, (
    source,
  ) {
    // 获取原始数据
    final id = source.getInt(0);
    final flags = source.getInt(1);
    final factionId = source.getInt(2);

    // 修改一些值(示例:增加 faction ID)
    return [
      id,
      flags,
      factionId + 1000, // 修改 faction ID
      source.getInt(3),
      source.getInt(4),
      source.getInt(5),
      source.getString(6),
      source.getInt(7),
      source.getInt(8),
      source.getInt(9),
      source.getInt(10),
      source.getString(11),
      source.getInt(12),
      source.getInt(13),
      source.getString(14),
      source.getString(15),
      // ... 其他字段(注意:这里为了简化只复制了部分字段)
    ];
  });

  print('复制修改完成');

  // 验证结果
  if (File(outputPath).existsSync()) {
    final outputLoader = DbcLoader(outputPath, Definitions.chrRaces.format);
    print('输出文件记录数: ${outputLoader.recordCount}');

    // 清理
    File(outputPath).deleteSync();
    print('已清理输出文件');
  }
}

/// 示例 7: 自定义结构
Future<void> example7_CustomSchema() async {
  // 创建自定义结构
  final customSchema = DbcSchema(
    name: 'CustomItem',
    format: 'niiiissff',
    fields: [
      const Field(
        index: 0,
        name: 'ID',
        description: 'Item ID',
        type: FieldType.id,
      ),
      const Field(
        index: 1,
        name: 'Class',
        description: 'Item Class',
        type: FieldType.int32,
      ),
      const Field(
        index: 2,
        name: 'SubClass',
        description: 'Item SubClass',
        type: FieldType.int32,
      ),
      const Field(
        index: 3,
        name: 'SoundID',
        description: 'Item SoundID',
        type: FieldType.int32,
      ),
      const Field(
        index: 4,
        name: 'DisplayID',
        description: 'Item DisplayID',
        type: FieldType.int32,
      ),
      const Field(
        index: 5,
        name: 'InventoryIcon',
        description: 'Item InventoryIcon',
        type: FieldType.string,
      ),
      const Field(
        index: 6,
        name: 'Name',
        description: 'Item Name',
        type: FieldType.string,
      ),
      const Field(
        index: 7,
        name: 'Price',
        description: 'Item Price',
        type: FieldType.float,
      ),
      const Field(
        index: 8,
        name: 'Quality',
        description: 'Item Quality',
        type: FieldType.float,
      ),
    ],
  );

  print('自定义结构创建: ${customSchema.name}');
  print('格式: ${customSchema.format}');
  print('字段数: ${customSchema.fieldCount}');
  print('记录大小: ${customSchema.recordSize} 字节');

  // 使用自定义结构
  final outputPath = 'custom_example.dbc';
  final records = [
    [1001, 2, 5, 0, 12345, 'inv_sword_04', 'Sword of Power', 1000.0, 0.5],
    [1002, 2, 5, 0, 12346, 'inv_axe_04', 'Axe of Fury', 1200.0, 0.6],
  ];

  DbcWriter.writeToPath(outputPath, customSchema.format, records);
  print('写入自定义结构文件: $outputPath');

  // 验证读取
  final loader = DbcLoader(outputPath, customSchema.format);
  print('读取验证: ${loader.recordCount} 条记录');

  for (final record in loader.records) {
    final id = record.getInt(0);
    final name = record.getString(6);
    final price = record.getFloat(7);
    print('  ID: $id, 名称: $name, 价格: $price');
  }

  // 清理
  File(outputPath).deleteSync();
  print('已清理自定义文件');
}

/// 示例 8: 错误处理
Future<void> example8_ErrorHandling() async {
  print('演示各种错误情况');

  // 错误 1: 无效的格式字符串
  try {
    final loader = DbcLoader('dummy.dbc', 'xyz');
    print('不应该到达这里');
  } catch (e) {
    print('✓ 捕获到格式字符串错误: ${e.toString().split(':')[0]}');
  }

  // 错误 2: 尝试读取不存在的文件
  try {
    final loader = DbcLoader('nonexistent.dbc', 'niiiiss');
    print('不应该到达这里');
  } catch (e) {
    print('✓ 捕获到文件错误: ${e.toString().split(':')[0]}');
  }

  // 错误 3: 字段类型不匹配
  try {
    DbcWriter.writeToPath('error_test.dbc', 'ni', [
      [1, 'not_a_number'], // 第二个字段应该是数字
    ]);
  } catch (e) {
    print('✓ 捕获到字段类型错误: ${e.toString().split(':')[0]}');
    // 清理可能创建的文件
    if (File('error_test.dbc').existsSync()) {
      File('error_test.dbc').deleteSync();
    }
  }

  print('错误处理示例完成');
}

/// 示例 9: 处理本地化字段
Future<void> example9_LocalizedFields() async {
  const dbcPath = 'ChrRaces.dbc';

  if (!File(dbcPath).existsSync()) {
    print('文件不存在: $dbcPath,跳过本地化示例');
    return;
  }

  final loader = DbcLoader(dbcPath, Definitions.chrRaces.format);

  print('ChrRaces 结构包含本地化字段:');
  print('  名称字段范围: 14-30 (16 种语言)');
  print('  女性名称字段范围: 31-47 (16 种语言)');
  print('  男性名称字段范围: 48-64 (16 种语言)');

  if (loader.recordCount > 0) {
    final firstRecord = loader.getRecord(0);

    print('\n示例记录 (索引 0):');
    print('  ID: ${firstRecord.getInt(0)}');
    print('  标志: ${firstRecord.getInt(1)}');

    // 尝试读取本地化名称
    try {
      // 通常英语是第一个本地化字段
      final englishName = firstRecord.getString(14);
      print('  英语名称: $englishName');
    } catch (e) {
      print('  无法读取本地化字段: $e');
    }
  }

  print('\n注意: 实际的本地化字段索引取决于具体结构定义');
}
1
likes
150
points
20
downloads

Publisher

verified publisherfoxwow.xyz

Weekly Downloads

A high-performance Dart library for reading and writing World of Warcraft DBC files.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

More

Packages that depend on warcrafty