Skip to content

Commit eaab0e1

Browse files
committed
支持SC3(scx)脚本导出导入;支持文件夹脚本的导出
1 parent c35c322 commit eaab0e1

File tree

12 files changed

+340
-127
lines changed

12 files changed

+340
-127
lines changed

README.md

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@
33
目标是完成尽可能通用的Mages工具集,目前仅以脚本为主
44

55
## 适配游戏
6-
- 《Chaos;Child》
7-
- 其他未测,理论都支持
6+
- 理论支持所有Mages引擎的游戏
7+
- 所有的MES(msb)、SC3(scx)脚本都可正常导出导入
88

99
## Usage
1010
```
1111
-charset string
1212
[script.optional] Character set containing only text. Must be utf8 encoding. Choose between "charset" and "tbl"
13+
-debug int
14+
[optional] Debug level
15+
0: Disable debug mode
16+
1: Show info message
17+
2: Show warning message (For example, the character table is missing characters)
18+
3: Not implemented
1319
-export
14-
[optional] Export mode
20+
[optional] Export mode. Support folder export
1521
-format string
1622
[script.required] Format of script export and import. Case insensitive
1723
NPCSManager format: "Npcs"
@@ -21,11 +27,11 @@
2127
-input string
2228
[optional] Usually the import mode requires
2329
-output string
24-
[required] Output file
30+
[required] Output file or folder
2531
-skip
26-
[script.optional] Skip duplicate code table characters. (default true)
32+
[script.optional] Skip repeated characters in the character table. (default true)
2733
-source string
28-
[required] Source file
34+
[required] Source files or folder
2935
-tbl string
3036
[script.optional] Text in TBL format. Must be utf8 encoding. Choose between "charset" and "tbl"
3137
-type string
@@ -34,11 +40,20 @@
3440
Now only MES format scripts are supported
3541
Diff Binary File: "diff"
3642
Diff input and output file
37-
43+
3844
3945
```
46+
### Example
4047

4148
```shell
49+
# 导出文件夹所有,使用tbl码表,格式为NpcsP,不跳过码表中相同字符,开启debug模式为2
50+
MagesTools -type=script -export -skip=false -debug=2\
51+
-format=NpcsP \
52+
-tbl=./data/CC/MJPN.txt \
53+
-source=./data/CC/script/mes00 \
54+
-output=./data/CC/txt
55+
56+
4257
# 导出文本,使用tbl码表,格式为NpcsP,跳过码表中相同字符
4358
MagesTools -type=script -export -skip=true \
4459
-format=NpcsP \
@@ -105,11 +120,16 @@ MagesTools -type=diff \
105120
```
106121

107122
## 计划
108-
- SC3文本导出
109-
- ~~MES和~~SC3文本导入
123+
- 支持更多格式
110124

111125
## 更新日志
112126

127+
### 2022.3.21
128+
- 支持SC3(scx)脚本的文本导入导出
129+
- 支持文件夹导出(暂不支持导入)
130+
- 增加简单的log
131+
- 优化代码细节
132+
113133
### 2022.3.20 2
114134
- 重构代码结构以支持更多导出格式
115135
- 支持NPCSManager格式的导出与导入

main.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,48 @@ import (
77
"flag"
88
"fmt"
99
"github.com/go-restruct/restruct"
10+
"path"
1011
"strings"
1112
)
1213

