Guides

Paths

Where Source2Mod keeps configs, gamedata, plugins and shared data — ask instead of hard-coding paths.

ISource2ModPaths tells a plugin where things are on disk. Ask it rather than spelling paths out against the game directory: when the layout moves, every plugin that asks keeps working without an edit.

plugin.cpp
#include "source2mod/ISource2ModPaths.h"

The layout

Under the game directory (.../game/csgo):

addons/source2mod/
  configs/              core.json, and one directory per plugin
    <PluginName>/       this plugin's own configs
  gamedata/             every .json here is read into the game config
  plugins/              the .smx files themselves
  shared/               data more than one plugin reads
CallMacroPath
GameDirectory()SOURCE2MOD_GAME_DIR()The game directory, e.g. .../game/csgo
RootDirectory()SOURCE2MOD_ROOT_DIR()addons/source2mod
ConfigsDirectory()SOURCE2MOD_CONFIGS_DIR()addons/source2mod/configs
GamedataDirectory()SOURCE2MOD_GAMEDATA_DIR()addons/source2mod/gamedata
PluginsDirectory()SOURCE2MOD_PLUGINS_DIR()addons/source2mod/plugins
SharedDirectory()SOURCE2MOD_SHARED_DIR()addons/source2mod/shared
PluginConfigDirectory(PluginId owner)PLUGIN_CONFIG_DIR()configs/<PluginName> for this plugin

All of them are absolute paths built on the game directory, without a trailing slash — append "/file.json" yourself. In SourcePawn they are Source2ModPaths.GameDirectory(buffer, maxlen) and so on, writing into a buffer (char path[PLATFORM_MAX_PATH]); PluginConfigDirectory() there takes no plugin id, it is always the calling plugin's.

Your plugin's config directory

PLUGIN_CONFIG_DIR() is PluginConfigDirectory(g_PluginID): the configs/<PluginName> directory, keyed on the name your plugin returns from GetName(). A script reads the file with Source2ModFiles.ReadFile() (see Files and KeyValues).

config.cpp
#include <fstream>
#include <sstream>

bool LoadConfig()
{
    const char* dir = PLUGIN_CONFIG_DIR();
    if (!dir)
        return false;

    std::ifstream file(std::string(dir) + "/config.json");
    if (!file)
        return false;

    std::stringstream text;
    text << file.rdbuf();

    ISource2ModJSONDocument* doc = g_pSource2ModJSON->Parse(text.str().c_str());
    // ... read values, see the JSON guide ...
    doc->Release();
    return true;
}

In C++ a small wrapper that turns nullptr into an empty string keeps call sites simple — FUNPLAY's plugins do this (SourcePawn needs none: it always gets a string, empty when there is no path):

inline std::string FromSource2Mod(const char* p) { return p ? std::string(p) : std::string(); }
inline std::string ConfigDirectory() { return FromSource2Mod(PLUGIN_CONFIG_DIR()) + "/config"; }

Pitfalls

  • PluginConfigDirectory() can return nullptr — for an unknown PluginId, or when the plugin's GetName() is empty. SourcePawn gets an empty string instead.
  • The directory is not created for you. It is where your plugin's files are expected to have been installed; create it yourself if you write files there.
  • Copy the string if you keep it past Source2Mod's lifetime (C++ only; SourcePawn already has its own copy). The returned pointers are owned by Source2Mod and stay valid while it is loaded.
  • Ask after load. The game directory is only known once the engine is up; call these from Load() / OnPluginStart() or later, not from static initialisers.

Reference

On this page