Skip to content

Commit b14d9a7

Browse files
authored
Merge pull request #178 from Source-Python-Dev-Team/plugins_changes
Plugins changes
2 parents 3817074 + 21f6236 commit b14d9a7

26 files changed

+829
-514
lines changed

addons/source-python/docs/source-python/source/developing/module_tutorials/listeners.rst

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,21 +372,50 @@ Called when a plugin has been loaded successfully.
372372
from listeners import OnPluginLoaded
373373
374374
@OnPluginLoaded
375-
def on_plugin_loaded(plugin_name):
375+
def on_plugin_loaded(plugin):
376+
pass
377+
378+
379+
OnPluginLoading
380+
---------------
381+
382+
Called right before a plugin is imported and loaded. All checks (e.g. plugin
383+
file exists, etc.) have been done at this point.
384+
385+
.. code-block:: python
386+
387+
from listeners import OnPluginLoading
388+
389+
@OnPluginLoading
390+
def on_plugin_loading(plugin):
376391
pass
377392
378393
379394
OnPluginUnloaded
380395
----------------
381396

382-
Called when a plugin has been unloaded.
397+
Called when a plugin has been unloaded sucessfully.
383398

384399
.. code-block:: python
385400
386401
from listeners import OnPluginUnloaded
387402
388403
@OnPluginUnloaded
389-
def on_plugin_unloaded(plugin_name):
404+
def on_plugin_unloaded(plugin):
405+
pass
406+
407+
408+
OnPluginUnloading
409+
-----------------
410+
411+
Called right before a loaded plugin is unloaded.
412+
413+
.. code-block:: python
414+
415+
from listeners import OnPluginUnloading
416+
417+
@OnPluginUnloading
418+
def on_plugin_unloading(plugin):
390419
pass
391420
392421
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
plugins
2+
=======
3+
4+
This page contains tutorials about the :mod:`plugins` package.
5+
6+
7+
PluginInfo
8+
----------
9+
10+
For every plugin a :class:`plugins.info.PluginInfo` instance can be retrieved,
11+
even if the plugin isn't loaded. The :class:`plugins.info.PluginInfo` instance
12+
is created based on a file called ``info.ini`` that has to reside in the
13+
plugin's main directory. This file is completely optional. So, if it doesn't
14+
exist, the :class:`plugins.info.PluginInfo` instance will still be created,
15+
but it won't contain much more information beside the name of the plugin.
16+
17+
Here is an example ``info.ini`` file containing the most basic options:
18+
19+
.. code:: ini
20+
21+
# A verbose name of the plugin.
22+
# If this option is not defined, the plugin's name will be used, all
23+
# underscores are replaced with spaces and the first letter of every word is
24+
# being capitalized.
25+
verbose_name = "Paintball"
26+
27+
# Name of the Author.
28+
# If this option is not defined, the plugin info will contain 'None'.
29+
author = "Ayuto"
30+
31+
# A description of what the plugin does.
32+
# If this option is not defined, the plugin info will contain 'None'.
33+
description = "Adds paintball effects to the game."
34+
35+
# Version of the plugin.
36+
# If this option is not defined, the plugin info will contain 'unversioned'.
37+
version = "1.3"
38+
39+
# An link to the 'Plugin Releases' forum or the plugin's SPPM link (hopefully
40+
# coming some day).
41+
# If this option is not defined, the plugin info will contain 'None'.
42+
url = "http://forums.sourcepython.com/viewtopic.php?f=7&t=502"
43+
44+
45+
You can also note which permissions are defined by your plugin. This helps
46+
server owners to configure their authorization settings properly. See the
47+
example below:
48+
49+
.. code:: ini
50+
51+
# Permissions defined by the plugin.
52+
# If this option is not defined, the plugin info will contain an empty list.
53+
[permissions]
54+
admin.kick = "Ability to kick a player."
55+
admin.ban = "Ability to ban a player."
56+
57+
58+
As soon as a plugin is being loaded, a public console variable is created that
59+
contains the following information:
60+
61+
* Name: ``<plugin name>_version``
62+
* Value: ``<version of the plugin>``
63+
* Description: ``<verbose name> version.``
64+
65+
66+
If you don't want a public console variable, you can simply use the following
67+
option in your info file to disable that feature:
68+
69+
.. code:: ini
70+
71+
public_convar = False
72+
73+
74+
If you wish to use different values to create the public console variable, you
75+
can use the following in your info file:
76+
77+
.. code:: ini
78+
79+
[public_convar]
80+
# All of these options are optional.
81+
name = "my_plugin_version"
82+
value = "My custom value."
83+
description = "My custom description."
84+
85+
86+
Sometimes you might also want to define some custom options for the plugin
87+
info. Adding those is quite easy. You just need to define them:
88+
89+
.. code:: ini
90+
91+
my_custom_option = "something"
92+
my_custom_option2 = "something else"
93+
94+
95+
Since those are custom options, they are not displayed when the list of loaded
96+
plugins is printed (e.g. via ``sp plugin list``). If you want to change that
97+
behaviour, you can define the ``display_in_listing`` option:
98+
99+
.. code:: ini
100+
101+
display_in_listing = "my_custom_option", "my_custom_option2"
102+
103+
104+
Retrieving a PluginInfo instance
105+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
106+
107+
.. note::
108+
109+
If you retrieve a :class:`plugins.info.PluginInfo` instance of a plugin
110+
that isn't loaded, the :class:`plugins.info.PluginInfo` instance is
111+
recreated everytime you retrieve it. Only loaded plugins will cache the
112+
instance.
113+
114+
115+
The following example will show how to retrieve a
116+
:class:`plugins.info.PluginInfo` instance for a specific plugin.
117+
118+
.. code:: python
119+
120+
from plugins.manager import plugin_manager
121+
122+
# Retrieve the plugin info of the paintball plugin. This is case sensitive!
123+
info = plugin_manager.get_plugin_info('paintball')
124+
125+
# Print the plugin's description
126+
print(info.description)
127+
128+
129+
You are not only restricted to the plugin's name, but you can also use the
130+
plugin's import path. See the example below:
131+
132+
.. code:: python
133+
134+
from plugins.manager import plugin_manager
135+
136+
info = plugin_manager.get_plugin_info('paintball.paintball')
137+
138+
139+
Obviously, this doesn't make much sense as the first example is shorter and
140+
both result in the same. But this feature has been added, so plugin's can pass
141+
their own ``__name__`` variable, which contains their import path. Thus, you
142+
can use the following snippet to retrieve the plugin info of your own plugin,
143+
without directly specifying the plugin's name.
144+
145+
.. code:: python
146+
147+
from plugins.manager import plugin_manager
148+
149+
info = plugin_manager.get_plugin_info(__name__)
150+
151+
152+
You can also use this snippet outside of your plugin's main file (e.g. in
153+
other sub-modules or sub-packages).
154+
155+
156+
Adding sub-plugins
157+
------------------
158+
159+
Adding sub-plugins to your plugin is done a very few steps. All you actually
160+
need is a new instance of the :class:`plugins.manager.PluginManager` class.
161+
This instance allows you to load plugins from a specifc directory.
162+
163+
Imagine your plugin resides in ``../addons/source-python/plugins/my_plugin``
164+
and within that directory you have created a new directory called ``plugins``,
165+
which should contain all sub-plugins of ``my_plugin``. Then the plugin manager
166+
could be created using the following code:
167+
168+
.. code:: python
169+
170+
from plugins.manager import PluginManager
171+
172+
my_plugin_manager = PluginManager('my_plugin.plugins.')
173+
174+
175+
That's all you need! Now you can load sub-plugins using ``my_plugin_manager``
176+
from your sub-plugins directory with the following code:
177+
178+
.. code:: python
179+
180+
# Load the plugin 'my_sub_plugin' from
181+
# ../addons/source-python/plugins/my_plugin/plugins
182+
my_plugin_manager.load('my_sub_plugin')
183+
184+
185+
However, this doesn't print any messages like Source.Python does when you load
186+
a plugin via ``sp plugin load``. If you would like to have those messages as
187+
well, without implementing them on your own, you can simply create an instance
188+
of ``plugins.command.SubCommandManager``.
189+
190+
.. code:: python
191+
192+
from plugins.command import SubCommandManager
193+
194+
my_sub_command_manager = SubCommandManager(
195+
# Tell the sub command manager to use this plugin manager to load plugins
196+
my_plugin_manager,
197+
198+
# If you create sub-commands, they will use 'my_plugin' as the base
199+
# command like Source.Python uses 'sp'
200+
'my_plugin'
201+
)
202+
203+
204+
Now, you can load your sub-plugin using the following code:
205+
206+
.. code:: python
207+
208+
my_sub_command_manager.load_plugin('my_sub_plugin')
209+
210+
211+
So far, so good. But what if you want to load your plugins via a server
212+
command? Well, just add it using the following code:
213+
214+
.. code:: python
215+
216+
@my_sub_command_manager.server_sub_command(['plugin', 'load'])
217+
def plugin_load(command_info, plugin):
218+
my_sub_command_manager.load_plugin(plugin)
219+
220+
@my_sub_command_manager.server_sub_command(['plugin', 'unload'])
221+
def plugin_unload(command_info, plugin):
222+
my_sub_command_manager.unload_plugin(plugin)
223+
224+
225+
Now you can also load your sub-plugins using ``my_plugin plugin load`` and
226+
unload them using ``my_plugin plugin unload``.
227+
228+
There is only one last thing left to do. If your main plugin is being
229+
unloaded, you should also unload all of your sub-plugins. It doesn't cause any
230+
problems with Source.Python if you don't do that, because Source.Python also
231+
unloads all :class:`core.AutoUnload` and :class:`core.WeakAutoUnload`
232+
instances of your sub-plugins. But if you don't do that the ``unload``
233+
functions of your sub-plugins are never getting called. To avoid this issue
234+
use the following code:
235+
236+
.. code:: python
237+
238+
def unload():
239+
for plugin in tuple(my_plugin_manager.values()):
240+
plugin.unload()
241+
242+
243+
Here is the full example code to implement sub-plugins:
244+
245+
.. code:: python
246+
247+
from plugins.manager import PluginManager
248+
from plugins.command import SubCommandManager
249+
250+
my_plugin_manager = PluginManager('my_plugin.plugins.')
251+
my_sub_command_manager = SubCommandManager(
252+
# Tell the sub command manager to use this plugin manager to load plugins
253+
my_plugin_manager,
254+
255+
# If you create sub-commands, they will use 'my_plugin' as the base
256+
# command like Source.Python uses 'sp'
257+
'my_plugin'
258+
)
259+
260+
@my_sub_command_manager.server_sub_command(['plugin', 'load'])
261+
def plugin_load(command_info, plugin):
262+
my_sub_command_manager.load_plugin(plugin)
263+
264+
@my_sub_command_manager.server_sub_command(['plugin', 'unload'])
265+
def plugin_unload(command_info, plugin):
266+
my_sub_command_manager.unload_plugin(plugin)
267+
268+
def unload():
269+
for plugin in tuple(my_plugin_manager.values()):
270+
plugin.unload()

