edited March 2021 in ORK Scripting
If you've delved into using ORK via its API, you will no doubt have encountered situations where you can access ORK's data (Status Values, Abilities, etc) through a function but you need to provide its id/index from the list it is contained in.

For example, if you want to get the current HP of a combatant (using the demo/tutorial project file), you would use:

Combatant.Status[1].GetValue()

But it would be much nicer to be able to use:

Combatant.Status[ORKStatusValue.HP].GetValue()


I've been thinking about building a constant/emun generator for ORK but I've kept putting it off. However, the open source Unity Toolbag has a script for generating Unity constants (tags, layers, etc) and I thought that I might be able to re-use its structure to build this little tool that I'd been thinking about. Well, it works!

Here is the script file. I only included four of the data lists, but they would all follow the same pattern.


#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
using System.IO;
using System.Linq;
using System.Text;
using ORKFramework;
using UnityEditor;
using ORKFramework.Editor;

namespace MyGame
{
public static class ORKConstantsGenerator
{
[MenuItem("Edit/Generate ORKConstants.cs")]
public static void Generate()
{
// Try to find an existing file in the project called "ORKConstants.cs"
string filePath = string.Empty;
foreach (var file in Directory.GetFiles(Application.dataPath, "*.cs", SearchOption.AllDirectories)) {
if (Path.GetFileNameWithoutExtension(file) == "ORKConstants") {
filePath = file;
break;
}
}

// If no such file exists already, use the save panel to get a folder in which the file will be placed.
if (string.IsNullOrEmpty(filePath)) {
string directory = EditorUtility.OpenFolderPanel("Choose location for ORKConstants.cs", Application.dataPath, "");

// Canceled choose? Do nothing.
if (string.IsNullOrEmpty(directory)) {
return;
}

filePath = Path.Combine(directory, "ORKConstants.cs");
}


// Ensure that ORK is instantiated
if (!ORK.Instantiated)
{
ORK.Initialize(ORKAssetHelper.LoadORKProject());
}

Debug.Log("Generating ORKConstants.cs...");
// Write out our file
using (var writer = new StreamWriter(filePath)) {
writer.WriteLine("// This file is auto-generated. Modifications are not saved.");
writer.WriteLine();
writer.WriteLine("namespace MyGame");
writer.WriteLine("{");

// Write out the tags

writer.WriteLine(BuildClass("CombatantStatusValue", ORK.StatusValues.GetNames(false).ToList()));
writer.WriteLine(BuildClass("CombatantStatusEffect", ORK.StatusEffects.GetNames(false).ToList()));
writer.WriteLine(BuildClass("CombatantAbility", ORK.Abilities.GetNames(false).ToList()));
writer.WriteLine(BuildClass("CombatantEquipmentPart", ORK.EquipmentParts.GetNames(false).ToList()));

// End of namespace ORKConstants
writer.WriteLine("}");
writer.WriteLine();

}

Debug.Log("Completed");

// Refresh
AssetDatabase.Refresh();
}


private static string BuildClass(string className, List<string> constantNames)
{
StringBuilder sb = new StringBuilder(" public static class ");
sb.AppendLine(className);
sb.AppendLine(" {");

try
{
for (int i = 0; i < constantNames.Count; i++)
{
sb.AppendLine(string.Format(" public const int {0} = {1};", MakeSafeForCode(constantNames[i].ToUpper()),
i));
}
}
catch (Exception ex)
{
Debug.LogError(string.Format("Could not generate class {0}: {1}", className, ex.Message));
}
finally
{
sb.AppendLine(" }");
sb.AppendLine();
}


return sb.ToString();
}

private static string MakeSafeForCode(string str)
{
str = Regex.Replace(str, "[^a-zA-Z0-9_]", "_", RegexOptions.Compiled);
if (char.IsDigit(str[0])) {
str = "_" + str;
}
return str;
}
}
}
#endif //UNITY_EDITOR


