Dumping Particles
nosoop a editat această pagină 8 ani în urmă

Particles aren't exactly part of engine / game mod code, but there hasn't been a good way to dump it yet, so I wrote up a script to do just that.

Bash function to dump the particle files from the game package (output can be redirected):

dump_particle_systems() {
	# dump particle system info
	PACKAGE_FILE='/path/to/tf2_misc_dir.vpk'
	script_dir='/path/to/pcfdump.py'
	
	# extract to temporary directory
	temp_dir=$(mktemp -d)
	pushd "${temp_dir}" > /dev/null
		mkdir particles
		vpk x ${PACKAGE_FILE} `vpk l ${PACKAGE_FILE} | grep '\.pcf'` > /dev/null
		
		python3 "${script_dir}"
	popd > /dev/null

	if [[ -d ${temp_dir} ]]; then
		rm -r "${temp_dir}"
	fi
}

Python script to parse all the unique PCF files and output sorted particle system names:

#!/usr/bin/python3

import struct
import pathlib

ignored_suffixes = [ '_high', '_dx80', '_dx90_slow' ]

def unpack(fmt, stream):
	'''
	unpacks values from a stream
	source: https://stackoverflow.com/a/17537253
	'''
	size = struct.calcsize(fmt)
	buf = stream.read(size)
	return struct.unpack(fmt, buf)

def unpack_string(stream, offset = None, encoding = 'utf-8'):
	''' unpacks a variable-length, zero-terminated string from a stream '''
	if offset is not None:
		stream.seek(offset)
	
	return bytes(iter(lambda: ord(stream.read(1)), 0)).decode(encoding)

particle_map = {}

# dumps particle names from particles/*.pcf
for filepath in pathlib.Path('particles').glob('*.pcf'):
	string_dict = []
	particle_list = []
	
	if any(filepath.stem.endswith(suffix) for suffix in ignored_suffixes):
		continue
	
	with open(str(filepath), 'rb') as particle_file:
		header = unpack_string(particle_file)
		
		# string table
		num_strings, *_ = unpack('<H', particle_file)
		for _ in range(0, num_strings):
			string_entry = unpack_string(particle_file)
			string_dict.append(string_entry)
		
		num_elements, *_ = unpack('<I', particle_file)
		for _ in range(0, num_elements):
			# CDmxElement
			index, *_ = unpack('<H', particle_file)
			element_name = unpack_string(particle_file)
			sig = unpack('<16c', particle_file)
			
			if string_dict[index] == 'DmeParticleSystemDefinition':
				particle_list.append(element_name)
	particle_map[filepath.stem] = particle_list

# dump the stuff
for filename, particle_list in sorted(particle_map.items()):
	print(filename)
    print(*('\t' + p for p in sorted(particle_list)), sep = '\n')