Stopping workshop maps from overriding cvars

All other Source.Python topics and issues.
JustGR
Junior Member
Posts: 20
Joined: Tue Apr 28, 2020 12:39 pm

Stopping workshop maps from overriding cvars

Postby JustGR » Tue Apr 28, 2020 12:58 pm

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.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Stopping workshop maps from overriding cvars

Postby L'In20Cible » Tue Apr 28, 2020 1:13 pm

Welcome to Source.Python! :smile:

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,))
JustGR
Junior Member
Posts: 20
Joined: Tue Apr 28, 2020 12:39 pm

Re: Stopping workshop maps from overriding cvars

Postby JustGR » Tue Apr 28, 2020 4:00 pm

L'In20Cible wrote:Welcome to Source.Python! :smile:

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.
decompile
Senior Member
Posts: 416
Joined: Sat Oct 10, 2015 10:37 am
Location: Germany
Contact:

Re: Stopping workshop maps from overriding cvars

Postby decompile » Tue Apr 28, 2020 4:49 pm

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,))
JustGR
Junior Member
Posts: 20
Joined: Tue Apr 28, 2020 12:39 pm

Re: Stopping workshop maps from overriding cvars

Postby JustGR » Tue Apr 28, 2020 10:01 pm

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?
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Stopping workshop maps from overriding cvars

Postby L'In20Cible » Wed Apr 29, 2020 1:14 am

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.
JustGR
Junior Member
Posts: 20
Joined: Tue Apr 28, 2020 12:39 pm

Re: Stopping workshop maps from overriding cvars

Postby JustGR » Wed Apr 29, 2020 2:11 am

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.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Stopping workshop maps from overriding cvars

Postby L'In20Cible » Wed Apr 29, 2020 2:48 am

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.
JustGR
Junior Member
Posts: 20
Joined: Tue Apr 28, 2020 12:39 pm

Re: Stopping workshop maps from overriding cvars

Postby JustGR » Wed Apr 29, 2020 2:57 am

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 30 guests