synapse: when using '*' for the minor, work extra hard to match with a single, already active provider. this fixes the problems related to having pk3 vfs and qlpk3 vfs both loaded for instance

This commit is contained in:
Timothee 'TTimo' Besset 2012-09-16 22:57:31 -05:00
parent 2061e40028
commit def29cb7b4
7 changed files with 111 additions and 20 deletions

View file

@ -387,7 +387,7 @@ extern "C" CSynapseClient * SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( cons
g_SynapseClient.AddAPI( PLUGIN_MAJOR, "HydraToolz", sizeof( _QERPluginTable ) );
g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable );
g_SynapseClient.AddAPI( VFS_MAJOR, "wad", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable );
g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); // wad, typically
g_SynapseClient.AddAPI( ENTITY_MAJOR, NULL, sizeof( g_EntityTable ), SYN_REQUIRE, &g_EntityTable );
return &g_SynapseClient;
}

View file

@ -404,6 +404,11 @@ virtual bool OnActivate() { return true; }
\return wether all APIs given were successfully found in the config
*/
bool ConfigXML( CSynapseServer *pServer, const char *client_name, const XMLConfigEntry_t entries[] );
/*!
search for a SYN_PROVIDE with that major in this client, return the index, or -1 if fail
*/
APIDescriptor_t * FindProvidesMajor( const char * major ) const;
};
/*!
@ -607,8 +612,13 @@ virtual PFN_SYN_PRINTF_VA Get_Syn_Printf();
the minors have to be both NULL, or equal, or one the minors be '*'
NOTE: the '*' minor should ONLY be used on an API that will be unique. It is hackish and kinda dangerous
*/
static bool MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 );
static bool MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 );
bool MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 );
/*!
\return 0: not matching
\return 1: matching
\return 2: do extended checks for a minor of "*"
*/
static int MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 );
#if defined( _WIN32 )
/*!
@ -655,6 +665,15 @@ bool GetConfigForAPI( const char *api, char **minor );
returns the filename of the module that the passed on client exists in
*/
const char *GetModuleFilename( CSynapseClient *pClient );
/*!
look for a client that is active, and provides a specific major
\return 0: not found
\return 1: single found
\return 2: multiple found
*/
int FindActiveMajorClient( const char * major, APIDescriptor_t ** ret ) const;
};
#endif

View file

