.:: Bots United ::.  
filebase forums discord server github wiki web
cubebot epodbot fritzbot gravebot grogbot hpbbot ivpbot jkbotti joebot
meanmod podbotmm racc rcbot realbot sandbot shrikebot soulfathermaps yapb

Go Back   .:: Bots United ::. > Developer's Farm > SDK Programming discussions > Half-Life 2 SDK
Half-Life 2 SDK For developments focused around the Half-Life 2 engine Half-Life 2

Reply
 
Thread Tools
the new event interface...
Old
  (#1)
Pierre-Marie Baty
Roi de France
 
Pierre-Marie Baty's Avatar
 
Status: Offline
Posts: 5,049
Join Date: Nov 2003
Location: 46°43'60N 0°43'0W 0.187A
Default the new event interface... - 21-02-2005

I can't seem to be able to hook all the events like before and iterate through all their key/values and display them... it looks like Valve changed the event listening interface and wants us to use something else, but the server plugin sample from the SDK hasn't been updated to reflect it

Does anybody know anything about this issue ?



RACC home - Bots-United: beer, babies & bots (especially the latter)
"Learn to think by yourself, else others will do it for you."
  
Reply With Quote
Re: the new event interface...
Old
  (#2)
botman
Super Moderator
 
Status: Offline
Posts: 280
Join Date: Jan 2004
Location: Plano, TX
Default Re: the new event interface... - 22-02-2005

You shouldn't have left the hlcoders email list...

http://www.mail-archive.com/hlcoders.../msg10848.html

botman
  
Reply With Quote
Re: the new event interface...
Old
  (#3)
Pierre-Marie Baty
Roi de France
 
Pierre-Marie Baty's Avatar
 
Status: Offline
Posts: 5,049
Join Date: Nov 2003
Location: 46°43'60N 0°43'0W 0.187A
Default Re: the new event interface... - 22-02-2005

thank you botman

*edit* WHOA!
  1. get 3 files from the Steam cache
  2. parse them and build ourselves an array of the event list
  3. register ourselves as listener successively for every single event
  4. for every single event received, match it against our array and use this info to request each of its subkeys
  5. display!
quite an overhead o_O

We've also had a conversation with Alfred regarding the Source interface. For me I see a major flaw in their current design. They use version numbers as if the interface providers were capable of backwards compatibility whereas it's not, which means that
  1. I can't use the same plugin DLL on different Source games
  2. I need to maintain one version of the SDK for each of these games
  3. Anytime Valve changes one single interface, all hell breaks loose.
Quote:
Originally Posted by PMB
Hello,

Not sure where I should have sent this, so please forward to whom may be concerned with my apologies if it's not to you.

I am developing Source server plugins and I found a bug in the engine's interfaceFactory related to the new game event manager interface.

In my plugins I am using an interface loader macro, that tries to find the right version number automatically for each interface I load. This enables me to run the same plugin DLL on different games (such as CS:Source and HL2DM). This macro first assumes a high interface version and builds the corresponding version string, and downgrades successively until it finds the right version and the interface can be attached.

This used to work fine for all the interfaces, but since the latest source SDK update relative to HL2DM, it happens that if you don't ask interfaceFactory() the right version number for the IGameEventManager interface, instead of just refusing to attach the interface it makes HL2DM crash. This is annoying because I can't use my macro anymore.

I believe it should be fairly simple to fix it for the next HL2DM engine update.

Thanks in advance for your time.
Quote:
Originally Posted by Alfred
Can you be more precise about the problem. Does it crash if you load the new interface? Or only the old interface (with HL2MP loading the new one)?
Quote:
Originally Posted by PMB
I can load the old interface *only* if I ask the correct version number, but not with my macro that tries to guess the version numbers. Instead of returning a NULL pointer when the version number I ask isn't the right one (which is what it does for all the other interfaces BUT this one), interfaceFactory() makes the game crash. To me, it's most likely because the old IGameEventManager and the new IGameEventManager2 are completely different classes but with similar version strings. Perhaps it would have been wiser to make IGameEventManager2 a separate interface, using a different version string (such as "GAMEEVENTSMANAGER2_001" for example).

I needed the old interface because until another solution is found, I want to be able to hook any event without needing to register it explicitly, and be able to iterate through all its key/values in order to display them, even if I don't know their name.

Perhaps it would be wise to update the sample server plugin project of the SDK to show how to use the new event manager interface.

Thanks for your time, anyway.
Quote:
Originally Posted by Alfred
The version string doesn't effect anything. Are you querying for the old interface but using the new IGameEventManager2 class defn against it? (or vice-versa, old IGameEventManager with new interface) Because that would never work (and is just plain bad code). Could you send me a snippet of (un macro'd) code that causes the crash so I can better understand what you are doing
Quote:
Originally Posted by PMB
I beg to differ: that's precisely the problem. My macro takes out the 3 last digits of the version string and appends arbitrary ones, forming a number which goes decreasing until the interface can be loaded. And since the IGameEventManager and IGameEventManager2 classes have similar version strings, I can't use this method anymore, and thus my plugins cannot be used on different game/mods.

This is what the macro does (simplified), which makes the game crash (you'll see why at first sight I suppose):
Code:
char ifv_string[64]; // version string, last 3 digits stripped
int ifv_number; // version number to append to the above
char interface_version[64]; // resulting string
 
// copy the version string in a new string, strip out the last 3 digits
strcpy (ifv_string, INTERFACEVERSION_GAMEEVENTSMANAGER);
ifv_string[strlen (INTERFACEVERSION_GAMEEVENTSMANAGER) - 3] = 0;
 
// build a new version string
// downgrade from 100 to 1 until the interface can be loaded
for (ifv_number = 100; ifv_number > 0; ifv_number--)
{
sprintf (interface_version, "%s%03d", ifv_string, ifv_number);
if (gameevents = (IGameEventManager *) interfaceFactory (interface_version, NULL))
	 break; // stop trying as soon as the interface is found
}
...and this causes the crash, because interfaceFactory returns a pointer to a IGameEventManager2 when ifv_number reaches 2, because interface_version is then "GAMEEVENTSMANAGER002". Like I said, the problem comes from the use of similar version strings for returning different interface classes. It makes further guessing of the interface version, and hence cross-game reusability, impossible

I hope this can be sorted out in some way
Quote:
Originally Posted by Alfred
Your method of walking interfaces is flawed, there is not guarantee (or even expectation) that two versions of an interface will have a compatible vtable representation (hence the use of versions). You should only use versions your plugin knows about (hard coded versions), with special cases for supporting older interfaces.
Quote:
Originally Posted by PMB
Well thanks. I was expecting you would be doing like with HL1, and only add new class members at the end of the vtable to ensure backwards compatibility to a certain extent, but if that's not the case, guessing the interface number is indeed pointless.

Now I will need to maintain one version of the SDK for each Steam game I intend to use my plugins with. Needless to say I preferred the HL1 method.

I don't get it. Even the use of version strings is pointless, since when a plugin *requires* an interface and that interface cannot be loaded, returning false in CPlugin::Load() only makes the server crash. I don't understand you people at Valve. What's the point of using version numbers if there's no backwards compatibility ? :-/
I hope I can get an answer, but still, the way they designed their interfaces is incomprehensible to me



RACC home - Bots-United: beer, babies & bots (especially the latter)
"Learn to think by yourself, else others will do it for you."

Last edited by Pierre-Marie Baty; 22-02-2005 at 16:07..
  
Reply With Quote
Re: the new event interface...
Old
  (#4)
botman
Super Moderator
 
Status: Offline
Posts: 280
Join Date: Jan 2004
Location: Plano, TX
Default Re: the new event interface... - 23-02-2005

I think the engine maintains backward compatibility by keeping EACH version of a class separate. (i.e. the engine keeps a separate copy of version 001, and a separate copy of version 002, and a separate copy of version 003, etc). So that when you ask for version 002, you get EXACTLY that class definition as it was defined at the time that SDK was released. For newer MODs (using a newer SDK) that ask for version 003, they get EXACTLY what the class definition was in the SDK at the time that interface version was released in the SDK (and these class definitions can be completely different from each other).

The engine basically keeps an archive of all the current and previous class definitions and has code that supports each one, so that no matter which interface version you ask for, the engine gives you exactly that one (without any assumed knowledge of what previous versions of that interface looked like). So you shouldn't assume that version C is version B with a little bit more added at the end and version B is version A with a little bit more added at the end. It could be that they created version A, then went "Oh, shit!", we can do this an entirely different way, let's change everything in version B. Then when version C comes out they go, "Oh, heck!", we could have used version A with some minor changes, lets change the class definition again to go back to version A with a couple of minor changes, etc. Each class definition can be completely different than the previous version. It makes the engine a lot bigger and a lot more complicated, but it completely prevents the newer version of the engine from breaking older (not updated) MODs.

botman

Last edited by botman; 23-02-2005 at 15:23..
  
Reply With Quote
Re: the new event interface...
Old
  (#5)
Cheeseh
[rcbot]
 
Cheeseh's Avatar
 
Status: Offline
Posts: 361
Join Date: Dec 2003
Location: China
Default Re: the new event interface... - 19-03-2005

so how do you pick up events with the new SDK, whats the firing method??

I mean, I know I need to make the plugin implement the IGameEventListener2 interface as well, then add the FireGameEvent(IGameEvent*) method into the plugin. Then add a listener to every event I want to catch. But the events never get called, I don't know whats wrong, maybe it's because I'm trying to support both old & new methods at the same time.

[edit]

8o ok looks as though yuo can only do one at a time (or maybe it's only certain events that seem to work -- what happens to the bulletimpact event?), after I made an interface to work on both, oh well it's easy to switch between the two. Although I was wondering, you could get the "eventid" from the keyvalues as an integer instead of having to seach the string all the time you can check the integer for the correct event. It doesn't seem to wok with IGameEvent anymore, alwasy returns 0

Last edited by Cheeseh; 19-03-2005 at 03:23..
  
Reply With Quote
Re: the new event interface...
Old
  (#6)
Pierre-Marie Baty
Roi de France
 
Pierre-Marie Baty's Avatar
 
Status: Offline
Posts: 5,049
Join Date: Nov 2003
Location: 46°43'60N 0°43'0W 0.187A
Default Re: the new event interface... - 19-03-2005

I have managed to sort of "repair" the event interface in server plugins (I mean make the plugin able to hook ANY event, known or unknown).
Code:
// global variables
KeyValues *GameEvents;
KeyValues *EngineEvents;
KeyValues *ModEvents;

void CPlugin::LevelInit (const char *pMapName)
{
   KeyValues *pEvent;
   // read the game events
   GameEvents = new KeyValues ("GameEventsFile");
   if (GameEvents->LoadFromFile (filesystem, "resource/gameevents.res", "GAME"))
   {
	  // loop through all events in this file and record ourselves as listener for each
	  for (pEvent = GameEvents->GetFirstSubKey (); pEvent; pEvent = pEvent->GetNextKey ())
		 gameeventmanager->AddListener (this, pEvent->GetName (), true);
   }
   else
	  ServerConsole_printf ("Unable to read game events from file\n");
   // read the engine events
   EngineEvents = new KeyValues ("EngineEventsFile");
   if (EngineEvents->LoadFromFile (filesystem, "resource/serverevents.res", "GAME"))
   {
	  // loop through all events in this file and record ourselves as listener for each
	  for (pEvent = EngineEvents->GetFirstSubKey (); pEvent; pEvent = pEvent->GetNextKey ())
		 gameeventmanager->AddListener (this, pEvent->GetName (), true);
   }
   else
	  ServerConsole_printf ("Unable to read engine events from file\n");
   // read the MOD events
   ModEvents = new KeyValues ("ModEventsFile");
   if (ModEvents->LoadFromFile (filesystem, "resource/modevents.res", "MOD"))
   {
	  // loop through all events in this file and record ourselves as listener for each
	  for (pEvent = ModEvents->GetFirstSubKey (); pEvent; pEvent = pEvent->GetNextKey ())
		 gameeventmanager->AddListener (this, pEvent->GetName (), true);
   }
   else
	  ServerConsole_printf ("Unable to read MOD events from file\n");
   return;
}

void CPlugin::LevelShutdown (void)
{
   // forget about game, engine and mod events
   GameEvents->deleteThis ();
   EngineEvents->deleteThis ();
   ModEvents->deleteThis ();
   gameeventmanager->RemoveListener (this); // and stop listening to them
}

void CPlugin::FireGameEvent (IGameEvent *event)
{
   // do we want to display game events on the fly ?
   if (hook_events.GetInt () > 0)
   {
	  printf ("Event \"%s\" received\n", event->GetName ()); // notify the player on his HUD
	  PrintEvent (event);
   }
   return; // finished
}

CON_COMMAND (listevt, "List all the events matching a given pattern")
{
   KeyValues *pEventAsKey;
   int event_count;
   char arg1[128]; // no way, I hate pointers...
   sprintf (arg1, engine->Cmd_Argv (1)); // get any argument to the command
   // tell people what we are going to do
   if (arg1[0] == 0)
	  ServerConsole_printf ("Printing out ALL game, server and MOD events...\n");
   else
	  ServerConsole_printf ("Printing out game, server and MOD events matching \"%s\"...\n", arg1);
   ServerConsole_printf ("Game events:\n");
   event_count = 0;
   for (pEventAsKey = GameEvents->GetFirstSubKey (); pEventAsKey; pEventAsKey = pEventAsKey->GetNextKey ())
   {
	  // if we want a particular pattern AND this event does not match
	  if ((arg1[0] != 0) && (strstr (pEventAsKey->GetName (), arg1) == NULL))
		 continue; // then skip it
	  PrintEventStructure (pEventAsKey); // display this event's structure
	  event_count++;
   }
   ServerConsole_printf ("%d game event%s.\n", event_count, (event_count > 1 ? "s" : ""));
   ServerConsole_printf ("Engine events:\n");
   event_count = 0;
   for (pEventAsKey = EngineEvents->GetFirstSubKey (); pEventAsKey; pEventAsKey = pEventAsKey->GetNextKey ())
   {
	  // if we want a particular pattern AND this event does not match
	  if ((arg1[0] != 0) && (strstr (pEventAsKey->GetName (), arg1) == NULL))
		 continue; // then skip it
	  PrintEventStructure (pEventAsKey); // display this event's structure
	  event_count++;
   }
   ServerConsole_printf ("%d engine event%s.\n", event_count, (event_count > 1 ? "s" : ""));
   ServerConsole_printf ("MOD events:\n");
   event_count = 0;
   for (pEventAsKey = ModEvents->GetFirstSubKey (); pEventAsKey; pEventAsKey = pEventAsKey->GetNextKey ())
   {
	  // if we want a particular pattern AND this event does not match
	  if ((arg1[0] != 0) && (strstr (pEventAsKey->GetName (), arg1) == NULL))
		 continue; // then skip it
	  PrintEventStructure (pEventAsKey); // display this event's structure
	  event_count++;
   }
   ServerConsole_printf ("%d MOD event%s.\n", event_count, (event_count > 1 ? "s" : ""));
   return;
}

void PrintEvent (IGameEvent *pEvent)
{
   KeyValues *pEventAsKey;
   KeyValues *pKey;
   ServerConsole_printf ("Got event \"%s\"\n", pEvent->GetName ()); // event name
   ServerConsole_printf ("{\n"); // print the open brace
   // find the key/value corresponding to this event
   pEventAsKey = NULL;
   // look in the game events first...
   if (pEventAsKey == NULL)
	  for (pEventAsKey = GameEvents->GetFirstSubKey (); pEventAsKey; pEventAsKey = pEventAsKey->GetNextKey ())
		 if (strcmp (pEventAsKey->GetName (), pEvent->GetName ()) == 0)
			break;
   // if not found, then look in the engine events...
   if (pEventAsKey == NULL)
	  for (pEventAsKey = EngineEvents->GetFirstSubKey (); pEventAsKey; pEventAsKey = pEventAsKey->GetNextKey ())
		 if (strcmp (pEventAsKey->GetName (), pEvent->GetName ()) == 0)
			break;
   // and finally look for it in the mod events
   if (pEventAsKey == NULL)
	  for (pEventAsKey = ModEvents->GetFirstSubKey (); pEventAsKey; pEventAsKey = pEventAsKey->GetNextKey ())
		 if (strcmp (pEventAsKey->GetName (), pEvent->GetName ()) == 0)
			break;
   // display the whole key/value tree for this event
   for (pKey = pEventAsKey->GetFirstSubKey (); pKey; pKey = pKey->GetNextKey ())
   {
	  // given the data type, print out the data
	  if (strcmp (pKey->GetString (), "none") == 0)
		 ServerConsole_printf ("   \"%s\" = no value (TYPE_NONE)\n", pKey->GetName ());
	  else if (strcmp (pKey->GetString (), "string") == 0)
		 ServerConsole_printf ("   \"%s\" = \"%s\" (TYPE_STRING)\n", pKey->GetName (), pEvent->GetString (pKey->GetName ()));
	  else if (strcmp (pKey->GetString (), "bool") == 0)
		 ServerConsole_printf ("   \"%s\" = %s (TYPE_BOOL)\n", pKey->GetName (), (pEvent->GetBool (pKey->GetName ()) ? "true" : "false"));
	  else if (strcmp (pKey->GetString (), "byte") == 0)
		 ServerConsole_printf ("   \"%s\" = %d (TYPE_BYTE)\n", pKey->GetName (), pEvent->GetInt (pKey->GetName ()));
	  else if (strcmp (pKey->GetString (), "short") == 0)
		 ServerConsole_printf ("   \"%s\" = %d (TYPE_SHORT)\n", pKey->GetName (), pEvent->GetInt (pKey->GetName ()));
	  else if (strcmp (pKey->GetString (), "long") == 0)
		 ServerConsole_printf ("   \"%s\" = %d (TYPE_LONG)\n", pKey->GetName (), pEvent->GetInt (pKey->GetName ()));
	  else if (strcmp (pKey->GetString (), "float") == 0)
		 ServerConsole_printf ("   \"%s\" = %f (TYPE_FLOAT)\n", pKey->GetName (), pEvent->GetFloat (pKey->GetName ()));
   }
   ServerConsole_printf ("}\n"); // print the closing brace
   return;
}

void PrintEventStructure (KeyValues *pEventAsKey)
{
   KeyValues *pKey;
   ServerConsole_printf ("Event \"%s\"\n", pEventAsKey->GetName ()); // event name
   ServerConsole_printf ("{\n"); // print the open brace
   // display the whole key/value tree for this event
   for (pKey = pEventAsKey->GetFirstSubKey (); pKey; pKey = pKey->GetNextKey ())
   {
	  // given the data type, print out the data
	  if (strcmp (pKey->GetString (), "none") == 0)
		 ServerConsole_printf ("   \"%s\", no value (TYPE_NONE)\n", pKey->GetName ());
	  else if (strcmp (pKey->GetString (), "string") == 0)
		 ServerConsole_printf ("   \"%s\" (TYPE_STRING)\n", pKey->GetName ());
	  else if (strcmp (pKey->GetString (), "bool") == 0)
		 ServerConsole_printf ("   \"%s\" (TYPE_BOOL)\n", pKey->GetName ());
	  else if (strcmp (pKey->GetString (), "byte") == 0)
		 ServerConsole_printf ("   \"%s\" (TYPE_BYTE)\n", pKey->GetName ());
	  else if (strcmp (pKey->GetString (), "short") == 0)
		 ServerConsole_printf ("   \"%s\" (TYPE_SHORT)\n", pKey->GetName ());
	  else if (strcmp (pKey->GetString (), "long") == 0)
		 ServerConsole_printf ("   \"%s\" (TYPE_LONG)\n", pKey->GetName ());
	  else if (strcmp (pKey->GetString (), "float") == 0)
		 ServerConsole_printf ("   \"%s\" (TYPE_FLOAT)\n", pKey->GetName ());
   }
   ServerConsole_printf ("}\n"); // print the closing brace
   return;
}
Here are code bits from PMTools2, you should have enough to do something usable with them



RACC home - Bots-United: beer, babies & bots (especially the latter)
"Learn to think by yourself, else others will do it for you."
  
Reply With Quote
Re: the new event interface...
Old
  (#7)
Cheeseh
[rcbot]
 
Cheeseh's Avatar
 
Status: Offline
Posts: 361
Join Date: Dec 2003
Location: China
Default Re: the new event interface... - 20-03-2005

thanks, I've kinda got it working. I've just makde a command that can be used in the console to tell whether you want the bot to use the new or old method or getting events.

By the way, is there no "eventid" anymore? I posted in hlcoders, no response yet, just wondering if you found the same thing. There used to be an "int" called "eventid" that was a unique number for that event, so instead of comparing the event name string , it's qjuicker to check the event id.
  
Reply With Quote
Re: the new event interface...
Old
  (#8)
Pierre-Marie Baty
Roi de France
 
Pierre-Marie Baty's Avatar
 
Status: Offline
Posts: 5,049
Join Date: Nov 2003
Location: 46°43'60N 0°43'0W 0.187A
Default Re: the new event interface... - 20-03-2005

no eventid anymore AFAIK.



RACC home - Bots-United: beer, babies & bots (especially the latter)
"Learn to think by yourself, else others will do it for you."
  
Reply With Quote
Re: the new event interface...
Old
  (#9)
DrEvil
Member
 
DrEvil's Avatar
 
Status: Offline
Posts: 142
Join Date: Jan 2004
Location: Los Angeles, CA
Default Re: the new event interface... - 26-05-2005

PMB, does your event code you posted above work in the latest version of HL2DM or CS:S ? I'm getting an odd crash in the gameeventmanager->AddListener (this, pEvent->GetName (), true); line, even though all the gameeventmanager and pEvent are valid pointers and pEvent->GetName() is even returning a valid event name.

edit: nevermind, apparently it was a problem elsewhere that caused a crash there.



Omni-bot AI framework
http://www.omni-bot.com

Foxbot - for Team Fortress Classic
http://www.foxbot.net



Last edited by DrEvil; 26-05-2005 at 15:20..
  
Reply With Quote
Re: the new event interface...
Old
  (#10)
Pierre-Marie Baty
Roi de France
 
Pierre-Marie Baty's Avatar
 
Status: Offline
Posts: 5,049
Join Date: Nov 2003
Location: 46°43'60N 0°43'0W 0.187A
Default Re: the new event interface... - 26-05-2005

I might be interested in knowing more about what your problem was because I'm having crashes at level change in the RACC HL2 interface since recently ?



RACC home - Bots-United: beer, babies & bots (especially the latter)
"Learn to think by yourself, else others will do it for you."
  
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump



Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
vBulletin Skin developed by: vBStyles.com