Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flags: Do not hardcode one Flag field per class #492

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
11 changes: 8 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ set(LCF_SOURCES
src/lmu_movecommand.cpp
src/lmu_reader.cpp
src/log.h
src/lsd_reader.cpp
src/log_handler.cpp
src/lsd_reader.cpp
src/reader_flags.cpp
src/reader_lcf.cpp
src/reader_struct.h
Expand All @@ -54,6 +54,8 @@ set(LCF_SOURCES
src/saveopt.cpp
src/writer_lcf.cpp
src/writer_xml.cpp
src/generated/fwd_flags_impl.h
src/generated/fwd_flags_instance.h
src/generated/fwd_struct_impl.h
src/generated/ldb_actor.cpp
src/generated/ldb_animation.cpp
Expand Down Expand Up @@ -83,7 +85,7 @@ set(LCF_SOURCES
src/generated/ldb_system.cpp
src/generated/ldb_terms.cpp
src/generated/ldb_terrain.cpp
src/generated/ldb_terrain_flags.h
src/generated/ldb_terrain_special_flags.h
src/generated/ldb_testbattler.cpp
src/generated/ldb_troop.cpp
src/generated/ldb_troopmember.cpp
Expand All @@ -109,10 +111,13 @@ set(LCF_SOURCES
src/generated/lsd_saveeasyrpgwindow.cpp
src/generated/lsd_saveeasyrpgwindow_flags.h
src/generated/lsd_saveeventexecframe.cpp
src/generated/lsd_saveeventexecframe_easyrpg_runtime_flags.h
src/generated/lsd_saveeventexecstate.cpp
src/generated/lsd_saveeventexecstate_easyrpg_runtime_flags.h
src/generated/lsd_saveinventory.cpp
src/generated/lsd_savemapevent.cpp
src/generated/lsd_savemapeventbase.cpp
src/generated/lsd_savemapeventbase_easyrpg_runtime_flags.h
src/generated/lsd_savemapinfo.cpp
src/generated/lsd_savepanorama.cpp
src/generated/lsd_savepartylocation.cpp
Expand Down Expand Up @@ -205,8 +210,8 @@ set(LCF_HEADERS
src/lcf/ldb/reader.h
src/lcf/lmt/reader.h
src/lcf/lmu/reader.h
src/lcf/lsd/reader.h
src/lcf/log_handler.h
src/lcf/lsd/reader.h
src/lcf/reader_lcf.h
src/lcf/reader_util.h
src/lcf/reader_xml.h
Expand Down
9 changes: 7 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ liblcf_la_SOURCES = \
src/lmu_movecommand.cpp \
src/lmu_reader.cpp \
src/log.h \
src/lsd_reader.cpp \
src/log_handler.cpp \
src/lsd_reader.cpp \
src/reader_flags.cpp \
src/reader_lcf.cpp \
src/reader_struct.h \
Expand All @@ -71,6 +71,8 @@ liblcf_la_SOURCES = \
src/saveopt.cpp \
src/writer_lcf.cpp \
src/writer_xml.cpp \
src/generated/fwd_flags_impl.h \
src/generated/fwd_flags_instance.h \
src/generated/fwd_struct_impl.h \
src/generated/ldb_actor.cpp \
src/generated/ldb_animation.cpp \
Expand Down Expand Up @@ -100,7 +102,7 @@ liblcf_la_SOURCES = \
src/generated/ldb_system.cpp \
src/generated/ldb_terms.cpp \
src/generated/ldb_terrain.cpp \
src/generated/ldb_terrain_flags.h \
src/generated/ldb_terrain_special_flags.h \
src/generated/ldb_testbattler.cpp \
src/generated/ldb_troop.cpp \
src/generated/ldb_troopmember.cpp \
Expand All @@ -126,10 +128,13 @@ liblcf_la_SOURCES = \
src/generated/lsd_saveeasyrpgwindow.cpp \
src/generated/lsd_saveeasyrpgwindow_flags.h \
src/generated/lsd_saveeventexecframe.cpp \
src/generated/lsd_saveeventexecframe_easyrpg_runtime_flags.h \
src/generated/lsd_saveeventexecstate.cpp \
src/generated/lsd_saveeventexecstate_easyrpg_runtime_flags.h \
src/generated/lsd_saveinventory.cpp \
src/generated/lsd_savemapevent.cpp \
src/generated/lsd_savemapeventbase.cpp \
src/generated/lsd_savemapeventbase_easyrpg_runtime_flags.h \
src/generated/lsd_savemapinfo.cpp \
src/generated/lsd_savepanorama.cpp \
src/generated/lsd_savepartylocation.cpp \
Expand Down
5 changes: 5 additions & 0 deletions generator/csv/fields_easyrpg.csv
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ SaveEventExecFrame,maniac_event_id,f,Int32,0x0F,0,0,0,Event ID
SaveEventExecFrame,maniac_event_page_id,f,Int32,0x10,0,0,0,Page ID when it is a map event
SaveEventExecFrame,maniac_loop_info_size,f,Int32,0x11,0,0,0,Amount of loop info groups
SaveEventExecFrame,maniac_loop_info,f,Vector<Int32>,0x12,,0,0,"One group of (Current loop count, end loop value) for each identation"
SaveEventExecFrame,easyrpg_runtime_flags,f,EasyRpgRuntime_Flags,0xCC,0,0,0,Runtime changes to the engine config
SaveEventExecState,easyrpg_active,f,Boolean,0xC9,False,0,0,When true state of an event is preserved in easyrpg_string and easyrpg_parameters
SaveEventExecState,easyrpg_string,f,DBString,0xCA,,0,0,Preserved string data of an event
SaveEventExecState,easyrpg_parameters,f,Vector<Int32>,0xCB,,0,0,Preserved int parameter of an event
SaveEventExecState,easyrpg_runtime_flags,f,EasyRpgRuntime_Flags,0xCC,0,0,0,Runtime changes to the engine config
SavePicture,easyrpg_flip,f,Enum<EasyRpgFlip>,0xC8,0,0,1,How to flip the picture
SavePicture,easyrpg_blend_mode,f,Int32,0xC9,0,0,1,Blend mode to use for blit. See Bitmap::BlendMode
SavePicture,easyrpg_type,f,Enum<EasyRpgPictureType>,0xCA,0,0,1,Type of this picture
Expand All @@ -31,6 +33,9 @@ SaveEasyRpgText,letter_spacing,f,Int32,0x06,0,0,0,Additional spacing between let
SaveEasyRpgText,line_spacing,f,Int32,0x07,4,0,0,Additional spacing between lines
SaveEasyRpgText,flags,f,SaveEasyRpgText_Flags,0x08,3,0,0,Various text settings
SaveMapEventBase,easyrpg_move_failure_count,f,Int32,0xC9,0,0,0,Tracks how often the current move operation in a move route failed
SaveMapEventBase,easyrpg_clone_map_id,f,UInt32,0xCA,0,0,0,The original map id of a cloned event
SaveMapEventBase,easyrpg_clone_event_id,f,UInt32,0xCB,0,0,0,The original event id of a cloned event
SaveMapEventBase,easyrpg_runtime_flags,f,EasyRpgRuntime_Flags,0xCC,0,0,0,Runtime changes to the engine config
SavePartyLocation,maniac_horizontal_pan_speed,f,Double,0x8D,0,0,0,horizontal speed in the scrolls of the screen
SavePartyLocation,maniac_vertical_pan_speed,f,Double,0x8E,0,0,0,vertical speed in the scrolls of the screen
SaveSystem,maniac_strings,f,Vector<DBString>,0x24,,0,0,rpg::Strings
Expand Down
20 changes: 20 additions & 0 deletions generator/csv/flags_easyrpg.csv
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,23 @@ SaveEasyRpgText,draw_gradient,0
SaveEasyRpgText,draw_shadow,0
SaveEasyRpgText,bold,0
SaveEasyRpgText,italic,0
EasyRpgRuntime,conf_override_active,0
EasyRpgRuntime,reserved_1,0
EasyRpgRuntime,reserved_2,0
EasyRpgRuntime,reserved_3,0
EasyRpgRuntime,patch_destiny_on,0
EasyRpgRuntime,patch_destiny_off,0
EasyRpgRuntime,patch_dynrpg_on,0
EasyRpgRuntime,patch_dynrpg_off,0
EasyRpgRuntime,patch_maniac_on,0
EasyRpgRuntime,patch_maniac_of,0
EasyRpgRuntime,patch_common_this_event_on,0
EasyRpgRuntime,patch_common_this_event_off,0
EasyRpgRuntime,patch_unlock_pics_on,0
EasyRpgRuntime,patch_unlock_pics_off,0
EasyRpgRuntime,patch_keypatch_on,0
EasyRpgRuntime,patch_keypatch_off,0
EasyRpgRuntime,patch_rpg2k3_cmds_on,0
EasyRpgRuntime,patch_rpg2k3_cmds_off,0
EasyRpgRuntime,use_rpg2k_battle_system_on,0
EasyRpgRuntime,use_rpg2k_battle_system_off,0
49 changes: 37 additions & 12 deletions generator/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def cpp_type(ty, prefix=True):

m = re.match(r'(.*)_Flags$', ty)
if m:
ty = m.expand(r'\1::Flags')
ty = m.expand(r'\1::\1_Flags')
if prefix:
ty = 'rpg::' + ty
return ty
Expand Down Expand Up @@ -133,9 +133,6 @@ def pod_default(field):

return " = " + str(dfl)

def num_flags(flag):
return len(flag)

def flag_size(flag):
return (len(flag) + 7) // 8

Expand All @@ -149,6 +146,9 @@ def flag_set(field, bit):

return str(res).lower()

def flags_for(typ):
return flags[typ[:-6]]

def filter_structs_without_codes(structs):
for struct in structs:
if all(f.code for f in sfields[struct.name]):
Expand Down Expand Up @@ -392,11 +392,14 @@ def type_is_array_of_struct(ty):
def is_monotonic_from_0(enum):
expected = 0
for (val, idx) in enum:
if int(idx) != expected:
if int(idx, 0) != expected:
return False
expected += 1
return True

def is_scoped_enum(enum_name):
return enum_name == "Code"

def openToRender(path):
subdir = os.path.dirname(path)
if not os.path.exists(subdir):
Expand Down Expand Up @@ -426,6 +429,8 @@ def generate():
structs=sorted([x.name for x in structs_flat])
))

flag_fields = []

for filetype, structlist in structs.items():
for struct in structlist:
filename = struct.name.lower()
Expand All @@ -442,8 +447,8 @@ def generate():
type=filetype
))


filepath = os.path.join(tmp_dir, 'lcf', 'rpg', '%s.h' % filename)
struct_header = os.path.join('lcf', 'rpg', '%s.h' % filename)
filepath = os.path.join(tmp_dir, struct_header)
with openToRender(filepath) as f:
f.write(rpg_header_tmpl.render(
struct_name=struct.name,
Expand All @@ -459,14 +464,31 @@ def generate():
filename=filename
))

if struct.name in flags:
filepath = os.path.join(tmp_dir, '%s_%s_flags.h' % (filetype, filename))
struct_flag_fields = [s for s in sfields[struct.name] if s.type.endswith("_Flags")]
for flag_field in struct_flag_fields:
header_file = '%s_%s_%s.h' % (filetype, filename, flag_field.name)
filepath = os.path.join(tmp_dir, header_file)
flag_fields.append(dict(struct_name=struct.name, struct_header=struct_header, field_name=flag_field.type, flag_header=header_file))
with openToRender(filepath) as f:
f.write(flags_tmpl.render(
struct_name=struct.name,
type=filetype
type=filetype,
flag_name=flag_field.type,
flag_item=flags[flag_field.type[:-6]]
))

filepath = os.path.join(tmp_dir, 'fwd_flags_impl.h')
with openToRender(filepath) as f:
f.write(flags_fwd_tmpl.render(
flags=flag_fields
))

filepath = os.path.join(tmp_dir, 'fwd_flags_instance.h')
with openToRender(filepath) as f:
f.write(flags_instance_tmpl.render(
flags=flag_fields
))

for dirname, subdirlist, filelist in os.walk(tmp_dir, topdown=False):
subdir = os.path.relpath(dirname, tmp_dir)

Expand All @@ -486,7 +508,7 @@ def main(argv):
os.mkdir(dest_dir)

global structs, structs_flat, sfields, enums, flags, functions, constants, headers
global chunk_tmpl, lcf_struct_tmpl, rpg_header_tmpl, rpg_source_tmpl, flags_tmpl, enums_tmpl, fwd_tmpl, fwd_struct_tmpl
global chunk_tmpl, lcf_struct_tmpl, rpg_header_tmpl, rpg_source_tmpl, flags_tmpl, flags_fwd_tmpl, flags_instance_tmpl, enums_tmpl, fwd_tmpl, fwd_struct_tmpl

structs, structs_flat = get_structs('structs.csv', 'structs_easyrpg.csv')
sfields = get_fields('fields.csv', 'fields_easyrpg.csv')
Expand All @@ -504,10 +526,11 @@ def main(argv):
env.filters["field_is_used"] = filter_unused_fields
env.filters["field_is_written"] = filter_unwritten_fields
env.filters["field_is_not_size"] = filter_size_fields
env.filters["num_flags"] = num_flags
env.filters["flag_size"] = flag_size
env.filters["flag_set"] = flag_set
env.filters["flags_for"] = flags_for
env.tests['monotonic_from_0'] = is_monotonic_from_0
env.tests['scoped_enum'] = is_scoped_enum
env.tests['is_db_string'] = type_is_db_string
env.tests['is_array'] = type_is_array
env.tests['is_array_of_struct'] = type_is_array_of_struct
Expand All @@ -529,6 +552,8 @@ def main(argv):
rpg_header_tmpl = env.get_template('rpg_header.tmpl', globals=globals)
rpg_source_tmpl = env.get_template('rpg_source.tmpl', globals=globals)
flags_tmpl = env.get_template('flag_reader.tmpl', globals=globals)
flags_fwd_tmpl = env.get_template('flag_fwd.tmpl', globals=globals)
flags_instance_tmpl = env.get_template('flag_instance.tmpl', globals=globals)
fwd_tmpl = env.get_template('fwd.tmpl', globals=globals)
fwd_struct_tmpl = env.get_template('fwd_struct.tmpl', globals=globals)

Expand Down
3 changes: 3 additions & 0 deletions generator/templates/chunks.tmpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{#
This template is used for the chunks.h files
-#}
{% include "copyright.tmpl" %}
#ifndef LCF_{{ type|upper }}_CHUNKS_H
#define LCF_{{ type|upper }}_CHUNKS_H
Expand Down
13 changes: 13 additions & 0 deletions generator/templates/flag_fwd.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{#
This template generates "fwd_flags_impl.h" which is included by "reader_struct.h"
and is used to declare the templates used by "Flags"
-#}
{% include "copyright.tmpl" %}

{%- for flag in flags %}
#include "{{ flag.struct_header }}"
{%- endfor %}

{%- for flag in flags %}
template <> struct lcf::TypeCategory<lcf::rpg::{{ flag.struct_name }}::{{ flag.field_name }}> { static const Category::Index value = Category::Flags; };
{%- endfor %}
15 changes: 15 additions & 0 deletions generator/templates/flag_instance.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{#
This template generates "fwd_flags_instance.h" which is included by "reader_flags.cpp"
to instantiate the templates used by "Flags"
-#}
{% include "copyright.tmpl" %}

{%- for flag in flags %}
#include "{{ flag.flag_header }}"
{%- endfor %}

namespace lcf {
{%- for flag in flags %}
template class Flags<rpg::{{ flag.struct_name }}::{{ flag.field_name }}>;
{%- endfor %}
}
14 changes: 9 additions & 5 deletions generator/templates/flag_reader.tmpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{#
This template generates "*_flags.h" which is used to define the classes used
by flags. Flags are classes that encode bitfields using bools.
-#}
{% include "copyright.tmpl" %}
/*
* Headers
Expand All @@ -11,18 +15,18 @@ namespace lcf {
// Read {{ struct_name }}.

template <>
char const* const Flags<rpg::{{ struct_name }}::Flags>::name = "{{ struct_name }}_Flags";
char const* const Flags<rpg::{{ struct_name }}::{{ flag_name }}>::name = "{{ struct_name }}_{{ flag_name }}";

template <>
decltype(Flags<rpg::{{ struct_name }}::Flags>::flag_names) Flags<rpg::{{ struct_name }}::Flags>::flag_names = {
{%- for flag in flags[struct_name] %}
decltype(Flags<rpg::{{ struct_name }}::{{ flag_name }}>::flag_names) Flags<rpg::{{ struct_name }}::{{ flag_name }}>::flag_names = {
{%- for flag in flag_item %}
"{{ flag.field }}"{%- if not loop.last %}, {%- endif %}
{%- endfor %}
};

template <>
decltype(Flags<rpg::{{ struct_name }}::Flags>::flags_is2k3) Flags<rpg::{{ struct_name }}::Flags>::flags_is2k3 = {
{%- for flag in flags[struct_name] %}
decltype(Flags<rpg::{{ struct_name }}::{{ flag_name }}>::flags_is2k3) Flags<rpg::{{ struct_name }}::{{ flag_name }}>::flags_is2k3 = {
{%- for flag in flag_item %}
{{ flag.is2k3 }}{%- if not loop.last %}, {%- endif %}
{%- endfor %}
};
Expand Down
4 changes: 4 additions & 0 deletions generator/templates/fwd.tmpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{#
This template generates "fwd.h" which is installed as part of the library
and is used to forward declare all classes generated by liblcf.
-#}
{% include "copyright.tmpl" %}
#ifndef LCF_RPG_FWD_H
#define LCF_RPG_FWD_H
Expand Down
4 changes: 4 additions & 0 deletions generator/templates/fwd_struct.tmpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{#
This template generates "fwd_struct_impl.h" which is included by "reader_struct_impl.h"
and is used to forward declare Struct::fields[] to reduce compile times.
-#}
{% include "copyright.tmpl" %}
// MSVC incorrectly treats these declarations as definitions and fails.
#ifndef _MSC_VER
Expand Down
8 changes: 8 additions & 0 deletions generator/templates/reader.tmpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{#
This template generates the source files for the metadata of the chunk readers.
Files generated are "ldb/lmu/lsd/lmt_*.cpp"
-#}
{% include "copyright.tmpl" %}
// Headers
#include "lcf/{{ type }}/reader.h"
Expand All @@ -15,7 +19,11 @@ char const* const Struct<rpg::{{ LCF_CURRENT_STRUCT }}>::name = "{{ LCF_CURRENT_

{%- for field in fields[struct_base]|field_is_written|list + fields[struct_name]|field_is_written|list %}
{%- if field|lcf_type in ["Typed", "DatabaseVersion"] %}
{%- if field.type.endswith("_Flags") %}
static {{ field|lcf_type }}Field<rpg::{{ LCF_CURRENT_STRUCT }}, rpg::{{ LCF_CURRENT_STRUCT }}::{{ field.type }}> static_{{ field.name }}(
{%- else %}
static {{ field|lcf_type }}Field<rpg::{{ LCF_CURRENT_STRUCT }}, {{ field.type|cpp_type }}> static_{{ field.name }}(
{%- endif %}
&rpg::{{ LCF_CURRENT_STRUCT }}::{{ field.name }},
{{ LCF_CHUNK_SUFFIX }}::Chunk{{ LCF_CURRENT_STRUCT }}::{{ field.name }},
"{{ field.name }}",
Expand Down
Loading