Skip to content

Commit 6d90665

Browse files
authored
Server output hook (#201)
* Added server output hooking functionality * Removed redundant include * Added docs for OnServerOutput * Fixed compiler errors * Added warning to OnServerOutput docu
1 parent 2b5b98c commit 6d90665

File tree

8 files changed

+271
-1
lines changed

8 files changed

+271
-1
lines changed

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,33 @@ Called when a map starts and the server is ready to accept clients.
448448
pass
449449
450450
451+
OnServerOutput
452+
----------------
453+
454+
Called when something is printed to the console. You can decide whether the
455+
message is logged/printed or not.
456+
457+
.. warning::
458+
459+
Be careful when printing something within this listener. It can easily
460+
result into a recursion, which results into a crash of the server.
461+
462+
463+
.. code-block:: python
464+
465+
from listeners import OnServerOutput
466+
from core import OutputReturn
467+
468+
@OnServerOutput
469+
def on_server_output(severity, msg):
470+
# Block everything starting with 'sv_' or 'mp_' from being logged.
471+
# This keeps the console clean in CS:GO.
472+
if msg.startswith(('sv_', 'mp_')):
473+
return OutputReturn.BLOCK
474+
475+
return OutputReturn.CONTINUE
476+
477+
451478
OnTick
452479
------
453480

addons/source-python/packages/source-python/core/__init__.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
# Core
4848
from _core import console_message
4949
from _core import get_interface
50+
from _core import OutputReturn
5051
from _core import SOURCE_ENGINE
5152
from _core import SOURCE_ENGINE_BRANCH
5253

@@ -58,6 +59,7 @@
5859
'GameConfigObj',
5960
'WeakAutoUnload',
6061
'GAME_NAME',
62+
'OutputReturn',
6163
'PLATFORM',
6264
'SOURCE_ENGINE',
6365
'SOURCE_ENGINE_BRANCH',
@@ -66,6 +68,7 @@
6668
'get_interface',
6769
'get_public_ip',
6870
'ignore_unicode_errors',
71+
'server_output',
6972
)
7073

7174

@@ -166,6 +169,7 @@ def echo_console(text):
166169
for line in text.split('\n'):
167170
console_message(line + '\n')
168171

172+
169173
@contextmanager
170174
def ignore_unicode_errors(errors='ignore'):
171175
"""Overwrite the ``strict`` codecs error handler temporarily.
@@ -218,3 +222,62 @@ def get_public_ip():
218222
This functions makes a call to http://ip.42.pl/raw to retrieve the public IP.
219223
"""
220224
return urlopen('http://ip.42.pl/raw').read().decode()
225+
226+
227+
@contextmanager
228+
def server_output(action=OutputReturn.CONTINUE):
229+
"""Gather all server output sent during the execution of the with-statement.
230+
231+
:param OutputReturn action:
232+
Determines what happens with the output.
233+
:rtype: list
234+
:return:
235+
A list that will be filled with a tuple for every line that is being
236+
logged. The tuple contains the severity and the message.
237+
238+
Example:
239+
240+
.. code:: python
241+
242+
from cvars import cvar
243+
from core import server_output
244+
from core import OutputReturn
245+
246+
status = cvar.find_command('status')
247+
248+
with server_output(OutputReturn.BLOCK) as output:
249+
status()
250+
251+
# Print everything that was logged by the 'status' command
252+
print(output)
253+
254+
255+
Output:
256+
257+
.. code:: python
258+
259+
[(_core.MessageSeverity.MESSAGE, 'hostname: Counter-Strike: Global Offensive\\n'),
260+
(_core.MessageSeverity.MESSAGE, 'version : 1.35.8.4/13584 513/6771 secure [A:1:2435270659:8640] \\n'),
261+
(_core.MessageSeverity.MESSAGE, 'udp/ip : 192.168.178.60:27015 (public ip: 46.83.158.27)\\n'),
262+
(_core.MessageSeverity.MESSAGE, 'os : Windows\\n'),
263+
(_core.MessageSeverity.MESSAGE, 'type : community dedicated\\n'),
264+
(_core.MessageSeverity.MESSAGE, 'players : 0 humans, 0 bots (20/0 max) (hibernating)\\n\\n'),
265+
(_core.MessageSeverity.MESSAGE, '# userid name uniqueid connected ping loss state rate'),
266+
(_core.MessageSeverity.MESSAGE, ' adr'),
267+
(_core.MessageSeverity.MESSAGE, '\\n'),
268+
(_core.MessageSeverity.MESSAGE, '#end\\n')]
269+
"""
270+
# Import this here to fix a cyclic import
271+
from listeners import OnServerOutput
272+
273+
msg_buffer = []
274+
275+
def intercepter(severity, msg):
276+
msg_buffer.append((severity, msg))
277+
return action
278+
279+
OnServerOutput.manager.register_listener(intercepter)
280+
try:
281+
yield msg_buffer
282+
finally:
283+
OnServerOutput.manager.unregister_listener(intercepter)

addons/source-python/packages/source-python/listeners/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
from _listeners import on_query_cvar_value_finished_listener_manager
6363
from _listeners import on_server_activate_listener_manager
6464
from _listeners import on_tick_listener_manager
65+
from _listeners import on_server_output_listener_manager
6566
# Entity output
6667
from listeners._entity_output import on_entity_output_listener_manager
6768

