Unknown ❤ RESPAWN.ZAFEST.RO | VIP FREE | FREE FOR ALL ❤ 0/32
Romania XPlayZM.CSBlackDevil.COM # Zombie Plague UltimateX [ Respawn + FDL + VIP 22-12PM + POINTS] ® 18/32
Sunucu tanitimi

Add fakemeta-basics/en.md

Browse Source
Daemon666 committed parent 55f4d690e4 commit 7cb0476f40490489e96e3445e2186efe30acaaff
1 changed file with 99 additions and 0 deletions
+99 -0 fakemeta-basics/en.md A
@@ -0,0 +1,99 @@
1 +---
2 +title: "Fakemeta Basics: pev, set_pev and Engine Forwards"
3 +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."
4 +category: "plugin-dev"
5 +tags: "fakemeta, amxmodx"
6 +image: ""
7 +read_time: "7 min read"
8 +---
9 +<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>
10 +
11 +<h2>1. Reading entity variables with pev</h2>
12 +<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>
13 +<pre>#include &lt;amxmodx&gt;
14 +#include &lt;fakemeta&gt;
15 +
16 +public show_state(id)
17 +{
18 + new Float:health = pev(id, pev_health)
19 + new flags = pev(id, pev_flags)
20 + new team = pev(id, pev_team)
21 +
22 + new Float:origin[3]
23 + pev(id, pev_origin, origin)
24 +
25 + new classname[32]
26 + pev(id, pev_classname, classname, charsmax(classname))
27 +
28 + server_print("hp=%.0f onground=%d team=%d at %.0f %.0f %.0f",
29 + health, (flags &amp; FL_ONGROUND) ? 1 : 0, team,
30 + origin[0], origin[1], origin[2])
31 +}</pre>
32 +<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>
33 +
34 +<h2>2. Writing with set_pev</h2>
35 +<p><code>set_pev</code> mirrors <code>pev</code>. Set a scalar directly, a vector from an array:</p>
36 +<pre>public buff_player(id)
37 +{
38 + set_pev(id, pev_health, 150.0)
39 + set_pev(id, pev_maxspeed, 320.0)
40 +
41 + new Float:vel[3]
42 + pev(id, pev_velocity, vel)
43 + vel[2] = 300.0 // launch upward
44 + set_pev(id, pev_velocity, vel)
45 +}</pre>
46 +<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>
47 +
48 +<h2>3. engfunc and dllfunc</h2>
49 +<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>
50 +<pre>// teleport safely through the engine
51 +new Float:dest[3] = { 0.0, 0.0, 128.0 }
52 +engfunc(EngFunc_SetOrigin, id, dest)
53 +
54 +// give the player a weapon through the game DLL
55 +dllfunc(DLLFunc_GiveNamedItem, id, "weapon_ak47")
56 +
57 +// slay a player cleanly
58 +dllfunc(DLLFunc_ClientKill, id)</pre>
59 +<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>
60 +
61 +<h2>4. Engine forwards</h2>
62 +<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>
63 +<pre>public plugin_init()
64 +{
65 + register_plugin("Fakemeta Demo", "1.0", "CSB")
66 + register_forward(FM_PlayerPreThink, "fw_prethink")
67 + register_forward(FM_EmitSound, "fw_emitsound")
68 +}
69 +
70 +public fw_prethink(id)
71 +{
72 + if (!is_user_alive(id))
73 + return FMRES_IGNORED
74 +
75 + // enforce a speed cap every frame
76 + set_pev(id, pev_maxspeed, 300.0)
77 + return FMRES_IGNORED
78 +}
79 +
80 +public fw_emitsound(id, channel, const sample[])
81 +{
82 + // block footstep sounds
83 + if (containi(sample, "player/pl_step") != -1)
84 + return FMRES_SUPERCEDE
85 +
86 + return FMRES_IGNORED
87 +}</pre>
88 +<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>
89 +
90 +<h2>Common errors</h2>
91 +<ul>
92 +<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>
93 +<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>
94 +<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>
95 +<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>
96 +</ul>
97 +
98 +<h2>Verification</h2>
99 +<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>
0 100