This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/server/global/dll_int.cpp

443 lines
13 KiB
C++

//=======================================================================
// Copyright (C) Shambler Team 2005
// dll_int.cpp - dll entry points
//=======================================================================
#include "extdll.h"
#include "utils.h"
#include "cbase.h"
#include "saverestore.h"
#include "client.h"
#include "decals.h"
#include "gamerules.h"
#include "game.h"
#include "defaults.h"
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd );
BOOL gTouchDisabled = FALSE;
enginefuncs_t g_engfuncs;
globalvars_t *gpGlobals;
// Main DLL entry point
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
return TRUE;
}
static DLL_FUNCTIONS gFunctionTable =
{
sizeof( DLL_FUNCTIONS ),
GameDLLInit, // pfnGameInit
GameDLLShutdown, // pfnGameShutdown
DispatchSpawn, // pfnSpawn
DispatchCreate, // pfnCreate
DispatchThink, // pfnThink
DispatchUse, // pfnUse
DispatchTouch, // pfnTouch
DispatchBlocked, // pfnBlocked
DispatchKeyValue, // pfnKeyValue
DispatchSave, // pfnSave
DispatchRestore, // pfnRestore
DispatchObjectCollsionBox, // pfnAbsBox
SaveWriteFields, // pfnSaveWriteFields
SaveReadFields, // pfnSaveReadFields
SaveGlobalState, // pfnSaveGlobalState
RestoreGlobalState, // pfnRestoreGlobalState
ResetGlobalState, // pfnResetGlobalState
ClientConnect, // pfnClientConnect
ClientDisconnect, // pfnClientDisconnect
ClientKill, // pfnClientKill
ClientPutInServer, // pfnClientPutInServer
ClientCommand, // pfnClientCommand
ClientUserInfoChanged, // pfnClientUserInfoChanged
ServerActivate, // pfnServerActivate
ServerDeactivate, // pfnServerDeactivate
PlayerPreThink, // pfnPlayerPreThink
PlayerPostThink, // pfnPlayerPostThink
StartFrame, // pfnStartFrame
DispatchFrame, // pfnFrame
EndFrame, // pfnEndFrame
BuildLevelList, // pfnBuildLevelList
ServerClassifyEdict, // pfnClassifyEdict
UpdateEntityState, // pfnUpdateEntityState
GetGameDescription, // pfnGetGameDescription - returns string describing current .dll game.
};
//=======================================================================
// General API entering point
//=======================================================================
int CreateAPI( DLL_FUNCTIONS *pFunctionTable, enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals )
{
if( !pFunctionTable || !pengfuncsFromEngine || !pGlobals )
{
return FALSE;
}
memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ));
memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof( enginefuncs_t ));
gpGlobals = pGlobals;
return TRUE;
}
//=======================================================================
// dispatch functions
//=======================================================================
int DispatchSpawn( edict_t *pent )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if( pEntity )
{
// Initialize these or entities who don't link to the world won't have anything in here
pEntity->pev->absmin = pEntity->pev->origin - Vector(1,1,1);
pEntity->pev->absmax = pEntity->pev->origin + Vector(1,1,1);
pEntity->Spawn();
pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if ( pEntity )
{
pEntity->pev->colormap = ENTINDEX(pent);
if ( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) )
return -1; // return that this entity should be deleted
if ( pEntity->pev->flags & FL_KILLME )
return -1;
}
// Handle global stuff here
if ( pEntity && pEntity->pev->globalname )
{
const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname );
if ( pGlobal )
{
// Already dead? delete
if ( pGlobal->state == GLOBAL_DEAD ) return -1;
else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) )
pEntity->MakeDormant();// Hasn't been moved to this level yet, wait but stay alive
// In this level & not dead, continue on as normal
}
else gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON );
}
}
return 0;
}
int DispatchCreate( edict_t *pent, const char *szName )
{
return -1; // -1 = failed, 0 = done
}
void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd )
{
if ( !pkvd || !pentKeyvalue )return;
EntvarsKeyvalue( VARS(pentKeyvalue), pkvd );
// If the key was an entity variable, or there's no class set yet, don't look for the object, it may
// not exist yet.
if ( pkvd->fHandled || pkvd->szClassName == NULL )return;
// Get the actualy entity object
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentKeyvalue);
if ( !pEntity )return;
pEntity->KeyValue( pkvd );
}
void DispatchFrame( edict_t *pent )
{
}
void DispatchTouch( edict_t *pentTouched, edict_t *pentOther )
{
if ( gTouchDisabled ) return;
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentTouched);
CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther );
if ( pEntity && pOther && ! ((pEntity->pev->flags | pOther->pev->flags) & FL_KILLME) )
pEntity->Touch( pOther );
}
void DispatchUse( edict_t *pentUsed, edict_t *pentOther )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentUsed);
CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE(pentOther);
if (pEntity && !(pEntity->pev->flags & FL_KILLME) )
pEntity->Use( pOther, pOther, USE_TOGGLE, 0 );
}
void DispatchThink( edict_t *pent )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if (pEntity)
{
if ( FBitSet( pEntity->pev->flags, FL_DORMANT ) )
Msg("ERROR: Dormant entity %s is thinking!!\n", STRING(pEntity->pev->classname) );
pEntity->Think();
}
}
void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentBlocked );
CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther );
if (pEntity)pEntity->Blocked( pOther );
}
void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if ( pEntity && pSaveData )
{
ALERT( at_console, "DispatchSave( %s )\n", STRING( pent->v.classname ));
ENTITYTABLE *pTable = &pSaveData->pTable[ pSaveData->currentIndex ];
if ( pTable->pent != pent )
ALERT( at_error, "ENTITY TABLE OR INDEX IS WRONG!!!!\n" );
if ( pEntity->ObjectCaps() & FCAP_DONT_SAVE )return;
// These don't use ltime & nextthink as times really, but we'll fudge around it.
if ( pEntity->pev->movetype == MOVETYPE_PUSH )
{
float delta = gpGlobals->time - pEntity->pev->ltime;
pEntity->pev->ltime += delta;
pEntity->pev->nextthink += delta;
pEntity->m_fPevNextThink = pEntity->pev->nextthink;
pEntity->m_fNextThink += delta;
}
pTable->location = pSaveData->size; // Remember entity position for file I/O
pTable->classname = pEntity->pev->classname; // Remember entity class for respawn
CSave saveHelper( pSaveData );
pEntity->Save( saveHelper );
pTable->size = pSaveData->size - pTable->location;// Size of entity block is data size written to block
}
}
int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if( pEntity && pSaveData )
{
entvars_t tmpVars;
Vector oldOffset;
ALERT( at_console, "DispatchRestore( %s )\n", STRING( pent->v.classname ));
CRestore restoreHelper( pSaveData );
if ( globalEntity )
{
CRestore tmpRestore( pSaveData );
tmpRestore.PrecacheMode( 0 );
tmpRestore.ReadEntVars( "ENTVARS", &tmpVars );
pSaveData->size = pSaveData->pTable[pSaveData->currentIndex].location;
pSaveData->pCurrentData = pSaveData->pBaseData + pSaveData->size;
const globalentity_t *pGlobal = gGlobalState.EntityFromTable( tmpVars.globalname );
// Don't overlay any instance of the global that isn't the latest
// pSaveData->szCurrentMapName is the level this entity is coming from
// pGlobla->levelName is the last level the global entity was active in.
// If they aren't the same, then this global update is out of date.
if ( !FStrEq( pSaveData->szCurrentMap, pGlobal->levelName ) )return 0;
// Compute the new global offset
oldOffset = pSaveData->vecLandmarkOffset;
CBaseEntity *pNewEntity = UTIL_FindGlobalEntity( tmpVars.classname, tmpVars.globalname );
if ( pNewEntity )
{
// Tell the restore code we're overlaying a global entity from another level
restoreHelper.SetGlobalMode( 1 ); // Don't overwrite global fields
pSaveData->vecLandmarkOffset = (pSaveData->vecLandmarkOffset - pNewEntity->pev->mins) + tmpVars.mins;
pEntity = pNewEntity;// we're going to restore this data OVER the old entity
pent = ENT( pEntity->pev );
// Update the global table to say that the global definition of this entity should come from this level
gGlobalState.EntityUpdate( pEntity->pev->globalname, gpGlobals->mapname );
}
else
{
// This entity will be freed automatically by the engine. If we don't do a restore on a matching entity (below)
// or call EntityUpdate() to move it to this level, we haven't changed global state at all.
return 0;
}
}
if ( pEntity->ObjectCaps() & FCAP_MUST_SPAWN )
{
pEntity->Restore( restoreHelper );
pEntity->Spawn();
}
else
{
pEntity->Restore( restoreHelper );
pEntity->Precache( );
}
// Again, could be deleted, get the pointer again.
pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if (pEntity )pEntity->pev->colormap = ENTINDEX(pent);
// Is this an overriding global entity (coming over the transition), or one restoring in a level
if ( globalEntity )
{
pSaveData->vecLandmarkOffset = oldOffset;
if ( pEntity )
{
pEntity->RestorePhysics();
UTIL_SetOrigin( pEntity, pEntity->pev->origin );
pEntity->OverrideReset();
}
}
else if ( pEntity && pEntity->pev->globalname )
{
const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname );
if ( pGlobal )
{
// Already dead? delete
if ( pGlobal->state == GLOBAL_DEAD ) return -1;
else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) )
{
pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive
}
// In this level & not dead, continue on as normal
}
else
{
ALERT( at_error, "Global Entity %s (%s) not in table!!!\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->classname) );
// Spawned entities default to 'On'
gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON );
}
}
}
return 0;
}
void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount )
{
CSave saveHelper( pSaveData );
saveHelper.WriteFields( "SWF", pname, pBaseData, pFields, fieldCount );
}
void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount )
{
CRestore restoreHelper( pSaveData );
restoreHelper.ReadFields( pname, pBaseData, pFields, fieldCount );
}
void SetObjectCollisionBox( entvars_t *pev )
{
if ( (pev->solid == SOLID_BSP) && (pev->angles.x || pev->angles.y|| pev->angles.z) )
{ // expand for rotation
float max, v;
int i;
max = 0;
for (i=0 ; i<3 ; i++)
{
v = fabs( ((float *)pev->mins)[i]);
if (v > max) max = v;
v = fabs( ((float *)pev->maxs)[i]);
if (v > max) max = v;
}
for (i=0 ; i<3 ; i++)
{
((float *)pev->absmin)[i] = ((float *)pev->origin)[i] - max;
((float *)pev->absmax)[i] = ((float *)pev->origin)[i] + max;
}
}
else
{
pev->absmin = pev->origin + pev->mins;
pev->absmax = pev->origin + pev->maxs;
}
pev->absmin.x -= 1;
pev->absmin.y -= 1;
pev->absmin.z -= 1;
pev->absmax.x += 1;
pev->absmax.y += 1;
pev->absmax.z += 1;
}
void DispatchObjectCollsionBox( edict_t *pent )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if( pEntity ) pEntity->SetObjectCollisionBox();
else SetObjectCollisionBox( &pent->v );
}
//=======================================================================
// ehandle operations
//=======================================================================
edict_t * EHANDLE::Get( void )
{
if (m_pent)
{
if (m_pent->serialnumber == m_serialnumber) return m_pent;
else return NULL;
}
return NULL;
};
edict_t *EHANDLE::Set( edict_t *pent )
{
m_pent = pent;
if (pent) m_serialnumber = m_pent->serialnumber;
return pent;
};
EHANDLE :: operator CBaseEntity *()
{
return (CBaseEntity *)GET_PRIVATE(Get());
};
CBaseEntity *EHANDLE :: operator = (CBaseEntity *pEntity)
{
if (pEntity)
{
m_pent = ENT( pEntity->pev );
if (m_pent)m_serialnumber = m_pent->serialnumber;
}
else
{
m_pent = NULL;
m_serialnumber = 0;
}
return pEntity;
}
EHANDLE :: operator int()
{
return Get() != NULL;
}
CBaseEntity *EHANDLE :: operator->()
{
return (CBaseEntity *)GET_PRIVATE(Get());
}