Don't forget to regenerate your ORKConstants.cs file after you add or remove items from your ORK lists, or if you re-order your lists!

Post edited by Keldryn on
  • edited July 2016
    Here's a sample of the file it generates:

    // This file is auto-generated. Modifications are not saved.

    namespace MyGame
    {
    public static class CombatantStatusValue
    {
    public const int MAX_HEALTH = 0;
    public const int HEALTH = 1;
    public const int MAX_STAMINA = 2;
    public const int STAMINA = 3;
    public const int MAX_MANA = 4;
    public const int MANA = 5;
    public const int ATK = 6;
    public const int DEF = 7;
    public const int MATK = 8;
    public const int MDEF = 9;
    public const int AGI = 10;
    public const int DEX = 11;
    public const int LUK = 12;
    public const int EXP = 13;
    }


    public static class CombatantStatusEffect
    {
    public const int POISON = 0;
    public const int BLIND = 1;
    public const int BLOCK = 2;
    public const int ENCHANT_FIRE = 3;
    public const int STRENGTHEN = 4;
    public const int WEAKEN = 5;
    public const int SPEED_UP = 6;
    public const int SPEED_DOWN = 7;
    }


    public static class CombatantAbility
    {
    public const int TPC_MELEE_CALCULATION = 0;
    public const int AI_ATTACK = 1;
    public const int PLAYER_ATTACK = 2;
    public const int MUG_ATTACK = 3;
    public const int FIRE = 4;
    public const int WATER = 5;
    public const int POISON = 6;
    public const int SMALL_HEAL = 7;
    public const int BOOST = 8;
    public const int LESSEN = 9;
    public const int HEALTH_BONUS = 10;
    public const int IMMUNE = 11;
    public const int TEST_ATTACK = 12;
    }


    public static class CombatantEquipmentPart
    {
    public const int HELMET = 0;
    public const int RIGHT_HAND = 1;
    public const int LEFT_HAND = 2;
    public const int ARMOR = 3;
    public const int ACCESSORY = 4;
    }
    }




    EDIT: Removed the Names[ ] array from the previous version, as it didn't really offer anything over just calling GetName() on the ORK array items. Also switched it to use cool old-school uppercase for the constant names, despite the fact that it's not the Approved .NET way. Take out the .ToUpper() call if you don't like the uppercase names. :-)
    Post edited by Keldryn on
  • edited July 2016
    Nice work, pinned it :)
    Post edited by gamingislove on
    Please consider rating/reviewing my products on the Asset Store (hopefully positively), as that helps tremendously with getting found.
    If you're enjoying my products, updates and support, please consider supporting me on patreon.com!
  • You are a gentleman and a scholar, sir. I have so many hacky comments in my code to the effect of "[1] = HP, change if updated" that'll be lovely to delete.
    My little chunk of the internet: http://artemic.com
  • Updated the source code listing. @hellwalker reminded me that adding this code before any of the ORK calls eliminates the need to have the editor open when you generate the constants file:


    // Ensure that ORK is instantiated
    if (!ORK.Instantiated)
    {
    ORK.Initialize(ORKAssetHelper.LoadORKProject());
    }
  • This is awesome. I was making all of my enums by hand.

    Does anyone have the full list available? If so, can you post to pastebin or somewhere?

    Thanks
  • edited January 2020
    Also here's my updated version that uses enums rather than static class consts and optionally using reflection, so there's less typing:

    Replace "// Write out the tags" section with:


    // Write out the tags
    // GUI
    WriteEnum(writer, ORK.GUIBoxes);

    // combatant
    WriteEnum(writer, ORK.StatusValues, "CombatantStatusValue");
    WriteEnum(writer, ORK.StatusEffects, "CombatantStatusEffect");
    WriteEnum(writer, ORK.Abilities, "CombatantAbility");
    WriteEnum(writer, ORK.EquipmentParts, "CombatantEquipmentPart");


    Add this private method

    private static void WriteEnum(StreamWriter writer, BaseSettings values, string enumTypeName = "")
    {
    string name = enumTypeName;
    if (string.IsNullOrEmpty(enumTypeName))
    {
    name = values.GetType().Name;
    name = name.Replace("Settings", string.Empty);
    name = name.Trim();
    }
    writer.WriteLine(@" // Derived from " + values.GetType().FullName);
    writer.WriteLine(BuildEnum(name, values.GetNames(false).ToList()));
    }


    Change the Build Class to

    private static string BuildEnum(string enumTypeName, List<string> enumValues)
    {
    StringBuilder sb = new StringBuilder(" public enum ");
    sb.AppendLine(enumTypeName);
    sb.AppendLine(" {");

    try
    {
    for (int i = 0; i < enumValues.Count; i++)
    {
    sb.AppendLine(string.Format(" {0} = {1},", MakeSafeForCode(enumValues[i].ToUpper()), i));
    }
    }
    catch (Exception ex)
    {
    Debug.LogError(string.Format("Could not generate class {0}: {1}", enumTypeName, ex.Message));
    }
    finally
    {
    sb.AppendLine(" }");
    sb.AppendLine();
    }

    return sb.ToString();
    }


    This produces:

    // Derived from ORKFramework.GUIBoxesSettings
    public enum GUIBoxes
    {
    MainMenu = 0,
    BottomDialogue = 1,
    AreaNotification = 2,
    }


    // Derived from ORKFramework.StatusValuesSettings
    public enum CombatantStatusValue
    {
    MaxHealth = 0,
    Health = 1,
    MaxStamina = 2,
    }


    This allows you to use enums (personal preference), and either use the actual name (such as "StatusValues" or provide your own name such as "CombatantStatusValues" as the enum type name.


    I also changed it from upper snake case to Pascal case using below in the MakeSafeForCode method

    str = cultureInfo.TextInfo.ToTitleCase(str.ToLower()).Replace("_", string.Empty);


    If anyone wants the full class code, just let me know and I'll post its entirety to pastebin.
    Post edited by Shurijo on
  • Shurijo said: If anyone wants the full class code, just let me know and I'll post its entirety to pastebin.
    Yes please :)
  • edited September 2020
    Shurijo said: If anyone wants the full class code, just let me know and I'll post its entirety to pastebin.
    Seconding this as well, as I'd get a lot of use out of it. This is a fantastic resource. Thanks to everyone who has worked on this!
    Post edited by Juupo on
  • Shurijo said: If anyone wants the full class code, just let me know and I'll post its entirety to pastebin.
    This would be a really useful addition to my game. How do I access the script on pastebin?

    Thanks to both Keldryn and Shurijo!

  • Shurijo said: If anyone wants the full class code, just let me know and I'll post its entirety to pastebin.
    Where can I get this script?
  • I cant get the generator to make the Combatant list
  • Hi, I just wanted to check back in on this thread and ask if anything changed in the ORK API that would cause this script to generate the following error:

    "Assets\Scripts\ORKConstantsGenerator.cs(9,20): error CS0234: The type or namespace name 'Editor' does not exist in the namespace 'ORKFramework' (are you missing an assembly reference?)"

    @Keldryn I copied the ORKConstantsGenerator script into a new .cs file and this and only this error popped up in my console. But maybe this is a better question for GiL? I'm not sure.

    I'm using Unity 2019.4.22(LTS) and using Visual Studio Community 2017 as my IDE if that helps. I'd love to hear ideas on what I can do to possibly fix this and use these constants.

    Thanks.
  • The whole first class to generate the constants should be put into a folder named Editor, since it's an editor script and uses functionality that's not available during play.
    Please consider rating/reviewing my products on the Asset Store (hopefully positively), as that helps tremendously with getting found.
    If you're enjoying my products, updates and support, please consider supporting me on patreon.com!
  • @gamingislove I appreciate that. Worked like a charm and taught me something new!
Sign In or Register to comment.