Compare commits

..

19 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
161 changed files with 2601 additions and 56 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]
@@ -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