Promuj serwer
99 lines 6.6 KiB Markdown Source Rendered Raw Permalink History
---
title: "Fakemeta Basics: pev, set_pev and Engine Forwards"
excerpt: "Read and write entity variables with pev/set_pev, call engine and DLL functions, and hook engine forwards like FM_PlayerPreThink and FM_EmitSound."
category: "plugin-dev"
tags: "fakemeta, amxmodx"
image: ""
read_time: "7 min read"
---
<p>Fakemeta (module <code>fakemeta</code>) gives AMXX plugins the same low-level access to the engine that a Metamod plugin written in C++ would have: it reads and writes the <code>entvars_t</code> struct of any entity, calls engine and game-DLL functions directly, and hooks the engine's forwards. It is fast and it is everywhere, but it is also unforgiving &mdash; there are no named members and no safety rails. This guide covers the three things you will use constantly: <code>pev</code>/<code>set_pev</code>, <code>engfunc</code>/<code>dllfunc</code>, and <code>register_forward</code>.</p>

<h2>1. Reading entity variables with pev</h2>
<p>Every entity &mdash; players, weapons, grenades, doors &mdash; has an <code>entvars_t</code> block. <code>pev(index, member)</code> reads a field. Integer fields return directly; vector fields are read into a passed array; string fields into a buffer:</p>
<pre>#include &lt;amxmodx&gt;
#include &lt;fakemeta&gt;

public show_state(id)
{
    new Float:health = pev(id, pev_health)
    new flags        = pev(id, pev_flags)
    new team         = pev(id, pev_team)

    new Float:origin[3]
    pev(id, pev_origin, origin)

    new classname[32]
    pev(id, pev_classname, classname, charsmax(classname))

    server_print("hp=%.0f onground=%d team=%d at %.0f %.0f %.0f",
        health, (flags &amp; FL_ONGROUND) ? 1 : 0, team,
        origin[0], origin[1], origin[2])
}</pre>
<p>The <code>pev_*</code> constants are the field names. The ones you will reach for most are <code>pev_origin</code>, <code>pev_velocity</code>, <code>pev_health</code>, <code>pev_maxspeed</code>, <code>pev_flags</code>, <code>pev_button</code>, <code>pev_team</code>, <code>pev_frags</code>, <code>pev_deadflag</code>, and the generic user fields <code>pev_iuser1</code>..<code>pev_iuser4</code>.</p>

<h2>2. Writing with set_pev</h2>
<p><code>set_pev</code> mirrors <code>pev</code>. Set a scalar directly, a vector from an array:</p>
<pre>public buff_player(id)
{
    set_pev(id, pev_health, 150.0)
    set_pev(id, pev_maxspeed, 320.0)

    new Float:vel[3]
    pev(id, pev_velocity, vel)
    vel[2] = 300.0                 // launch upward
    set_pev(id, pev_velocity, vel)
}</pre>
<p>Note the types: <code>pev_health</code> and <code>pev_maxspeed</code> are floats, so pass <code>150.0</code>, not <code>150</code>. Writing an integer into a float member is a tag-mismatch warning and produces nonsense in-game. When you move a player, prefer setting velocity or using the engine's <code>SetOrigin</code> (below) over writing <code>pev_origin</code> directly, which can push a player into a wall.</p>

<h2>3. engfunc and dllfunc</h2>
<p><code>engfunc</code> calls an engine function; <code>dllfunc</code> calls a game-DLL function. Both take a constant naming the function followed by its arguments:</p>
<pre>// teleport safely through the engine
new Float:dest[3] = { 0.0, 0.0, 128.0 }
engfunc(EngFunc_SetOrigin, id, dest)

// give the player a weapon through the game DLL
dllfunc(DLLFunc_GiveNamedItem, id, "weapon_ak47")

// slay a player cleanly
dllfunc(DLLFunc_ClientKill, id)</pre>
<p>These call the same functions the game itself calls, so side effects (sounds, prediction, physics) happen correctly &mdash; unlike poking <code>entvars_t</code> by hand. The full list of <code>EngFunc_*</code> and <code>DLLFunc_*</code> constants is in <code>fakemeta.inc</code>; read the include for exact argument orders rather than guessing.</p>

<h2>4. Engine forwards</h2>
<p>The real power of fakemeta is <code>register_forward</code>: it hooks an engine function so your code runs every time the engine calls it. <code>FM_PlayerPreThink</code> runs each frame per player, <code>FM_Touch</code> when two entities touch, <code>FM_EmitSound</code> whenever a sound plays:</p>
<pre>public plugin_init()
{
    register_plugin("Fakemeta Demo", "1.0", "CSB")
    register_forward(FM_PlayerPreThink, "fw_prethink")
    register_forward(FM_EmitSound, "fw_emitsound")
}

public fw_prethink(id)
{
    if (!is_user_alive(id))
        return FMRES_IGNORED

    // enforce a speed cap every frame
    set_pev(id, pev_maxspeed, 300.0)
    return FMRES_IGNORED
}

public fw_emitsound(id, channel, const sample[])
{
    // block footstep sounds
    if (containi(sample, "player/pl_step") != -1)
        return FMRES_SUPERCEDE

    return FMRES_IGNORED
}</pre>
<p>The return value controls what happens next. <code>FMRES_IGNORED</code> lets the engine proceed normally. <code>FMRES_SUPERCEDE</code> blocks the original call entirely &mdash; that is how you silence a sound or cancel a touch. <code>FMRES_HANDLED</code> marks it handled without blocking. Registering a forward as a <em>post</em> hook (pass <code>1</code> as the last argument to <code>register_forward</code>) runs your code after the engine, when you want the result rather than the chance to block it.</p>

<h2>Common errors</h2>
<ul>
<li><strong>Tag mismatch on <code>pev_health</code> / <code>pev_origin</code></strong> &mdash; you used an integer where a float is required. Vector and health fields are <code>Float:</code>.</li>
<li><strong><code>FM_PlayerPreThink</code> tanks the server</strong> &mdash; it fires every frame for every player. Do the absolute minimum inside it, and bail early with <code>is_user_alive</code>. Heavy work here is the classic cause of <a href="/tutorials/fix-low-server-fps-linux">low server FPS</a>.</li>
<li><strong>Blocking a forward does nothing</strong> &mdash; you returned <code>FMRES_IGNORED</code>. Only <code>FMRES_SUPERCEDE</code> stops the original call.</li>
<li><strong>Player stuck in geometry after moving</strong> &mdash; you wrote <code>pev_origin</code> directly. Use <code>engfunc(EngFunc_SetOrigin, ...)</code> so the engine relinks the entity.</li>
</ul>

<h2>Verification</h2>
<p>Print a value you set and read it back the next frame to confirm the write stuck: set <code>pev_maxspeed</code> in <code>FM_PlayerPreThink</code>, then check in-game that movement speed actually changed. For blocking hooks, trigger the sound or touch and confirm <code>FMRES_SUPERCEDE</code> suppressed it. When you need to <em>modify</em> damage or spawning rather than engine calls, Ham Sandwich is the better tool &mdash; see <a href="/tutorials/hamsandwich-basics">the Ham Sandwich guide</a> &mdash; and on ReGameDLL, <a href="/tutorials/reapi-getting-started">ReAPI</a> replaces most raw fakemeta with named members.</p>