addons/source-python/docs/source-python/source/developing/modules/core.manager.rst

Lines changed: 0 additions & 7 deletions
This file was deleted.

addons/source-python/docs/source-python/source/developing/modules/core.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ Submodules
99

1010
core.command
1111
core.dumps
12-
core.manager
1312
core.settings
1413
core.table
1514
core.version
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
entities.engines.csgo.csgo module
2+
==================================
3+
4+
.. automodule:: entities.engines.csgo.csgo
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
entities.engines.csgo package
2+
==============================
3+
4+
Module contents
5+
---------------
6+
7+
.. automodule:: entities.engines.csgo
8+
:members:
9+
:undoc-members:
10+
:show-inheritance:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
entities.engines package
2+
=========================
3+
4+
Subpackages
5+
-----------
6+
7+
.. toctree::
8+
:titlesonly:
9+
10+
entities.engines.csgo
11+
12+
Module contents
13+
---------------
14+
15+
.. automodule:: entities.engines
16+
:members:
17+
:undoc-members:
18+
:show-inheritance:
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
players.engines.bms package
2+
============================
3+
4+
Module contents
5+
---------------
6+
7+
.. automodule:: players.engines.bms
8+
:members:
9+
:undoc-members:
10+
:show-inheritance:

0 commit comments

Comments
 (0)