Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/unittests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ jobs:
with:
submodules: true

- name: Setup Python 3.10
- name: Setup Python 3.101
uses: actions/[email protected]
with:
python-version: 3.10.6
python-version: 3.11

# Runs a single command using the runners shell
- name: Dependencies
Expand All @@ -39,7 +39,6 @@ jobs:
python utils/shared/base_utils2.py -i "$PWD" -e "$PWD"
python utils/shared/cstr.py
python utils/shared/cppkeyvalues.py
python utils/shared/keyvalues3.py
python utils/shared/material_proxies.py
python utils/shared/qc.py

Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
Pillow
numpy

# Particles, prop_data
keyvalues3==0.1a2

# Maps
vdf
dataclassy==0.10.4
Expand Down
55 changes: 14 additions & 41 deletions utils/models_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import shutil
from typing import Literal, Type, Union
import shared.base_utils2 as sh
import keyvalues3 as kv3
from pathlib import Path
from itertools import tee
from srctools import smd
from shared.keyvalues3 import KV3File, KV3Header

"""
Import Source Engine models to Source 2
Expand Down Expand Up @@ -93,11 +93,10 @@ def main():


def ImportMDLtoVMDL(mdl_path: Path):
vmdl_path = mdl_path.with_suffix('.vmdl')
vmdl = KV3File(
vmdl = dict(
m_sMDLFilename = ("../"*SAMPBOX) + mdl_path.local.as_posix()
)
vmdl_path.write_text(vmdl.ToString())
kv3.write(vmdl, mdl_path.with_suffix('.vmdl'))
print('+ Generated', vmdl_path.local)
return vmdl_path

Expand All @@ -117,7 +116,7 @@ def ImportMDLtoVMDL(mdl_path: Path):


def ImportQCtoVMDL(qc_path: Path):
vmdl = ModelDocVMDL()
vmdl = ModelDoc()

# local paths
active_folder: Path = qc_path.local.parent
Expand Down Expand Up @@ -192,8 +191,8 @@ def add_rendermesh_from_body(body: QC.body):
for command in qc_commands:
match command:
case QC.staticprop():
vmdl.root.model_archetype = "static_prop_model"
vmdl.root.primary_associated_entity = "prop_static"
vmdl.rootNode.model_archetype = "static_prop_model"
vmdl.rootNode.primary_associated_entity = "prop_static"
case QC.popd():
try:
active_folder = dir_stack.pop()
Expand Down Expand Up @@ -526,7 +525,7 @@ def add_rendermesh_from_body(body: QC.body):
# grab $animation, $sequence, $attachment and $collisiontext from this model
elif isinstance(command, QC.includemodel):
command: QC.includemodel
vmdl.root.base_model_name = (models / command.filename).with_suffix('.vmdl').as_posix()
vmdl.rootNode.base_model_name = (models / command.filename).with_suffix('.vmdl').as_posix()

elif isinstance(command, QC.declaresequence):
sequences_declared.append(command.name)
Expand Down Expand Up @@ -606,7 +605,7 @@ def add_rendermesh_from_body(body: QC.body):
out_vmdl_path.parent.MakeDir()

if len(sequences_declared):
vmdl_prefab = ModelDocVMDL()
vmdl_prefab = ModelDoc()
out_vmdl_prefab_path = out_vmdl_path.with_name("declared_sequences.vmdl_prefab")

for sequence in sequences_declared:
Expand All @@ -615,45 +614,19 @@ def add_rendermesh_from_body(body: QC.body):
)
vmdl_prefab.add_to_appropriate_list(animfile)

out_vmdl_prefab_path.write_text(vmdl_prefab.ToString())
kv3.write(vmdl_prefab, out_vmdl_prefab_path)
print('+ Saved prefab', out_vmdl_prefab_path.local)

if len(skeleton.children):
vmdl.root.add_nodes(skeleton)
vmdl.rootNode.add_nodes(skeleton)

out_vmdl_path.write_text(vmdl.ToString())
kv3.write(vmdl, out_vmdl_path)
print('+ Saved', out_vmdl_path.local)


from dataclasses import asdict
class ModelDocVMDL(KV3File):
def __init__(self):
self.header = KV3Header(
format='source1imported',
format_ver='3cec427c-1b0e-4d48-a90a-0436f33a6041' if sh.SBOX else 'fb63b6ca-f435-4aa0-a2c7-c66ddc651dca'
)
self.root = ModelDoc.RootNode()

self.base_lists: dict[Type[_BaseNode], _BaseNode] = {}

def __str__(self):
self["rootNode"] = asdict(self.root)
return super().__str__()

def add_to_appropriate_list(self, node: _Node):
"""
Adds bodygroup to bodygrouplist, animfile to animationlist, etc. Only makes one list.
"""
container_type = ModelDoc.get_container(type(node))
container = self.base_lists.get(container_type)
if container is None:
if container_type is None:
raise RuntimeError(f"Don't know where {type(node)} belongs.")
container = container_type()
self.base_lists[container_type] = container
self.root.add_nodes(container)

container.add_nodes(node)
from dataclasses import dataclass, asdict



if __name__ == "__main__":
# TODO: Don't ask for src1?
Expand Down
18 changes: 9 additions & 9 deletions utils/particles_import.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import shared.base_utils2 as sh
import shared.datamodel as dmx
import shared.keyvalues3 as kv3
from uuid import UUID
import keyvalues3 as kv3
from dataclasses import dataclass
from pathlib import Path

Expand Down Expand Up @@ -152,7 +153,7 @@ def __call__(self, oldval, existing = default.copy()):
# },
# ]
'sequence 0 model': lambda mdl_path: ('m_ModelList',
[{'m_model': kv3.resource(Path('models/' + mdl_path).with_suffix('.vmdl'))}]
[{'m_model': kv3.flagged_value(Path('models/' + mdl_path).with_suffix('.vmdl'), kv3.Flag.resource)}]
),
'orient model z to normal': 'm_bOrientZ',
'activity override': 'm_ActivityName',
Expand Down Expand Up @@ -1831,7 +1832,7 @@ def process_material(value: str):

vmt_path = sh.IMPORT_GAME / "materials" / value # vmts are found in game (as most things)
vmat_path = vmt_path.local.with_suffix('.vmat')
vpcf._base_t['m_Renderers']['m_hMaterial'] = kv3.resource(vmat_path)
vpcf._base_t['m_Renderers']['m_hMaterial'] = kv3.flagged_value(vmat_path, kv3.Flag.resource)
try:
vmt = VMT(KV.FromFile(vmt_path))
except FileNotFoundError:
Expand Down Expand Up @@ -1864,7 +1865,7 @@ def process_material(value: str):
with open(vtex_path, 'w') as fp:
fp.write(VTEX_TEMPLATE.replace('<>', tex.as_posix(), 1))
vpcf_replacement_key = 'm_hTexture' if vmtkey in ('$basetexture', '$material') else 'm_hNormalTexture'
vpcf._base_t['m_Renderers'][vpcf_replacement_key] = kv3.resource(vtex_path.local)
vpcf._base_t['m_Renderers'][vpcf_replacement_key] = kv3.flagged_value(vtex_path.local, kv3.Flag.resource)
continue
if vmtkey not in vmt_to_vpcf:
#un((vmtkey, vmtval), "VMT")
Expand Down Expand Up @@ -1905,7 +1906,7 @@ def pcfkv_convert(key, value):
return
if key == 'snapshot':
vsnaps[vpcf.path.local] = value
return str(vpcf_translation), kv3.resource(Path(vpcf.path.local.parent / (value + '.vpcf')))
return str(vpcf_translation), kv3.flagged_value(Path(vpcf.path.local.parent / (value + '.vpcf')), kv3.Flag.resource)

return vpcf_translation, value
elif isinstance(vpcf_translation, tuple):
Expand Down Expand Up @@ -1984,7 +1985,7 @@ def pcfkv_convert(key, value):
if isinstance(value2, dmx.Element):
value2 = value2.name
else: input(f'Ref not an element {key2}: {value2}')
value2 = kv3.resource(Path(vpcf.path.local.parent / (value2 + '.vpcf')))
value2 = kv3.flagged_value(Path(vpcf.path.local.parent / (value2 + '.vpcf')), kv3.Flag.resource)
elif isinstance(subkey, (minof, maxof)):
bMin = isinstance(subkey, minof)
if str(subkey) in subKV:
Expand Down Expand Up @@ -2053,10 +2054,9 @@ def ImportParticleSnapshotFile(psf_path: Path) -> Path:
vsnap_path.parent.MakeDir()
return copyfile(psf_path, vsnap_path)

class VPCF(kv3.KV3File):
class VPCF(dict):
def __init__(self, path, **kwargs):
super().__init__(**kwargs)
self.header = kv3.KV3Header(format='vpcf26', format_ver='26288658-411e-4f14-b698-2e1e5d00dec6')
self['_class'] = 'CParticleSystemDefinition'
self.update(kwargs)

Expand Down Expand Up @@ -2100,7 +2100,7 @@ def ImportPSD(ParticleSystemDefinition: dmx.Element, out_root: Path, bOverwrite
vpcf.setdefault('m_PreEmissionOperators', list())
vpcf['m_PreEmissionOperators'].append(operator)

vpcf.path.write_text(vpcf.ToString())
kv3.write(dict(vpcf), vpcf.path, format=kv3.Format("vpcf26", UUID("26288658-411e-4f14-b698-2e1e5d00dec6")))

print("+ Saved", vpcf.path.local.as_posix())

Expand Down
24 changes: 12 additions & 12 deletions utils/scripts_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from shutil import copyfile
from pathlib import Path
from shared.keyvalues1 import KV, VDFDict
from shared.keyvalues3 import KV3File
import keyvalues3
import itertools

OVERWRITE_ASSETS = False
Expand Down Expand Up @@ -84,7 +84,7 @@ def main():
sh.MakeDir(sh.output(scripts))
if not (sh.output(propdata, ".vdata").is_file() and not OVERWRITE_ASSETS):
kv = KV.FromFile(propdata, case_sensitive=True)
kv3 = KV3File(generic_data_type = "prop_data")
kv3 = dict(generic_data_type = "prop_data")
for name, data in kv.items():
if name.lower() == "breakablemodels":
continue
Expand All @@ -93,7 +93,7 @@ def main():
if key.lower() == "base":
key = "_base"
kv3[name][key] = value
sh.output(propdata, ".vdata").write_text(kv3.ToString())
keyvalues3.write(kv3, sh.output(propdata, ".vdata"))
print("+ Saved scripts/propdata.vdata")
else:
sh.import_context['dest'] = sh.EXPORT_GAME
Expand Down Expand Up @@ -185,7 +185,7 @@ def ImportSoundscapesToVdata(file: Path):
}
}
"""
sndscape_file.write_text(KV3File(data=sndscape_data).ToString())
keyvalues3.write(dict(data=sndscape_data), sndscape_file)
print("+ Saved", sndscape_file.local)
return sndscape_folder

