Skip to content

Instantly share code, notes, and snippets.

@GuyPaddock
Last active July 5, 2024 02:24
Show Gist options
  • Save GuyPaddock/ea3f439191b9910a47f46e9dc20a576b to your computer and use it in GitHub Desktop.
Save GuyPaddock/ea3f439191b9910a47f46e9dc20a576b to your computer and use it in GitHub Desktop.
Python Script for Converting Gameplay Tags from INI to Native CPP
#!/usr/bin/env python3
##
# Copyright 2024, Guy Elsmore-Paddock. All Rights Reserved.
#
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
# distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
#
# This script can be used to convert Unreal Engine gameplay tags in INI format into native tags. See the following
# article for an overview of native gameplay tags:
# https://unrealdirective.com/tips/declare-define-native-gameplay-tags
#
#
# Consider the following gameplay tag INI file (`sample.ini`):
# ```
# ; Some comment
# [/Script/GameplayTags.GameplayTagsList]
# GameplayTagList=(Tag="Sample.Tag",DevComment="Comment about this tag.")
#
# ; Another comment
# GameplayTagList=(Tag="Sample.Tag2")
# ```
#
# Now, consider invoking this script using the following command:
# ```
# python3 convert_tags.py sample.ini \
# --tag-prefix=TagExample \
# --declaration-linkage=SAMPLE_PROJECT_API \
# --comment-prefix='[Prefix] ' \
# --comment-suffix=' [Suffix]'
# ```
#
# The generated header would be:
# ```
# #pragma once
#
# #include <NativeGameplayTags.h>
#
# // Some comment
# SAMPLE_PROJECT_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TagExampleSampleTag)
# // Another comment
# SAMPLE_PROJECT_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TagExampleSampleTag2)
# ```
# And the generated C++ file would be:
# ```
# #include "sample.h"
#
# // Some comment
# UE_DEFINE_GAMEPLAY_TAG_COMMENT(
# TagExampleSampleTag,
# "Sample.Tag",
# "[Prefix] Comment about this tag. [Suffix]"
# )
#
# // Another comment
# UE_DEFINE_GAMEPLAY_TAG(
# TagExampleSampleTag2,
# "Sample.Tag2"
# )
# ```
#
# Implementation by ChatGPT :)
#
import os
import sys
import argparse
def process_ini_file(input_file, tag_prefix, declaration_linkage, comment_prefix="", comment_suffix=""):
base_name = os.path.splitext(os.path.basename(input_file))[0]
header_file = f'{base_name}.h'
cpp_file = f'{base_name}.cpp'
with open(input_file, 'rb') as f:
content = f.read()
# Remove BOM if present
if content.startswith(b'\xef\xbb\xbf'):
content = content[3:]
lines = content.decode('utf-8').splitlines()
header_content = []
cpp_content = []
for line in lines:
line = line.strip()
if line.startswith(';'):
comment_line = '// ' + line[1:].strip()
header_content.append(comment_line)
cpp_content.append(comment_line)
elif line.startswith('['):
# Ignore section headers
continue
elif line.startswith('GameplayTagList'):
tag_name = line.split('Tag="')[1].split('"')[0]
if 'DevComment="' in line:
comment = line.split('DevComment="')[1].split('"')[0]
tag_identifier = tag_prefix + tag_name.replace('.', '')
full_comment = f'{comment_prefix}{comment}{comment_suffix}'
if declaration_linkage:
header_content.append(f'{declaration_linkage} UE_DECLARE_GAMEPLAY_TAG_EXTERN({tag_identifier})')
else:
header_content.append(f'UE_DECLARE_GAMEPLAY_TAG_EXTERN({tag_identifier})')
cpp_content.append(f'UE_DEFINE_GAMEPLAY_TAG_COMMENT(')
cpp_content.append(f'\t{tag_identifier},')
cpp_content.append(f'\t"{tag_name}",')
cpp_content.append(f'\t"{full_comment}"')
cpp_content.append(f')\n')
else:
tag_identifier = tag_prefix + tag_name.replace('.', '')
if declaration_linkage:
header_content.append(f'{declaration_linkage} UE_DECLARE_GAMEPLAY_TAG_EXTERN({tag_identifier})')
else:
header_content.append(f'UE_DECLARE_GAMEPLAY_TAG_EXTERN({tag_identifier})')
cpp_content.append(f'UE_DEFINE_GAMEPLAY_TAG(')
cpp_content.append(f'\t{tag_identifier},')
cpp_content.append(f'\t"{tag_name}"')
cpp_content.append(f')\n')
else:
continue
with open(header_file, 'w') as f:
f.write('#pragma once\n')
f.write('\n')
f.write('#include <NativeGameplayTags.h>\n')
f.write('\n')
f.write('\n'.join(header_content))
f.write('\n')
with open(cpp_file, 'w') as f:
f.write(f'#include "{header_file}"\n')
f.write('\n')
f.write('\n'.join(cpp_content))
f.write('\n')
print(f'Generated header file: {header_file}')
print(f'Generated CPP file: {cpp_file}')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate header and cpp files from INI file.")
parser.add_argument("input_file", help="The input INI file.")
parser.add_argument("--tag-prefix", help="Prefix for the tag identifiers.", default="Tag")
parser.add_argument("--declaration-linkage", help="String for the declaration linkage.", default="")
parser.add_argument("--comment-prefix", help="String to prepend to generated tag dev comments.", default="")
parser.add_argument("--comment-suffix", help="String to append to generated tag dev comments.", default="")
args = parser.parse_args()
process_ini_file(args.input_file, args.tag_prefix, args.declaration_linkage, args.comment_prefix, args.comment_suffix)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment