Program Listing for File script_globals.cpp

Return to documentation for file (blam\components\haloscript\script_globals.cpp)

#include "haloscript.h"

#include <regex>
#include <fstream>

#include "components/core/utils/converters/converters.h"
#include "components/core/utils/io/io.h"
#include "components/core/config/config.h"
#include "components/core/logger/logger.h"
#include "components/3rdparty/rapidxml/rapidxml.hpp"

using namespace BlamScript::Globals;

std::map<std::string, ScriptGlobal> globals;

std::map<std::string, ScriptGlobal>* BlamScript::Globals::GetGlobalsList()
{
    return &globals;
}

bool BlamScript::Globals::GlobalExists(std::string id)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->first == id)
        {
            return true;
        }
    }

    return false;
}

std::string BlamScript::Globals::GetGvarTypeLabel(GvarType type)
{
    switch (type)
    {
        case GvarType::Boolean:
            return "boolean";
        case GvarType::Int:
            return "int";
        case GvarType::Short:
            return "short";
        case GvarType::Long:
            return "long";
        case GvarType::String:
            return "string";
        case GvarType::Object:
            return "object";
        case GvarType::Float:
            return "float";
        default:
            return "unknown";
    }
}

void BlamScript::Globals::RegisterGvar(ScriptGlobal var)
{
    switch (var.type)
    {
        case GvarType::Boolean:
        {
            var.boolean_value = Blam::Converters::StringToBool(var.value_raw);
            break;
        }
        case GvarType::Short:
        {
            bool contains_letter = std::regex_match(var.value_raw, std::regex("[^0-9]"));

            if (!contains_letter)
            {
                long value = bstoi(var.value_raw);

                if (value > 32767 || value < -32768)
                {
                    Blam::Logger::LogEvent("### ERROR tried to register short gvar " + var.name + " with invalid value " + var.value_raw, WSV_ERROR);
                }
                else
                {
                    var.short_value = (short)value;
                }
            }

            break;
        }
        case GvarType::Long:
        {
            bool contains_letter = std::regex_match(var.value_raw, std::regex("[^0-9]"));

            if (!contains_letter)
            {
                long value = bstoi(var.value_raw);

                if (value > 2147483647/* || value < -2147483648*/)
                {
                    Blam::Logger::LogEvent("### ERROR tried to register long gvar " + var.name + " with invalid value " + var.value_raw, WSV_ERROR);
                }
                else
                {
                    var.long_value = (long)value;
                }
            }

            break;
        }
        case GvarType::Int:
        {
            bool contains_letter = std::regex_match(var.value_raw, std::regex("[^0-9]"));

            if (!contains_letter)
            {
                long value = bstoi(var.value_raw);

                if (value > 2147483647/* || value < -2147483648*/)
                {
                    Blam::Logger::LogEvent("### ERROR tried to register int gvar " + var.name + " with invalid value " + var.value_raw, WSV_ERROR);
                }
                else
                {
                    var.int_value = (int)value;
                }
            }

            break;
        }
        case GvarType::Float:
        {
            bool contains_letter = std::regex_match(var.value_raw, std::regex("[^0-9]"));

            if (!contains_letter)
            {
                float value = bstof(var.value_raw);

                var.float_value = value;
            }

            break;
        }
        break;
    }

    globals.insert(std::pair<std::string, ScriptGlobal>(var.name, var));
}

void BlamScript::Globals::RegisterGvar(std::string name, std::string value_raw, GvarType type)
{
    ScriptGlobal var;

    var.name = name;
    var.value_raw = value_raw;
    var.type = type;

    globals.insert(std::pair<std::string, ScriptGlobal>(name, var));
}

void BlamScript::Globals::RegisterGvar(std::string name, std::string value_raw, GvarType type, std::string info)
{
    ScriptGlobal var;

    var.name = name;
    var.value_raw = value_raw;
    var.type = type;
    var.info = info;

    globals.insert(std::pair<std::string, ScriptGlobal>(name, var));
}

ScriptGlobal* BlamScript::Globals::GetGlobal(std::string name)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->first == name)
        {
            return &i->second;
        }
    }

    return nullptr;
}

bool BlamScript::Globals::LoadGlobalsFromFile()
{
    using namespace rapidxml;

    std::string file_path = Blam::Config::GetConfig()->GetString("game_data_root") + GVARS_FILE;

    if (Blam::Utils::IO::file_exists(file_path))
    {
        xml_document<> font_xml_file;

        //read file into vector buffer
        std::ifstream font_file(file_path);
        std::vector<char> buffer((std::istreambuf_iterator<char>(font_file)), std::istreambuf_iterator<char>());
        buffer.push_back('\0');

        //load document
        font_xml_file.parse<0>(&buffer[0]);

        //get root node
        xml_node<>* root_node = font_xml_file.first_node("globals");

        for (xml_node<>* global_node = root_node->first_node("global"); global_node; global_node = global_node->next_sibling())
        {
            xml_attribute<char>* id_attribute = global_node->first_attribute("id");
            xml_attribute<char>* type_attribute = global_node->first_attribute("type");
            xml_attribute<char>* info_attribute = global_node->first_attribute("info");
            xml_attribute<char>* protected_attribute = global_node->first_attribute("protected");

            std::string value = global_node->value();
            std::string id = "";
            std::string info = "";
            GvarType type;
            bool _protected = false;

            bool valid_global = true;

            // get id attribute
            if (id_attribute)
            {
                id = id_attribute->value();
            }
            else
            {
                Blam::Logger::LogEvent("### ERROR global variable '" + id + "' does not contain an id attribute, global will NOT be loaded!", WSV_ERROR);
                valid_global = false;
            }

            // get type attribute
            if (type_attribute)
            {
                if (Blam::Utils::String::to_lower(type_attribute->value()) == "string")
                {
                    type = GvarType::String;
                }
                else if (Blam::Utils::String::to_lower(type_attribute->value()) == "short")
                {
                    type = GvarType::Short;
                }
                else if (Blam::Utils::String::to_lower(type_attribute->value()) == "long")
                {
                    type = GvarType::Long;
                }
                else if (Blam::Utils::String::to_lower(type_attribute->value()) == "boolean")
                {
                    type = GvarType::Boolean;
                }
                else if (Blam::Utils::String::to_lower(type_attribute->value()) == "int")
                {
                    type = GvarType::Int;
                }
                else if (Blam::Utils::String::to_lower(type_attribute->value()) == "float")
                {
                    type = GvarType::Float;
                }
                else
                {
                    Blam::Logger::LogEvent("### WARNING global variable '" + id + "' has invalid type '" + Blam::Utils::String::to_lower(type_attribute->value()) + "', setting to string. this may have unexpected consequences", WSV_WARNING);
                    type = GvarType::String;
                }
            }
            else
            {
                Blam::Logger::LogEvent("### ERROR global variable '" + id + "' does not contain a type attribute, setting to string. this may have unexpected consequences", WSV_ERROR);
                type = GvarType::String;
            }

            // get info attribute
            if (info_attribute)
            {
                info = info_attribute->value();
            }
            else
            {
                Blam::Logger::LogEvent("global variable '" + id + "' does not contain an info attribute. consider providing one");
            }

            // get protected attribute
            if (protected_attribute)
            {
                _protected = Blam::Converters::StringToBool(protected_attribute->value());
            }

            if (valid_global)
            {
                ScriptGlobal global;

                global.name = id;
                global.type = type;
                global.value_raw = value;
                global.read_only = _protected;

                RegisterGvar(global);
            }
        }

        Blam::Logger::LogEvent("successfully loaded " + std::to_string(globals.size()) + " global variables");

        return true;
    }

    Blam::Logger::LogEvent("### ERROR failed to locate gvars.xml at path '" + file_path + "'", WSV_ERROR);

    return false;
}

#pragma region global retrieval

bool* BlamScript::Globals::GetGlobalAsBoolean(std::string name)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->first == name)
        {
            return &i->second.boolean_value;
        }
    }

    return nullptr;
}

std::string* BlamScript::Globals::GetGlobalAsString(std::string name)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->first == name)
        {
            return &i->second.value_raw;
        }
    }

    //return "could not find global: '" + name + "'";
    return nullptr;
}

short* BlamScript::Globals::GetGlobalAsShort(std::string name)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->first == name)
        {
            return &i->second.short_value;
        }
    }

    return 0;
}

long* BlamScript::Globals::GetGlobalAsLong(std::string name)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->first == name)
        {
            return &i->second.long_value;
        }
    }

    return 0;
}

int* BlamScript::Globals::GetGlobalAsInteger(std::string name)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->first == name)
        {
            return &i->second.int_value;
        }
    }

    return 0;
}

float* BlamScript::Globals::GetGlobalAsFloat(std::string name)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->first == name)
        {
            return &i->second.float_value;
        }
    }

    return 0;
}

#pragma endregion

#pragma region global updating

