Compare commits
10 Commits
10341ed46a
...
b225dbe90c
| Author | SHA1 | Date | |
|---|---|---|---|
| b225dbe90c | |||
| 98f7f074cf | |||
| 592115c8f0 | |||
| 89fed62dcc | |||
| dac89497d0 | |||
| a799681194 | |||
| 14c8a3b910 | |||
| 2a9d9609ab | |||
| b7b4ab9ad1 | |||
| 1c9744eba6 |
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@@ -14,7 +14,8 @@
|
||||
"webpack:///./*": "${workspaceRoot}/*",
|
||||
"webpack:///*": "*"
|
||||
},
|
||||
"cwd": "D:/work/repositories/zombie/config/新配表",
|
||||
"cwd": "C:/Users/Geequlim/Desktop/sheet",
|
||||
// "cwd": "D:/work/repositories/zombie/config/新配表",
|
||||
// "cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/dist/binary.js",
|
||||
"args": [
|
||||
|
||||
70
README.md
70
README.md
@@ -3,11 +3,11 @@
|
||||
将 Excel 配置表中的数据导出为方便程序读取和使用的数据。
|
||||
|
||||
## 支持将Excel配置表导出为:
|
||||
- [x] JSON 文件
|
||||
- [x] YAML 文件
|
||||
- [x] JSON 数据文件
|
||||
- [x] YAML 数据文件
|
||||
- [x] C# 类型声明
|
||||
- [x] TypeScript interface类型声明、class类型定义(可用 `instanceof` 进行类型检查)
|
||||
- [ ] Godot 引擎的 GDScript 脚本文件
|
||||
- [x] 能够扩展导出其他数据格式和代码声明
|
||||
|
||||
## 表格格式说明
|
||||
|
||||
@@ -15,15 +15,46 @@
|
||||
* 表名为 `@skip` 或以 `@skip` 开头的表会被忽略,不会导出数据文件
|
||||
* 第一列值为 `@skip` 的行会被忽略,视为无效数据行
|
||||
* 整行所有列为空的行会被忽略,视为无效数据行
|
||||
* 每张表的**第一个有效数据行**用作字段名,决定了导出数据所拥有的属性,**字段名必须符合标识符命名规范**
|
||||
* 字段名所在的行中不填名称的列视为空字段,该列的数据在导出时会被忽略
|
||||
* 第一列名为`@field`的行用作字段名,决定了导出数据所拥有的属性,**字段名必须符合标识符命名规范**;该行中不填名称的列视为空字段,该列的数据在导出时会被忽略,可以用于辅助数据列
|
||||
* 第一列名为`@comment`的行用作字段注释文档,用于描述其底下对应的字段
|
||||
* 相同名称的字段导出时会被合并为数组
|
||||
* 导出属性的数据类型由**整列所填写的数据类型**决定,支持以下数据类型
|
||||
* 字符串
|
||||
* 数值(优先使用整形)
|
||||
* 布尔值
|
||||
* 空(`null`)
|
||||
* 该工具设计原则是简单易用,表格字段可由策划自由调整,不支持数据引用,暂不支持结构体
|
||||
* 该工具设计原则是简单易用,表格字段可由策划自由调整,不支持数据引用
|
||||
|
||||
### 表格式示例
|
||||

|
||||
以 TypeScript 为例,上图所示的表格将被导出为下面的数据格式,每行数据可被表示为一个 `EffectSequenceData` 类型的对象
|
||||
```ts
|
||||
export class EffectSequenceData {
|
||||
readonly id: number;
|
||||
/** 关键帧 */
|
||||
readonly frames: readonly {
|
||||
/** 时间 */
|
||||
readonly time: number;
|
||||
/** 事件 */
|
||||
readonly event: string;
|
||||
/** 特效 */
|
||||
readonly effect: string;
|
||||
/** 音效 */
|
||||
readonly audio: string;
|
||||
}[];
|
||||
/** 动作 */
|
||||
readonly animation: string;
|
||||
/** 时长 */
|
||||
readonly length: number;
|
||||
|
||||
static $bind_rows(rows: object[]) {
|
||||
for (const row of rows) {
|
||||
Object.setPrototypeOf(row, EffectSequenceData.prototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 安装
|
||||
- 安装 NodeJS 和 NPM, 注意将 Node 和 NPM 添加到环境变量 `PATH` 中
|
||||
@@ -41,33 +72,28 @@ npm run build
|
||||
### 配置示例
|
||||
|
||||
```yaml
|
||||
parser:
|
||||
first_row_as_field_comment: true
|
||||
input:
|
||||
- file: 配置表.xlsx
|
||||
encode: GBK
|
||||
- 特效表.xlsx
|
||||
parser:
|
||||
first_column_as_id: true # 第一列用作 ID 列
|
||||
constant_array_length: [
|
||||
# 这里填入需要固定数组长度的表名称
|
||||
]
|
||||
output:
|
||||
json:
|
||||
enabled: true
|
||||
directory: output/json
|
||||
enabled: false
|
||||
directory: "../../project/Assets/res/data/excel"
|
||||
indent: "\t"
|
||||
yaml:
|
||||
enabled: true
|
||||
directory: output/yaml
|
||||
directory: "../../project/Assets/res/data/excel"
|
||||
indent: 2
|
||||
csharp:
|
||||
enabled: true
|
||||
directory: output/csharp
|
||||
namespace: game.data
|
||||
base_type: tiny.data.UniqueIDObject
|
||||
file_name: data
|
||||
ignore_id: true
|
||||
typescript:
|
||||
enabled: true
|
||||
declaration: false
|
||||
type: class
|
||||
class_name_prefix: ''
|
||||
class_name_extension: Data
|
||||
directory: output/typescript
|
||||
file_name: data
|
||||
directory: "../../project/Scripts/src/game/configs"
|
||||
file_name: excel
|
||||
```
|
||||
BIN
screentshot-sheet-example.png
Normal file
BIN
screentshot-sheet-example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
@@ -5,6 +5,7 @@ import { path } from "tiny/path";
|
||||
export interface ExporterConfigs {
|
||||
enabled: boolean,
|
||||
directory: string,
|
||||
extension?: string;
|
||||
}
|
||||
|
||||
export class TableExporter {
|
||||
@@ -15,7 +16,7 @@ export class TableExporter {
|
||||
this.configs = configs;
|
||||
}
|
||||
|
||||
get extension(): string { return ''}
|
||||
get extension(): string { return this.configs.extension || ''; }
|
||||
|
||||
protected line(text = "", indent = 0) {
|
||||
return this.indent_text(text, indent) + '\n';
|
||||
|
||||
@@ -29,6 +29,11 @@ interface RawTableCell extends xlsl.CellObject {
|
||||
|
||||
type RawTableData = RawTableCell[][];
|
||||
|
||||
export interface TableData {
|
||||
struct: Field;
|
||||
data: {[key: string]: any}[];
|
||||
}
|
||||
|
||||
export interface ParserConfigs {
|
||||
/** 第一列作为ID */
|
||||
first_column_as_id: boolean;
|
||||
@@ -52,6 +57,8 @@ export class Field {
|
||||
type?: DataType;
|
||||
/** 保持数组长度和配置表中的列数量一致,没填的数据使用 null 填充 */
|
||||
constant_array_length?: boolean;
|
||||
/** 所属字段 */
|
||||
parent: Field;
|
||||
|
||||
/** 添加子字段 */
|
||||
add_field(field: Field) {
|
||||
@@ -126,11 +133,18 @@ export class Field {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type === DataType.null) {
|
||||
console.log(colors.red(`\t\t${name}(${xlsl.utils.encode_col(fields[0].columns.start)}列) 没有填入有效数据, 无法推断其数据类型`));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const c of this.children) {
|
||||
c.constant_array_length = this.constant_array_length;
|
||||
c.parent = this;
|
||||
c.build();
|
||||
if (c.type === DataType.null && !c._is_array) {
|
||||
console.log(colors.red(`\t\t${c.name}(${xlsl.utils.encode_col(c.columns.start)}列) 没有填入有效数据, 无法推断其数据类型`));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,17 +169,18 @@ export class Field {
|
||||
let obj = {};
|
||||
let isAllNullish = true;
|
||||
for (const c of this.children) {
|
||||
let value = c.parse_row(row);
|
||||
const value = c.parse_row(row);
|
||||
const is_null = this.check_is_null(row);
|
||||
if (c.is_array) {
|
||||
let arr: any[] = obj[c.name] || [];
|
||||
if (this.constant_array_length || value != null) {
|
||||
if (this.constant_array_length || value !== null) {
|
||||
arr.push(value);
|
||||
}
|
||||
obj[c.name] = arr;
|
||||
} else {
|
||||
obj[c.name] = value;
|
||||
}
|
||||
isAllNullish = isAllNullish && value == null;
|
||||
isAllNullish = isAllNullish && is_null;
|
||||
}
|
||||
return isAllNullish ? null : obj;
|
||||
}
|
||||
@@ -174,7 +189,7 @@ export class Field {
|
||||
protected get_cell_value(cell: RawTableCell, type: DataType) {
|
||||
switch (type) {
|
||||
case DataType.bool:
|
||||
return cell && cell.v as boolean == true;
|
||||
return cell ? cell.v as boolean == true : false;
|
||||
case DataType.int:
|
||||
return cell ? cell.v as number : 0;
|
||||
case DataType.float:
|
||||
@@ -185,26 +200,22 @@ export class Field {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TypeCompatibility = {
|
||||
string: 5,
|
||||
float: 4,
|
||||
int: 3,
|
||||
bool: 2,
|
||||
null: 1
|
||||
};
|
||||
|
||||
export interface ColumnDescription {
|
||||
type: DataType;
|
||||
name: string;
|
||||
is_array?: boolean;
|
||||
comment?: string;
|
||||
}
|
||||
|
||||
export interface TableData {
|
||||
struct: Field;
|
||||
data: {[key: string]: any}[];
|
||||
protected check_is_null(row: RawTableCell[]): boolean {
|
||||
if (this.children) {
|
||||
let isAllNullish = true;
|
||||
for (const c of this.children) {
|
||||
isAllNullish = isAllNullish && c.check_is_null(row);
|
||||
if (!isAllNullish) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return isAllNullish;
|
||||
} else {
|
||||
let cell = row[this.columns.start];
|
||||
return !cell || cell.t === 'z';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TableParser {
|
||||
|
||||
@@ -17,7 +17,7 @@ export class JSONExporter extends TableExporter {
|
||||
}
|
||||
}
|
||||
|
||||
get extension(): string { return 'json'}
|
||||
get extension(): string { return this.configs.extension || 'json'; }
|
||||
|
||||
protected recursively_order_keys(unordered: object | Array<object>) {
|
||||
// If it's an array - recursively order any
|
||||
|
||||
@@ -57,6 +57,9 @@ export class TypeScriptExporter extends TableExporter {
|
||||
}
|
||||
type += ignore_root ? '' : this.indent_text('}', indent);
|
||||
} break;
|
||||
case DataType.null:
|
||||
type = "null";
|
||||
break;
|
||||
default:
|
||||
type = "any";
|
||||
break;
|
||||
|
||||
@@ -12,7 +12,7 @@ interface YAMLExporterConfigs extends ExporterConfigs {
|
||||
|
||||
export class YAMLExporter extends JSONExporter {
|
||||
|
||||
get extension(): string { return 'yaml'}
|
||||
get extension(): string { return this.configs.extension || 'yaml'; }
|
||||
|
||||
constructor(configs: ExporterConfigs) {
|
||||
super(configs);
|
||||
|
||||
Reference in New Issue
Block a user