sourcemod icon indicating copy to clipboard operation
sourcemod copied to clipboard

[Bug]: Argument issue with + / - commands

Open mariokeks opened this issue 6 months ago • 2 comments

Prerequisites

  • [x] I have checked that my issue doesn't exist yet in the issue tracker

Operating System and Version

Debian GNU/Linux 12 (bookworm)

Game / AppID and Version

CS:S (240)

SourceMod Version

SourceMod 1.13.0.7224

Metamod:Source Version

Metamod:Source version 1.12.0-dev+1217

Version Verification

  • [x] I have updated SourceMod to the latest version and the issue persists
  • [x] I have updated SourceMod to the latest snapshot and the issue persists
  • [x] I have updated Metamod:Source to the latest snapshot and the issue persists

Updated SourceMod Version

SourceMod Version: 1.13.0.7245

Updated Metamod:Source Version

Metamod:Source version 2.0.0-dev+1353

Description

Number of arguments returns more than actually provided. GetCmdArg return a "15" and GetCmdArgString adds a " 15". Using the command via server console does not have any issues.

Steps to Reproduce

#pragma semicolon 1
#pragma newdecls required

public void OnPluginStart() 
{
	RegConsoleCmd("+sm_test5", Command_Test5, "Test command");
	RegConsoleCmd("-sm_test5", Command_Test5, "Test command");
}

Action Command_Test5(int client, int args)
{
	char sCommand[32];
	GetCmdArg(0, sCommand, sizeof(sCommand));
	ReplyToCommand(client, "command: '%s' args: %d", sCommand, args);

	char sArguments[128];
	GetCmdArgString(sArguments, sizeof(sArguments));
	ReplyToCommand(client, "GetCmdArgString: '%s' args: %d", sArguments, args);

	for(int i = 1; i <= args; i++)
	{
		GetCmdArg(i, sArguments, sizeof(sArguments));
		ReplyToCommand(client, "GetCmdArg %d: '%s'", i, sArguments);
	}
	return Plugin_Handled;
}

Relevant Log Output

bind e "+sm_test5"
command: '+sm_test5' args: 1
GetCmdArgString: '15' args: 1
GetCmdArg 1: '15'

command: '-sm_test5' args: 1
GetCmdArgString: '15' args: 1
GetCmdArg 1: '15'


bind e "+sm_test5 quack"
command: '+sm_test5' args: 2
GetCmdArgString: 'quack 15' args: 2
GetCmdArg 1: 'quack'
GetCmdArg 2: '15'

command: '-sm_test5' args: 2
GetCmdArgString: 'quack 15' args: 2
GetCmdArg 1: 'quack'
GetCmdArg 2: '15'

mariokeks avatar Jun 25 '25 19:06 mariokeks

~So far what I have looked. When bind plus or minus plugin command to keyboard button -> plugin command callback gets one extra argument, when push button. And last argument holds key index which command has binded, ex. value 15 is keyboard button 'e'. 26 is 'p'. 25 is 'o'. Not sure, is this behaviour coming from game itself or sourcemod.~

~I try look more.~

Ok, this is in game engine behaviour. When keyboard button is binded with + "button command", it will start carry button key index, it is last argument in command callback. This is for keep tracking when "button command" is pushed down or released (key events).

You can test like this in game console: bind p "+whatever" and in game when you push button many times, you see key release -

Unknown command: +whatever
Unknown command: -whatever
Unknown command: +whatever
Unknown command: -whatever
Unknown command: +whatever
Unknown command: -whatever

you not need create SM command for see this behaviour.

ambaca avatar Jun 29 '25 23:06 ambaca

Perhaps I am only one, who would like to still keep this game engine feature in Sourcemod. After all, you have a way to get button name. This work also on AddCommandListener.

char ButtonCodeName[][] =
{
	"",
	"0","1","2","3","4","5","6","7","8","9",
	"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
	"KP_INS","KP_END","KP_DOWNARROW","KP_PGDN","KP_LEFTARROW","KP_5","KP_RIGHTARROW","KP_HOME","KP_UPARROW","KP_PGUP","KP_SLASH","KP_MULTIPLY","KP_MINUS","KP_PLUS","KP_ENTER","KP_DEL",
	"[","]","SEMICOLON","'","`",",",".","/","\\","-","=",
	"ENTER","SPACE","BACKSPACE","TAB","CAPSLOCK","NUMLOCK","ESCAPE","SCROLLLOCK","INS","DEL","HOME","END","PGUP","PGDN","PAUSE","SHIFT","RSHIFT","ALT","RALT","CTRL","RCTRL","LWIN","RWIN","APP","UPARROW","LEFTARROW","DOWNARROW","RIGHTARROW",
	"F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12",
	"CAPSLOCKTOGGLE","NUMLOCKTOGGLE","SCROLLLOCKTOGGLE",
	"MOUSE1","MOUSE2","MOUSE3","MOUSE4","MOUSE5","MWHEELUP","MWHEELDOWN"
	// lot of joystic buttons
}

#define BUTTONS_MAX 195 // Not 100% sure


public void OnPluginStart()
{
	RegConsoleCmd("+sm_test", test);
	RegConsoleCmd("-sm_test", test);
}

public Action test(int client, int args)
{
	int arguments = args;
	int code = 0;

	char cmd[20];
	char button_name[20];
	char buffer[256];

	GetCmdArg(0, cmd, sizeof(cmd));

	// When button command +command
	if(arguments >= 1 && (cmd[0] == '+' || cmd[0] == '-'))
	{
		// look last argument
		GetCmdArg(arguments, button_name, sizeof(button_name));

		code = StringToInt(button_name);

		if(0 < code < BUTTONS_MAX) // in button range
		{
			arguments = arguments - 1; // decrease argument count by one
		}
		else
		{
			code = 0; // invalid
		}

		button_name[0] = '\0'; // clear string
	}

	GetCmdArgString(buffer, sizeof(buffer));

	// arguments count have decreased, button found
	if(arguments < args && code > 0)
	{
		// name button
		if(code >= sizeof(ButtonCodeName))
		{
			Format(button_name, sizeof(button_name), "joystic");
		}
		else
		{
			Format(button_name, sizeof(button_name), "%s", ButtonCodeName[code]);
		}

		// remove last argument from buffer[]
		if(arguments <= 0)
		{
			buffer[0] = '\0';
		}
		else
		{
			int index = FindCharInString(buffer, ' ', true);

			if(index != -1)
				buffer[index] = '\0';
		}
	}

	// Results!

	PrintToServer("\ncommand: %s\n\
button: %s\n\
GetCmdArgString: %s\n\
args: %i/%i",
	cmd, button_name, buffer, arguments, args);


	for(int x = 1; x <= arguments; x++)
	{
		GetCmdArg(x, buffer, sizeof(buffer));
		PrintToServer("GetCmdArg %i: %s", arguments, buffer);
	}

	return Plugin_Handled;
}

Results

bind p "+sm_test"
command: +sm_test
button: p
GetCmdArgString:
args: 0/1

command: -sm_test
button: p
GetCmdArgString:
args: 0/1


bind p "+sm_test quack"
command: +sm_test
button: p
GetCmdArgString: quack
args: 1/2
GetCmdArg 1: quack

command: -sm_test
button: p
GetCmdArgString: quack
args: 1/2
GetCmdArg 1: quack



+sm_test
command: +sm_test
button:
GetCmdArgString:
args: 0/0

+sm_test quack
command: +sm_test
button:
GetCmdArgString: quack
args: 1/1
GetCmdArg 1: quack

ambaca avatar Jun 30 '25 21:06 ambaca