Hooks
Les événements auxquels un addon réagit avec hook.Add, et qu'un gamemode définit avec function GM:Événement(...).
Valeurs de retour
Pour un même événement, les hooks des addons sont appelés les uns après les autres, puis la fonction du gamemode. Dès qu'un hook renvoie une valeur (autre que nil), la suite n'est pas appelée et cette valeur est utilisée par le jeu, comme dans Garry's Mod. Ne renvoie donc rien si tu veux seulement observer l'événement. Les valeurs par défaut viennent du gamemode (Base, Sandbox…).
Pour les hooks qui autorisent ou bloquent quelque chose (CanTool, PlayerSpawnProp, HUDShouldDraw…), seuls true et false comptent : une autre valeur (texte, nombre, table) est ignorée comme si le hook ne renvoyait rien.
Liste des hooks
| Événement | Arguments | Valeur de retour |
|---|---|---|
Initialize | — | — |
Think | dt | — |
Tick | — | — |
PostGamemodeLoaded | — | — |
OnReloaded | — | — |
ShutDown | — | — |
InitPostEntity | — | — |
PostCleanupMap | — | — |
CheckPassword | steamID64, ip, mdpServeur, mdpDonné, nom | false, "raison" refuse, true laisse entrer |
PlayerInitialSpawn | ply | — |
PlayerAuthed | ply, steamid, uniqueid | — |
PlayerSpawn | ply | — |
PlayerLoadout | ply | — |
PlayerNoClip | ply | true pour autoriser |
PlayerGiveWeapon | ply, arme | true pour accepter |
PlayerSetModel | ply, id | false refuse le playermodel choisi dans Apparence |
PlayerSetBodygroup | ply, groupe, option (à partir de 0) | false refuse ce changement de tenue choisi dans Apparence (le joueur garde l'ancienne option et un message le prévient). ply:SetBodygroup ne passe pas par ce hook. |
PlayerSpawnNPC | ply, classe | true pour autoriser l'onglet PNJ |
PlayerSpawnedNPC / NPCSpawned | ply, pnj / pnj | — |
NPCTakeDamage | pnj, dégâts, attaquant, type | false annule, un nombre remplace |
OnNPCKilled | pnj, attaquant, cause | — |
NPCReachedGoal / NPCRemoved | pnj, pos / pnj | — |
PlayerShouldTakeDamage | ply, cause, attaquant | false pour annuler |
ScalePlayerDamage | ply, hitgroup, dmginfo | true annule le dégât |
PlayerHurt | ply, attaquant, vieRestante, dégâts | — |
OnPlayerHitGround | ply, dansEau, surFlotteur, vitesse | true : pas de dégâts de chute |
GetFallDamage | ply, vitesse | un nombre : les dégâts de chute |
PlayerDeath | ply, cause, attaquant | — |
PlayerDeathNotice | ply, cause, attaquant | false ou texte de remplacement |
AddDeathNotice client | tueur, équipeTueur, inflicteur, victime, équipeVictime | une valeur : pas de ligne dans le fil par défaut |
DrawDeathNotice client | x, y | une valeur cache le fil par défaut |
CanPlayerSuicide | ply | false bloque /kill |
PlayerChangedTeam | ply, ancienne, nouvelle | — |
PlayerCanRespawn | ply | false empêche de réapparaître d'un clic |
EntityTakeDamage | ent, attaquant, dégâts, arme | true annule la poussée |
PlayerSay | ply, texte | texte de remplacement, ou "" pour bloquer |
PlayerCanSeePlayersChat | texte, équipeSeulement, auditeur, auteur | false : cet auditeur ne voit pas le message |
PlayerCanHearPlayersVoice | auditeur, parleur | false pour couper la voix |
PlayerDisconnected | ply | — |
PlayerSpawnProp | ply, modèle | false pour refuser |
PropSpawned | prop, ply | — |
PlayerSpawnedProp | ply, modèle, ent | — |
OnEntityCreated | ent | — |
EntityRemoved | ent | — |
EntityNetworkedVarChanged | ent, nom, ancienne, nouvelle | — |
ShouldCollide | ent1, ent2 | false : ils se traversent |
EntityEmitSound | données | false bloque le son, true le joue modifié |
EntityFireBullets | tireur, balle | false annule le tir, true l'applique modifié |
ProtectionCanTouch | ply, ent, action | true / false tranche avant la protection des props |
PhysgunPickup | ply, ent (prop, véhicule ou PNJ) | false pour refuser |
PhysgunDrop | ply, ent | — |
OnPhysgunFreeze | ply, prop | false lâche sans figer |
CanPlayerUnfreeze | ply, prop | false garde le prop figé |
CanTool | ply, trace, outil | false refuse l'action du toolgun |
PlayerUse | ply, ent | false bloque E |
PlayerSwitchWeapon | ply, ancienne, nouvelle | true bloque le changement d'arme |
PlayerCanPickupWeapon | ply, id | false : pas de ramassage |
PlayerButtonDown | ply, touche | — |
PlayerButtonUp | ply, touche | — |
KeyPress | ply, IN_… | — |
KeyRelease | ply, IN_… | — |
PlayerSwitchFlashlight | ply, allumée | false refuse |
PlayerStartGesture | ply, nom | false refuse le geste |
TriggerStartTouch | zone, ent | — |
TriggerEndTouch | zone, ent | — |
CanPlayerEnterVehicle | ply, veh, place | false pour refuser |
PlayerEnteredVehicle | ply, veh, place | — |
PlayerLeaveVehicle | ply, veh | — |
CanExitVehicle | ply, veh | false empêche de descendre avec E |
CanUndo | ply, entrée | false garde l'entrée (pas d'annulation) |
OnUndo | nom, texte, ply | — |
CanCleanup | ply, catégorie | false refuse le nettoyage |
CanDuplicate | ply, liste | false refuse le collage d'une dupe |
PreDuplicate / PostDuplicate | ply, liste / ply, créées | — |
PlayerSpawnSENT | ply, classe | false refuse l'entité (onglet Entités) |
PlayerSpawnedSENT | ply, ent | — |
CanProperty | ply, nom, ent | false cache et refuse une action du menu contextuel |
EnvChanged | quoi | — |
PlayerVRGrab | ply, ent, main | false empêche d'attraper |
PlayerVRDrop | ply, ent, main | — |
ClientReady client | — | — |
PlayerFireWeapon | ply, id | false annule le tir (armes d'addon) |
PlayerReload | ply, id | false empêche le rechargement |
WeaponAnimEvent (client) | ply, id, nom | — Un « Événement Lua » d'une animation faite dans l'éditeur d'arme |
WeaponExplosion | pos, rayon, attaquant, id | — |
HUDPaint client | — | — |
PreDrawHUD, HUDPaintBackground, PostDrawHUD client | — | — |
HUDShouldDraw client | nom | false pour cacher |
SpawnMenuOpen client | — | false pour bloquer |
ScoreboardShow client | — | true : le gamemode affiche son tableau |
ScoreboardHide client | — | — |
OnPlayerChat client | ply, texte, équipe, mort | true cache la ligne par défaut |
ChatText client | index, nom, texte, type | true cache la ligne |
CalcView client | ply, origine, angles, fov, znear, zfar | table {origin, angles, fov, drawviewer} |
CalcViewModelView client | arme, vm, ancPos, ancAng, pos, ang | pos, ang du modèle de vue |
PreDrawViewModel / PostDrawViewModel client | vm, ply, arme | true cache le modèle de vue (Pre) |
CalcMainActivity client | ply, vitesse | nom d'un clip du playermodel |
UpdateAnimation client | ply, vitesse, vitesseMax | vitesse de lecture |
DoAnimationEvent client | ply, évènement, action | true : pas de geste ; un nom de clip le remplace |
PrePlayerDraw / PostPlayerDraw client | ply | true cache le joueur (Pre) |
PlayerFootstep client | ply, pos, pied, son, volume | true : pas de bruit de pas |
PlayerBindPress client | ply, action, appuyé | true bloque l'action |
ContextMenuOpen client | — | false empêche d'ouvrir le menu contextuel |
OnContextMenuOpen / OnContextMenuClose client | — | — |
AddToolMenuTabs, AddToolMenuCategories, PopulateToolMenu client | — | — |
StartCommand client | ply, cmd | — |
CreateMove client | cmd | — |
SetupMove client | ply, mv, cmd | — |
Move client | ply, mv | true remplace le déplacement du jeu |
FinishMove client | ply, mv | — |
PreDrawHalos client | — | — |
PostDrawOpaqueRenderables client | false, false | — |
PostDrawTranslucentRenderables client | false, false | — |
PreRender, PostRender client | — | — |
RenderScreenspaceEffects client | — | — |
ForceDermaSkin client | — | nom d'une peau Derma |
Sauf mention client, les événements sont déclenchés sur le serveur. Initialize, Think, ShutDown, EntityRemoved, PlayerButtonDown, PlayerButtonUp, KeyPress, KeyRelease, CanTool, CanProperty, PlayerSwitchWeapon, Tick, PostGamemodeLoaded, OnReloaded, OnEntityCreated, EntityNetworkedVarChanged, ShouldCollide, EntityEmitSound et EntityFireBullets existent des deux côtés.
Les armes et outils Lua ont leurs propres fonctions (SWEP:PrimaryAttack, TOOL:LeftClick…).
Les entités scriptées ont en plus leurs propres fonctions (ENT:Use, ENT:PhysicsCollide, ENT:KeyValue…).
Initialize
Une fois, quand tous les scripts sont chargés (juste après PostGamemodeLoaded), et après chaque redémarrage des scripts (bouton Tester, F5). Un simple enregistrement de fichier lance OnReloaded à la place.
Think
Appelé à chaque image physique (60 fois par seconde). dt est la durée de l'image en secondes (≈ 0,0167). Garde ce code léger.
local total = 0
hook.Add("Think", "monaddon_horloge", function(dt)
total = total + dt
if total >= 60 then
total = 0
PrintMessage("Une minute de plus sur le serveur.")
end
end)
Tick
Serveur et client, à chaque image physique (60 fois par seconde), juste après Think, sans argument. C'est le nom de Garry's Mod pour le même moment : utilise l'un ou l'autre.
PostGamemodeLoaded
Serveur et client, une fois, quand tous les fichiers du gamemode et des addons ont été lancés, juste avant Initialize.
OnReloaded
Serveur et client : un fichier Lua enregistré pendant la partie vient d'être ré-exécuté (autorefresh), sans redémarrage. Les variables, joueurs et entités sont gardés : c'est l'endroit pour reconstruire ce qui dépend du fichier (menus ouverts, caches…). Le bouton Tester (F5) redémarre tout et lance Initialize à la place.
hook.Add("OnReloaded", "monaddon_menu", function()
if CLIENT and IsValid(MonAddonMenu) then MonAddonMenu:Remove() end
end)
ShutDown
Serveur et client : la partie se termine, la map change (game.ChangeMap), le serveur s'arrête ou les scripts sont rechargés. C'est le dernier moment pour sauvegarder.
local scores = {} -- rempli pendant la partie
hook.Add("ShutDown", "monaddon_sauvegarde", function()
if SERVER then file.Write("scores.json", util.TableToJSON(scores)) end
end)
InitPostEntity et PostCleanupMap
Serveur. InitPostEntity est appelé une fois par lancement des scripts, quand la map est chargée et ses props et entités placées créés (aussi sur une map intégrée) : c'est là qu'on lit les points et zones de la map, encore vides pendant Initialize. PostCleanupMap est appelé après game.CleanUpMap(), quand les props et entités de la map ont été recréés.
CheckPassword
Serveur, à la connexion d'un joueur, avant tout le reste. Arguments : steamID64, ip, mot de passe du serveur, mot de passe donné par le joueur, nom. return false, "raison" refuse (la raison est affichée au joueur) ; return true laisse entrer sans vérifier le mot de passe ; ne rien renvoyer applique les règles normales. Les bans et le nombre de places restent toujours vérifiés.
local liste_blanche = { ["76561198000000000"] = true }
hook.Add("CheckPassword", "monserveur_whitelist", function(steamid64, ip, mdp_serveur, mdp_donne, nom)
if not liste_blanche[steamid64] then
return false, "Serveur privé : demande l'accès sur notre Discord."
end
end)
PlayerInitialSpawn
Un joueur apparaît pour la première fois après avoir rejoint (ou l'hôte au lancement de la partie). Idéal pour un message de bienvenue.
PlayerAuthed
Serveur : un joueur arrive, juste avant PlayerInitialSpawn. La vérification Steam est déjà faite à ce moment (un joueur non vérifié n'entre pas). steamid et uniqueid valent tous deux son SteamID64 en texte.
PlayerSpawn
Un joueur apparaît : à son arrivée (juste après PlayerInitialSpawn) et à chaque réapparition après une mort.
hook.Add("PlayerSpawn", "monaddon_armure", function(ply)
ply:SetArmor(50)
end)
PlayerLoadout
Le gamemode Base l'appelle à chaque apparition après avoir retiré les armes : donne ici les armes de départ avec ply:Give(...) (identifiants dans Armes). Sandbox donne toutes les armes : physgun, toolgun, pied-de-biche, pistolet, fusil à pompe et fusil d'assaut.
function GM:PlayerLoadout(ply)
ply:Give("crowbar")
ply:Give("pistol")
end
PlayerGiveWeapon
Un joueur clique sur une arme dans l'onglet Armes du menu de spawn. Renvoie true pour la lui donner (avec un plein de munitions) ; sinon il reçoit un message de refus. Base renvoie false, Sandbox true. ply:Give dans un script n'appelle pas ce hook.
-- Seuls les admins peuvent prendre le fusil d'assaut.
hook.Add("PlayerGiveWeapon", "monaddon_armes", function(ply, arme)
if arme == "rifle" and not ply:IsAdmin() then
return false
end
end)
PlayerNoClip
Appelé à chaque apparition : renvoie true pour que le joueur puisse utiliser le noclip (V). Base renvoie false, Sandbox true. Un script peut aussi utiliser ply:SetNoclipAllowed(b).
PlayerShouldTakeDamage
Avant chaque dégât (chute, prop, arme…) : renvoie false pour l'annuler. attaquant est le joueur qui a tiré ou frappé avec une arme du jeu, sinon nil. ply:Kill() et ply:SetHealth(0) passent toujours. Les armes ne blessent les autres joueurs que si le réglage serveur pvp (« Dégâts entre joueurs ») est activé.
-- Pas de tir ami entre coéquipiers.
hook.Add("PlayerShouldTakeDamage", "monmode_equipes", function(ply, cause, attaquant)
if attaquant and attaquant:Team() ~= 0 and attaquant:Team() == ply:Team() then
return false
end
end)
ScalePlayerDamage
Avant chaque dégât sur un joueur (après PlayerShouldTakeDamage). Renvoie true pour l'annuler, ou modifie dmginfo. hitgroup vaut HITGROUP_HEAD (tête), HITGROUP_CHEST (torse) ou HITGROUP_LEFTLEG (jambes) pour les balles des armes du jeu et des armes d'addon, sinon HITGROUP_GENERIC.
Méthode de dmginfo | Rôle |
|---|---|
:GetDamage(), :SetDamage(n), :ScaleDamage(f), :AddDamage(n), :SubtractDamage(n) | Lire ou changer le montant |
:GetAttacker(), :GetInflictor() | Le joueur responsable, l'id de l'arme |
:GetDamageType(), :IsDamageType(DMG_…) | Type : DMG_GENERIC, DMG_BULLET, DMG_CLUB (corps à corps), DMG_BLAST, DMG_FALL, DMG_BURN, DMG_CRUSH, DMG_SLASH |
:IsBulletDamage(), :IsFallDamage(), :IsExplosionDamage() | Raccourcis |
:GetCause(), :GetHitGroup() | Texte de mort, zone touchée |
-- Moitié des dégâts dans la tête, double dans les jambes, pas de dégâts de chute.
hook.Add("ScalePlayerDamage", "zones", function(ply, hitgroup, dmg)
if hitgroup == HITGROUP_HEAD then dmg:ScaleDamage(0.5) elseif hitgroup == HITGROUP_LEFTLEG then dmg:ScaleDamage(2) end
if dmg:IsFallDamage() then return true end
end)
PlayerHurt
Après chaque dégât sur un joueur, y compris le coup fatal : attaquant (ou nil), la vie restante et les dégâts subis.
hook.Add("PlayerHurt", "monmode_touche", function(ply, attaquant, vie, degats)
if IsValid(attaquant) and attaquant ~= ply then
attaquant:ChatPrint("Touché ! " .. degats .. " dégâts (" .. vie .. " PV restants)")
end
end)
OnPlayerHitGround et GetFallDamage
Serveur : un joueur touche le sol après une chute. OnPlayerHitGround(ply, dansEau, surFlotteur, vitesse) (vitesse de chute en m/s ; surFlotteur vaut toujours false) : renvoie true pour qu'il ne prenne aucun dégât. Sinon, au-delà d'environ 13,4 m/s, GetFallDamage(ply, vitesse) peut renvoyer les dégâts (10 par défaut ; 0 = aucun). OnPlayerHitGround est appelé dès 2 m/s si un hook ou le gamemode l'utilise.
-- Dégâts de chute qui grandissent avec la vitesse.
hook.Add("GetFallDamage", "chute_realiste", function(ply, vitesse)
return math.floor((vitesse - 13) * 8)
end)
PlayerDeath
Un joueur vient de mourir. cause est la fin de la phrase affichée dans le chat, par exemple "s'est écrasé au sol", "s'est suicidé", "est mort" ou "a été abattu par Alex (pistolet)". attaquant est le tueur (arme du jeu), sinon nil ; il gagne automatiquement un point (Frags).
PlayerDeathNotice
Avant l'annonce d'une mort dans le chat. Renvoie false (ou "") pour ne rien annoncer, ou un texte pour remplacer l'annonce (une phrase complète).
hook.Add("PlayerDeathNotice", "monmode_annonce", function(ply, cause, attaquant)
if attaquant then return attaquant:Nick() .. " a éliminé " .. ply:Nick() .. "." end
return false -- les autres morts restent discrètes
end)
AddDeathNotice et DrawDeathNotice
Client, pour le fil des éliminations en haut à droite. AddDeathNotice(tueur, équipeTueur, inflicteur, victime, équipeVictime) : une mort arrive ; les noms sont des textes (tueur vaut "" et son équipe -1 s'il n'y a personne ; un PNJ tueur donne son nom), inflicteur la classe de l'arme du tueur ou la cause ("fall", "explosion", "suicide"…). Un hook qui renvoie une valeur, ou une fonction GM:AddDeathNotice, remplace l'ajout au fil par défaut. DrawDeathNotice(x, y) (position du fil en fractions de l'écran) est appelé pendant HUDPaint quand le fil a des lignes : renvoyer une valeur le cache.
-- Remplace le fil par des lignes de chat.
hook.Add("AddDeathNotice", "fil_chat", function(tueur, eqT, arme, victime, eqV)
chat.AddText(Color(255, 120, 80), tueur ~= "" and (tueur .. " [" .. arme .. "] ") or "", Color(255, 255, 255), victime)
return true
end)
CanPlayerSuicide
Un joueur tape /kill : renvoie false pour l'en empêcher (par exemple pendant une manche).
PlayerChangedTeam
Après ply:SetTeam, si l'équipe change : ply, ancienne, nouvelle.
hook.Add("PlayerChangedTeam", "monmode_equipe", function(ply, ancienne, nouvelle)
PrintMessage(ply:Nick() .. " rejoint " .. team.GetName(nouvelle))
end)
PlayerCanRespawn
Un joueur mort clique pour réapparaître. Renvoie false pour refuser : il reste mort, par exemple jusqu'à la fin de la manche. ply:Spawn() le fait toujours réapparaître.
EntityTakeDamage
Une arme touche un prop : balles, coups, projectiles et explosions, des armes du jeu comme des armes d'addon. attaquant est le tireur, dégâts ce qu'aurait pris un joueur (après la baisse avec la distance) et arme l'id de l'arme. Renvoie true pour que le prop ne soit pas poussé. Aussi lancé par ent:TakeDamage(montant, attaquant, inflicteur) (avec arme = l'inflicteur, sans poussée). Ensuite, si aucun hook n'a renvoyé true, le jeu appelle ENT:OnTakeDamage(dmginfo) de l'entité scriptée touchée. Voir l'exemple Prop Hunt dans Objets.
PlayerSay
Un joueur envoie un message dans le chat (hors commandes /…, qui passent par concommand).
- Renvoie un texte pour remplacer le message.
- Renvoie
""(texte vide) pour bloquer le message. - Ne renvoie rien pour le laisser passer tel quel.
hook.Add("PlayerSay", "monaddon_filtre", function(ply, texte)
if string.find(string.lower(texte), "gros mot") then
ply:ChatPrint("Message bloqué.")
return ""
end
end)
PlayerCanSeePlayersChat
Pour chaque joueur qui pourrait lire un message du chat : renvoie false pour que cet auditeur ne le voie pas (chat de proximité, chat des morts…). équipeSeulement vaut toujours false.
-- Chat de proximité : 20 m.
hook.Add("PlayerCanSeePlayersChat", "monmode_proximite", function(texte, equipe, auditeur, auteur)
if IsValid(auteur) and auditeur:GetPos():Distance(auteur:GetPos()) > 20 then return false end
end)
PlayerCanHearPlayersVoice
Chat vocal : parleur parle (touche X par défaut, modifiable dans Options → Touches) et le serveur demande si auditeur peut l'entendre. Renvoie false pour qu'il ne l'entende pas ; ne renvoie rien pour laisser tout le monde s'entendre. La réponse est gardée une seconde pour chaque paire de joueurs. En plus de cette règle, chaque joueur peut couper la voix d'un autre pour lui seul (maintenir Tab et cliquer sur son micro dans le tableau des scores) et choisir des voix en 3D, qui viennent de la tête du joueur et baissent avec la distance (Options → Audio, activé par défaut).
-- Chacun n'entend que son équipe.
hook.Add("PlayerCanHearPlayersVoice", "monmode_equipes", function(auditeur, parleur)
return auditeur:Team() == parleur:Team()
end)
PlayerDisconnected
Un joueur quitte la partie. Il est encore valide pendant l'appel (tu peux lire son nom, ses props…).
PlayerSpawnProp
Un joueur demande à faire apparaître un prop : depuis le menu de spawn, en collant une dupe, ou en posant un gadget avec le toolgun (gadget:thruster…). Renvoie false pour refuser. N'est pas appelé pour ents.SpawnProp.
hook.Add("PlayerSpawnProp", "monaddon_pas_de_beton", function(ply, modele)
if modele == "builtin:concrete_block" then
ply:ChatPrint("Le béton est interdit ici !")
return false
end
end)
PropSpawned
Un prop vient d'apparaître. ply est le joueur qui l'a créé, ou nil s'il vient de ents.SpawnProp ou de la map (props posés dans l'éditeur). Teste toujours if ply then avant d'utiliser le joueur.
PlayerSpawnedProp
Serveur : le nom de Garry's Mod pour PropSpawned quand un joueur a créé le prop : ply, modèle (l'id du prop) et l'entité. Pas d'appel pour ents.SpawnProp ni pour les props de la map.
OnEntityCreated
Serveur et client : un prop, un véhicule ou une entité scriptée vient d'apparaître (y compris ceux de la map et de ents.SpawnProp). Appelé à l'image suivante, quand l'entité est prête ; pas pour les joueurs ni les PNJ. Seulement si un hook ou le gamemode l'utilise.
Physgun et toolgun
Serveur. PhysgunDrop(ply, prop) : le joueur lâche un prop du physgun (information). OnPhysgunFreeze(ply, prop) : clic droit en tenant un prop ; false le lâche sans le figer. CanPlayerUnfreeze(ply, prop) : R au physgun sur un prop figé ; false le garde figé.
CanTool
Serveur et client, avant chaque action du toolgun (outils du jeu et outils Lua ; clic, clic droit, R). outil est l'id de l'outil ("remover", "color", "weld"…, ou le nom d'un outil Lua). Renvoie false pour refuser ; pour une contrainte, le hook est appelé pour chacun des deux props. Côté client, l'action refusée n'est même pas envoyée.
-- Seul le propriétaire (ou un admin) peut modifier un prop.
hook.Add("CanTool", "proprio", function(ply, trace, outil)
local ent = trace and trace.Entity
if IsValid(ent) and ent:GetOwner() ~= ply and not ply:IsAdmin() then
if SERVER then ply:ChatPrint("Ce prop n'est pas à toi.") end
return false
end
end)
PlayerUse
Serveur : le joueur appuie sur E en visant un prop à portée (4 m du bord du prop, plus pour un véhicule). Renvoie false pour bloquer l'usage : monter dans un véhicule, ENT:Use, bouton d'un gadget, ramasser une arme au sol. 8 usages par seconde au plus.
PlayerSwitchWeapon
Serveur et client : le joueur change d'arme (ancienne et nouvelle sont des ids : "pistol", une classe Lua…). Renvoie true pour bloquer le changement (client : avant le changement ; serveur : le joueur est renvoyé sur l'ancienne arme). ply:SelectWeapon côté serveur ne passe pas par ce hook.
PlayerCanPickupWeapon
Serveur : le joueur marche sur une arme au sol ou la vise avec E. Renvoie false pour qu'il ne la ramasse pas. Voir Armes au sol.
EntityRemoved
Serveur et client : un prop ou une entité va disparaître. Elle est encore valide pendant l'appel.
EntityNetworkedVarChanged
Serveur et client : une variable NW a changé (ent, nom, ancienne, nouvelle), après le proxy de ent:SetNWVarProxy. Côté client, à l'arrivée de la nouvelle valeur. Pour une variable globale (SetGlobal…), ent vaut nil.
ShouldCollide
Sur chaque machine (le serveur, et chaque joueur pour ce qu'il simule) : un corps arrive à moins de 50 cm d'une entité marquée par ent:SetCustomCollisionCheck(true). Renvoie false pour que les deux se traversent (jusqu'à ent:CollisionRulesChanged()). Le même code doit donner la même réponse partout : mets-le dans un fichier partagé. Voir Entités scriptées.
hook.Add("ShouldCollide", "fantome", function(a, b)
if a:GetClass() == "mur_fantome" and istable(b) and b.IsPlayer and b:IsPlayer() then return false end
end)
EntityEmitSound
Serveur et client, avant chaque son joué par Lua (ent:EmitSound, sound.Play), seulement si un hook ou le gamemode l'utilise. données : SoundName, OriginalSoundName, Pos, SoundLevel, Pitch, Volume, Entity. Renvoie false pour bloquer le son, true pour le jouer avec les champs que tu as changés.
-- Tous les sons plus graves pendant le ralenti.
hook.Add("EntityEmitSound", "ralenti", function(data)
if GetGlobalBool("ralenti") then data.Pitch = data.Pitch * 0.6 return true end
end)
EntityFireBullets
Serveur et client : une arme Lua tire avec SWEP:FireBullets(balle) (aussi SWEP:ShootBullet, qui passe par là). tireur est le joueur, balle la table { Damage, Num, Spread, Distance, Force }. Renvoie false pour annuler le tir, true (ou rien) pour l'appliquer avec la table modifiée.
-- Munitions explosives : double dégâts pour tout le monde.
hook.Add("EntityFireBullets", "double", function(tireur, balle)
balle.Damage = (balle.Damage or 10) * 2
return true
end)
PhysgunPickup
Un joueur essaie d'attraper un prop, un véhicule ou un PNJ (ent:IsNPC()) avec le physgun. Renvoie false pour l'en empêcher. Ce hook passe après la protection des props (qui a déjà refusé les props des autres selon les règles du serveur) : il ne peut que refuser en plus. Les PNJ ne sont attrapables que si le gamemode le permet : Base les refuse, Sandbox les accepte (en multijoueur, la protection décide pour ceux des autres). Un PNJ tenu reste debout, suit le faisceau et retombe quand on le lâche (le clic droit le lâche aussi : un PNJ ne se fige pas).
-- Les props lourds ne s'attrapent pas, même les siens.
hook.Add("PhysgunPickup", "monaddon_lourds", function(ply, ent)
if ent.GetMass and ent:GetMass() > 2000 then -- les PNJ n'ont pas de GetMass
return false
end
end)
ProtectionCanTouch
Serveur (et client, pour l'affichage à côté du viseur et le refus immédiat) : avant chaque règle de la protection des props. ent est un prop, un véhicule ou un PNJ ; action vaut "physgun", "toolgun", "use", "damage" ou "enter" (monter dans un véhicule). Renvoie true pour autoriser, false pour refuser (même au propriétaire), rien pour laisser décider les règles du menu. Les hooks PhysgunPickup, CanTool, PlayerUse… passent ensuite. Pour couper toute la protection dans un gamemode : GM.PropProtection = false (dans shared.lua, pour que les joueurs le sachent aussi).
-- Gamemode RP : la police peut fouiller (toolgun) et déplacer tous les véhicules.
hook.Add("ProtectionCanTouch", "rp_police", function(ply, ent, action)
if ply:Team() == TEAM_POLICE and ent.IsVehicle and ent:IsVehicle() and (action == "physgun" or action == "toolgun") then
return true
end
end)
PlayerButtonDown
Un joueur appuie sur une touche ou un bouton de souris (PlayerButtonUp quand il la relâche). touche est un code KEY_* ou MOUSE_*. Côté client, seulement pour son propre joueur ; côté serveur, pour chaque joueur. Pas d'appel pendant la saisie de texte ni dans les menus du jeu. Voir Touches et souris.
hook.Add("PlayerButtonDown", "monaddon_f3", function(ply, touche)
if CLIENT and touche == KEY_F3 then
Derma_Message("Bienvenue sur le serveur !", "Aide")
end
end)
KeyPress et KeyRelease
Serveur et client : le joueur appuie sur une action du jeu (IN_JUMP, IN_ATTACK, IN_USE…) puis la relâche. Contrairement à PlayerButtonDown (touches physiques KEY_*), ces constantes suivent les touches choisies par le joueur. Côté serveur pour chaque joueur, côté client pour son propre joueur. Liste des constantes et ply:KeyDown : voir Objets.
hook.Add("KeyPress", "monmode_utiliser", function(ply, touche)
if SERVER and touche == IN_RELOAD and ply:KeyDown(IN_SPEED) then
ply:ChatPrint("Rechargement rapide !")
end
end)
PlayerSwitchFlashlight
Serveur : le joueur appuie sur la touche de la lampe torche (F). allumée est le nouvel état demandé ; renvoie false pour refuser.
hook.Add("PlayerSwitchFlashlight", "monmode_lampe", function(ply, allumee)
if allumee and ply:Team() == 2 then return false end -- les chasseurs n'ont pas de lampe
end)
PlayerStartGesture
Serveur : un joueur lance un geste lui-même (roue d'emotes G, ou ply:PlayGesture côté client). nom est le nom du geste ("dance", "sit"…, voir Taille et gestes) ; renvoie false pour refuser. Un ply:PlayGesture appelé par le serveur ne passe pas par ce hook.
hook.Add("PlayerStartGesture", "monmode_gestes", function(ply, nom)
if ply:Team() == 2 then return false end -- pas de gestes pour les chasseurs
end)
TriggerStartTouch et TriggerEndTouch
Serveur : un joueur ou un prop entre dans une zone déclencheur placée dans l'éditeur de map, puis en sort. Voir Points, zones et entités de map.
CanExitVehicle
Serveur : un joueur appuie sur E pour descendre d'un véhicule. Renvoie false pour l'en empêcher ; veh:EjectAll() et ply:ExitVehicle() restent possibles.
CanUndo
Serveur : le joueur appuie sur Annuler. entrée est la dernière entrée de sa pile : une entrée undo.Create (Name, Entities, Functions, Owner, CustomUndoText), ou une table de même forme pour celles du jeu (Name = "Prop", "Dupe", "NPC" ou "Constraint"). false la garde : le joueur lit « Impossible d'annuler : nom. »
OnUndo
Serveur : une annulation vient de réussir. nom et texte valent tous deux le nom de l'entrée (celui du message « Annulé : … »), ply est le joueur.
CanCleanup
Serveur : un bouton de l'onglet Nettoyage ou cleanup.CC_Cleanup / CC_AdminCleanup. catégorie : "props", "vehicles", "npcs", "sents", "constraints", une catégorie de cleanup.Register, ou "" (tout). false refuse. Voir Nettoyage.
CanDuplicate, PreDuplicate et PostDuplicate
Serveur, autour du collage d'une dupe (toolgun, onglet Dupes, duplicator.Paste). CanDuplicate(ply, liste) : liste = { { Class = …, Model = … }, … }, false refuse la dupe entière. PreDuplicate(ply, liste) suit si elle est acceptée. PostDuplicate(ply, créées) : après le collage, avec les entités créées. ply vaut nil pour un collage sans joueur. Voir Dupes.
-- Pas de coffres dans les dupes des joueurs non admins.
hook.Add("CanDuplicate", "pas_de_coffres", function(ply, liste)
if not IsValid(ply) or ply:IsAdmin() then return end
for _, entree in ipairs(liste) do
if entree.Class == "coffre" then return false end
end
end)
PlayerSpawnSENT et PlayerSpawnedSENT
Serveur : un joueur fait apparaître une entité scriptée depuis l'onglet Entités du menu de spawn. PlayerSpawnSENT(ply, classe) : false refuse (« Le mode de jeu n'autorise pas cette entité. »). PlayerSpawnedSENT(ply, ent) : l'entité vient d'apparaître. Voir Entités dans le menu de spawn.
CanProperty
Serveur et client : demandé par les actions "remove" et "freeze" du gamemode Sandbox (et par les propriétés d'addon qui l'appellent dans leur Filter). nom : le nom de la propriété. false la cache du menu contextuel (client) et la refuse (serveur).
EnvChanged
Serveur et client : une fonction env.Set… a changé le soleil, le ciel, l'heure, la lumière ambiante ou le brouillard. quoi dit quoi : "sun_angle", "sun_color", "sun_brightness", "sky_color", "sky_time", "time_scale", "ambient", "fog" ou "sky_texture" (env.SetSkyTexture). Lancé dans le realm qui appelle ; un appel serveur le lance aussi côté client chez chaque joueur. L'horloge qui avance toute seule (env.SetTimeScale) ne le lance pas.
PlayerVRGrab
Serveur : un joueur en réalité virtuelle serre le grip près d'un prop (main : "left" ou "right"), après la protection des props. Renvoie false pour qu'il ne l'attrape pas. PlayerVRDrop(ply, ent, main) : il le lâche (le prop garde sa vitesse).
ClientReady
Client : le joueur vient d'entrer dans la partie (map, addons du serveur et scripts client chargés, écran de chargement du jeu fermé). Appelé à chaque arrivée, et aussi après un changement de map ou de gamemode. Idéal pour un écran de bienvenue ou pour précharger les modèles.
HUDPaint
Client, à chaque image : dessine le HUD avec draw.* et surface.*. Dans l'ordre de GMod : PreDrawHUD, HUDPaintBackground, HUDPaint, puis PostDrawHUD (dessiné par-dessus). Voir Dessiner le HUD.
ChatText
Client : une ligne sans joueur arrive dans le chat (messages du serveur, PrintMessage, arrivées et départs). Arguments : 0, "Console", le texte, et le type "joinleave" (« a rejoint / a quitté la partie ») ou "none". Renvoie true pour cacher la ligne.
HUDShouldDraw
Client : renvoie false pour cacher "Health", "Weapon", "WeaponSelection", "Voice", "Crosshair", "PropOwner", "Damage" ou "Scoreboard" (le tableau des scores du jeu). Voir Cacher des parties du HUD.
SpawnMenuOpen
Client, quand le joueur appuie sur la touche du menu de spawn : false pour l'en empêcher. Base renvoie false, Sandbox true. Côté serveur, PlayerSpawnProp refuse en plus les apparitions.
ScoreboardShow et ScoreboardHide
Client : la touche du tableau des scores (Tab) est enfoncée, puis relâchée. Si ScoreboardShow renvoie true, le gamemode affiche son propre tableau : celui du jeu ne s'ouvre pas (et la souris reste capturée). ScoreboardHide est toujours appelé. Exemple dans Tableau des scores.
OnPlayerChat
Client : une ligne de chat d'un joueur arrive (après PlayerSay sur le serveur). Renvoie true pour cacher la ligne par défaut, par exemple pour l'afficher autrement avec chat.AddText. ply peut être nil (joueur parti) ; équipe vaut toujours false ; mort : le joueur est mort. Exemple dans Chat en couleurs.
CalcView
Client, à chaque image, avec la caméra prévue (ply, origine, angles, fov, znear, zfar). Renvoie une table { origin = Vector, angles = Angle, fov = nombre, drawviewer = booléen } (tous les champs sont facultatifs) pour remplacer la caméra ; ne rien renvoyer garde la caméra normale. drawviewer = true affiche son propre corps (vue de dessus, cinématique).
-- Vue de dessus façon jeu d'arcade.
hook.Add("CalcView", "vue_dessus", function(ply, pos, ang, fov)
return { origin = ply:GetPos() + Vector(0, 15, 0), angles = Angle(-89, 0, 0), fov = 70, drawviewer = true }
end)
CalcViewModelView, PreDrawViewModel et PostDrawViewModel
Client, à chaque image, pour le modèle de vue d'une arme Lua (SWEP.ViewModel). CalcViewModelView(arme, vm, ancPos, ancAng, pos, ang) renvoie pos, ang (dans le monde) pour le déplacer, après SWEP:GetViewModelPosition et SWEP:CalcViewModelView. PreDrawViewModel(vm, ply, arme) : true le cache pour cette image ; PostDrawViewModel(vm, ply, arme) suit. vm vaut toujours nil (pas d'entité de modèle de vue).
Hooks d'animation du joueur
Client, à chaque image, pour chaque joueur, seulement si un hook ou le gamemode les utilise :
CalcMainActivity(ply, vitesse): renvoie le nom d'un clip du playermodel pour remplacer celui que le jeu choisit (il peut aussi être la deuxième valeur, la « séquence » de GMod). Un nom que le modèle n'a pas est ignoré.UpdateAnimation(ply, vitesse, vitesseMax): renvoie une vitesse de lecture (0 à 4).DoAnimationEvent(ply, évènement, action): le joueur tire, frappe, lance, recharge ou sort une arme (action:"fire","attack","throw","reload","draw";évènement: 0 pour un tir, 3 pour un rechargement, 21 pour une arme sortie, comme lesPLAYERANIMEVENT_*de GMod).true: pas de geste ; un nom de clip : ce clip à la place.PrePlayerDraw(ply):truecache le joueur pour cette image ;PostPlayerDraw(ply)suit.
-- Les autres joueurs accroupis sont invisibles.
hook.Add("PrePlayerDraw", "furtif", function(ply)
if ply ~= LocalPlayer() and ply:Crouching() then return true end
end)
PlayerFootstep
Client, à chaque pas d'un joueur (ply, pos, pied, son, volume ; pied : 0 ou 1 ; son : "player/footstep_concrete", …_wood, …_metal ou …_grass). Renvoie true pour ne pas jouer le bruit. Seulement si un hook ou le gamemode l'utilise.
PlayerBindPress
Client : une action du jeu est pressée (appuyé vaut toujours true : le relâchement n'appelle pas ce hook). action est le nom de l'action : "jump", "attack", "attack2", "use", "reload", "spawn_menu", "noclip", "third_person", "flashlight", "chat", "scoreboard", "crouch", "sprint", "move_forward"… (voir Paramètres → Touches). Renvoie true pour bloquer l'action (les déplacements restent bloqués tant que la touche est enfoncée). Pas d'appel pendant la saisie de texte.
-- Pas de saut pendant la préparation.
hook.Add("PlayerBindPress", "pas_de_saut", function(ply, action, appuye)
if action == "jump" and GetGlobalBool("preparation") then return true end
end)
ContextMenuOpen, OnContextMenuOpen et OnContextMenuClose
Client : le joueur maintient la touche Menu contextuel (N par défaut). ContextMenuOpen() : false l'empêche de s'ouvrir. OnContextMenuOpen() : il vient de s'ouvrir ; OnContextMenuClose() : il se ferme (touche relâchée, Échap). Voir Menu contextuel.
AddToolMenuTabs, AddToolMenuCategories et PopulateToolMenu
Client, dans cet ordre, une fois par lancement des scripts, quand le menu de spawn a besoin de ses onglets et options d'outils pour la première fois. C'est là qu'on appelle spawnmenu.AddToolTab, AddToolCategory et AddToolMenuOption. Voir Options d'outils.
Hooks de déplacement
Client, pour le joueur local, à chaque image physique, seulement si un hook ou le gamemode les utilise : StartCommand(ply, cmd), CreateMove(cmd), SetupMove(ply, mv, cmd), Move(ply, mv) (true : le jeu ne déplace pas le joueur, mv donne sa vitesse et sa position), puis FinishMove(ply, mv) après le déplacement. cmd est un CUserCmd, mv un CMoveData. Si le serveur a aussi un de ces hooks (fichier partagé), son anti-triche ne contrôle plus la vitesse ni le vol. Exemple de jetpack dans Déplacement du joueur.
Hooks de rendu
Client, à chaque image, dans cet ordre : PreRender, PreDrawHalos (pour halo.Add), RenderScreenspaceEffects (pour DrawColorModify, DrawBloom…, remis à zéro à chaque image), PostRender. PostDrawOpaqueRenderables et PostDrawTranslucentRenderables servent à cam.Start3D2D et render.Draw*. Le dessin 3D de l'image (render.DrawBeam, mesh…) se fait depuis n'importe lequel de ces hooks. Voir Rendu 3D et effets.
ForceDermaSkin
Client : renvoie le nom d'une peau Derma (derma.DefineSkin) pour qu'elle serve de peau par défaut à tous les panneaux.
Tes propres événements
hook.Run accepte n'importe quel nom : tes addons peuvent s'envoyer des événements.
-- Addon A
hook.Add("MonJeu_ManchePerdue", "addon_a", function(equipe)
PrintMessage("L'équipe " .. equipe .. " a perdu la manche.")
end)
-- Addon B
hook.Run("MonJeu_ManchePerdue", "rouge")