Expand Down Expand Up @@ -277,7 +277,7 @@ def _handle_range(k, v) -> "median, deviation":
return out_v, range

kv = KV.CollectionFromFile(asset_path)
kv3 = KV3File()
kv3 = dict()

for gamesound, gs_data in kv.items(): # "weapon.fire", {}

Expand Down Expand Up @@ -379,7 +379,7 @@ def _handle_range(k, v) -> "median, deviation":
out_kv[out_k] = out_v

if sh.SBOX:
sound_file.write_text(KV3File(data=sound_data).ToString())
keyvalues3.write(dict(data=sound_data), sound_file)
print("+ Saved", sound_file.local)
else:
if out_kv == dict(type='src1_3d'): # empty
Expand All @@ -396,7 +396,7 @@ def _handle_range(k, v) -> "median, deviation":
if sh.SBOX:
return out_sound_folder
else:
vsndevts_file.write_text(kv3.ToString())
keyvalues3.write(kv3, vsndevts_file)

print("+ Saved", vsndevts_file.local)
return vsndevts_file
Expand Down Expand Up @@ -432,7 +432,7 @@ def ImportSurfaceProperties(asset_path: Path):
surface_folder.MakeDir()

surface_collection = KV.CollectionFromFile(asset_path)
vsurf = KV3File(SurfacePropertiesList = [])
vsurf = dict(SurfacePropertiesList = [])

