Compare commits

...

20 Commits

Author SHA1 Message Date
CakeLancelot
a3856cdc9d Merge pull request #2 from CakeLancelot/main
dx2cg: Allow usage as module and handle a few more features used by built-in Unity shaders
2024-02-14 05:11:14 -06:00
CakeLancelot
672d7e2b42 Address PR review comments 2024-02-14 03:15:09 -06:00
CakeLancelot
d5b58d96da dx2cg: Implement RECT, CUBE texture types
Also tried to implement 3D texture type, but that will likely require a few other instructions to get working - namely texldp and dcl_volume.
2024-02-13 03:18:19 -06:00
CakeLancelot
06869164a1 dx2cg: Implement mov_sat instruction
Basically just mov but clamp the result.
https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-ps-instructions-modifiers-ps-2-0#saturate
2024-02-13 03:18:19 -06:00
CakeLancelot
99c80c9c7b dx2cg: Allow usage as Python module
e.g.
from dx2cg.swapper import process_shader
cg_shader = process_shader(text)
2024-02-13 01:40:07 -06:00
4196766a2b Client credentials and change root password 2024-01-26 15:28:53 -05:00
7922fc060a Set XDB server charset to utf8 2024-01-26 13:46:43 -05:00
5bf1ce01e3 Change db name to XDB 2024-01-24 20:09:14 -05:00
27143ccb01 Schemas, split fields, and padding 2024-01-24 17:47:06 -05:00
349e7b6e07 Table schemas 2024-01-24 16:10:26 -05:00
9fd6441606 Fix for large packet size 2024-01-24 13:57:43 -05:00
8b1bd5b1ee Update gitignore 2024-01-24 13:52:59 -05:00
4f7b6b28e4 Fix DB table mappings 2024-01-24 13:52:41 -05:00
99193a198b Add json2xdb 2024-01-24 05:15:00 -05:00
CakeLancelot
249af1d2d3 Ensure all objects are deleted after export + use env var for user directory 2024-01-19 14:30:17 -06:00
gsemaj
c7b4182a4b Export terrain meshes as FBX instead of OBJ 2024-01-19 10:42:49 -08:00
FinnHornhoover
b70816fa64 Non-updating rank table fix and tiebreaker logic (#1) 2023-12-25 21:37:22 +01:00
9deba1956f [rankendpoint] Add invocation instructions 2023-12-24 21:35:35 +01:00
1a3a530c7f [rankendpoint] Get DB path and endpoint route from env vars
Also reverted the use of main() that made it incompatible with uwsgi and
flask run.
2023-12-24 20:57:05 +01:00
f62f3af483 Revert "Autorun Flask app"
This reverts commit e0e0b3c5e3.

Flask applications are not supposed to be run this way. We run the
endpoints with uwsgi in prod or with the flask program for debugging.

https://flask.palletsprojects.com/en/3.0.x/api/#flask.Flask.run
2023-12-24 03:36:33 +01:00
161 changed files with 2601 additions and 57 deletions

0
dx2cg/__init__.py Normal file
View File

View File

@@ -41,6 +41,7 @@ decls = {
ops = {
"mov": "{0} = {1};",
"mov_sat": "{0} = clamp({1}, 0.0, 1.0)",
"add": "{0} = {1} + {2};",
"mul": "{0} = {1} * {2};",
"mad": "{0} = {1} * {2} + {3};",
@@ -53,7 +54,7 @@ ops = {
"slt": "{0} = float4(({1}.x < {2}.x) ? 1.0f : 0.0f, ({1}.y < {2}.y) ? 1.0f : 0.0f, ({1}.z < {2}.z) ? 1.0f : 0.0f, ({1}.w < {2}.w) ? 1.0f : 0.0f);",
"sge": "{0} = float4(({1}.x >= {2}.x) ? 1.0f : 0.0f, ({1}.y >= {2}.y) ? 1.0f : 0.0f, ({1}.z >= {2}.z) ? 1.0f : 0.0f, ({1}.w >= {2}.w) ? 1.0f : 0.0f);",
"rcp": "{0} = ({1} == 0.0f) ? FLT_MAX : (({1} == 1.0f) ? {1} : (1 / {1}));",
"texld": "{0} = tex2D({2}, (float2){1});",
"texld": "{0} = {3}({2}, (float2){1});",
}
struct_a2v = """struct a2v {
@@ -185,12 +186,20 @@ def process_header(prog):
i = i - 1
elif line.startswith("SetTexture"):
dec = line.split(' ')
if dec[2] != "{2D}":
if dec[2] == "{2D}":
texture_type = "sampler2D"
elif dec[2] == "{3D}":
texture_type = "sampler3D"
elif dec[2] == "{RECT}":
texture_type = "samplerRECT"
elif dec[2] == "{CUBE}":
texture_type = "samplerCUBE"
else:
raise ValueError(f"Unknown texture type {dec[2]}")
key = f"s{textures}"
val = dec[1][1:-1]
loctab[key] = val
locdecl.append(f"sampler2D {val};")
locdecl.append(f"{texture_type} {val};")
textures = textures + 1
del prog[i]
@@ -217,7 +226,7 @@ def resolve_args(args, loctab, consts):
arg = arg[:dot]
else:
swiz = ""
if arg[0] == 'r':
pass
elif arg[0] == 'v':
@@ -238,7 +247,23 @@ def resolve_args(args, loctab, consts):
args[a] = neg + arg + swiz
def decode(code, args):
def get_cgtex_type(name, locdecl):
for loc in locdecl:
loc = loc.split(' ')
if name == loc[1][:-1]:
if loc[0] == 'sampler2D':
return "tex2D"
elif loc[0] == 'sampler3D':
return "tex3D"
elif loc[0] == 'samplerCUBE':
return "texCUBE"
elif loc[0] == 'samplerRECT':
return "texRECT"
else:
raise ValueError(f"Unknown CG texture type {loc[0]}")
raise ValueError(f"Could not find texture {name} in locals")
def decode(code, args, locdecl):
if code in decls:
return [decls[code].format(*args)]
elif code in ops:
@@ -253,14 +278,18 @@ def decode(code, args):
else:
swiz = "xyzw"
lines = [ops[code].format("tmp", *args[1:])]
if code == "texld":
lines = [ops[code].format("tmp", *args[1:], get_cgtex_type(args[2], locdecl))]
else:
lines = [ops[code].format("tmp", *args[1:])]
for c in swiz:
lines.append(f"{target}.{c} = tmp.{c};")
return lines
else:
raise ValueError(f"Unknown opcode {code}")
def process_asm(asm, loctab):
def process_asm(asm, loctab, locdecl):
shadertype = ""
if asm[0] == "\"vs_1_1":
shadertype = "vertex"
@@ -293,7 +322,7 @@ def process_asm(asm, loctab):
code = code[:pp]
resolve_args(args, loctab, consts)
disasm = decode(code, args)
disasm = decode(code, args, locdecl)
# print(f"{instruction} \t==>\t{disasm}")
disasm.insert(0, f"// {instruction}")
translated.extend(disasm)
@@ -316,7 +345,7 @@ def disassemble(blocks):
binds.update(bds)
lighting |= light
(shadertype, disasm) = process_asm(asm, ltab)
(shadertype, disasm) = process_asm(asm, ltab, locdecl)
shaders[shadertype] = disasm
text = ""

View File

@@ -3,7 +3,7 @@
import os
import sys
from swapper import process
from .swapper import process
def process_file(filename, suffix):
dot = filename.rfind(".")

View File

@@ -5,7 +5,7 @@
import re
import sys
from disassembler import disassemble
from .disassembler import disassemble
tabs = 3
def indent(block):

2
json2xdb/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.vscode
xdt*.json

9
json2xdb/README.md Normal file
View File

@@ -0,0 +1,9 @@
# json2xdb
This script populates a functional, near-complete FusionFall XDB tabledata server.
You need an existing MySQL server (an old version; 5.5.42 seems to work with the FusionFall client). This can be set up pretty easily using Docker.
You also need a copy of xdt.json from the [OpenFusion tabledata repository](https://github.com/OpenFusionProject/tabledata).
It is interesting to note that the JSON tabledata file is really just a Unity ScriptableObject containing all the XDT/XDB state packaged into a FusionFall client build. The devs likely kept a central tabledata server around (XDB) and, whenever it was time for a client build, they fetched it into local binary files (XDT) before finally packing them into the XdtTableScript asset.
I would like to thank my girlfriend for showing me the wonders of `tqdm`. It really helped being able to see that things were happening.

View File

@@ -0,0 +1,13 @@
# Uses default credentials
version: '3.1'
services:
db:
image: mysql:5.5.42
command: --character-set-server utf8
restart: always
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: mypassword
MYSQL_DATABASE: XDB

View File

@@ -0,0 +1,76 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"import json"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"def to_db_table_name_mappings(table):\n",
" mappings = {}\n",
" for subtable_name in table:\n",
" mappings[subtable_name] = \"\"\n",
" return mappings"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"def gen_mappings(xdt):\n",
" mappings = {}\n",
" for table_name in xdt:\n",
" if \"table\" not in table_name.lower():\n",
" continue\n",
" table = xdt[table_name]\n",
" mappings[table_name] = to_db_table_name_mappings(table)\n",
" return mappings\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"with open('xdt.json', 'r') as f:\n",
" xdt = json.load(f)\n",
"mappings = gen_mappings(xdt)\n",
"with open('mappings.json', 'w') as f:\n",
" json.dump(mappings, f, indent=4)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

222
json2xdb/json2xdb.py Normal file
View File

@@ -0,0 +1,222 @@
# %%
import json
import sys
from tqdm import tqdm
import mysql.connector
SPLIT_FIELDS = {
"m_iMissionRewardItem": ("m_iMissionRewardItemID", "m_iMissionRewarItemType"),
"m_iMissionRewardItem2": ("m_iMissionRewardItemID2", "m_iMissionRewardItemType2"),
"m_iCSTItem": ("m_iCSTItemID", "m_iCSTItemNumNeeded"),
"m_iCSUEnemy": ("m_iCSUEnemyID", "m_iCSUNumToKill"),
"m_iCSUItem": ("m_iCSUItemID", "m_iCSUItemNumNeeded"),
"m_iSTItem": ("m_iSTItemID", "m_iSTItemNumNeeded", "m_iSTItemDropRate"),
"m_iSUItem_": ("m_iSUItem", "m_iSUInstancename"),
"m_iFItem": ("m_iFItemID", "m_iFItemNumNeeded"),
}
# %%
def get_db_column_name(xdt_field_name):
# special case 1
if xdt_field_name == "m_iitemID":
return "ItemID"
try:
# find the first uppercase character and split the string there
idx_of_first_uppercase = next(i for i, c in enumerate(xdt_field_name) if c.isupper())
except StopIteration:
# special case 2
if xdt_field_name == "m_ibattery":
idx_of_first_uppercase = 3
else:
print(f"Could not find uppercase character in {xdt_field_name}")
sys.exit(1)
prefix = xdt_field_name[:idx_of_first_uppercase]
db_field_name = xdt_field_name[idx_of_first_uppercase:]
return db_field_name
# %%
def table_entry_to_tuple(table_entry):
vals = []
for field_name in table_entry:
field = table_entry[field_name]
vals.append(field)
return tuple(vals)
def flatten_table_entry(table_entry):
flattened_entry = {}
for field_name in table_entry:
field = table_entry[field_name]
if type(field) == list:
for i, item in enumerate(field):
flattened_entry[f"{field_name}{i}"] = item
else:
flattened_entry[field_name] = field
return flattened_entry
def handle_dict_table(table_entries, identifier_key, items_key):
new_table_entries = []
for table_entry in table_entries:
identifier = table_entry[identifier_key]
items = table_entry[items_key]
for item in items:
new_item = {}
new_item[identifier_key] = identifier # needs to be first
for field_name in item:
new_item[field_name] = item[field_name]
new_table_entries.append(new_item)
return new_table_entries
def apply_schema(schema, entry):
fixed_entry = {}
padding = 0
for field_name in schema:
if field_name is None:
fixed_entry[f"m_iPadding{padding}"] = 0
padding += 1
continue
if field_name in entry:
fixed_entry[field_name] = entry[field_name]
elif field_name in SPLIT_FIELDS:
split_field_names = SPLIT_FIELDS[field_name]
interleaved_arr_len = len(entry[split_field_names[0]])
val = []
for i in range(interleaved_arr_len):
for split_field_name in split_field_names:
val.append(entry[split_field_name][i])
for l in range(len(val)):
n = l % len(split_field_names)
i = l // len(split_field_names)
new_field_name = f"{split_field_names[n]}{i}"
fixed_entry[new_field_name] = val[l]
else:
print("Missing field: {}".format(field_name))
return fixed_entry
# %%
def gen_column_sql(field_name, field_value):
field_type = type(field_value)
if field_type == int:
return f"`{field_name}` INT,"
elif field_type == float:
return f"`{field_name}` FLOAT,"
elif field_type == str:
# TODO maybe ascii vs unicode?
return f"`{field_name}` TEXT,"
else:
print(f"Unknown type {field_type} for field {field_name}, skipping")
return ""
# %%
def table_create(cursor, table_name, xdt_template_entry):
sql = f"CREATE TABLE {table_name} ("
sql += "id INT AUTO_INCREMENT PRIMARY KEY,"
for field_name in xdt_template_entry:
db_field_name = get_db_column_name(field_name)
val = xdt_template_entry[field_name]
sql += gen_column_sql(db_field_name, val)
sql = sql[:-1] # remove trailing comma
sql += ")"
cursor.execute(sql)
# %%
def table_populate(cursor, table_name, table_entries):
# generate the SQL first
sql = f"INSERT INTO {table_name} ("
template_entry = table_entries[0]
for field_name in template_entry:
db_field_name = get_db_column_name(field_name)
sql += f"`{db_field_name}`,"
sql = sql[:-1] # remove trailing comma
sql += ") VALUES ("
for field_name in template_entry:
sql += f"%s,"
sql = sql[:-1] # remove trailing comma
sql += ")"
vals = [table_entry_to_tuple(entry) for entry in table_entries]
try:
cursor.executemany(sql, vals)
except Exception as e:
print(sql)
print(vals)
raise e
# %%
def process_xdt_table(cursor, root, table_name, mappings):
table = root[table_name]
for subtable_name in tqdm(table, desc=table_name, total=len(table)):
if subtable_name not in mappings[table_name]:
print(f"No mapping found for {table_name}.{subtable_name}")
raise Exception()
db_table_name = mappings[table_name][subtable_name]
with open(f"schema/{db_table_name}.json", 'r') as f:
schema = json.load(f)
#print(f"{subtable_name} => {db_table_name}")
table_entries = table[subtable_name]
if db_table_name == "CutSceneText":
table_entries = handle_dict_table(table_entries, "m_iEvent", "m_TextElement")
table_entries = [apply_schema(schema, entry) for entry in table_entries]
table_entries = [flatten_table_entry(entry) for entry in table_entries]
# clear the table
drop_sql = f"DROP TABLE IF EXISTS {db_table_name}"
cursor.execute(drop_sql)
# create the table
table_create(cursor, db_table_name, table_entries[0])
table_populate(cursor, db_table_name, table_entries)
# %%
def main(conn, xdt_path):
with open("mappings.json", 'r') as f:
mappings = json.load(f)
with open(xdt_path, 'r') as f:
root = json.load(f)
cursor = conn.cursor()
for table_name in root:
if "Table" in table_name:
process_xdt_table(cursor, root, table_name, mappings)
finalize(cursor)
conn.commit()
def connect_to_db():
return mysql.connector.connect(
host="localhost",
user="root",
password="mypassword",
database="XDB"
)
def prep_db():
conn = connect_to_db()
cursor = conn.cursor()
# we have to upload a lot of data, so we need to raise the limit
cursor.execute("SET GLOBAL max_allowed_packet=1073741824")
conn.commit()
conn.close()
def finalize(cursor):
# credentials used by the game
cursor.execute("GRANT SELECT ON XDB.* TO 'cmog' IDENTIFIED BY 'scooby'")
# change the root password to something more secure
new_root_pw = input("Enter new root password: ")
cursor.execute(f"SET PASSWORD = PASSWORD('{new_root_pw}')")
# %%
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python3 json2xdb.py <path to xdt file>")
sys.exit(1)
xdt_path = sys.argv[1]
prep_db()
conn = connect_to_db()
main(conn, xdt_path)
conn.close()
# %%

232
json2xdb/mappings.json Normal file
View File

@@ -0,0 +1,232 @@
{
"m_pAnimationTable": {
"m_pAvatarData": "M",
"m_pNpcData": "Mob",
"m_pNanoData": "Nano"
},
"m_pAvatarTable": {
"m_pAvatarData": "AvatarTable",
"m_pAvatarGrowData": "AvatarGrowTable"
},
"m_pChatTable": {
"m_pFirstChatData": "1stChatTable",
"m_pSecondChatData": "2ndChatTable",
"m_pThirdChatData": "3rdChatTable",
"m_pChatStringData": "ChatString",
"m_pMenuChatData": "ChatTable",
"m_pMenuChatClassData": "ClassTable",
"m_pMenuChatEmoteData": "EmoteLink"
},
"m_pEmoteTable": {
"m_pEmoteAnimationData": "EmoteTable",
"m_pEmoteTextureData": "EmoteTexture"
},
"m_pGuideTable": {
"m_pGuideData": "GuideTable",
"m_pGuideStringData": "GuideStringTable"
},
"m_pInstanceTable": {
"m_pInstanceData": "InstanceTable",
"m_pWarpData": "WarpTable",
"m_pWarpNameData": "NameString"
},
"m_pMessageTable": {
"m_pMessageData": "SystemMessage"
},
"m_pMissionTable": {
"m_pJournalData": "Journal_ID",
"m_pMissionData": "MissionField",
"m_pMissionStringData": "MissionStringTable",
"m_pRewardData": "Reward"
},
"m_pNameTable": {
"m_pFirstName": "FirstNameTable",
"m_pMiddleName": "MiddleNameTable",
"m_pLastName": "LastNameTable"
},
"m_pNanoTable": {
"m_pNanoData": "NanoTable",
"m_pNanoStringData": "NanoString",
"m_pNanoMeshData": "NanoMesh",
"m_pNanoIconData": "NanoIcon",
"m_pNanoTuneData": "NanoTuneTable",
"m_pNanoTuneStringData": "NanoTuneString",
"m_pNanoTuneIconData": "NanoTuneIcon"
},
"m_pNpcTable": {
"m_pNpcData": "NpcTable",
"m_pNpcStringData": "NpcString",
"m_pNpcBarkerData": "BarkerTable",
"m_pNpcMeshData": "NpcMesh",
"m_pNpcIconData": "NpcIcon",
"m_pNpcGroupData": "NpcGroup",
"m_pNpcServiceData": "ServiceString"
},
"m_pShinyTable": {
"m_pShinyData": "ShinyTable",
"m_pShinyStringData": "ShinyString",
"m_pShinyMeshData": "ShinyMesh"
},
"m_pSkillTable": {
"m_pSkillData": "SkillTable",
"m_pSkillBuffData": "SkillBuffEffect",
"m_pSkillIconData": "SkillIcon",
"m_pSkillStringData": "SkillString"
},
"m_pConditionTable": {
"m_pConditionData": "StatusTable"
},
"m_pTransportationTable": {
"m_pTransportationMeshData": "TransportationMesh",
"m_pTransportationData": "TransportationTable",
"m_pTransportationWarpLocation": "WarpLocationTable",
"m_pTransportationWarpString": "TransportationWarpString",
"m_pBroomstickLocation": "WyvernLocationTable",
"m_pBroomstickString": "TransportationWyvernString",
"m_pTransIcon": "TransIcon"
},
"m_pVendorTable": {
"m_pItemData": "VendorTable"
},
"m_pXComTable": {
"m_pXComData": "XComTable"
},
"m_pBackItemTable": {
"m_pItemData": "ItemBackTable",
"m_pItemStringData": "ItemBackString",
"m_pItemIconData": "ItemBackIcon",
"m_pItemMeshData": "ItemBackMesh",
"m_pItemSoundData": "ItemBackSound"
},
"m_pFaceItemTable": {
"m_pItemData": "ItemFaceTable",
"m_pItemStringData": "ItemFaceString",
"m_pItemIconData": "ItemFaceIcon",
"m_pItemMeshData": "ItemFaceMesh",
"m_pItemSoundData": "ItemFaceSound"
},
"m_pGlassItemTable": {
"m_pItemData": "ItemGlassTable",
"m_pItemStringData": "ItemGlassString",
"m_pItemIconData": "ItemGlassIcon",
"m_pItemMeshData": "ItemGlassMesh",
"m_pItemSoundData": "ItemGlassSound"
},
"m_pHatItemTable": {
"m_pItemData": "ItemHatTable",
"m_pItemStringData": "ItemHatString",
"m_pItemIconData": "ItemHatIcon",
"m_pItemMeshData": "ItemHatMesh",
"m_pItemSoundData": "ItemHatSound"
},
"m_pHeadItemTable": {
"m_pItemData": "ItemHeadTable",
"m_pItemStringData": "ItemHeadString",
"m_pItemIconData": "ItemHeadIcon",
"m_pItemMeshData": "ItemHeadMesh",
"m_pItemSoundData": "ItemHeadSound"
},
"m_pPantsItemTable": {
"m_pItemData": "ItemPantsTable",
"m_pItemStringData": "ItemPantsString",
"m_pItemIconData": "ItemPantsIcon",
"m_pItemMeshData": "ItemPantsMesh",
"m_pItemSoundData": "ItemPantsSound"
},
"m_pShirtsItemTable": {
"m_pItemData": "ItemShirtTable",
"m_pItemStringData": "ItemShirtString",
"m_pItemIconData": "ItemShirtIcon",
"m_pItemMeshData": "ItemShirtMesh",
"m_pItemSoundData": "ItemShirtSound"
},
"m_pShoesItemTable": {
"m_pItemData": "ItemShoesTable",
"m_pItemStringData": "ItemShoesString",
"m_pItemIconData": "ItemShoesIcon",
"m_pItemMeshData": "ItemShoesMesh",
"m_pItemSoundData": "ItemShoesSound"
},
"m_pWeaponItemTable": {
"m_pItemData": "ItemWpnTable",
"m_pItemStringData": "ItemWpnString",
"m_pItemIconData": "ItemWpnIcon",
"m_pItemMeshData": "ItemWpnMesh",
"m_pItemSoundData": "ItemWpnSound"
},
"m_pVehicleItemTable": {
"m_pItemData": "ItemVehicleTable",
"m_pItemStringData": "ItemVehicleString",
"m_pItemIconData": "ItemVehicleIcon",
"m_pItemMeshData": "ItemVehicleMesh",
"m_pItemSoundData": "ItemVehicleSound"
},
"m_pGeneralItemTable": {
"m_pItemData": "ItemGeneralTable",
"m_pItemStringData": "ItemGeneralString",
"m_pItemIconData": "ItemGeneralIcon"
},
"m_pChestItemTable": {
"m_pItemData": "ItemChestTable",
"m_pItemStringData": "ItemChestString",
"m_pItemIconData": "ChestIconTable"
},
"m_pQuestItemTable": {
"m_pItemData": "ItemQuestTable",
"m_pItemStringData": "ItemQuestString",
"m_pItemIconData": "ItemQuestIcon"
},
"m_pCreationItemTable": {
"m_pCreationItemData": "ItemCreationTable"
},
"m_pFirstUseTable": {
"m_pFirstUseData": "FirstUseTable",
"m_pFirstUseString": "FirstUseString"
},
"m_pRulesTable": {
"m_pRulesData": "RulesTable",
"m_pRulesString": "RulesString"
},
"m_pHelpTable": {
"m_pHelpData": "HelpTable",
"m_pHelpPageData": "DescriptionTable",
"m_pHelpPageDescData": "Description",
"m_pHelpPageString": "DescriptionString",
"m_pHelpString": "HelpString"
},
"m_pCutSceneTable": {
"m_SceneData": "CutSceneText"
},
"m_pCombiningTable": {
"m_pCombiningData": "CombiningTable"
},
"m_pFilterTable": {
"m_pWhiteFilterData": "UnfilterTable",
"m_pBlackFilterData": "FilterTable",
"m_pNameFilterData": "NamefilterTable"
},
"m_pClassTable": {
"m_pClassTypeData": "ClassType",
"m_pClassWpnTypeData": "ClassWpnType",
"m_pClassString": "ClassString",
"m_pClassIconData": "ClassIcon"
},
"m_pEnchantTable": {
"m_pEnchantData": "EnchantTable"
},
"m_pClassSkillTable": {
"m_pClassSkillChargingElement": "ClassSkill_Charging",
"m_pSkillManagerData": "ClassSkill_Manager",
"m_pSkillData": "ClassSkill_Skill",
"m_pSkillBuffElement": "ClassSkill_BuffEffect",
"m_pSkillString": "ClassSkill_String",
"m_pClassSkillCondition": "Condition_Character",
"m_pSkillIconData": "ClassSkill_Icon",
"m_pSkillSound": "ClassSkill_Sound"
},
"m_pSkillBookTable": {
"m_pSkillBookElement": "ItemSkillBookTable",
"m_pSkillBookString": "ItemSkillBookString",
"m_pSkillBookIconData": "ItemSkillBookIcon"
}
}

283
json2xdb/prototyping.ipynb Normal file
View File

@@ -0,0 +1,283 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"import sys\n",
"from tqdm import tqdm\n",
"import mysql.connector"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [],
"source": [
"def get_db_column_name(xdt_field_name):\n",
" # special case 1\n",
" if xdt_field_name == \"m_iitemID\":\n",
" return \"ItemID\"\n",
" \n",
" try:\n",
" # find the first uppercase character and split the string there\n",
" idx_of_first_uppercase = next(i for i, c in enumerate(xdt_field_name) if c.isupper())\n",
" except StopIteration:\n",
" # special case 2\n",
" if xdt_field_name == \"m_ibattery\":\n",
" idx_of_first_uppercase = 3\n",
" else:\n",
" print(f\"Could not find uppercase character in {xdt_field_name}\")\n",
" sys.exit(1)\n",
" prefix = xdt_field_name[:idx_of_first_uppercase]\n",
" db_field_name = xdt_field_name[idx_of_first_uppercase:]\n",
" return db_field_name"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [],
"source": [
"def table_entry_to_tuple(table_entry):\n",
" vals = []\n",
" for field_name in table_entry:\n",
" field = table_entry[field_name]\n",
" vals.append(field)\n",
" return tuple(vals)\n",
"\n",
"def flatten_table_entry(table_entry):\n",
" flattened_entry = {}\n",
" for field_name in table_entry:\n",
" field = table_entry[field_name]\n",
" if type(field) == list:\n",
" for i, item in enumerate(field):\n",
" flattened_entry[f\"{field_name}{i}\"] = item\n",
" else:\n",
" flattened_entry[field_name] = field\n",
" return flattened_entry\n",
"\n",
"def handle_dict_table(table_entries, identifier_key, items_key):\n",
" new_table_entries = []\n",
" for table_entry in table_entries:\n",
" identifier = table_entry[identifier_key]\n",
" items = table_entry[items_key]\n",
" for item in items:\n",
" new_item = {}\n",
" new_item[identifier_key] = identifier # needs to be first\n",
" for field_name in item:\n",
" new_item[field_name] = item[field_name]\n",
" new_table_entries.append(new_item)\n",
" return new_table_entries\n"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [],
"source": [
"def gen_column_sql(field_name, field_value):\n",
" field_type = type(field_value)\n",
" if field_type == int:\n",
" return f\"`{field_name}` INT,\"\n",
" elif field_type == float:\n",
" return f\"`{field_name}` FLOAT,\"\n",
" elif field_type == str:\n",
" # TODO maybe ascii vs unicode?\n",
" return f\"`{field_name}` TEXT,\"\n",
" else:\n",
" print(f\"Unknown type {field_type} for field {field_name}, skipping\")\n",
" return \"\""
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [],
"source": [
"def table_create(cursor, table_name, xdt_template_entry):\n",
" sql = f\"CREATE TABLE {table_name} (\"\n",
" sql += \"id INT AUTO_INCREMENT PRIMARY KEY,\"\n",
" for field_name in xdt_template_entry:\n",
" db_field_name = get_db_column_name(field_name)\n",
" val = xdt_template_entry[field_name]\n",
" sql += gen_column_sql(db_field_name, val)\n",
" sql = sql[:-1] # remove trailing comma\n",
" sql += \")\"\n",
" cursor.execute(sql)"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [],
"source": [
"def table_populate(cursor, table_name, table_entries):\n",
" # generate the SQL first\n",
" sql = f\"INSERT INTO {table_name} (\"\n",
" template_entry = table_entries[0]\n",
" for field_name in template_entry:\n",
" db_field_name = get_db_column_name(field_name)\n",
" sql += f\"`{db_field_name}`,\"\n",
" sql = sql[:-1] # remove trailing comma\n",
" sql += \") VALUES (\"\n",
" for field_name in template_entry:\n",
" sql += f\"%s,\"\n",
" sql = sql[:-1] # remove trailing comma\n",
" sql += \")\"\n",
" \n",
" vals = [table_entry_to_tuple(entry) for entry in table_entries]\n",
" try:\n",
" cursor.executemany(sql, vals)\n",
" except Exception as e:\n",
" print(sql)\n",
" print(vals)\n",
" raise e"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [],
"source": [
"def process_xdt_table(cursor, root, table_name, mappings):\n",
" table = root[table_name]\n",
" for (i, subtable_name) in tqdm(enumerate(table), desc=table_name, total=len(table)):\n",
" db_table_name = mappings[table_name][i]\n",
" #print(f\"{subtable_name} => {db_table_name}\")\n",
" \n",
" table_entries = table[subtable_name]\n",
" if db_table_name == \"CutSceneText\":\n",
" table_entries = handle_dict_table(table_entries, \"m_iEvent\", \"m_TextElement\")\n",
" table_entries = [flatten_table_entry(entry) for entry in table_entries]\n",
"\n",
" # clear the table\n",
" drop_sql = f\"DROP TABLE IF EXISTS {db_table_name}\"\n",
" cursor.execute(drop_sql)\n",
"\n",
" # create the table\n",
" table_create(cursor, db_table_name, table_entries[0])\n",
" table_populate(cursor, db_table_name, table_entries)"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [],
"source": [
"def main(conn, xdt_path):\n",
" with open(\"mappings.json\", 'r') as f:\n",
" mappings = json.load(f)\n",
" with open(xdt_path, 'r') as f:\n",
" root = json.load(f)\n",
" cursor = conn.cursor()\n",
" for table_name in root:\n",
" if \"Table\" in table_name:\n",
" process_xdt_table(cursor, root, table_name, mappings)\n",
" conn.commit()"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"m_pAnimationTable: 100%|██████████| 3/3 [00:00<00:00, 9.30it/s]\n",
"m_pAvatarTable: 100%|██████████| 2/2 [00:00<00:00, 5.76it/s]\n",
"m_pChatTable: 100%|██████████| 7/7 [00:00<00:00, 9.55it/s]\n",
"m_pEmoteTable: 100%|██████████| 2/2 [00:00<00:00, 12.84it/s]\n",
"m_pGuideTable: 100%|██████████| 2/2 [00:00<00:00, 11.23it/s]\n",
"m_pInstanceTable: 100%|██████████| 3/3 [00:00<00:00, 9.99it/s]\n",
"m_pMessageTable: 100%|██████████| 1/1 [00:00<00:00, 8.64it/s]\n",
"m_pMissionTable: 100%|██████████| 4/4 [00:01<00:00, 2.57it/s]\n",
"m_pNameTable: 100%|██████████| 3/3 [00:00<00:00, 9.74it/s]\n",
"m_pNanoTable: 100%|██████████| 7/7 [00:00<00:00, 9.92it/s]\n",
"m_pNpcTable: 100%|██████████| 7/7 [00:01<00:00, 4.86it/s]\n",
"m_pShinyTable: 100%|██████████| 3/3 [00:00<00:00, 9.07it/s]\n",
"m_pSkillTable: 100%|██████████| 4/4 [00:00<00:00, 11.26it/s]\n",
"m_pConditionTable: 100%|██████████| 1/1 [00:00<00:00, 11.58it/s]\n",
"m_pTransportationTable: 100%|██████████| 7/7 [00:00<00:00, 10.35it/s]\n",
"m_pVendorTable: 100%|██████████| 1/1 [00:00<00:00, 4.68it/s]\n",
"m_pXComTable: 100%|██████████| 1/1 [00:00<00:00, 9.32it/s]\n",
"m_pBackItemTable: 100%|██████████| 5/5 [00:00<00:00, 9.05it/s]\n",
"m_pFaceItemTable: 100%|██████████| 5/5 [00:00<00:00, 9.85it/s]\n",
"m_pGlassItemTable: 100%|██████████| 5/5 [00:00<00:00, 8.95it/s]\n",
"m_pHatItemTable: 100%|██████████| 5/5 [00:00<00:00, 10.58it/s]\n",
"m_pHeadItemTable: 100%|██████████| 5/5 [00:00<00:00, 9.31it/s]\n",
"m_pPantsItemTable: 100%|██████████| 5/5 [00:00<00:00, 8.16it/s]\n",
"m_pShirtsItemTable: 100%|██████████| 5/5 [00:00<00:00, 7.10it/s]\n",
"m_pShoesItemTable: 100%|██████████| 5/5 [00:00<00:00, 6.49it/s]\n",
"m_pWeaponItemTable: 100%|██████████| 5/5 [00:00<00:00, 6.26it/s]\n",
"m_pVehicleItemTable: 100%|██████████| 5/5 [00:00<00:00, 9.41it/s]\n",
"m_pGeneralItemTable: 100%|██████████| 3/3 [00:00<00:00, 11.56it/s]\n",
"m_pChestItemTable: 100%|██████████| 3/3 [00:00<00:00, 6.83it/s]\n",
"m_pQuestItemTable: 100%|██████████| 3/3 [00:00<00:00, 11.19it/s]\n",
"m_pCreationItemTable: 100%|██████████| 1/1 [00:00<00:00, 12.50it/s]\n",
"m_pFirstUseTable: 100%|██████████| 2/2 [00:00<00:00, 10.72it/s]\n",
"m_pRulesTable: 100%|██████████| 2/2 [00:00<00:00, 8.38it/s]\n",
"m_pHelpTable: 100%|██████████| 5/5 [00:00<00:00, 9.11it/s]\n",
"m_pCutSceneTable: 100%|██████████| 1/1 [00:00<00:00, 11.51it/s]\n",
"m_pCombiningTable: 100%|██████████| 1/1 [00:00<00:00, 13.88it/s]\n",
"m_pFilterTable: 100%|██████████| 3/3 [00:00<00:00, 9.08it/s]\n",
"m_pClassTable: 100%|██████████| 4/4 [00:00<00:00, 10.94it/s]\n",
"m_pEnchantTable: 100%|██████████| 1/1 [00:00<00:00, 11.75it/s]\n",
"m_pClassSkillTable: 100%|██████████| 8/8 [00:00<00:00, 9.37it/s]\n",
"m_pSkillBookTable: 100%|██████████| 3/3 [00:00<00:00, 10.67it/s]\n"
]
}
],
"source": [
"xdt_path = \"tdata/xdt.json\"\n",
"conn = mysql.connector.connect(\n",
" host=\"localhost\",\n",
" user=\"root\",\n",
" password=\"mypassword\",\n",
" database=\"tabledata\"\n",
")\n",
"main(conn, xdt_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -0,0 +1,6 @@
[
"m_iItemStringIndex",
"m_iItemConditionNum",
"m_iItemConditionNum2",
"m_iNextItem"
]

View File

@@ -0,0 +1,6 @@
[
"m_iItemStringIndex",
"m_iItemConditionNum",
"m_iItemConditionNum2",
"m_iNextItem"
]

View File

@@ -0,0 +1,6 @@
[
"m_iItemStringIndex",
"m_iItemConditionNum",
"m_iItemConditionNum2",
"m_iNextItem"
]

View File

@@ -0,0 +1,17 @@
[
"m_iLevel",
"m_iHpUp",
"m_iMaxHP",
"m_iAccuracy",
"m_iDodge",
"m_iPower",
"m_iProtection",
"m_iReqBlob_NanoCreate",
"m_iReqBlob_NanoTune",
"m_iFMLimit",
"m_iMobFM",
"m_iNanoQuestTaskID",
"m_iNanoID",
"m_iBonusFM",
"m_iDeathFM"
]

View File

@@ -0,0 +1,22 @@
[
"m_iPower",
"m_iAccuracy",
"m_iProtection",
"m_iDodge",
"m_iRunSpeed",
"m_iSwimSpeed",
"m_iJumpHeight",
"m_iJumpDistance",
"m_iViewAngle",
"m_iViewDistance",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitialTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iBonusUp"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,12 @@
[
"m_iChatNum1",
"m_iChatNum2",
"m_iChatNum3",
"m_iChatNum4",
"m_iChatNum5",
"m_iChatNum6",
"m_iChatNum7",
"m_iChatNum8",
"m_iChatNum9",
"m_iChatNum10"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,5 @@
[
"m_iBuffNumber",
"m_iBuffEffect",
"m_iBuffEffectInstant"
]

View File

@@ -0,0 +1,10 @@
[
"m_iMax",
"m_iStandard",
"m_fTickplus",
"m_fTickminus",
"m_iAttackplus",
"m_iDefensplus",
"m_iDeadline",
"m_iDeaddown"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,10 @@
[
"m_iPriority",
"m_iSkillbutton",
"m_iSkillNumber",
"m_iConditionChar",
"m_iConditionSkill",
"m_iKeyMintime",
"m_iKeyMaxtime",
"m_iMotionSkipTime"
]

View File

@@ -0,0 +1,41 @@
[
"m_iSkillNumber",
"m_iSkillType",
"m_iEffectTarget",
"m_iEffectType",
"m_iTargetType",
"m_iValueA_Type",
"m_iValueA",
"m_iValueB_Type",
"m_iValueB",
"m_iValueC_Type",
"m_iValueC",
"m_iEffectRange",
"m_iEffectAngle",
"m_iEffectArea",
"m_iCoolTime",
"m_iTargetNumber",
"m_iBatteryDrainType",
"m_iBatteryDrainUse",
"m_iInitialTime",
"m_iDeleverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iDBType",
"m_iIcon",
"m_iEffect",
"m_iTargetEffect",
"m_iBuffEffect",
"m_iSound",
"m_iCoolType",
"m_iClassType",
"m_iClassNum",
"m_iWpnType",
"m_iDisCharging",
"m_iPlusCharging",
"m_iMoveType",
"m_iMoveSpeed",
"m_iJumpPower",
"m_iSkillLevel",
"m_iAnimationTime"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,8 @@
[
"m_SkillName",
"m_ClassName",
"m_WpnName",
"m_skillAccount1",
"m_skillAccount2",
"m_animationName"
]

View File

@@ -0,0 +1,4 @@
[
"m_strName",
"m_strComment"
]

View File

@@ -0,0 +1,4 @@
[
"m_iChatString",
"m_iLinkChatNum"
]

View File

@@ -0,0 +1,13 @@
[
"m_iClassNum",
"m_iClassName",
"m_iWpnType1",
"m_iWpnType2",
"m_iBasicWpn",
"m_iBonusHP",
"m_iBonusPow",
"m_iBonusAcc",
"m_iBonusPro",
"m_iBonusDod",
"m_iIcon"
]

View File

@@ -0,0 +1,10 @@
[
"m_iWpnType",
"m_iRateOfFire",
"m_iOverheatMax",
"m_iOverheatUse",
"m_iUnuseCool",
"m_iUseCool",
"m_iCoolTime",
"m_iOverheatEffect"
]

View File

@@ -0,0 +1,10 @@
[
"m_iLevelGap",
"m_fSameGrade",
"m_fOneGrade",
"m_fTwoGrade",
"m_fThreeGrade",
"m_fLevelGapStandard",
"m_iLookConstant",
"m_iStatConstant"
]

View File

@@ -0,0 +1,6 @@
[
"m_iIndex",
"m_iBattleCondition",
"m_iMoveCondition",
"m_iJumpCondition"
]

View File

@@ -0,0 +1,5 @@
[
"m_iEvent",
"m_iLine",
"m_strText"
]

View File

@@ -0,0 +1,6 @@
[
"m_iType",
"m_iSize",
"m_iColor",
"m_iString"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,4 @@
[
"m_iStartContent",
"m_iEndContent"
]

View File

@@ -0,0 +1,3 @@
[
"m_iLinkEmoteNum"
]

View File

@@ -0,0 +1,8 @@
[
"m_iEmoteNumber",
"m_iUser",
"m_iAvatarAnimation",
"m_iNanoAnimation",
"m_iTexture",
"m_iDuration"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,16 @@
[
"m_iEnchantGrade",
"m_iCost",
"m_iClass",
"m_iWpnMatter",
"m_iCostumeMatter",
"m_iProbability",
"m_iOffenceUp",
"m_iDefenceUp",
"m_iFailType",
"m_iNoDropProb",
"m_iOneDropProb",
"m_iTwoDropProb",
"m_iThreeDropProb",
"m_iFourDropProb"
]

View File

@@ -0,0 +1,3 @@
[
"m_strText"
]

View File

@@ -0,0 +1,3 @@
[
"m_pstrNameString"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,7 @@
[
"m_iString",
"m_iCompDuration",
"m_iIconDuration",
"m_iHelpSub",
"m_iHelpMain"
]

View File

@@ -0,0 +1,4 @@
[
"m_iNum",
"m_pszString"
]

View File

@@ -0,0 +1,8 @@
[
"m_iNameIndex",
"m_iQuest",
"m_iSelect",
"m_iLoginNomail",
"m_iLoginMail",
"m_iLevelUp"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,4 @@
[
"m_iTitleStartString",
"m_iSubEndString"
]

View File

@@ -0,0 +1,26 @@
[
null,
"m_iZoneX",
"m_iZoneY",
null,
"m_iInstanceNameID",
null,
null,
null,
"m_iIsEP",
null,
null,
null,
null,
null,
"m_ScoreMax",
null,
null,
null,
null,
null,
null,
null,
null,
"m_SortIndex"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,50 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iEquipLoc",
"m_iEquipType",
"m_ibattery",
"m_iBatteryDrain",
"m_iMinReqLev",
"m_iReqSex",
"m_iMentor",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitalTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iUp_power",
"m_iUp_accuracy",
"m_iUp_protection",
"m_iUp_dodge",
"m_iUp_runSpeed",
"m_iUp_swimSpeed",
"m_iUp_jumpHeight",
"m_iUp_jumpDistance",
"m_iUp_atkRate",
"m_iUp_effectArea",
"m_iUp_addFusionMatter",
"m_iUp_addCandy",
"m_iUp_addItemfind",
"m_iMesh",
"m_iIcon",
"m_iEffect1",
"m_iSound1",
"m_iRarity",
"m_iPointRat",
"m_iGroupRat",
"m_iDefenseRat",
"m_iEffect2",
"m_iSound2",
"m_iCashAble"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,12 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iChestDesc",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iIcon",
"m_iChestCheck"
]

View File

@@ -0,0 +1,13 @@
[
"m_iShirtM",
"m_iPantsM",
"m_iShoesM",
"m_iHairM",
"m_iFaceM",
"m_iShirtF",
"m_iPantsF",
"m_iShoesF",
"m_iHairF",
"m_iFaceF",
"m_iWeapon"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,50 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iEquipLoc",
"m_iEquipType",
"m_ibattery",
"m_iBatteryDrain",
"m_iMinReqLev",
"m_iReqSex",
"m_iMentor",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitalTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iUp_power",
"m_iUp_accuracy",
"m_iUp_protection",
"m_iUp_dodge",
"m_iUp_runSpeed",
"m_iUp_swimSpeed",
"m_iUp_jumpHeight",
"m_iUp_jumpDistance",
"m_iUp_atkRate",
"m_iUp_effectArea",
"m_iUp_addFusionMatter",
"m_iUp_addCandy",
"m_iUp_addItemfind",
"m_iMesh",
"m_iIcon",
"m_iEffect1",
"m_iSound1",
"m_iRarity",
"m_iPointRat",
"m_iGroupRat",
"m_iDefenseRat",
"m_iEffect2",
"m_iSound2",
"m_iCashAble"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,16 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iBatteryRecharge",
"m_iItemType",
"m_iStimPackAttri",
"m_iLinkSkill",
"m_iIcon",
"m_iCash"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,50 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iEquipLoc",
"m_iEquipType",
"m_ibattery",
"m_iBatteryDrain",
"m_iMinReqLev",
"m_iReqSex",
"m_iMentor",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitalTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iUp_power",
"m_iUp_accuracy",
"m_iUp_protection",
"m_iUp_dodge",
"m_iUp_runSpeed",
"m_iUp_swimSpeed",
"m_iUp_jumpHeight",
"m_iUp_jumpDistance",
"m_iUp_atkRate",
"m_iUp_effectArea",
"m_iUp_addFusionMatter",
"m_iUp_addCandy",
"m_iUp_addItemfind",
"m_iMesh",
"m_iIcon",
"m_iEffect1",
"m_iSound1",
"m_iRarity",
"m_iPointRat",
"m_iGroupRat",
"m_iDefenseRat",
"m_iEffect2",
"m_iSound2",
"m_iCashAble"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,50 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iEquipLoc",
"m_iEquipType",
"m_ibattery",
"m_iBatteryDrain",
"m_iMinReqLev",
"m_iReqSex",
"m_iMentor",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitalTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iUp_power",
"m_iUp_accuracy",
"m_iUp_protection",
"m_iUp_dodge",
"m_iUp_runSpeed",
"m_iUp_swimSpeed",
"m_iUp_jumpHeight",
"m_iUp_jumpDistance",
"m_iUp_atkRate",
"m_iUp_effectArea",
"m_iUp_addFusionMatter",
"m_iUp_addCandy",
"m_iUp_addItemfind",
"m_iMesh",
"m_iIcon",
"m_iEffect1",
"m_iSound1",
"m_iRarity",
"m_iPointRat",
"m_iGroupRat",
"m_iDefenseRat",
"m_iEffect2",
"m_iSound2",
"m_iCashAble"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,50 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iEquipLoc",
"m_iEquipType",
"m_ibattery",
"m_iBatteryDrain",
"m_iMinReqLev",
"m_iReqSex",
"m_iMentor",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitalTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iUp_power",
"m_iUp_accuracy",
"m_iUp_protection",
"m_iUp_dodge",
"m_iUp_runSpeed",
"m_iUp_swimSpeed",
"m_iUp_jumpHeight",
"m_iUp_jumpDistance",
"m_iUp_atkRate",
"m_iUp_effectArea",
"m_iUp_addFusionMatter",
"m_iUp_addCandy",
"m_iUp_addItemfind",
"m_iMesh",
"m_iIcon",
"m_iEffect1",
"m_iSound1",
"m_iRarity",
"m_iPointRat",
"m_iGroupRat",
"m_iDefenseRat",
"m_iEffect2",
"m_iSound2",
"m_iCashAble"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,50 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iEquipLoc",
"m_iEquipType",
"m_ibattery",
"m_iBatteryDrain",
"m_iMinReqLev",
"m_iReqSex",
"m_iMentor",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitalTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iUp_power",
"m_iUp_accuracy",
"m_iUp_protection",
"m_iUp_dodge",
"m_iUp_runSpeed",
"m_iUp_swimSpeed",
"m_iUp_jumpHeight",
"m_iUp_jumpDistance",
"m_iUp_atkRate",
"m_iUp_effectArea",
"m_iUp_addFusionMatter",
"m_iUp_addCandy",
"m_iUp_addItemfind",
"m_iMesh",
"m_iIcon",
"m_iEffect1",
"m_iSound1",
"m_iRarity",
"m_iPointRat",
"m_iGroupRat",
"m_iDefenseRat",
"m_iEffect2",
"m_iSound2",
"m_iCashAble"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iQuestStart",
"m_iDelete",
"m_iIcon"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,50 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iEquipLoc",
"m_iEquipType",
"m_ibattery",
"m_iBatteryDrain",
"m_iMinReqLev",
"m_iReqSex",
"m_iMentor",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitalTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iUp_power",
"m_iUp_accuracy",
"m_iUp_protection",
"m_iUp_dodge",
"m_iUp_runSpeed",
"m_iUp_swimSpeed",
"m_iUp_jumpHeight",
"m_iUp_jumpDistance",
"m_iUp_atkRate",
"m_iUp_effectArea",
"m_iUp_addFusionMatter",
"m_iUp_addCandy",
"m_iUp_addItemfind",
"m_iMesh",
"m_iIcon",
"m_iEffect1",
"m_iSound1",
"m_iRarity",
"m_iPointRat",
"m_iGroupRat",
"m_iDefenseRat",
"m_iEffect2",
"m_iSound2",
"m_iCashAble"
]

View File

@@ -0,0 +1,4 @@
[
"m_iIconType",
"m_iIconNumber"
]

View File

@@ -0,0 +1,8 @@
[
"m_pstrMMeshModelString",
"m_pstrMTextureString",
"m_pstrMTextureString2",
"m_pstrFMeshModelString",
"m_pstrFTextureString",
"m_pstrFTextureString2"
]

View File

@@ -0,0 +1,5 @@
[
"m_pstrSoundString1",
"m_pstrSoundString2",
"m_pstrSoundString3"
]

View File

@@ -0,0 +1,7 @@
[
"m_strName",
"m_strComment",
"m_strComment1",
"m_strComment2",
"m_iExtraNumber"
]

View File

@@ -0,0 +1,50 @@
[
"m_iItemNumber",
"m_iItemName",
"m_iComment",
"m_iTradeAble",
"m_iItemPrice",
"m_iItemSellPrice",
"m_iSellAble",
"m_iStackNumber",
"m_iEquipLoc",
"m_iEquipType",
"m_ibattery",
"m_iBatteryDrain",
"m_iMinReqLev",
"m_iReqSex",
"m_iMentor",
"m_iAtkRange",
"m_iAtkAngle",
"m_iEffectArea",
"m_iTargetMode",
"m_iTargetNumber",
"m_iInitalTime",
"m_iDeliverTime",
"m_iDelayTime",
"m_iDurationTime",
"m_iUp_power",
"m_iUp_accuracy",
"m_iUp_protection",
"m_iUp_dodge",
"m_iUp_runSpeed",
"m_iUp_swimSpeed",
"m_iUp_jumpHeight",
"m_iUp_jumpDistance",
"m_iUp_atkRate",
"m_iUp_effectArea",
"m_iUp_addFusionMatter",
"m_iUp_addCandy",
"m_iUp_addItemfind",
"m_iMesh",
"m_iIcon",
"m_iEffect1",
"m_iSound1",
"m_iRarity",
"m_iPointRat",
"m_iGroupRat",
"m_iDefenseRat",
"m_iEffect2",
"m_iSound2",
"m_iCashAble"
]

Some files were not shown because too many files have changed in this diff Show More