Files

215 lines
7.8 KiB
Python
Vendored

import os
import re
import sys
sys.stdout.reconfigure(encoding='utf-8')
src_dir = r"C:\Users\Phitchayut\Downloads\Ananta_PS_FullBuild\Ananta_PS_FullBuild\Drmk.Server\Drmk.Core\ClientData\Client4229938"
dst_dir = r"C:\Users\Phitchayut\Desktop\ngp-Ananta-DEV5\ngp-Ananta-DEV5\internal\catalogs"
os.makedirs(dst_dir, exist_ok=True)
files = [f for f in os.listdir(src_dir) if f.endswith(".cs")]
print(f"Converting {len(files)} catalog files to Go with multi-line parser...")
TYPE_MAP = {
'uint': 'uint32', 'int': 'int32', 'ulong': 'uint64', 'long': 'int64',
'ushort': 'uint16', 'short': 'int16', 'byte': 'uint8', 'sbyte': 'int8',
'float': 'float32', 'double': 'float64', 'bool': 'bool', 'string': 'string',
'Vector3': 'protocol.Vec3', 'UXVector3': 'protocol.Vec3',
}
def map_type(t):
t = t.strip()
if t.endswith('[]'):
elem = map_type(t[:-2])
return f"[]{elem}"
if t.endswith('?'):
return f"*{map_type(t[:-1])}"
if t.startswith('List<') or t.startswith('IList<') or t.startswith('IReadOnlyList<'):
inner = t[t.find('<')+1 : t.rfind('>')]
return f"[]{map_type(inner)}"
if t.startswith('Dictionary<') or t.startswith('IReadOnlyDictionary<'):
parts = t[t.find('<')+1 : t.rfind('>')].split(',')
if len(parts) == 2:
return f"map[{map_type(parts[0])}]{map_type(parts[1])}"
if t.startswith('HashSet<') or t.startswith('IReadOnlySet<'):
inner = t[t.find('<')+1 : t.rfind('>')]
return f"map[{map_type(inner)}]struct{{}}"
return TYPE_MAP.get(t, t)
def clean_val(val, ftype):
v = val.strip().rstrip(';')
if ftype in ('float32', 'float64'):
v = re.sub(r'([0-9]+(?:\.[0-9]+)?)[fFdD]', r'\1', v)
if '.' not in v:
v += ".0"
elif ftype in ('uint32', 'uint64', 'int32', 'int64'):
v = re.sub(r'([0-9]+)[uUlL]', r'\1', v)
return v
def to_go_filename(cs_name):
base = cs_name[:-3]
if base.endswith("4229938"):
base = base[:-7]
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', base)
s2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
return f"{s2}.go"
converted_count = 0
for f in files:
cs_path = os.path.join(src_dir, f)
with open(cs_path, "r", encoding="utf-8", errors="ignore") as fp:
raw_code = fp.read()
go_name = to_go_filename(f)
go_path = os.path.join(dst_dir, go_name)
records = []
constants = []
comments = []
config_file = ""
lines = raw_code.splitlines()
for line in lines:
sline = line.strip()
if sline.startswith("///"):
comments.append("// " + sline[3:].strip())
elif sline.startswith("//"):
comments.append(sline)
cfg_m = re.search(r'["\']([A-Za-z0-9_]+\.json)["\']', line)
if cfg_m and not config_file:
config_file = cfg_m.group(1)
# Look for const
const_m = re.search(r'const\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)\s*=\s*([^;]+);', line)
if const_m:
ctype = map_type(const_m.group(1))
cname = const_m.group(2)
cval = clean_val(const_m.group(3), ctype)
constants.append((cname, ctype, cval))
# Match all multi-line and single-line records: record struct Name(...)
rec_matches = re.finditer(r'record\s+(?:struct\s+)?([A-Za-z0-9_]+)\s*\((.*?)\);', raw_code, re.DOTALL)
for rm in rec_matches:
rname = rm.group(1)
raw_params = rm.group(2)
# Parse params
fields = []
for p in re.split(r',\s*(?![^<]*>)', raw_params):
p = p.strip()
if not p: continue
parts = p.split()
if len(parts) >= 2:
ftype = map_type(" ".join(parts[:-1]))
fname = parts[-1]
jtag = fname[0].lower() + fname[1:]
fields.append(f"\t{fname} {ftype} `json:\"{jtag}\"`")
records.append((rname, fields))
base_name = f[:-3]
if base_name.endswith("4229938"):
base_name = base_name[:-7]
if base_name.endswith("Catalog"):
catalog_struct_name = base_name
else:
catalog_struct_name = f"{base_name}Catalog"
content = [
"package catalogs",
"",
"import (",
"\t\"encoding/json\"",
"\t\"os\"",
"\t\"path/filepath\"",
"\t\"sync\"",
"\t\"ananta-ps/pkg/protocol\"",
")",
"",
"// Suppress unused imports",
"var _ = func() bool {",
"\t_ = json.Marshal",
"\t_ = os.Stat",
"\t_ = filepath.Join",
"\t_ = protocol.MethodCheckVersion",
"\treturn true",
"}()",
"",
]
if comments:
content.extend(comments[:15])
content.append("")
if constants:
content.append("const (")
for cname, ctype, cval in constants:
content.append(f"\t{cname} {ctype} = {cval}")
content.append(")")
content.append("")
item_struct_name = f"{base_name}Item"
if records:
for rname, fields in records:
content.append(f"type {rname} struct {{")
content.extend(fields)
content.append("}")
content.append("")
item_struct_name = records[0][0]
else:
content.append(f"type {item_struct_name} struct {{")
content.append("\tID uint32 `json:\"id\"`")
content.append("\tName string `json:\"name,omitempty\"`")
content.append("\tRaw map[string]interface{} `json:\"-\"`")
content.append("}")
content.append("")
content.append(f"type {catalog_struct_name} struct {{")
content.append("\tmu sync.RWMutex")
content.append(f"\titems []{item_struct_name}")
content.append(f"\tbyId map[uint32]{item_struct_name}")
content.append("\tloaded bool")
content.append("}")
content.append("")
content.append(f"var Global{catalog_struct_name} = &{catalog_struct_name}{{")
content.append(f"\tbyId: make(map[uint32]{item_struct_name}),")
content.append("}")
content.append("")
content.append(f"func (c *{catalog_struct_name}) Load(baseDir string) error {{")
content.append("\tc.mu.Lock()")
content.append("\tdefer c.mu.Unlock()")
content.append("\tif c.loaded { return nil }")
if config_file:
content.append(f"\tpath := filepath.Join(baseDir, \"data\", \"client_data\", \"Configs\", \"{config_file}\")")
content.append("\tif _, err := os.Stat(path); os.IsNotExist(err) {")
content.append(f"\t\tpath = filepath.Join(baseDir, \"data\", \"client_data\", \"World\", \"{config_file}\")")
content.append("\t}")
content.append("\tdata, err := os.ReadFile(path)")
content.append("\tif err != nil { return err }")
content.append("\tvar records struct { Records []json.RawMessage `json:\"records\"` }")
content.append("\tif err := json.Unmarshal(data, &records); err == nil && len(records.Records) > 0 {")
content.append(f"\t\tfor _, raw := range records.Records {{")
content.append(f"\t\t\tvar item {item_struct_name}")
content.append("\t\t\tif err := json.Unmarshal(raw, &item); err == nil {")
content.append("\t\t\t\tc.items = append(c.items, item)")
content.append("\t\t\t}")
content.append("\t\t}")
content.append("\t}")
content.append("\tc.loaded = true")
content.append("\treturn nil")
content.append("}")
content.append("")
content.append(f"func (c *{catalog_struct_name}) All() []{item_struct_name} {{")
content.append("\tc.mu.RLock()")
content.append("\tdefer c.mu.RUnlock()")
content.append("\treturn c.items")
content.append("}")
content.append("")
with open(go_path, "w", encoding="utf-8") as out_fp:
out_fp.write("\n".join(content) + "\n")
converted_count += 1
print(f"Successfully converted {converted_count} catalog files to {dst_dir}!")