Skip to content

Plugin examples

Karol Szuster edited this page Apr 26, 2022 · 4 revisions

Plugin examples

Bare minimum

This the minimum code to have loadable metamod plugin.

#include <IAnubis.hpp>
#include <ILogger.hpp>
#include <game/ILibrary.hpp>
#include <engine/ILibrary.hpp>

class Plugin : public Anubis::IPlugin
{
public:
    Anubis::InterfaceVersion getInterfaceVersion() const
    {
        return Anubis::IAnubis::VERSION;
    }
    
    std::string_view getName() const
    {
        return "Minimal plugin";
    }
    
    std::string_view getVersion() const
    {
        return "1.0";
    }
    
    std::string_view getDate() const
    {
        return __DATE__;
    }
    
    std::string_view getAuthor() const
    {
        return "Anubis Dev Team";
    }
    
    std::string_view getUrl() const
    {
        return "https://github.com/Amaroq7/Anubis";
    }
    
    Type getType() const
    {
        return Type::Extension;
    }
};

nstd::observer_ptr<Anubis::IAnubis> gApi;
nstd::observer_ptr<Anubis::Game::ILibrary> gGame;
nstd::observer_ptr<Anubis::Engine::ILibrary> gEng;
std::unique_ptr<Anubis::ILogger> gLogger;

/* The following functions are exported from the plugin */
namespace Anubis
{
    nstd::observer_ptr<IPlugin> Query()
    {
        static auto pluginInfo = std::make_unique<Plugin>();
        return pluginInfo;
    }

    bool Init(nstd::observer_ptr<IAnubis> api)
    {
        gApi = api;
        gGame = gApi->getGame(Game::ILibrary::VERSION);
        gEng = gApi->getEngine(Engine::ILibrary::VERSION);
        
        gLogger = gApi->getLogger(ILogger::VERSION);
        gLogger->setLogTag("TEST");
        gLogger->setLogLevel(LogLevel::Debug);
        
        return true;
    }
    
    void Shutdown()
    { 
        gLogger.reset();
    }
}

ClientCmd hook

This example shows how to hook ClientCmd func. It prints info about the 1st argument of the say command.

#include <IAnubis.hpp>
#include <game/ILibrary.hpp>
#include <game/IHooks.hpp>
#include <engine/ILibrary.hpp>
#include <engine/IEdict.hpp>

class Plugin : public Anubis::IPlugin
{
public:
    Anubis::InterfaceVersion getInterfaceVersion() const
    {
        return Anubis::IAnubis::VERSION;
    }
    
    std::string_view getName() const
    {
        return "Example";
    }
    
    std::string_view getVersion() const
    {
        return "1.0";
    }
    
    std::string_view getDate() const
    {
        return __DATE__;
    }
    
    std::string_view getAuthor() const
    {
        return "Author";
    }
    
    std::string_view getUrl() const
    {
        return "URL";
    }
    
    Type getType() const
    {
        return Type::Extension;
    }
};
nstd::observer_ptr<Anubis::IAnubis> gApi;
nstd::observer_ptr<Anubis::Game::ILibrary> gGame;
nstd::observer_ptr<Anubis::Engine::ILibrary> gEng;
std::unique_ptr<Anubis::ILogger> gLogger;

nstd::observer_ptr<Anubis::IHookInfo> gOnClientCmdHook;

void OnClientCmd(nstd::observer_ptr<Anubis::Game::IClientCmdHook> hook, nstd::observer_ptr<Anubis::Engine::IEdict> e)
{
    // pre stuff
    // ...
    
    /**
     * Calls the next hook in the chain.
     * callOriginal() will call the original funcs omitting other plugins' hooks.
     * If no callNext or callOriginal is called then the original func won't be called resulting in no commands sent to the gamedll.
     * This can to useful to f.e. hide commands on the say.
    */
    hook->callNext(e);
    
    // post stuff
    if (gEng->cmdArgv(0, Anubis::FuncCallType::Direct) == "say")
    {
        using namespace std::string_literals;
        gLogger->logMsg(Anubis::LogDest::Console, Anubis::LogLevel::Info, "Client "s + std::to_string(e->getIndex()));
        gLogger->logMsg(Anubis::LogDest::Console, Anubis::LogLevel::Info, "say: "s + gEng->cmdArgv(1, Anubis::FuncCallType::Direct).data());
    }
}

/* The following functions are exported from the plugin */
namespace Anubis
{
    nstd::observer_ptr<IPlugin> Query()
    {
        static auto pluginInfo = std::make_unique<Plugin>();
        return pluginInfo;
    }

    bool Init(nstd::observer_ptr<IAnubis> api)
    {
        gApi = api;
        gGame = gApi->getGame(Game::ILibrary::VERSION);
        gEng = gApi->getEngine(Engine::ILibrary::VERSION);
        
        gLogger = gApi->getLogger(ILogger::VERSION);
        gLogger->setLogTag("TEST");
        gLogger->setLogLevel(LogLevel::Debug);
    
        gOnClientCmdHook = gGame->getHooks()->clientCmd()->registerHook(OnClientCmd, HookPriority::Default);
        return true;
    }

    void Shutdown()
    {
        gGame->getHooks()->clientCmd()->unregisterHook(gOnClientCmdHook);
    }
}

CBasePlayer TakeDamage hook

This example demonstrates how to hook virutal func of CBasePlayer class. It also shows how to disable/enable hook using say command.

