[Cs:s] chat command to change map

A place for requesting new Source.Python plugins to be made for your server.

Please request only one plugin per thread.
cssbestrpg
Senior Member
Posts: 287
Joined: Sun May 17, 2020 7:56 am
Location: Finland
Contact:

[Cs:s] chat command to change map

Postby cssbestrpg » Thu Oct 29, 2020 6:44 pm

Hi, can some one make a plugin that changes map?

like !map <name>, then it changes map to name has typed for map
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: [Cs:s] chat command to change map

Postby VinciT » Thu Oct 29, 2020 9:37 pm

I'm in a bit of a hurry so this might not be fully working, but give it a shot:

Syntax: Select all

# ../change_map/change_map.py

# Python
from textwrap import wrap

# Source.Python
from commands import CommandReturn
from commands.say import SayCommand
from engines.server import queue_command_string
from engines.sound import Sound
from listeners.tick import Delay
from messages import SayText2
from messages.colors.saytext2 import GREEN, ORANGE
from paths import GAME_PATH


# Get the path to the server's maps folder.
MAPS_PATH = GAME_PATH / 'maps'
# List for storing maps found on the server.
maps = [file.namebase for file in MAPS_PATH.files('*.bsp')]


CHAT_SEND_SOUND = Sound('common/talk.wav', volume=1)


@SayCommand('!map')
def map_command(command, index, team_only=False):
try:
map_name = command[1]
# Format the name of the map so we don't have to do it later.
map_name_f = f'{GREEN}{map_name}{ORANGE}'
except IndexError:
SayText2(f'Usage: {GREEN}!map <partial/full map name>').send(index)
CHAT_SEND_SOUND.play(index)
return CommandReturn.BLOCK

possible_maps = []
# Go through all of our maps.
for _map in maps:
# Is the specified 'map_name' fully or partially similar to this map?
if map_name in _map:
possible_maps.append(_map)

# Is there at least one possible map?
if possible_maps:
# Do we have an exact match or only one possible map?
if map_name in possible_maps or len(possible_maps) == 1:
map_found = f'{GREEN}{possible_maps[0]}{ORANGE}'
SayText2(
f'Changing map to {map_found} in 3 seconds...').send(index)
Delay(
3, queue_command_string, (f'changelevel {possible_maps[0]}',))

# Or are there multiple options?
else:
# Change the color of the given 'map_name' in all of the possible
# maps.
possible_maps = [
_map.replace(map_name, map_name_f) for _map in possible_maps]

# Turn the list of maps into a list of string chunks, this way we
# won't break the engine's user message size limit.
messages = wrap(
# Add an empty character at the end to prevent coloring issues.
text='Be more specific: ' + ', '.join(possible_maps) + '\x01',
width=250,
break_long_words=False
)

for msg in messages:
SayText2(msg).send(index)

else:
SayText2(f'Unable to find {map_name_f} on the server.').send(index)

CHAT_SEND_SOUND.play(index)
return CommandReturn.BLOCK
Last edited by VinciT on Sat Oct 31, 2020 7:03 am, edited 1 time in total.
ImageImageImageImageImage
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: [Cs:s] chat command to change map

Postby satoon101 » Thu Oct 29, 2020 10:03 pm

I'm not sure you want the possible_maps logic. For instance, if you want to switch to de_dust, it will always give you that "Be more specific" message, because there's de_dust and de_dust2.
Image
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: [Cs:s] chat command to change map

Postby satoon101 » Fri Oct 30, 2020 3:40 am

Sorry for the double post, but I also noticed that you imported listdir. Since SP ships with the path package and all of the paths in our 'paths' package are path.Path instances, listing files in a directory are actually even easier. For instance, you can use the path.Path.files method to not only list the files in the MAPS_PATH directory, but filter them based on the .bsp extension:

Syntax: Select all

def load():
"""Called when the plugin gets loaded."""
# Go through all the files found in '../cstrike/maps/'.
for MAPS_PATH.files('*.bsp'):
# Remove the file extension and add it to our list of maps.
maps.append(file[:-4])


Also, to get the name of the file without the path and without the extension, you can use the namebase property (note that this property is removed in future versions of path, unfortunately...so that would have to change if/when we upgrade):

Syntax: Select all

def load():
"""Called when the plugin gets loaded."""
# Go through all the files found in '../cstrike/maps/'.
for MAPS_PATH.files('*.bsp'):
# Remove the file extension and add it to our list of maps.
maps.append(file.namebase)


And now that we've gotten that simple, we could even just use list comprehension:

Syntax: Select all

maps = [file.namebase for file in MAPS_PATH.files('*.bsp')]
Image
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: [Cs:s] chat command to change map

Postby L'In20Cible » Fri Oct 30, 2020 4:41 am

Listing files from the maps directory can be inaccurate though, since they can also be found into custom or even packed in vpk. It would be best to just ask the engine whether the map is valid or not:

Syntax: Select all

from commands.typed import TypedSayCommand
from engines.server import engine_server
from engines.server import queue_command_string
from listeners.tick import Delay

@TypedSayCommand('!map')
def map_cmd(cmd, map_name:str):
if not engine_server.is_map_valid(map_name):
return cmd.reply(f'"{map_name}" is not a valid map.')

cmd.reply(f'Changing map to {map_name} in 3 seconds...')
Delay(3, queue_command_string, (f'changelevel {map_name}',))


Also, although it wasn't specifically mentioned, I'm pretty sure this isn't meant to be a command available to all players.
cssbestrpg
Senior Member
Posts: 287
Joined: Sun May 17, 2020 7:56 am
Location: Finland
Contact:

Re: [Cs:s] chat command to change map

Postby cssbestrpg » Fri Oct 30, 2020 6:07 am

L'In20Cible wrote:Listing files from the maps directory can be inaccurate though, since they can also be found into custom or even packed in vpk. It would be best to just ask the engine whether the map is valid or not:

Syntax: Select all

from commands.typed import TypedSayCommand
from engines.server import engine_server
from engines.server import queue_command_string
from listeners.tick import Delay

@TypedSayCommand('!map')
def map_cmd(cmd, map_name:str):
if not engine_server.is_map_valid(map_name):
return cmd.reply(f'"{map_name}" is not a valid map.')

cmd.reply(f'Changing map to {map_name} in 3 seconds...')
Delay(3, queue_command_string, (f'changelevel {map_name}',))


Also, although it wasn't specifically mentioned, I'm pretty sure this isn't meant to be a command available to all players.


I tried to use that !map <mapname>, it didn't register the command, no errors come, but the command didn't work either
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: [Cs:s] chat command to change map

Postby satoon101 » Fri Oct 30, 2020 1:14 pm

I'm not sure what your issue might be, but it worked fine for me. I used "!map de_dust" in chat and it told me it was changing the map in 3 seconds, and then it changed maps to de_dust.
Image
cssbestrpg
Senior Member
Posts: 287
Joined: Sun May 17, 2020 7:56 am
Location: Finland
Contact:

Re: [Cs:s] chat command to change map

Postby cssbestrpg » Fri Oct 30, 2020 1:48 pm

satoon101 wrote:I'm not sure what your issue might be, but it worked fine for me. I used "!map de_dust" in chat and it told me it was changing the map in 3 seconds, and then it changed maps to de_dust.


When i type !map de_dust nothing appears to chat or console
even it loads fine, but no register the command for me
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: [Cs:s] chat command to change map

Postby Ayuto » Fri Oct 30, 2020 3:49 pm

What's the output of "sp info". It might be a conflict with another server plugin.
cssbestrpg
Senior Member
Posts: 287
Joined: Sun May 17, 2020 7:56 am
Location: Finland
Contact:

Re: [Cs:s] chat command to change map

Postby cssbestrpg » Fri Oct 30, 2020 5:41 pm

Ayuto wrote:What's the output of "sp info". It might be a conflict with another server plugin.

sp info

IMPORTANT: Please copy the full output.
--------------------------------------------------------
Checksum : c0141713e9220755875794d8c5fbc4ea
Date : 2020-10-30 17:40:42.069789
OS : Windows-10-10.0.18362
Game : css
SP version : 701
Github commit : f9d71cec67ef3662df07d579bba68fedea0558ad
Server plugins:
00: Source.Python, (C) 2012-2020, Source.Python Team.
SP plugins:
00: rpg
01: items
02: map
--------------------------------------------------------
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: [Cs:s] chat command to change map

Postby VinciT » Sat Oct 31, 2020 7:07 am

satoon101 wrote:I'm not sure you want the possible_maps logic. For instance, if you want to switch to de_dust, it will always give you that "Be more specific" message, because there's de_dust and de_dust2.
I knew this was a problem the moment I hit submit, I completely forgot about that scenario while making the plugin.
satoon101 wrote:And now that we've gotten that simple, we could even just use list comprehension:

Syntax: Select all

maps = [file.namebase for file in MAPS_PATH.files('*.bsp')]
Dang, that's awesome!

L'In20Cible wrote:Listing files from the maps directory can be inaccurate though, since they can also be found into custom or even packed in vpk.
In all my time making/hosting servers, I never used the custom folder or vpk files for maps, so I didn't think about this at all.
I wanted to use the engine's maps * command to get a list of maps, but I was unable to find how they did it in the SDK.

Even though my way of doing this can be inaccurate, I've updated the plugin just to make it functional. :smile:
Image Image
ImageImageImageImageImage
User avatar
Kami
Global Moderator
Posts: 263
Joined: Wed Aug 15, 2012 1:24 am
Location: Germany

Re: [Cs:s] chat command to change map

Postby Kami » Sat Oct 31, 2020 9:15 am

Hey VinciT, nice work! Since this is for CS:S you could handle the "be more specific" part with a popup menu. This way the user could quickly decide which map to choose without having to retype the map name.
If the user searches for a very broad term like de_ or for example bhop_ on a Bunnyhop Server your way of handling would potentialy output a very long list.
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: [Cs:s] chat command to change map

Postby VinciT » Mon Nov 02, 2020 6:56 am

Kami wrote:Hey VinciT, nice work! Since this is for CS:S you could handle the "be more specific" part with a popup menu. This way the user could quickly decide which map to choose without having to retype the map name.
If the user searches for a very broad term like de_ or for example bhop_ on a Bunnyhop Server your way of handling would potentialy output a very long list.
Thank you Kami, and you're absolutely right - if the server has plenty of maps, this would become unwieldy. I thought about adding a minimum length when specifying the map name, but your way seems much better. :grin:

Heading to bed right now, so I'll see what I can do about it tomorrow.
ImageImageImageImageImage
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: [Cs:s] chat command to change map

Postby VinciT » Wed Nov 04, 2020 12:23 am

As promised, albeit with a small delay, I've implemented Kami's excellent suggestion:

Syntax: Select all

# ../change_map/change_map.py

# Source.Python
from commands import CommandReturn
from commands.say import SayCommand
from engines.server import queue_command_string
from engines.sound import Sound
from listeners.tick import Delay
from menus import PagedMenu, PagedOption
from messages import SayText2
from messages.colors.saytext2 import GREEN, ORANGE
from paths import GAME_PATH


# Time (in seconds) until the map changes.
MAP_CHANGE_DELAY = 3


# Get the path to the server's maps folder.
MAPS_PATH = GAME_PATH / 'maps'
# List for storing maps found within the '../cstrike/maps' folder.
maps = [file.namebase for file in MAPS_PATH.files('*.bsp')]


CHAT_SEND_SOUND = Sound('common/talk.wav', volume=1)
# Separator used for the top and bottom part of the menu.
_menu_separator = '─' * 20


@SayCommand('!map')
def map_command(command, index, team_only=False):
try:
map_name = command[1]
except IndexError:
SayText2(f'Usage: {GREEN}!map <partial/full map name>').send(index)
CHAT_SEND_SOUND.play(index)
return CommandReturn.BLOCK

possible_maps = []
# Go through all of our maps.
for _map in maps:
# Is the specified 'map_name' fully or partially similar to this map?
if map_name in _map:
possible_maps.append(_map)

# Is there at least one possible map?
if possible_maps:
# Do we have an exact match or only one possible map?
if map_name in possible_maps or len(possible_maps) == 1:
change_level(possible_maps[0])

# Or are there multiple options?
else:
# Send the player a menu with all the possible maps.
PagedMenu(
data=[PagedOption(text=_map) for _map in possible_maps],
select_callback=lambda menu, index, choice: change_level(
choice.text),
title=f'Maps containing \'{map_name}\' ',
top_separator=_menu_separator,
bottom_separator=_menu_separator
).send(index)

else:
map_name_f = f'{GREEN}{map_name}{ORANGE}'
SayText2(f'Unable to find {map_name_f} on the server.').send(index)
CHAT_SEND_SOUND.play(index)

return CommandReturn.BLOCK


def change_level(map_name, delay=MAP_CHANGE_DELAY):
"""Changes the map.

Args:
map_name (str): Name of the map.
delay (float): Time until the map changes.
"""
Delay(
delay=delay,
callback=queue_command_string,
args=(f'changelevel {map_name}',),
cancel_on_level_end=True
)

map_name_f = f'{GREEN}{map_name}{ORANGE}'
SayText2(f'Changing map to {map_name_f} in {delay} seconds...').send()
CHAT_SEND_SOUND.play()
ImageImageImageImageImage

Return to “Plugin Requests”

Who is online

Users browsing this forum: No registered users and 35 guests