This is my first attempt at writing any kind of plugin, but I need this for the workshop maps that keep overriding my deathmatch config on map load and round start, so here I am. After scouring through the documentation, I attempted to rewrite the cvars affected on round_end and round_poststart events, but the map overrides the cvars even after round_poststart, so this has forced me to reevaluate how I go about this. Is there some way in SourcePython to prevent maps from changing cvars when loaded and triggering rounds?
The cvars in question are mp_roundtime, mp_maxrounds, mp_timelimit, mp_warmuptime and so on. Also I've come across at least one map that forces certain primary weapons on every spawn.
Stopping workshop maps from overriding cvars
- L'In20Cible
- Project Leader
- Posts: 1536
- Joined: Sat Jul 14, 2012 9:29 pm
- Location: Québec
Re: Stopping workshop maps from overriding cvars
Welcome to Source.Python! 
You could use the OnConVarChanged listener to revert the change if the value isn't the one you want to keep. For example:

You could use the OnConVarChanged listener to revert the change if the value isn't the one you want to keep. For example:
Syntax: Select all
from listeners import OnConVarChanged
from listeners.tick import Delay
convars = {
'mp_roundtime': '0',
'mp_maxrounds': '0',
'mp_timelimit': '0',
# ...
}
@OnConVarChanged
def on_convar_changed(convar, old_value):
"""Called when a convar has been changed."""
# Get the value we want to keep for the current convar
value = convars.get(convar.name, None)
# If this wasn't a convar we want to preserve the value of, just return
if value is None or convar.get_string() == value:
return
# Revert the change
Delay(0, convar.set_string, (value,))
Re: Stopping workshop maps from overriding cvars
L'In20Cible wrote:Welcome to Source.Python!
You could use the OnConVarChanged listener to revert the change if the value isn't the one you want to keep. For example:Syntax: Select all
from listeners import OnConVarChanged
from listeners.tick import Delay
convars = {
'mp_roundtime': '0',
'mp_maxrounds': '0',
'mp_timelimit': '0',
# ...
}
@OnConVarChanged
def on_convar_changed(convar, old_value):
"""Called when a convar has been changed."""
# Get the value we want to keep for the current convar
value = convars.get(convar.name, None)
# If this wasn't a convar we want to preserve the value of, just return
if value is None or convar.get_string() == value:
return
# Revert the change
Delay(0, convar.set_string, (value,))
I already tried @OnConVarChanged, even tried it with a nested Event decorator. This approach works for map loads, but fails when you try to manually change cvars via the console.
Re: Stopping workshop maps from overriding cvars
I think using server_cvar event should get manual cvar changing via console.
Syntax: Select all
from events import Event
from cvars import ConVar
from listeners import OnConVarChanged
from listeners.tick import Delay
convars = {
'mp_roundtime': '0',
'mp_maxrounds': '0',
'mp_timelimit': '0',
# ...
}
@Event('server_cvar')
def server_cvar(GameEvent):
"""Called when a convar has been changed."""
cvarname = GameEvent['cvarname'].lower()
cvarvalue = GameEvent['cvarvalue']
# Get the value we want to keep for the current convar
value = convars.get(cvarname , None)
# If this wasn't a convar we want to preserve the value of, just return
if value is None or cvarvalue == value:
return
# Revert the change
Delay(0, ConVar(cvarname).set_string, (value,))
Re: Stopping workshop maps from overriding cvars
decompile wrote:I think using server_cvar event should get manual cvar changing via console.Syntax: Select all
from events import Event
from cvars import ConVar
from listeners import OnConVarChanged
from listeners.tick import Delay
convars = {
'mp_roundtime': '0',
'mp_maxrounds': '0',
'mp_timelimit': '0',
# ...
}
@Event('server_cvar')
def server_cvar(GameEvent):
"""Called when a convar has been changed."""
cvarname = GameEvent['cvarname'].lower()
cvarvalue = GameEvent['cvarvalue']
# Get the value we want to keep for the current convar
value = convars.get(cvarname , None)
# If this wasn't a convar we want to preserve the value of, just return
if value is None or cvarvalue == value:
return
# Revert the change
Delay(0, ConVar(cvarname).set_string, (value,))
Hey this worked as intended, but since mp_warmup_time does not have a cvars.flags.ConVarFlags.NOTIFY flag, that doesn't get updated. Managed to manually end warmups via @Event('round_announce_warmup'), though it would be nice to just reverse all server cvar changes from the map. Is there a way to give the notify flag to all server cvars edited by the map?
- L'In20Cible
- Project Leader
- Posts: 1536
- Joined: Sat Jul 14, 2012 9:29 pm
- Location: Québec
Re: Stopping workshop maps from overriding cvars
JustGR wrote:I already tried @OnConVarChanged, even tried it with a nested Event decorator. This approach works for map loads, but fails when you try to manually change cvars via the console.
It works fine. I assume it doesn't because your server is hibernating which consequently means the delay will only process when waking up. You could set sv_hibernate_when_empty to 0.
Re: Stopping workshop maps from overriding cvars
L'In20Cible wrote:JustGR wrote:I already tried @OnConVarChanged, even tried it with a nested Event decorator. This approach works for map loads, but fails when you try to manually change cvars via the console.
It works fine. I assume it doesn't because your server is hibernating which consequently means the delay will only process when waking up. You could set sv_hibernate_when_empty to 0.
No I meant that it works TOO WELL. It catches all map changes and reverses them to old values, but when I manually change cvars, it goes after those too.
- L'In20Cible
- Project Leader
- Posts: 1536
- Joined: Sat Jul 14, 2012 9:29 pm
- Location: Québec
Re: Stopping workshop maps from overriding cvars
JustGR wrote:L'In20Cible wrote:JustGR wrote:I already tried @OnConVarChanged, even tried it with a nested Event decorator. This approach works for map loads, but fails when you try to manually change cvars via the console.
It works fine. I assume it doesn't because your server is hibernating which consequently means the delay will only process when waking up. You could set sv_hibernate_when_empty to 0.
No I meant that it works TOO WELL. It catches all map changes and reverses them to old values, but when I manually change cvars, it goes after those too.
If you want to update the value from the console, you could just use a command. For example:
Syntax: Select all
from commands.server import ServerCommand
from core import console_message
from cvars import ConVar
from listeners import OnConVarChanged
from listeners.tick import Delay
convars = {
'mp_roundtime': '0',
'mp_maxrounds': '0',
'mp_timelimit': '0',
# ...
}
@OnConVarChanged
def on_convar_changed(convar, old_value):
"""Called when a convar has been changed."""
# Get the value we want to keep for the current convar
value = convars.get(convar.name, None)
# If this wasn't a convar we want to preserve the value of, just return
if value is None or convar.get_string() == value:
return
# Revert the change
Delay(0, convar.set_string, (value,))
@ServerCommand('set')
def set_convar(command):
"""Set the value of a ConVar."""
# Was there enough parameters given?
if len(command) < 3:
return console_message('Syntax: set <convar name> <value>\n')
# Extract the parameters
name, value = command[1], command[2]
# Update the convars dictionary
convars[name] = value
# Set the convar value
ConVar(name, value).set_string(value)
Now you could use set <convar> <value> and it would update the given convar name to that value, etc. Other than that, I can't think of an easy way to determine who initiated the change.
Re: Stopping workshop maps from overriding cvars
L'In20Cible wrote:JustGR wrote:L'In20Cible wrote:It works fine. I assume it doesn't because your server is hibernating which consequently means the delay will only process when waking up. You could set sv_hibernate_when_empty to 0.
No I meant that it works TOO WELL. It catches all map changes and reverses them to old values, but when I manually change cvars, it goes after those too.
If you want to update the value from the console, you could just use a command. For example:Syntax: Select all
from commands.server import ServerCommand
from core import console_message
from cvars import ConVar
from listeners import OnConVarChanged
from listeners.tick import Delay
convars = {
'mp_roundtime': '0',
'mp_maxrounds': '0',
'mp_timelimit': '0',
# ...
}
@OnConVarChanged
def on_convar_changed(convar, old_value):
"""Called when a convar has been changed."""
# Get the value we want to keep for the current convar
value = convars.get(convar.name, None)
# If this wasn't a convar we want to preserve the value of, just return
if value is None or convar.get_string() == value:
return
# Revert the change
Delay(0, convar.set_string, (value,))
@ServerCommand('set')
def set_convar(command):
"""Set the value of a ConVar."""
# Was there enough parameters given?
if len(command) < 3:
return console_message('Syntax: set <convar name> <value>\n')
# Extract the parameters
name, value = command[1], command[2]
# Update the convars dictionary
convars[name] = value
# Set the convar value
ConVar(name, value).set_string(value)
Now you could use set <convar> <value> and it would update the given convar name to that value, etc. Other than that, I can't think of an easy way to determine who initiated the change.
The server command idea is a good one. Might settle for a typedsaycommand, but we'll see.
Return to “General Discussion”
Who is online
Users browsing this forum: No registered users and 144 guests