@ -424,23 +424,83 @@ void CSynapseServer::PushRequired( CSynapseClient *pClient ){
}
}
bool CSynapseServer::MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ){
return MatchAPI( p1->major_name, p1->minor_name, p2->major_name, p2->minor_name );
int CSynapseServer::FindActiveMajorClient( const char * major, APIDescriptor_t ** ret ) const {
Syn_Printf( "checking if we have a single active client for major \"%s\"\n", major );
*ret = NULL;
list<CSynapseClientSlot>::const_iterator iClient;
for ( iClient = mClients.begin(); iClient != mClients.end(); iClient++ ) {
CSynapseClient *pClient = ( *iClient ).mpClient;
if ( !pClient->IsActive() ) {
continue;
}
APIDescriptor_t * found = pClient->FindProvidesMajor( major );
if ( found == NULL ) {
continue;
}
Syn_Printf( " found in %s\n", pClient->GetInfo() );
if ( *ret != NULL ) {
return 2;
}
*ret = found;
}
if ( *ret == NULL ) {
return 0;
}
return 1;
}
bool CSynapseServer::MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ){
if ( strcmp( major1, major2 ) ) {
bool CSynapseServer::MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ){
int ret = MatchAPI( p1->major_name, p1->minor_name, p2->major_name, p2->minor_name );
if ( ret == 2 ) {
// find out if we can resolve the minor "*" situation
APIDescriptor_t * any_minor_descriptor;
APIDescriptor_t * provider_descriptor;
if ( strcmp( p1->minor_name, "*" ) == 0 ) {
any_minor_descriptor = p1;
provider_descriptor = p2;
} else {
assert( strcmp( p2->minor_name, "*" ) == 0 );
any_minor_descriptor = p2;
provider_descriptor = p1;
}
assert( any_minor_descriptor->mType == SYN_REQUIRE );
assert( provider_descriptor->mType == SYN_PROVIDE );
APIDescriptor_t * search_major;
int search_ret = FindActiveMajorClient( provider_descriptor->major_name, &search_major );
if ( search_ret == 2 ) {
// FIXME: ERROR
Syn_Printf( "ERROR: Multiple modules active for major \"%s\": cannot resolve \"*\" for it\n", provider_descriptor->major_name );
return false;
}
if ( search_ret == 0 ) {
// can't resolve yet
return false;
}
if ( search_major != provider_descriptor ) {
// the provider_descriptor we were passed is likely not active yet, so just ignore
return false;
}
return true; // this is a go, we have a unique match!
}
return ( ret != 0 );
}
int CSynapseServer::MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ){
if ( strcmp( major1, major2 ) != 0 ) {
return 0;
}
// either no minor at all for this API, or matching
if ( ( minor1 && minor2 ) && !strcmp( minor1, minor2 ) ) {
return true;
if ( ( minor1 != NULL && minor2 != NULL ) && strcmp( minor1, minor2 ) == 0 ) {
return 1;
}
// or one of the minors says "*" (knowing that the majors match already)
if ( ( minor1 && !strcmp( minor1, "*" ) ) || ( minor2 && !strcmp( minor2, "*" ) ) ) {
return true;
if ( ( minor1 != NULL && strcmp( minor1, "*" ) == 0 ) || ( minor2 != NULL && strcmp( minor2, "*" ) == 0 ) ) {
// one of the minors is "*", and the majors are matching
// there may be multiple SYN_PROVIDE for this major though, and we can't decide which with only this information
// e.g. "*" means "the one", not "any" (counter-intuitive, yeah)
// so let the caller know, maybe he'll figure it out
return 2;
}
return false;
return 0;
}
bool CSynapseServer::ResolveAPI( APIDescriptor_t* pAPI ){
@ -469,9 +529,9 @@ bool CSynapseServer::ResolveAPI( APIDescriptor_t* pAPI ){
continue;
}
// this is an active client, we can request
#ifdef SYNAPSE_VERBOSE
#ifdef SYNAPSE_VERBOSE
Syn_Printf( "RequestAPI '%s' '%s' from '%s' for API %p\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI );
#endif
#endif
if ( !pScanClient->RequestAPI( pAPI ) ) {
// this should never happen, means we think this module provides the API, but it answers that it doesn't
Syn_Printf( "ERROR: RequestAPI failed\n" );
@ -911,6 +971,18 @@ void CSynapseClient::AddManager( CSynapseAPIManager *pManager ){
}
}
APIDescriptor_t * CSynapseClient::FindProvidesMajor( const char * major ) const {
int i,max = GetAPICount();
for ( i = 0; i < max; i++ )
{
APIDescriptor_t *pAPI = GetAPIDescriptor( i );
if ( pAPI->mType == SYN_PROVIDE && strcmp( pAPI->major_name, major ) == 0 ) {
return pAPI;
}
}
return NULL;
}
CSynapseAPIManager::~CSynapseAPIManager(){
vector<APIDescriptor_t *>::iterator iAPI;
for ( iAPI = mAPIs.begin(); iAPI != mAPIs.end(); iAPI++ )

View file

@ -155,7 +155,7 @@ extern "C" CSynapseClient * SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( cons
g_SynapseClient.AddAPI( ECLASSMANAGER_MAJOR, NULL, sizeof( g_EClassManagerTable ), SYN_REQUIRE, &g_EClassManagerTable );
// Needs a 'default' option for this minor because we certainly don't load anything from wad files :)
g_SynapseClient.AddAPI( VFS_MAJOR, "wad", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable );
g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); // wad, typically
return &g_SynapseClient;
}

View file

@ -75,7 +75,7 @@ extern "C" CSynapseClient * SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( cons
g_SynapseClient.AddAPI( IMAGE_MAJOR, "spr", sizeof( _QERPlugImageTable ) );
#endif
// this "wad" needs to be "*" for the VFS, we don't care what VFS we have, as long as we have one.
g_SynapseClient.AddAPI( VFS_MAJOR, "wad", sizeof( _QERFileSystemTable ), SYN_REQUIRE, &g_FileSystemTable );
g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( _QERFileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); // wad, typically
g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( _QERFuncTable_1 ), SYN_REQUIRE, &g_FuncTable );
return &g_SynapseClient;

View file

@ -63,7 +63,7 @@ extern "C" CSynapseClient * SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( cons
g_SynapseClient.AddAPI( IMAGE_MAJOR, "png", sizeof( _QERPlugImageTable ) );
g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( _QERFuncTable_1 ), SYN_REQUIRE, &g_FuncTable );
g_SynapseClient.AddAPI( VFS_MAJOR, "pk3", sizeof( _QERFileSystemTable ), SYN_REQUIRE, &g_FileSystemTable );
g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( _QERFileSystemTable ), SYN_REQUIRE, &g_FileSystemTable );
return &g_SynapseClient;
}

View file

@ -62,7 +62,7 @@ void CSynapseBuiltinClientDef::EnumerateInterfaces( CSynapseServer *server ){
AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable );
AddAPI( ECLASSMANAGER_MAJOR, NULL, sizeof( g_EClassManagerTable ), SYN_REQUIRE, &g_EClassManagerTable );
// hardcode the minor for now, we can still add it to the synapse.config at some point
AddAPI( VFS_MAJOR, "pk3", sizeof( g_FileSystemTable_def ), SYN_REQUIRE, &g_FileSystemTable_def );
AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable_def ), SYN_REQUIRE, &g_FileSystemTable_def );
AddAPI( ECLASS_MAJOR, "def", sizeof( _EClassTable ) );
}