#include <IAnubis.hpp>

#include <game/IEntitiesHooks.hpp>
#include <game/ILibrary.hpp>
#include <game/IHooks.hpp>
#include <game/IBasePlayer.hpp>

#include <engine/ITraceResult.hpp>
#include <engine/IEdict.hpp>
#include <engine/ILibrary.hpp>

class Plugin : public Anubis::IPlugin
{
public:
    Anubis::InterfaceVersion getInterfaceVersion() const
    {
        return Anubis::IAnubis::VERSION;
    }
    
    std::string_view getName() const
    {
        return "Example";
    }
    
    std::string_view getVersion() const
    {
        return "1.0";
    }
    
    std::string_view getDate() const
    {
        return __DATE__;
    }
    
    std::string_view getAuthor() const
    {
        return "Author";
    }
    
    std::string_view getUrl() const
    {
        return "URL";
    }
    
    Type getType() const
    {
        return Type::Extension;
    }
};

nstd::observer_ptr<Anubis::IAnubis> gApi;
nstd::observer_ptr<Anubis::Game::ILibrary> gGame;
nstd::observer_ptr<Anubis::Engine::ILibrary> gEng;
std::unique_ptr<Anubis::ILogger> gLogger;

nstd::observer_ptr<Anubis::IHookInfo> gOnClientCmdHook;
nstd::observer_ptr<Anubis::IHookInfo> gCBasePlayerTakeDamageHook;

bool OnCBasePlayerTakeDamage(nstd::observer_ptr<Anubis::Game::IBasePlayerTakeDamageHook> hook,
                             nstd::observer_ptr<Anubis::Game::IBasePlayer> plr,
                             nstd::observer_ptr<Anubis::Game::IBaseEntity> pevInflictor,
                             nstd::observer_ptr<Anubis::Game::IBaseEntity> pevAttacker,
                             float &dmg, Anubis::Game::DmgType bits)
{
    bool result = hook->callNext(plr, pevInflictor, pevAttacker, dmg, bits);

    using namespace std::string_literals;
    gLogger->logMsg(Anubis::LogDest::Console, Anubis::LogLevel::Info, "this: "s + std::to_string(plr->edict()->getIndex()));
    gLogger->logMsg(Anubis::LogDest::Console, Anubis::LogLevel::Info, "pevInflictor: "s + std::to_string(pevInflictor->getIndex()));
    gLogger->logMsg(Anubis::LogDest::Console, Anubis::LogLevel::Info, "pevAttacker: "s + std::to_string(pevAttacker->getIndex()));
    gLogger->logMsg(Anubis::LogDest::Console, Anubis::LogLevel::Info, "dmg: "s + std::to_string(dmg));
    gLogger->logMsg(Anubis::LogDest::Console, Anubis::LogLevel::Info, "bits: "s + std::to_string(bits));
    
    return result;
}

void OnClientCmd(nstd::observer_ptr<Anubis::Game::IClientCmdHook> hook, nstd::observer_ptr<Anubis::Engine::IEdict> e)
{
    if (gEng->cmdArgv(0, Anubis::FuncCallType::Direct) == "say")
    {
        if (gEng->cmdArgv(1, Anubis::FuncCallType::Direct) == "/on")
        {
            gCBasePlayerTakeDamageHook->setState(Anubis::IHookInfo::State::Enabled);
            return;
        }
        else if (gEng->cmdArgv(1, Anubis::FuncCallType::Direct) == "/off")
        {
            gCBasePlayerTakeDamageHook->setState(Anubis::IHookInfo::State::Disabled);
            return;
        }
    }
    
    hook->callNext(e);
}

std::int32_t onSpawn(nstd::observer_ptr<Anubis::Game::IBasePlayerSpawnHook> hook, nstd::observer_ptr<Anubis::Engine::IEdict> e)
{
    static bool init = false;
    
    if (init)
        return hook->callNext(ed);
        
    gCBasePlayerTakeDamageHook = gGame->getCBasePlayerHooks()->takeDamage()->registerHook(OnCBasePlayerTakeDamage, Anubis::HookPriority::Default);
    init = true;
    
    return hook->callNext(ed);
}

namespace Anubis
{
    nstd::observer_ptr<IPlugin> Query()
    {
        static auto pluginInfo = std::make_unique<Plugin>();
        return pluginInfo;
    }

    bool Init(nstd::observer_ptr<IAnubis> api)
    {
        gApi = api;
        gGame = gApi->getGame(Game::ILibrary::VERSION);
        gEng = gApi->getEngine(Engine::ILibrary::VERSION);
        
        gLogger = gApi->getLogger(ILogger::VERSION);
        gLogger->setLogTag("TEST");
        gLogger->setLogLevel(LogLevel::Debug);
    
        gOnClientCmdHook = gGame->getHooks()->clientCmd()->registerHook(OnClientCmd, HookPriority::Default);
        return true;
    }

    void InstallVHooks()
    {
        gGame->getCBasePlayerHooks()->spawn()->registerHook(onSpawn, HookPriority::Default);
    }

    void Shutdown()
    {
        gGame->getHooks()->clientCmd()->unregisterHook(gOnClientCmdHook);
        gGame->getCBasePlayerHooks()->takeDamage()->unregisterHook(gCBasePlayerTakeDamageHook);
    }
}
Clone this wiki locally