diff options
| -rw-r--r-- | docs/es/hooks-script.md | 38 | ||||
| -rw-r--r-- | docs/hooks-script.md | 105 |
2 files changed, 73 insertions, 70 deletions
diff --git a/docs/es/hooks-script.md b/docs/es/hooks-script.md index 9ded3f6..699b3e1 100644 --- a/docs/es/hooks-script.md +++ b/docs/es/hooks-script.md @@ -2,7 +2,7 @@ El sistema ScriptAI implementado por AC utiliza una estrategia especial: [Patrón del observador](https://en.wikipedia.org/wiki/Observer_pattern) para implementar una programación dirigida por eventos que es también el **CORE** de nuestro sistema modular. -Esta guía, junto con nuestro [sistema de módulos] (create-a-module.md) te permite ampliar el AzerothCore sin parchearlo directamente. ¡Esto le permite actualizar su repositorio manteniendo sus adiciones y personalizaciones libres de conflictos! +Esta guía, junto con nuestro [sistema de módulos](create-a-module.md) te permite ampliar el AzerothCore sin parchearlo directamente. ¡Esto le permite actualizar su repositorio manteniendo sus adiciones y personalizaciones libres de conflictos! ## Recursos @@ -15,7 +15,7 @@ La lista de los hooks se encuentra dentro del archivo [ScriptMgr.h](https://gith - **Hook**: Una función que se declara dentro de un **_ScriptObject_** y que es definida por el **_Listeners_** - **ScriptObject**: Clase abstracta que debe ser extendida para crear el **_Observer_**. - **Script type**: La clase que extiende el `ScriptObject` y contiene hooks (por ejemplo, `PLayerScript`, `CreatureScript`, etc.), cuando extiendes la clase de tipo script estás inicializando un **_Concrete Observer_** -- **ScriptRegistry**: Esta clase contiene el registro de todos los Observadores registrados. +- **ScriptRegistry**: Esta clase contiene el registro de todos los `Observers` registrados. - **ScriptMgr**: La clase singleton que contiene la lista de todos los hooks disponibles y actúa como un **_Observer_** notificando a los **_Listeners_** cuando se despacha un evento. ## Cómo crear un hook @@ -42,7 +42,7 @@ Sin embargo, la mayoría de las veces sólo tienes que añadir nuevos hooks a lo ### 1) Procedimiento estándar al añadir nuevas clases de scripts -En primer lugar, define la clase actual, y haz que herede de ScriptObject, así: +En primer lugar, define la clase actual, y haz que herede de `ScriptObject`, así: ```cpp class MyScriptType : public ScriptObject @@ -106,7 +106,7 @@ void OnBeforeSomeEvent(uint32 someArg1, std::string& someArg2); void OnAnotherEvent(uint32 someArg); ``` -**NOTA:** para ciertos scripts el método declarado dentro de la clase ScriptMgr y el declarado en el ScriptObject relacionado, no siempre coinciden. Por ejemplo: `OnLogin` es un hook del PlayerScript que se declara como `OnPlayerLogin` cuando se utiliza dentro de la clase ScriptMgr, evitando así colisiones con otros métodos ya que la clase ScriptMgr recoge los hooks de todos los ScriptObjects dentro de la misma lista. +**NOTA:** para ciertos scripts el método declarado dentro de la clase `ScriptMgr` y el declarado en el `ScriptObject` relacionado, no siempre coinciden. Por ejemplo: `OnLogin` es un hook del PlayerScript que se declara como `OnPlayerLogin` cuando se utiliza dentro de la clase `ScriptMgr`, evitando así colisiones con otros métodos ya que la clase `ScriptMgr` recoge los hooks de todos los `ScriptObjects` dentro de la misma lista. #### Defina sus hooks @@ -121,6 +121,7 @@ void ScriptMgr::OnBeforeSomeEvent(uint32 someArg1, std::string& someArg2) { FOREACH_SCRIPT(MyScriptType)->OnBeforeSomeEvent(someArg1, someArg2); } + void ScriptMgr::OnAnotherEvent(uint32 someArg) { FOREACH_SCRIPT(MyScriptType)->OnAnotherEvent(someArg); @@ -131,7 +132,7 @@ Ahora basta con llamar a estas dos funciones desde cualquier lugar del core para ### Cómo llamar a tus hooks -La clase ScriptMgr se inicializa dentro del AC como un singleton que contendrá todos los observers (ScriptObjects) y sus listeners registrados relacionados (hooks). AC proporciona una propiedad global llamada "sScriptMgr" que puede utilizar para llamar a su script dentro de las funciones de AC. +La clase `ScriptMgr` se inicializa dentro del AC como un singleton que contendrá todos los observers (ScriptObjects) y sus listeners registrados relacionados (hooks). AC proporciona una propiedad global llamada "sScriptMgr" que puede utilizar para llamar a su script dentro de las funciones de AC. Por ejemplo: @@ -151,7 +152,7 @@ void CoreClass::SomeEvent() Recuerda documentar tu nuevo hook siguiendo la guía [Cómo documentar tu código](how-to-document-code.md). -Cuando creas un nuevo hook para publicarlo en el repo de AC, uno de los criterios de aceptación es escribir una documentación adecuada para él, para que otras personas sepan cómo usarlo correctamente. Así que, por favor, lee esa guía con atención. +Cuando creas un nuevo hook para publicarlo en el repo de `AzerothCore`, uno de los criterios de aceptación es escribir una documentación adecuada para él, para que otras personas sepan cómo usarlo correctamente. Así que, por favor, lee esa guía con atención. ### Escribir un registro de cambios @@ -159,7 +160,7 @@ Cuando creas o modificas cualquier hook, tienes que crear un nuevo changelog par ## Convenciones de nomenclatura -Cada hook debe tener la siguiente convención de nombres: +Cada `hook` debe tener la siguiente convención de nombres: `On[When]<Action>` @@ -168,13 +169,13 @@ Por ejemplo: - `OnBeforeConfigLoad` - `OnAfterArenaRatingCalculation` -La acción normalmente coincide con el nombre de la función dentro de la cual se llama al hook. +La acción normalmente coincide con el nombre de la función dentro de la cual se llama al `hook`. -Si la función madre es lo suficientemente compleja como para contener diferentes hooks, entonces la acción debe reflejar para qué se utiliza el hook. +Si la función madre es lo suficientemente compleja como para contener diferentes hooks, entonces la acción debe reflejar para qué se utiliza el `hook`. La parte "Cuando" es opcional, pero se recomienda encarecidamente. -Ayuda a entender en qué parte de la función padre se llama al hook. +Ayuda a entender en qué parte de la función padre se llama al `hook`. Por ejemplo, puedes tener tanto `OnBeforeConfigLoad` como `OnAfterConfigLoad`, para cambiar el comportamiento antes y después de cargar la configuración. @@ -182,11 +183,11 @@ Por ejemplo, puedes tener tanto `OnBeforeConfigLoad` como `OnAfterConfigLoad`, p ### Cómo cambiar el comportamiento de una función (filtrado) -Con los hooks no sólo puedes ejecutar acciones específicas en un momento determinado, incluso puedes cambiar el comportamiento de la función donde se llama al hook para hacerlo, tienes 2 soluciones: +Con los hooks no sólo puedes ejecutar acciones específicas en un momento determinado, incluso puedes cambiar el comportamiento de la función donde se llama al `hook` para hacerlo, tienes 2 soluciones: #### 1) Utilización de los parámetros de referencia -Este es el más común. Básicamente utilizando el concepto de pasar un parámetro por referencia se puede cambiar todo lo que se pasa al propio hook. +Este es el más común. Básicamente utilizando el concepto de pasar un parámetro por referencia se puede cambiar todo lo que se pasa al propio `hook`. Por ejemplo: @@ -194,16 +195,17 @@ Por ejemplo: OnMotdChange(std::string& newMotd) ``` -Pasando el `newMotd` con el carácter '&' se permite a los listeners cambiar el valor del Motd cuando se llama a esa acción. +Pasando el `newMotd` con el carácter '&' se permite a los listeners cambiar el valor del `Motd` cuando se llama a esa acción. #### 2) Utilizar un valor de retorno `bool` -Este enfoque no es muy común, la mayoría de los hooks devuelven un tipo "void", y trabajar con referencias es más fácil la mayoría de las veces, pero si realmente lo necesitas puedes implementar un hook declarado de esta manera: +Este enfoque no es muy común, la mayoría de los hooks devuelven un tipo **"void"**, y trabajar con referencias es más fácil la mayoría de las veces, pero si realmente lo necesitas puedes implementar un hook declarado de esta manera: ```cpp bool ScriptMgr::OnBeforePlayerTeleport(Player* player, uint32 mapid, float x, float y, float z, float orientation, uint32 options, Unit* target) { bool ret = true; + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // Devuelve true por defecto si no son scripts if (!itr->second->OnBeforeTeleport(player, mapid, x, y, z, orientation, options, target)) ret = false; // Cambiamos el valor de ret sólo cuando los scripts devuelven false @@ -212,7 +214,7 @@ bool ScriptMgr::OnBeforePlayerTeleport(Player* player, uint32 mapid, float x, fl } ``` -Este hook notifica a todos los listeners pero también captura cuando al menos uno de los listeners registrados devuelve "false", en ese caso el valor de retorno final también será false. +Este hook notifica a todos los listeners pero también captura cuando al menos uno de los listeners registrados devuelve **"false"**, en ese caso el valor de retorno final también será false. En este caso particular, este hook se utiliza dentro de una condición if para no permitir que un jugador sea teletransportado si uno de los listeners devuelve **false** por alguna razón. @@ -220,17 +222,17 @@ Puedes implementar tu lógica diferente (por ejemplo, falso por defecto, verdade ### Cree su sistema de hooks dentro de su módulo -Usando la guía anterior puedes incluso crear tu ScriptObject dentro de tu módulo para permitir que la gente lo extienda. +Usando la guía anterior puedes incluso crear tu `ScriptObject` dentro de tu módulo para permitir que la gente lo extienda. Algunos módulos, como el de balance automático, permiten personalizar cierta parte de su función mediante el uso de hooks internos. Puede ver este archivo como ejemplo: https://github.com/azerothcore/mod-autobalance/blob/master/src/AutoBalance.h -**NOTA:** También necesitas crear tu propia implementación de ScriptMgr y ofrecer un singleton que permita llamar a tus hooks. +**NOTA:** También necesitas crear tu propia implementación de `ScriptMgr` y ofrecer un singleton que permita llamar a tus hooks. ### Consideraciones finales -Existen otras características del sistema ScriptAI que no han sido incluidas en esta documentación, como la creación de scripts vinculados a entidades específicas dentro de nuestra base de datos (Ej. CreatureScript). Este uso avanzado puede ser implementado replicando el código relacionado que tenemos dentro de los archivos ScriptMgr. Si necesitas ayuda o quieres mejorar esta documentación, no dudes en pedir apoyo y editar esta página. +Existen otras características del sistema `ScriptAI` que no han sido incluidas en esta documentación, como la creación de scripts vinculados a entidades específicas dentro de nuestra base de datos (Ej. `CreatureScript`). Este uso avanzado puede ser implementado replicando el código relacionado que tenemos dentro de los archivos `ScriptMgr`. Si necesitas ayuda o quieres mejorar esta documentación, no dudes en pedir apoyo y editar esta página. ## Recursos externos diff --git a/docs/hooks-script.md b/docs/hooks-script.md index f3885ef..3df1cfa 100644 --- a/docs/hooks-script.md +++ b/docs/hooks-script.md @@ -31,11 +31,13 @@ Don't worry! is not scary as you may think! Before going through the next step you should ask yourself: do I have to create a new script type based on `ScriptObject` class or can I reuse one of those already existing? -A script type is normally strictly related to a certain class of the core. For example: +A script type is normally strictly related to a certain class of the core. For example: + - `PlayerScript` -> `Player` class - `WorldScript` -> `World` class - `CreatureScript` -> `Creature` class -and so on. + +And so on. There are some exceptions such as the `GlobalScript` which is an Observer used in different classes throughout the core. But generally speaking, a script type should refer to a specific class. @@ -46,32 +48,33 @@ However, most of the time you just have to add new hooks to existing scripts, in ### 1) Standard procedure when adding new script type classes First of all, define the actual class, and have it inherit from ScriptObject, like so: - - ```cpp - class MyScriptType : public ScriptObject - { - uint32 _someId; - private: - void RegisterSelf(); - protected: - MyScriptType(const char* name, uint32 someId) - : ScriptObject(name), _someId(someId) - { - ScriptRegistry<MyScriptType>::AddScript(this); - } - public: - // If a virtual function in your script type class is not necessarily - // required to be overridden, just declare it virtual with an empty - // body. If, on the other hand, it's logical only to override it (i.e. - // if it's the only method in the class), make it pure virtual, by adding - // = 0 to it. - virtual void OnBeforeSomeEvent(uint32 /*someArg1*/, std::string& /*someArg2/*) { } - // This is a pure virtual function: - virtual void OnAnotherEvent(uint32 /*someArg*/) = 0; - } + +```cpp +class MyScriptType : public ScriptObject +{ + uint32 _someId; + private: + void RegisterSelf(); + protected: + MyScriptType(const char* name, uint32 someId) + : ScriptObject(name), _someId(someId) + { + ScriptRegistry<MyScriptType>::AddScript(this); + } + public: + // If a virtual function in your script type class is not necessarily + // required to be overridden, just declare it virtual with an empty + // body. If, on the other hand, it's logical only to override it (i.e. + // if it's the only method in the class), make it pure virtual, by adding + // = 0 to it. + virtual void OnBeforeSomeEvent(uint32 /*someArg1*/, std::string& /*someArg2/*) { } + // This is a pure virtual function: + virtual void OnAnotherEvent(uint32 /*someArg*/) = 0; +} ``` Next, you need to add a specialization for ScriptRegistry. Put this at the beginning of ScriptMgr.cpp: + ```cpp template class ScriptRegistry<MyScriptType>; ``` @@ -85,7 +88,7 @@ MyScriptType::MyScriptType(const char* name) ScriptRegistry<MyScriptType>::AddScript(this); } ``` - + Then add a cleanup routine in `ScriptMgr::unload()` ``` @@ -96,24 +99,20 @@ And finally your class is good to go with the script system! ### 2) Implement the hooks functions -If you didn't follow point 1 and you want to reuse an existing ScriptObject, then you have to declare the functions -within one of the pre-existing ScriptObject classes first (such as PlayerScript, ServerScript etc.) - +If you didn't follow point 1 and you want to reuse an existing ScriptObject, then you have to declare the functions within one of the pre-existing ScriptObject classes first (such as PlayerScript, ServerScript etc.) + #### Declare your hooks -What you need to do now is add functions to ScriptMgr that can be called from the core to actually trigger -certain events. -In ScriptMgr.h , inside the `class ScriptMgr` +What you need to do now is add functions to ScriptMgr that can be called from the core to actually trigger certain events. + +In ScriptMgr.h, inside the `class ScriptMgr` ```cpp void OnBeforeSomeEvent(uint32 someArg1, std::string& someArg2); void OnAnotherEvent(uint32 someArg); ``` -NOTE: for certain scripts the method declared inside the ScriptMgr class and the one declared into the related ScriptObject, -don't always match. For instance: `OnLogin` is a hook from the PlayerScript that is declared as `OnPlayerLogin` when -used inside the ScriptMgr class, thus avoid collisions with other methods since the ScriptMgr class collects hooks from all -the ScriptObjects within the same list. +**NOTE:** for certain scripts the method declared inside the ScriptMgr class and the one declared into the related ScriptObject, don't always match. For instance: `OnLogin` is a hook from the PlayerScript that is declared as `OnPlayerLogin` when used inside the ScriptMgr class, thus avoid collisions with other methods since the ScriptMgr class collects hooks from allnthe ScriptObjects within the same list. #### Define your hooks @@ -127,6 +126,7 @@ void ScriptMgr::OnBeforeSomeEvent(uint32 someArg1, std::string& someArg2) { FOREACH_SCRIPT(MyScriptType)->OnBeforeSomeEvent(someArg1, someArg2); } + void ScriptMgr::OnAnotherEvent(uint32 someArg) { FOREACH_SCRIPT(MyScriptType)->OnAnotherEvent(someArg); @@ -139,6 +139,7 @@ event on all registered scripts of that type. ### How to call your hooks The ScriptMgr class is initialized within the AC as a singleton that will contain all the observers (ScriptObjects) and their related registered listeners (hooks). + AC provides a global property called "sScriptMgr" that you can use to call your script within the AC functions. For instance: @@ -150,7 +151,7 @@ void CoreClass::SomeEvent() std::string arg2="something"; sScriptMgr->OnBeforeSomeEvent(arg1, arg2); - + //[...] } ``` @@ -159,9 +160,7 @@ void CoreClass::SomeEvent() Remember to document your new hook by following the [How to document your code](how-to-document-code.md) guide. -When you create a new hook to publish into the AC repo, one of the acceptance criteria is to write proper documentation for it, -hence other people know how to use it properly. So please, read that guide carefully. - +When you create a new hook to publish into the AC repo, one of the acceptance criteria is to write proper documentation for it, hence other people know how to use it properly. So please, read that guide carefully. ### Write a changelog @@ -180,20 +179,20 @@ For example: * `OnAfterArenaRatingCalculation` The action normally matches the name of the function within which the hook is called. -If the parent function is complex enough to even host different hooks, then the action -should reflect what the hook is used for. + +If the parent function is complex enough to even host different hooks, then the action should reflect what the hook is used for. The `[When]` part is optional, but strongly suggested. + It helps to understand in which part of the parent function the hook is called. -For instance, you can have both `OnBeforeConfigLoad` and `OnAfterConfigLoad`, -to change the behaviour before and after the config is loaded. + +For instance, you can have both `OnBeforeConfigLoad` and `OnAfterConfigLoad`, to change the behaviour before and after the config is loaded. ## Advanced hooks ### How to change the behaviour of a function (filtering) -With hooks you can't only run specific actions at a specific time, you can even change the behaviour of the function where the hook is called -To do so, you have 2 solutions: +With hooks you can't only run specific actions at a specific time, you can even change the behaviour of the function where the hook is called to do so, you have 2 solutions: #### 1) Using reference parameters @@ -202,7 +201,7 @@ For instance: ```cpp OnMotdChange(std::string& newMotd) -``` +``` Passing the newMotd with the '&' character you allow the listeners to change the value of the Motd when that action is called. @@ -214,6 +213,7 @@ This approach is not very common, most of the hooks return a "void" type, and wo bool ScriptMgr::OnBeforePlayerTeleport(Player* player, uint32 mapid, float x, float y, float z, float orientation, uint32 options, Unit* target) { bool ret = true; + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts if (!itr->second->OnBeforeTeleport(player, mapid, x, y, z, orientation, options, target)) ret = false; // we change ret value only when scripts return false @@ -223,24 +223,25 @@ bool ScriptMgr::OnBeforePlayerTeleport(Player* player, uint32 mapid, float x, fl ``` This hook notifies all the listeners but also catches when at least one of the registered listener returns "false", in that case the final return value will be false as well. + In this particular case, this hook is used within an if-condition to disallow a player to be teleported if one of the listeners returns **false** for some reason. You can implement your different logic (e.g. false by default, true if any) just remember to document it properly! ### Create your hook system within your module -By using the guide above you can even create your ScriptObject within your module to allow people to extend it. +By using the guide above you can even create your ScriptObject within your module to allow people to extend it. + Some modules, such as the auto-balance, allows customizing certain part of their function by using internal hooks You can take a look at this file as an example: https://github.com/azerothcore/mod-autobalance/blob/master/src/AutoBalance.h -NOTE: You also need to create your own ScriptMgr implementation and offer a singleton to allow calling your hooks. - +**NOTE:** You also need to create your own ScriptMgr implementation and offer a singleton to allow calling your hooks. ### Final considerations -There are different other features of the ScriptAI system that have not been included in this documentation, such as the creation of scripts bound -to specific entities inside our database (E.g. CreatureScript). This advanced usage can be implemented by replicate the related code we have inside the ScriptMgr files. +There are different other features of the ScriptAI system that have not been included in this documentation, such as the creation of scripts bound to specific entities inside our database (E.g. CreatureScript). This advanced usage can be implemented by replicate the related code we have inside the ScriptMgr files. + If you need any help or you want to improve this documentation, feel free to ask for support and edit this page. ## External resources |