@@ -103,6 +104,7 @@
103104
'OnServerActivate',
104105
'OnTick',
105106
'OnVersionUpdate',
107+
'OnServerOutput',
106108
'get_button_combination_status',
107109
'on_client_active_listener_manager',
108110
'on_client_connect_listener_manager',
@@ -133,6 +135,7 @@
133135
'on_server_activate_listener_manager',
134136
'on_tick_listener_manager',
135137
'on_version_update_listener_manager',
138+
'on_server_output_listener_manager',
136139
)
137140

138141

@@ -427,6 +430,12 @@ class OnButtonStateChanged(ListenerManagerDecorator):
427430
manager = on_button_state_changed_listener_manager
428431

429432

433+
class OnServerOutput(ListenerManagerDecorator):
434+
"""Register/unregister a server output listener."""
435+
436+
manager = on_server_output_listener_manager
437+
438+
430439
# =============================================================================
431440
# >> FUNCTIONS
432441
# =============================================================================

src/core/modules/core/core.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,29 @@
3838
#define MAX_CON_MSG 1024
3939

4040

41+
//-----------------------------------------------------------------------------
42+
// MessageSeverity
43+
//-----------------------------------------------------------------------------
44+
enum MessageSeverity
45+
{
46+
SEVERITY_MESSAGE = 0,
47+
SEVERITY_WARNING,
48+
SEVERITY_ASSERT,
49+
SEVERITY_ERROR,
50+
SEVERITY_LOG,
51+
};
52+
53+
54+
//-----------------------------------------------------------------------------
55+
// OutputReturn
56+
//-----------------------------------------------------------------------------
57+
enum OutputReturn
58+
{
59+
OUTPUT_BLOCK = 0,
60+
OUTPUT_CONTINUE
61+
};
62+
63+
4164
//-----------------------------------------------------------------------------
4265
// ConMsg wrapper
4366
//-----------------------------------------------------------------------------

src/core/modules/core/core_wrap.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ extern CSourcePython g_SourcePythonPlugin;
4242
// Forward declarations.
4343
//-----------------------------------------------------------------------------
4444
static void export_source_python_plugin(scope);
45+
static void export_message_severity(scope);
46+
static void export_output_return(scope);
4547
static void export_constants(scope);
4648
static void export_functions(scope);
4749

@@ -52,6 +54,8 @@ static void export_functions(scope);
5254
DECLARE_SP_MODULE(_core)
5355
{
5456
export_source_python_plugin(_core);
57+
export_message_severity(_core);
58+
export_output_return(_core);
5559
export_constants(_core);
5660
export_functions(_core);
5761
}
@@ -69,6 +73,33 @@ void export_source_python_plugin(scope _core)
6973
}
7074

7175

76+
//-----------------------------------------------------------------------------
77+
// Expose MessageSeverity.
78+
//-----------------------------------------------------------------------------
79+
void export_message_severity(scope _core)
80+
{
81+
enum_<MessageSeverity> _MessageSeverity("MessageSeverity");
82+
83+
_MessageSeverity.value("MESSAGE", SEVERITY_MESSAGE);
84+
_MessageSeverity.value("WARNING", SEVERITY_WARNING);
85+
_MessageSeverity.value("ASSERT", SEVERITY_ASSERT);
86+
_MessageSeverity.value("ERROR", SEVERITY_ERROR);
87+
_MessageSeverity.value("LOG", SEVERITY_LOG);
88+
}
89+
90+
91+
//-----------------------------------------------------------------------------
92+
// Expose OutputReturn.
93+
//-----------------------------------------------------------------------------
94+
void export_output_return(scope _core)
95+
{
96+
enum_<OutputReturn> _OutputReturn("OutputReturn");
97+
98+
_OutputReturn.value("BLOCK", OUTPUT_BLOCK);
99+
_OutputReturn.value("CONTINUE", OUTPUT_CONTINUE);
100+
}
101+
102+
72103
//-----------------------------------------------------------------------------
73104
// Expose constants.
74105
//-----------------------------------------------------------------------------

src/core/modules/listeners/listeners_wrap.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ DEFINE_MANAGER_ACCESSOR(OnEntityDeleted)
5757
DEFINE_MANAGER_ACCESSOR(OnDataLoaded)
5858
DEFINE_MANAGER_ACCESSOR(OnCombinerPreCache)
5959
DEFINE_MANAGER_ACCESSOR(OnDataUnloaded)
60+
DEFINE_MANAGER_ACCESSOR(OnServerOutput)
6061

6162

6263
//-----------------------------------------------------------------------------
@@ -147,4 +148,6 @@ void export_listener_managers(scope _listeners)
147148
_listeners.attr("on_data_loaded_listener_manager") = object(ptr(GetOnDataLoadedListenerManager()));
148149
_listeners.attr("on_combiner_pre_cache_listener_manager") = object(ptr(GetOnCombinerPreCacheListenerManager()));
149150
_listeners.attr("on_data_unloaded_listener_manager") = object(ptr(GetOnDataUnloadedListenerManager()));
151+
152+
_listeners.attr("on_server_output_listener_manager") = object(ptr(GetOnServerOutputListenerManager()));
150153
}

0 commit comments

Comments
 (0)