GvarUpdateResult BlamScript::Globals::UpdateGlobalWrap(std::string name, std::string new_value)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->second.name == name)
        {
            if (!i->second.read_only)
            {
                switch (i->second.type)
                {
                    case GvarType::String:
                    {
                        i->second.value_raw = new_value;

                        return GvarUpdateResult::Ok;
                    }
                    case GvarType::Boolean:
                    {
                        std::string new_value_lower = Blam::Utils::String::to_lower(new_value);

                        if (new_value_lower == "true" || new_value_lower == "1" || new_value_lower == "t" || new_value_lower == "yes" || new_value_lower == "y")
                        {
                            i->second.boolean_value = true;
                            i->second.value_raw = "true";
                            return GvarUpdateResult::Ok;
                        }
                        else if (new_value_lower == "false" || new_value_lower == "0" || new_value_lower == "f" || new_value_lower == "no" || new_value_lower == "n")
                        {
                            i->second.boolean_value = false;
                            i->second.value_raw = "false";
                            return GvarUpdateResult::Ok;
                        }
                        else
                        {
                            return GvarUpdateResult::InvalidArgs;
                        }
                    }
                    case GvarType::Short:
                    {
                        bool contains_letter = std::regex_match(new_value, std::regex("[^0-9]"));

                        if (!contains_letter)
                        {
                            long value = stoi(new_value);

                            if (value > 32767 || value < -32768)
                            {
                                return GvarUpdateResult::OutOfBounds;
                            }
                            else
                            {
                                i->second.value_raw = new_value;
                                i->second.short_value = (short)value;
                                return GvarUpdateResult::Ok;
                            }
                        }
                        else
                        {
                            return GvarUpdateResult::InvalidArgs;
                        }
                    }
                    case GvarType::Long:
                    {
                        bool contains_letter = std::regex_match(new_value, std::regex("[^0-9]"));

                        if (!contains_letter)
                        {
                            long value = stoi(new_value);

                            if (value > 2147483647 || value < -2147483648)
                            {
                                return GvarUpdateResult::OutOfBounds;
                            }
                            else
                            {
                                i->second.value_raw = new_value;
                                i->second.long_value = value;
                                return GvarUpdateResult::Ok;
                            }
                        }
                        else
                        {
                            return GvarUpdateResult::InvalidArgs;
                        }
                    }
                    case GvarType::Int:
                    {
                        bool contains_letter = std::regex_match(new_value, std::regex("[^0-9]"));

                        if (!contains_letter)
                        {
                            long value = stoi(new_value);

                            if (value > 2147483647 || value < -2147483648)
                            {
                                return GvarUpdateResult::OutOfBounds;
                            }
                            else
                            {
                                i->second.value_raw = new_value;
                                i->second.int_value = (int)value;
                                return GvarUpdateResult::Ok;
                            }
                        }
                        else
                        {
                            return GvarUpdateResult::InvalidArgs;
                        }
                    }
                    case GvarType::Float:
                    {
                        bool contains_letter = std::regex_match(new_value, std::regex("[^0-9]"));

                        if (!contains_letter)
                        {
                            float value = bstof(new_value);

                            i->second.value_raw = new_value;
                            i->second.float_value = value;
                            return GvarUpdateResult::Ok;
                        }
                        else
                        {
                            return GvarUpdateResult::InvalidArgs;
                        }
                    }
                    default:
                    {
                        return GvarUpdateResult::InvalidType;
                    }
                }
            }
            else
            {
                return GvarUpdateResult::GlobalIsProtected;
            }

        }
    }

    return GvarUpdateResult::UnknownGlobal;
}

GvarUpdateResult BlamScript::Globals::UpdateGlobal(std::string name, std::string new_value)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->second.name == name)
        {
            if (i->second.type == GvarType::String)
            {
                i->second.value_raw = new_value;

                return GvarUpdateResult::Ok;
            }
        }
    }

    return GvarUpdateResult::UnknownGlobal;
}

GvarUpdateResult BlamScript::Globals::UpdateGlobal(std::string name, bool new_value)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->second.name == name)
        {
            if (i->second.type == GvarType::Boolean)
            {
                i->second.value_raw = std::to_string(new_value);
                i->second.boolean_value = new_value;

                return GvarUpdateResult::Ok;
            }
            else
            {
                return GvarUpdateResult::InvalidType;
            }
        }
    }

    return GvarUpdateResult::UnknownGlobal;
}

GvarUpdateResult BlamScript::Globals::UpdateGlobal(std::string name, short new_value)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->second.name == name)
        {
            if (i->second.type == GvarType::Short)
            {
                i->second.value_raw = std::to_string(new_value);
                i->second.short_value = new_value;

                return GvarUpdateResult::Ok;
            }
            else
            {
                return GvarUpdateResult::InvalidType;
            }
        }
    }

    return GvarUpdateResult::UnknownGlobal;
}

GvarUpdateResult BlamScript::Globals::UpdateGlobal(std::string name, long new_value)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->second.name == name)
        {
            if (i->second.type == GvarType::Long)
            {
                i->second.value_raw = std::to_string(new_value);
                i->second.long_value = new_value;

                return GvarUpdateResult::Ok;
            }
            else
            {
                return GvarUpdateResult::InvalidType;
            }
        }


    }

    return GvarUpdateResult::UnknownGlobal;
}

GvarUpdateResult BlamScript::Globals::UpdateGlobal(std::string name, int new_value)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->second.name == name)
        {
            if (i->second.type == GvarType::Int)
            {
                i->second.value_raw = std::to_string(new_value);
                i->second.int_value = new_value;

                return GvarUpdateResult::Ok;
            }
            else
            {
                return GvarUpdateResult::InvalidType;
            }
        }
    }

    return GvarUpdateResult::UnknownGlobal;
}

GvarUpdateResult BlamScript::Globals::UpdateGlobal(std::string name, float new_value)
{
    for (std::map<std::string, ScriptGlobal>::iterator i = globals.begin(); i != globals.end(); i++)
    {
        if (i->second.name == name)
        {
            if (i->second.type == GvarType::Float)
            {
                i->second.value_raw = std::to_string(new_value);
                i->second.float_value = new_value;

                return GvarUpdateResult::Ok;
            }
            else
            {
                return GvarUpdateResult::InvalidType;
            }
        }
    }

    return GvarUpdateResult::UnknownGlobal;
}

#pragma endregion