June 14, 2008

Viper Woes

Written by theY4Kman at 9:51 pm under Viper and Python

I have a small blog post for ya, but it’s mostly for my sake. I made some very stupid mistakes over the past week with Viper, and I wish to share them with you (and archive the solutions for when I inevitably make them again).

First off, I had this code to create ConCommands:

pCmd = new ConCommand(new_name, CommandCallback, new_help, flags);

It took me around three or four days to realize I wasn’t registering pCmd. I slipped in META_REGCVAR(pCmd), and it works beautifully :D

Secondly, and lastly, I had consistency issues with paths. Windows is very annoying because it uses backslashes instead of forward slashes. This means that I have to escape every directory in a path. Thankfully, Python accepts both forward and back slashes in paths. However, a trie a does not. I had a lot of trouble determining why Viper couldn’t recognize which plug-in called Register (that function finds the path of the script which called it, looks it up in the trie, then updates the plug-in’s info). After a lot of searching, it finally dawned on me that the path entered into the trie and the path from Register were different. You can thank my shotty eyesight; I had printed out the two paths into the console and still couldn’t see any differences for the longest time :P

April 20, 2008

ConVar Manager Update and more!

Written by theY4Kman at 10:06 pm under Viper, SourceMod and Programming

Last night and today I worked on finishing the ConVar manager, which I did actually complete! All convars created inside of a plug-in are added to the ConVar manager’s internal database (A Trie) and the plug-in’s convar list. Tomorrow I’ll work on adding a “cvars” option to the Viper menu, which will be accessed with “sm py cvars”. I’ve created a test plug-in to create many ConVars, which successfully created every single one, and was able to retrieve the value from each; each convar was declared as a different type of data (Float, int, string, etc.), and retrieved by each type, so as to test my error checking, also.

There is one problem, though: If you create a convar from the console by using the Python interpreter command I’ve created, “py”, it does not work. The Python convar object is created, so you can call functions on it and the such, but the Source ConVar class instantiated through “new ConVar(name, defaultVal, …)” equates to NULL when accessed. The chain of command is this:

  1. On the Python side, the user creates a convar object
    convar = console.CreateConVar("a_name", "a_value")
  2. CreateConVar does some simple error checking (Making sure the name isn’t blank, etc) and calls New_ConVarObject, then Init_ConVarObject. I’m going to showoff here and present the code of this:
    static PyObject * Console_CreateConVar(PyObject* self, PyObject* args, PyObject *keywds)
    {
    	char const *pName, *pDefaultValue, *pHelpString = NULL;
    	int flags = FCVAR_PLUGIN;
    	float fMin = NULL, fMax = NULL;
     
    	static char* kwds[] = {"name", "value", "desc", "flags", "max", "min", NULL};
     
    	if(!PyArg_ParseTupleAndKeywords(args, keywds, "ss|siff", kwds, &pName, &pDefaultValue, &pHelpString, &flags, &fMin, &fMax))
    		return NULL;
     
    	if(pName[0] == '\0')
    		Py_RETURN_NONE;
     
    	Py_XINCREF((PyObject*) &console_ConVarType);
    	PyObject* ConVarObj = (PyObject*) console_ConVarType->tp_new((_typeobject*)console_ConVarType, args, (PyObject*)NULL);
    	ConVarObj->ob_type->tp_init(ConVarObj, args, (PyObject*)NULL);
    	return ConVarObj;
    }
  3. New_ConVarObject just sets the values of the object. Nothing to see here.
  4. Init_ConVarObject does all the real work for the Python side: error rechecks (Just in case :D), creates the ConVar (Through the ConVar manager), and does some work after the ConVar object is created.
  5. The ConVar manager does all the real work on the C++ side:
    static int console_ConVar_Get(console_ConVarObject *self, PyObject *args, PyObject *keywds)
    {
    	char const *pName, *pDefaultValue, *pHelpString = NULL;
    	int iFlags = 0;
    	float fMin = NULL, fMax = NULL;
     
    	static char* kwds[] = {"name", "value", "desc", "flags", "max", "min", NULL};
     
    	if(!PyArg_ParseTupleAndKeywords(args, keywds, "ss|siff", kwds, &pName, &pDefaultValue, &pHelpString, &iFlags, &fMin, &fMax))
    		return -1;
     
    	// Make sure the ConVar has a name. teame06 would be dumb enough to make a ConVar with no name, which is why I add this check in!
    	if(pName[0] == '\0')
    	{
    		PyErr_SetString(PyExc_ValueError, "cannot have a blank ConVar name.");
    		return -1;
    	}
     
    	CPlugin* pPlugin = g_VPlugins.GetPluginByPath(GetCurrentPath());
     
    	if(pPlugin == NULL)
    	{
    		PyErr_SetString(PyExc_StandardError, "error in accessing the plugin.");
    		return -1;
    	}
     
    	self->info = g_VVars.CreateConVar(pPlugin, pName, pDefaultValue, pHelpString,
    				 iFlags, (fMin != NULL), fMin, (fMax != NULL), fMax);
     
    	if(!self->info || !self->info->pCvar)
    	{
    		PyErr_SetString(PyExc_StandardError, "error in creating ConVar.");
    		return -1;
    	}
     
    	self->info->handle = self;
    	self->convar = self->info->pCvar;
     
    	printf("Convar '%s': '%s'\n", self->convar->GetName(), self->convar->GetString());
     
    	return 0;
    }

Anyways, I’m getting way too technical now. Nobody understands me. I’ll go cry in a corner.

The “and more!” is that I added ClientCommand and FakeClientCommand to the Client object. I’ll work on the Client object tomorrow, too; it needs Kick and Ban. Now, off to workout and bed for me!

April 19, 2008

ConCmd/Var Manager Deadline

Written by theY4Kman at 10:11 pm under Viper and Programming

Today, I set a deadline for the console command and variable managers. I was to finish the pair in around 3 hours, beginning at 3pm EST. It worked very well for around an hour, until I had an urge to play Team Fortress 2, for which I paused development, played for an hour, and pushed the deadline ahead another hour. The time I spent developing Viper was extremely productive, compared to my regular barely-work-lots-of-play schedule, which wreaks havoc on my development and school work :P

The results of it were, well, okay, at best. However, the so-so results were caused by fixing compiler errors, not from lack of work. I had much trouble with the py_console files. For example, recent compiling brought forth new errors to py_console.cpp; first off, there was this:
'console_ConVarType' : redefinition; different types of indirection

Then, this sprung up:
C:\coding\hl2sdk\public\tier1/utlmemory.h(102) : error C2129: static function 'int console_ConVar_Get(PyObject *,PyObject *,PyObject *)' declared but not defined

It made absolutely no sense, for many reasons:

  1. utlmemory.h is not directly included from the file I suspected was causing the error (py_console.cpp)
  2. utlmemory.h is part of the HL2SDK, and should have nothing to do with my Python files
  3. Sawce loves Rukia!

I’ll be working on it tonight, and hopefully it’ll be committed working by the time I hit the showers.

Powered by WordPress. Driven by caffeine.