void GeneratePlanner(ProblemDefinition definition, string planName, string outputPath, bool includeEnums = false)
        {
            var customCumulativeRewardEstimator = definition.CustomCumulativeRewardEstimator;
            var rewardEstimatorTypeName         = string.IsNullOrEmpty(customCumulativeRewardEstimator) ? "DefaultCumulativeRewardEstimator" : $"global::{customCumulativeRewardEstimator}";

            var defaultCumulativeRewardEstimator = new
            {
                lower = definition.DefaultEstimateLower,
                avg   = definition.DefaultEstimateAverage,
                upper = definition.DefaultEstimateUpper,
            };

            var result = m_CodeRenderer.RenderTemplate(PlannerResources.instance.TemplatePlanExecutor, new
            {
                @namespace                     = $"{TypeHelper.PlansQualifier}.{planName}",
                plan_name                      = definition.Name,
                actions                        = definition.ActionDefinitions,
                traits                         = definition.GetTraitsUsed(),
                reward_estimator               = rewardEstimatorTypeName,
                default_reward_estimate        = defaultCumulativeRewardEstimator,
                terminations                   = definition.StateTerminationDefinitions.Where(t => t != null).Select(t => t.Name),
                include_enums                  = includeEnums,
                state_representation_qualifier = TypeHelper.StateRepresentationQualifier
            });

            SaveToFile(Path.Combine(outputPath, TypeHelper.PlansQualifier, planName, $"{definition.name}Executor.cs"), result);
        }
        void GeneratePlanStateRepresentation(string outputPath, ProblemDefinition problemDefinition)
        {
            var traits = problemDefinition.GetTraitsUsed()
                         .Append(PlannerAssetDatabase.TraitDefinitions.FirstOrDefault(t => t.name == nameof(PlanningAgent)))
                         .Distinct()
                         .Where(t => t != null)
                         .Select(t => new
            {
                name      = t.name,
                relations = t.Properties.Where(p =>
                                               p.Type == typeof(GameObject) || p.Type == typeof(Entity))
                            .Select(p => new { name = p.Name }),
                attributes = t.Properties.Where(p =>
                                                p.Type != typeof(GameObject) && p.Type != typeof(Entity) && GetRuntimePropertyType(p) != null)
                             .Select(p => new
                {
                    field_type = GetRuntimePropertyType(p),
                    field_name = p.Name
                })
            });

            int numTraits           = traits.Count();
            int traitsAlignmentSize = ((numTraits + 3) / 4) * 4;

            var result = m_CodeRenderer.RenderTemplate(PlannerResources.instance.TemplateStateRepresentation, new
            {
                @namespace     = $"{TypeHelper.StateRepresentationQualifier}.{problemDefinition.Name}",
                trait_list     = traits,
                num_traits     = numTraits,
                alignment_size = traitsAlignmentSize
            });

            SaveToFile(Path.Combine(outputPath, TypeHelper.StateRepresentationQualifier, problemDefinition.Name, "PlanStateRepresentation.cs"), result);
        }