for surface, properties in {**surface_collection}.items():
new_surface = dict(surfacePropertyName = surface)
Expand Down Expand Up @@ -486,7 +486,7 @@ def ImportSurfaceProperties(asset_path: Path):
surface_data["Sounds"][key] = value

if sh.SBOX:
surface_file.write_text(KV3File(data=surface_data).ToString())
keyvalues3.write(dict(data=surface_data), surface_file)
print("+ Saved", surface_file.local)
else:
# Add default base
Expand All @@ -503,7 +503,7 @@ def ImportSurfaceProperties(asset_path: Path):
if sh.SBOX:
return surface_folder
else:
vsurf_file.write_text(vsurf.ToString())
keyvalues3.write(vsurf, vsurf_file)
print("+ Saved", vsurf_file.local)

return vsurf_file, vsurf['SurfacePropertiesList']
Expand Down Expand Up @@ -532,7 +532,7 @@ def after_all_converted(self):
if not (self.manifest_files and self.all_surfaces):
return
vsurf_path = next(iter(self.all_surfaces)).with_stem('surfaceproperties')
vsurf = KV3File(SurfacePropertiesList = [])
vsurf = dict(SurfacePropertiesList = [])
for file in self.manifest_files[::-1]:
file = vsurf_path.parents[1] / 'surfaceproperties' / Path(file).with_suffix('.vsurf').name
for surfaceproperty in self.all_surfaces.get(file, ()):
Expand All @@ -545,7 +545,7 @@ def after_all_converted(self):
continue
vsurf['SurfacePropertiesList'].append(surfaceproperty)

vsurf_path.write_text(vsurf.ToString())
keyvalues3.write(vsurf, vsurf_path)
print("+ Saved", vsurf_path.local)

if __name__ == '__main__':
Expand Down
Loading