1314
func main() {
1415

1516
var pType, pSource, pInput, pOutput, pScriptFormat, pCharset, pTbl string
1617
var pImport, pExport, pSkipChar bool
18+
var pDebug int
1719
flag.StringVar(&pType, "type", "", `[required] Source file type.
1820
MES(msb) Script: "script"
1921
Now only MES format scripts are supported
2022
Diff Binary File: "diff"
2123
Diff input and output file
2224
`)
23-
flag.BoolVar(&pExport, "export", false, "[optional] Export mode")
25+
flag.BoolVar(&pExport, "export", false, "[optional] Export mode. Support folder export")
2426
flag.BoolVar(&pImport, "import", false, "[optional] Import mode")
27+
flag.IntVar(&pDebug, "debug", 0, `[optional] Debug level
28+
0: Disable debug mode
29+
1: Show info message
30+
2: Show warning message (For example, the character table is missing characters)
31+
3: Not implemented`)
2532

26-
flag.StringVar(&pSource, "source", "", `[required] Source file`)
33+
flag.StringVar(&pSource, "source", "", `[required] Source files or folder`)
2734

2835
flag.StringVar(&pInput, "input", "", `[optional] Usually the import mode requires`)
29-
flag.StringVar(&pOutput, "output", "", `[required] Output file`)
36+
flag.StringVar(&pOutput, "output", "", `[required] Output file or folder`)
3037

3138
flag.StringVar(&pScriptFormat, "format", "Npcs", `[script.required] Format of script export and import. Case insensitive
3239
NPCSManager format: "Npcs"
3340
NPCSManager Plus format: "NpcsP"`)
3441
flag.StringVar(&pCharset, "charset", "", `[script.optional] Character set containing only text. Must be utf8 encoding. Choose between "charset" and "tbl"`)
3542
flag.StringVar(&pTbl, "tbl", "", `[script.optional] Text in TBL format. Must be utf8 encoding. Choose between "charset" and "tbl"`)
3643

37-
flag.BoolVar(&pSkipChar, "skip", true, "[script.optional] Skip duplicate code table characters.")
44+
flag.BoolVar(&pSkipChar, "skip", true, "[script.optional] Skip repeated characters in the character table.")
3845

3946
flag.Parse()
4047
restruct.EnableExprBeta()
4148

49+
if pDebug >= 2 {
50+
utils.ShowWarning = true
51+
}
4252
switch pType {
4353
case "diff":
4454
if len(pInput) == 0 && len(pOutput) == 0 {
@@ -53,7 +63,7 @@ func main() {
5363
panic("必须指定export模式或import模式")
5464
}
5565
if len(pSource) == 0 {
56-
panic("必须指定source源文件")
66+
panic("必须指定source源文件或文件夹")
5767
}
5868

5969
var _format format.Format
@@ -65,7 +75,7 @@ func main() {
6575
default:
6676
panic("未知脚本导出格式")
6777
}
68-
scr := script.OpenScript(pSource, _format)
78+
scr := &script.Script{}
6979

7080
if len(pCharset) > 0 {
7181
scr.LoadCharset(pCharset, false, pSkipChar)
@@ -74,14 +84,29 @@ func main() {
7484
} else {
7585
panic("必须指定charset文件或tbl文件")
7686
}
77-
scr.Read()
87+
7888
if pExport {
79-
if len(pOutput) > 0 {
89+
if utils.IsDir(pSource) && utils.IsDir(pOutput) {
90+
files, _ := utils.GetDirFileList(pSource)
91+
for _, file := range files {
92+
if pDebug >= 1 {
93+
fmt.Println(file)
94+
}
95+
scr.Open(file, _format)
96+
scr.Read()
97+
// 导出
98+
scr.SaveStrings(path.Join(pOutput, path.Base(file)+".txt"))
99+
}
100+
} else if utils.IsFile(pSource) && utils.IsFile(pOutput) {
101+
scr.Open(pSource, _format)
102+
scr.Read()
80103
scr.SaveStrings(pOutput)
81104
} else {
82-
panic("必须指定output文件")
105+
panic("source和output必须同为文件,或同为文件夹")
83106
}
84107
} else if pImport {
108+
scr.Open(pSource, _format)
109+
scr.Read()
85110
if len(pInput) > 0 {
86111
scr.LoadStrings(pInput)
87112
} else {

script/format/NpcsFormat.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ func (f *Npcs) DecodeLine(data []byte) string {
138138
text.WriteString(char)
139139
}
140140
} else {
141+
if utils.ShowWarning && data[i] > 0x80 {
142+
fmt.Printf("Warning: 字库可能缺少 [%02X %02X] 对应的字符!\n", data[i], data[i+1])
143+
}
141144
if inName {
142145
name += utils.FormatBytes(data[i : i+2])
143146
} else {

script/format/NpcsPFormat.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package format
33
import (
44
"MagesTools/script/utils"
55
"bytes"
6+
"fmt"
67
"strings"
78
)
89

@@ -127,6 +128,9 @@ func (f *NpcsP) DecodeLine(data []byte) string {
127128
if char, has := f.decodeCharset[index]; has {
128129
text.WriteString(char)
129130
} else {
131+
if utils.ShowWarning && data[i] >= 0x80 {
132+
fmt.Printf("Warning: 字库可能缺少 [%02X %02X] 对应的字符!\n", data[i], data[i+1])
133+
}
130134
text.WriteString(utils.FormatBytes(data[i : i+2]))
131135
}
132136
i += 2

script/mes.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ func (m *Mes) SetStrings(strings []string) {
6363
}
6464

6565
func (m *Mes) WriteStrings(writeString func(string) []byte) {
66+
if m.Count == 0 {
67+
return
68+
}
6669
data := bytes.NewBuffer(nil)
6770

6871
offset := 0

script/mes_test.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package script
22

33
import (
4-
"encoding/hex"
54
"fmt"
65
"github.com/go-restruct/restruct"
76
"io"
87
"os"
9-
"strings"
108
"testing"
119
)
1210

@@ -21,13 +19,3 @@ func TestLoadMes(t *testing.T) {
2119
return ""
2220
})
2321
}
24-
25-
func Test001(t *testing.T) {
26-
src := []byte{1, 0, 123, 44}
27-
encodedStr := hex.EncodeToString(src)
28-
encodedStr = strings.ToUpper(encodedStr)
29-
fmt.Println(encodedStr)
30-
31-
test, _ := hex.DecodeString(encodedStr)
32-
fmt.Println(test)
33-
}

script/sc3.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package script
2+
3+
import (
4+
"MagesTools/script/utils"
5+
"bytes"
6+
"encoding/binary"
7+
"fmt"
8+
"github.com/go-restruct/restruct"
9+
)
10+
11+
type Sc3 struct {
12+
Magic string `struct:"[4]byte"`
13+
OffsetStart int `struct:"int32"`
14+
OffsetEnd int `struct:"int32"`
15+
Count int `struct:"-"`
16+
Offsets []Entry `struct:"-"`
17+
Strings []string `struct:"-"`
18+
Raw []byte `struct:"-"`
19+
}
20+
21+
func LoadSc3(data []byte) *Sc3 {
22+
sc3 := &Sc3{
23+
Raw: data,
24+
}
25+
return sc3
26+
}
27+
28+
func (s *Sc3) ReadStrings(readString func([]byte) string) {
29+
// 读取offset
30+
31+
err := restruct.Unpack(s.Raw, binary.LittleEndian, s)
32+
if err != nil {
33+
panic(err)
34+
}
35+
s.Count = (s.OffsetEnd - s.OffsetStart) / 4
36+
s.Offsets = make([]Entry, s.Count)
37+
offset := s.OffsetStart
38+
for i := 0; i < s.Count; i++ {
39+
s.Offsets[i].Offset = int(utils.BytesToUint32(s.Raw[offset : offset+4]))
40+
offset += 4
41+
if i >= 1 {
42+
s.Offsets[i-1].Length = s.Offsets[i].Offset - s.Offsets[i-1].Offset
43+
}
44+
}
45+
s.Offsets[s.Count-1].Length = len(s.Raw) - s.Offsets[s.Count-1].Offset
46+
47+
// 读取文本
48+
s.Strings = make([]string, s.Count)
49+
for i, offset := range s.Offsets {
50+
s.Strings[i] = readString(s.Raw[offset.Offset : offset.Offset+offset.Length])
51+
}
52+
53+
}
54+
func (s *Sc3) GetStrings() []string {
55+
return s.Strings
56+
}
57+
58+
func (s *Sc3) SetStrings(strings []string) {
59+
if s.Count != len(strings) {
60+
panic(fmt.Sprintf("导入文本行数不匹配。原脚本:%d,导入:%d", s.Count, len(strings)))
61+
return
62+
}
63+
s.Strings = strings
64+
65+
}
66+
67+
func (s *Sc3) WriteStrings(writeString func(string) []byte) {
68+
if s.Count == 0 {
69+
return
70+
}
71+
data := bytes.NewBuffer(nil) // 新文本段数据
72+
73+
offset := s.Offsets[0].Offset // 文本段开始
74+
for i, str := range s.Strings {
75+
line := writeString(str)
76+
s.Offsets[i].Offset = offset
77+
offset += len(line)
78+
79+
data.Write(line)
80+
}
81+
offset = s.Offsets[0].Offset // 文本段开始
82+
s.Raw = s.Raw[:offset] // 清除原文本段
83+
s.Raw = append(s.Raw, data.Bytes()...) // 写入新文本段
84+
85+
offset = s.OffsetStart // 偏移段开始
86+
for i := 0; i < s.Count; i++ { // 写入新偏移段
87+
copy(s.Raw[offset:offset+4], utils.Uint32ToBytes(uint32(s.Offsets[i].Offset)))
88+
offset += 4
89+
}
90+
}
91+
func (s *Sc3) GetRaw() []byte {
92+
return s.Raw
93+
}

script/sc3_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package script
2+
3+
import (
4+
"fmt"
5+
"github.com/go-restruct/restruct"
6+
"io"
7+
"os"
8+
"testing"
9+
)
10+
11+
func TestLoadSc3(t *testing.T) {
12+
restruct.EnableExprBeta()
13+
f, _ := os.Open("../data/CCLCC/script/claa01.scx")
14+
defer f.Close()
15+
data, _ := io.ReadAll(f)
16+
mes := LoadSc3(data)
17+
mes.ReadStrings(func(data []byte) string {
18+
fmt.Println(data)
19+
return ""
20+
})
21+
}

0 commit comments

Comments
 (0)