Instantly share code, notes, and snippets.
Last active
July 5, 2024 02:24
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save GuyPaddock/ea3f439191b9910a47f46e9dc20a576b to your computer and use it in GitHub Desktop.
Python Script for Converting Gameplay Tags from INI to Native CPP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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