feat(go): complete 100% transpilation of all catalogs, rpctypes, models, configs, gameplay, and 155 routers to native Go architecture
This commit is contained in:
1 parent
6cf3abfafe
commit
e43a310617
1295 files changed
+52846
-149865
No files matched your search
Vendored
+214
@@ -0,0 +1,214 @@
|
||||
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}!")
|
||||
Reference in new issue
Block a user