📄 listener.cpp
字号:
}
#endif
EXPORT_FROM_DLL qboolean Listener::ValidEvent
(
Event &e
)
{
ClassDef *c;
int ev;
ev = ( int )e;
c = this->classinfo();
assert( ( ev >= 0 ) && ( ev < c->numEvents ) );
if ( ( ev < 0 ) || ( ev >= c->numEvents ) )
{
warning( "ValidEvent", "Event '%s' out of response range for class '%s'. "
"Event probably invalid or allocated late.\n", e.getName().c_str(), getClassname() );
return false;
}
return ( c->responseLookup[ ev ] != NULL );
}
EXPORT_FROM_DLL qboolean Listener::ValidEvent
(
const char *name
)
{
ClassDef *c;
int ev;
ev = Event::FindEvent( name );
c = this->classinfo();
assert( ( ev >= 0 ) && ( ev < c->numEvents ) );
if ( ( ev < 0 ) || ( ev >= c->numEvents ) )
{
warning( "ValidEvent", "Event '%s' out of response range for class '%s'. "
"Event probably invalid or allocated late.\n", name, getClassname() );
return false;
}
return ( c->responseLookup[ ev ] != NULL );
}
EXPORT_FROM_DLL qboolean Listener::EventPending
(
Event &ev
)
{
eventcache_t *event;
int eventnum;
assert( EventQueue );
assert( EventQueue->next );
event = EventQueue->next;
eventnum = ( int )ev;
while( event != EventQueue )
{
if ( ( event->obj == this ) && ( (int)*event->event == eventnum ) )
{
return true;
}
event = event->next;
}
return false;
}
EXPORT_FROM_DLL inline qboolean Listener::CheckEventFlags
(
Event *event
)
{
// Special handling of console events
if ( event->GetSource() == EV_FROM_CONSOLE )
{
if ( !( event->info.flags & (EV_CONSOLE|EV_CHEAT) ) )
{
if ( isSubclassOf( Entity ) )
{
Entity *ent;
ent = ( Entity * )this;
gi.cprintf( ent->edict, PRINT_HIGH, "Command not available from console.\n" );
}
// don't process
return false;
}
// don't allow console cheats during deathmatch unless the server says it's ok.
if ( ( event->info.flags & EV_CHEAT ) && deathmatch->value && !sv_cheats->value )
{
if ( isSubclassOf( Entity ) )
{
Entity *ent;
ent = ( Entity * )this;
gi.cprintf( ent->edict, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n" );
}
// don't process
return false;
}
}
// ok to process
return true;
}
EXPORT_FROM_DLL qboolean Listener::ProcessEvent
(
Event *event
)
{
ClassDef *c;
int ev;
int i;
// Prevent overflow of the inuse count
if ( event->info.inuse >= MAX_EVENT_USE )
{
gi.error( "ProcessEvent : Event usage overflow on '%s' event. Possible infinite loop.\n", event->getName().c_str() );
}
if ( g_showevents->value )
{
int n;
str text;
text = va( "%.1f: %s", level.time, this->getClassname() );
if ( isSubclassOf( Entity ) )
{
text += va( " (*%d) ", ( ( Entity * )this )->entnum );
if ( ( ( Entity * )this )->Targeted() )
{
text += va( "'%s'", ( ( Entity * )this )->TargetName() );
}
}
else if ( isSubclassOf( ScriptThread ) )
{
text += va( " #%d:'%s'", ( ( ScriptThread * )this )->ThreadNum(), ( ( ScriptThread * )this )->ThreadName() );
}
else if ( isSubclassOf( ScriptVariable ) )
{
text += va( " '%s'", ( ( ScriptVariable * )this )->getName() );
}
switch( event->GetSource() )
{
default :
case EV_FROM_CODE :
text += " : Code :";
break;
case EV_FROM_SCRIPT :
assert( event->GetThread() );
text += va( " : %s(%d) :", event->GetThread()->Filename(), event->info.linenumber );
break;
case EV_FROM_CONSOLE :
text += " : Console :";
break;
}
text += event->getName().c_str();
n = event->NumArgs();
for( i = 1; i <= n; i++ )
{
text += va( " %s", event->GetToken( i ) );
}
text += "\n";
if ( !g_watch->value || ( isSubclassOf( Entity ) && ( g_watch->value == ( ( Entity * )this )->entnum ) ) )
{
if ( g_showevents->value == 2 )
{
G_DebugPrintf( text.c_str() );
}
else
{
gi.dprintf( "%s", text.c_str() );
}
}
}
ev = ( int )*event;
c = this->classinfo();
if ( ev >= c->numEvents )
{
event->Error( "Event out of response range for class '%s'. Event probably invalid or allocated late.\n", getClassname() );
return false;
}
if ( c->responseLookup[ ev ] )
{
int start;
int end;
event->info.inuse++;
if ( !g_timeevents->value )
{
// only process the event if we allow it
if ( CheckEventFlags( event ) )
{
( this->**c->responseLookup[ ev ] )( event );
}
}
else
{
start = G_Milliseconds();
// only process the event if we allow it
if ( CheckEventFlags( event ) )
{
( this->**c->responseLookup[ ev ] )( event );
}
end = G_Milliseconds();
if ( g_timeevents->value == 1 )
{
gi.printf( "'%s' : %d\n", event->getName().c_str(), end - start );
}
else
{
G_DebugPrintf( "'%s' : %d\n", event->getName().c_str(), end - start );
}
}
// Prevent an event from being freed twice, in case it's been re-used
event->info.inuse--;
if ( !event->info.inuse )
{
delete event;
}
return true;
}
if ( !event->info.inuse )
{
delete event;
}
return false;
}
EXPORT_FROM_DLL void Listener::PostEvent
(
Event *ev,
float time
)
{
eventcache_t *newevent;
eventcache_t *event;
if ( LoadingSavegame )
{
if ( !ev->info.inuse )
{
delete ev;
}
return;
}
if ( LL_Empty( FreeEvents, next, prev ) )
{
gi.error( "PostEvent : No more free events on '%s' event.\n", ev->getName().c_str() );
return;
}
newevent = FreeEvents->next;
LL_Remove( newevent, next, prev );
// Probably don't have this many events, but it's a good safety precaution
if ( ev->info.inuse >= MAX_EVENT_USE )
{
gi.error( "PostEvent : Event usage overflow on '%s' event. Possible infinite loop.\n", ev->getName().c_str() );
return;
}
ev->info.inuse++;
newevent->obj = this;
newevent->event = ev;
newevent->time = level.time + time;
event = EventQueue->next;
while( ( event != EventQueue ) && ( newevent->time >= event->time ) )
{
event = event->next;
}
LL_Add( event, newevent, next, prev );
numEvents++;
}
EXPORT_FROM_DLL qboolean Listener::PostponeEvent
(
Event &ev,
float time
)
{
eventcache_t *event;
eventcache_t *node;
int eventnum;
assert( EventQueue );
assert( EventQueue->next );
eventnum = ( int )ev;
event = EventQueue->next;
while( event != EventQueue )
{
if ( ( event->obj == this ) && ( ( int )*event->event == eventnum ) )
{
event->time += time;
node = event->next;
while( ( node != EventQueue ) && ( event->time >= node->time ) )
{
node = node->next;
}
LL_Remove( event, next, prev );
LL_Add( node, event, next, prev );
return true;
}
event = event->next;
}
return false;
}
EXPORT_FROM_DLL void Listener::CancelEventsOfType
(
Event *ev
)
{
eventcache_t *event;
eventcache_t *next;
int eventnum;
assert( EventQueue );
assert( EventQueue->next );
event = EventQueue->next;
eventnum = (int)*ev;
while( event != EventQueue )
{
next = event->next;
if ( ( event->obj == this ) && ( (int)*event->event == eventnum ) )
{
delete event->event;
event->event = NULL;
LL_Remove( event, next, prev );
LL_Add( FreeEvents, event, next, prev );
numEvents--;
}
event = next;
}
}
EXPORT_FROM_DLL void Listener::CancelPendingEvents
(
void
)
{
eventcache_t *event;
eventcache_t *next;
assert( EventQueue );
assert( EventQueue->next );
event = EventQueue->next;
while( event != EventQueue )
{
next = event->next;
if ( event->obj == this )
{
delete event->event;
event->event = NULL;
LL_Remove( event, next, prev );
LL_Add( FreeEvents, event, next, prev );
numEvents--;
}
event = next;
}
}
EXPORT_FROM_DLL qboolean Listener::ProcessPendingEvents
(
void
)
{
eventcache_t *event;
qboolean processedEvents;
float t;
assert( EventQueue );
assert( EventQueue->next );
assert( EventQueue->prev );
processedEvents = false;
t = level.time + 0.001;
event = EventQueue->next;
while( event != EventQueue )
{
assert( event );
assert( event->event );
assert( event->obj );
if ( event->time > t )
{
break;
}
if ( event->obj != this )
{
// traverse normally
event = event->next;
}
else
{
LL_Remove( event, next, prev );
numEvents--;
assert( event->obj );
// ProcessEvent increments the inuse count, so decrement it since we've already incremented it in PostEvent
event->event->info.inuse--;
event->obj->ProcessEvent( event->event );
event->event = NULL;
LL_Add( FreeEvents, event, next, prev );
// start over, since can't guarantee that we didn't process any previous or following events
event = EventQueue->next;
processedEvents = true;
}
}
return processedEvents;
}
EXPORT_FROM_DLL Listener::~Listener()
{
CancelPendingEvents();
}
EXPORT_FROM_DLL void G_ClearEventList
(
void
)
{
int i;
eventcache_t *e;
LL_Reset( FreeEvents, next, prev );
LL_Reset( EventQueue, next, prev );
memset( Events, 0, sizeof( Events ) );
for( e = &Events[ 0 ], i = 0; i < MAX_EVENTS; i++, e++ )
{
LL_Add( FreeEvents, e, next, prev );
}
numEvents = 0;
}
EXPORT_FROM_DLL void G_ProcessPendingEvents
(
void
)
{
eventcache_t *event;
float t;
int num;
int maxevents;
assert( EventQueue );
assert( EventQueue->next );
assert( EventQueue->prev );
maxevents = ( int )g_eventlimit->value;
num = 0;
t = level.time + 0.001;
while( !LL_Empty( EventQueue, next, prev ) )
{
event = EventQueue->next;
assert( event );
assert( event->event );
assert( event->obj );
if ( event->time > t )
{
break;
}
LL_Remove( event, next, prev );
numEvents--;
assert( event->obj );
// ProcessEvent increments the inuse count, so decrement it since we've already incremented it in PostEvent
assert( event->event->info.inuse > 0 );
event->event->info.inuse--;
event->obj->ProcessEvent( event->event );
event->event = NULL;
LL_Add( FreeEvents, event, next, prev );
// Don't allow ourselves to stay in here too long. An abnormally high number
// of events being processed is evidence of an infinite loop of events.
num++;
if ( num > maxevents )
{
gi.printf( "Event overflow. Possible infinite loop in script. "
"Enable g_showevents to trace. Aborting frame.\n" );
break;
}
}
}
EXPORT_FROM_DLL void G_ArchiveEvents
(
Archiver &arc
)
{
eventcache_t *event;
int num;
assert( EventQueue );
assert( EventQueue->next );
assert( EventQueue->prev );
num = 0;
for( event = EventQueue->next; event != EventQueue; event = event->next )
{
assert( event );
assert( event->event );
assert( event->obj );
if ( event->obj->isSubclassOf( Entity ) &&
( ( ( Entity * )event->obj )->flags & FL_DONTSAVE ) )
{
continue;
}
num++;
}
arc.WriteInteger( num );
for( event = EventQueue->next; event != EventQueue; event = event->next )
{
assert( event );
assert( event->event );
assert( event->obj );
if ( event->obj->isSubclassOf( Entity ) &&
( ( ( Entity * )event->obj )->flags & FL_DONTSAVE ) )
{
continue;
}
arc.WriteObjectPointer( event->obj );
arc.WriteEvent( *event->event );
arc.WriteFloat( event->time );
}
}
EXPORT_FROM_DLL void G_UnarchiveEvents
(
Archiver &arc
)
{
eventcache_t *e;
int i;
LL_Reset( FreeEvents, next, prev );
LL_Reset( EventQueue, next, prev );
memset( Events, 0, sizeof( Events ) );
arc.ReadInteger( &numEvents );
for( e = &Events[ 0 ], i = 0; i < numEvents; i++, e++ )
{
arc.ReadObjectPointer( ( Class ** )&e->obj );
e->event = new Event();
arc.ReadEvent( e->event );
arc.ReadFloat( &e->time );
LL_Add( EventQueue, e, next, prev );
}
for( ; i < MAX_EVENTS; i++, e++ )
{
LL_Add( FreeEvents, e, next, prev );
}
}
EXPORT_FROM_DLL void G_InitEvents
(
void
)
{
g_numevents = gi.cvar ( "g_numevents", "0", 0 );
g_showevents = gi.cvar ( "g_showevents", "0", 0 );
g_eventlimit = gi.cvar ( "g_eventlimit", "1500", 0 );
g_timeevents = gi.cvar ( "g_timeevents", "0", 0 );
g_watch = gi.cvar ( "g_watch", "0", 0 );
BuildEventResponses();
G_ClearEventList();
// Sort the list before we go on since we won't be adding any more events
Event::SortEventList();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -