Skip to content

Commit

Permalink
Merge pull request #1342 from Areloch/SpawnObjectOverrideOverhaul
Browse files Browse the repository at this point in the history
SpawnObject Override Overhaul
  • Loading branch information
Azaezel authored Jan 3, 2025
2 parents 0f4b042 + 46f6f6a commit 8274bbb
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 114 deletions.
5 changes: 4 additions & 1 deletion Engine/source/module/moduleDefinition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ mModuleId(StringTable->EmptyString()),
mLoadCount( 0 ),
mScopeSet( 0 ),
mLocked( false ),
mpModuleManager( NULL )
mpModuleManager( NULL ),
mPriority(0.0f)
{
// Set Vector Associations.
VECTOR_SET_ASSOCIATION( mDependencies );
Expand Down Expand Up @@ -111,6 +112,8 @@ void ModuleDefinition::initPersistFields()

/// Misc.
addProtectedField( "Signature", TypeString, 0, &defaultProtectedNotSetFn, &getSignature, &defaultProtectedNotWriteFn, "A unique signature of the module definition based upon its Id, version and build. This is read-only and is available only after the module has been registered by a module manager." );
addProtectedField( "Priority", TypeF32, 0, &setPriority, &defaultProtectedGetFn, &defaultProtectedNotWriteFn, "A numeric value indicating execution priority for certain callback commands. 0 has the highest priority and is then sorted from there ascending in value. This is read-only and is available only after the module has been registered by a module manager.");

}

//-----------------------------------------------------------------------------
Expand Down
6 changes: 6 additions & 0 deletions Engine/source/module/moduleDefinition.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class ModuleDefinition : public SimSet
SimObjectId mScopeSet;
bool mLocked;
ModuleManager* mpModuleManager;
F32 mPriority;

private:
inline bool checkUnlocked( void ) const { if ( mLocked ) { Con::warnf("Ignoring changes for locked module definition."); } return !mLocked; }
Expand Down Expand Up @@ -195,6 +196,9 @@ class ModuleDefinition : public SimSet
inline bool getModuleLocked( void ) const { return mLocked; }
inline ModuleManager* getModuleManager( void ) const { return mpModuleManager; }

inline void setPriority(const F32 pPriority) { if (checkUnlocked()) { mPriority = pPriority; } }
inline F32 getPriority(void) const { return mPriority; }

using Parent::save;
bool save( void );

Expand Down Expand Up @@ -332,6 +336,8 @@ class ModuleDefinition : public SimSet
}
static bool writeDependencies( void* obj, StringTableEntry pFieldName ) { return static_cast<ModuleDefinition*>(obj)->getDependencies().size() > 0; }
static const char* getSignature(void* obj, const char* data) { return static_cast<ModuleDefinition*>(obj)->getSignature(); }

static bool setPriority(void* obj, const char* index, const char* data) { static_cast<ModuleDefinition*>(obj)->setPriority((F32)dAtof(data)); return false; }
};

#endif // _MODULE_DEFINITION_H
Expand Down
19 changes: 18 additions & 1 deletion Engine/source/module/moduleManager_ScriptBinding.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,14 @@ DefineEngineMethod(ModuleManager, findModuleByFilePath, String, (const char* fil
}

//-----------------------------------------------------------------------------
static S32 QSORT_CALLBACK _findModulesSortByPriority(ModuleDefinition* const* a, ModuleDefinition* const* b)
{
F32 diff = (*a)->getPriority() - (*b)->getPriority();
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
}

DefineEngineMethod(ModuleManager, findModules, String, (bool loadedOnly), (true),

DefineEngineMethod(ModuleManager, findModules, String, (bool loadedOnly, bool sortByPriority, const char* moduleGroup), (true, false, ""),
"Find all the modules registered with the specified loaded state.\n"
"@param loadedOnly Whether to return only modules that are loaded or not.\n"
"@return A list of space - separated module definition object Ids.\n")
Expand All @@ -174,12 +180,23 @@ DefineEngineMethod(ModuleManager, findModules, String, (bool loadedOnly), (true)
char* pReturnBuffer = Con::getReturnBuffer( bufferSize );
char* pBufferWrite = pReturnBuffer;

if (sortByPriority)
moduleDefinitions.sort(_findModulesSortByPriority);

StringTableEntry moduleGroupStr = StringTable->insert(moduleGroup);

// Iterate module definitions.
for ( ModuleManager::typeConstModuleDefinitionVector::const_iterator moduleDefinitionItr = moduleDefinitions.begin(); moduleDefinitionItr != moduleDefinitions.end(); ++moduleDefinitionItr )
{
// Fetch module definition.
const ModuleDefinition* pModuleDefinition = *moduleDefinitionItr;

if(moduleGroupStr != StringTable->EmptyString())
{
if (pModuleDefinition->getModuleGroup() != moduleGroupStr)
continue;
}

// Format module definition.
const U32 offset = dSprintf( pBufferWrite, bufferSize, "%d ", pModuleDefinition->getId() );
pBufferWrite += offset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ function Core_ClientServer::finishMapLoad(%this)
Core_ClientServer.GetEventManager().postEvent( "mapLoadComplete" );
}

function Core_ClientServer::FailMapLoad(%this, %moduleName, %isFine)
function Core_ClientServer::FailMapLoad(%this, %moduleName, %canContinueOnFail)
{
Core_ClientServer.failedModuleName = %moduleName;
Core_ClientServer.GetEventManager().postEvent( "mapLoadFail", %isFine );
Core_ClientServer.GetEventManager().postEvent( "mapLoadFail", %canContinueOnFail );
}

function Core_ClientServerListener::onMapLoadComplete(%this)
Expand All @@ -50,9 +50,9 @@ function Core_ClientServerListener::onMapLoadComplete(%this)
}
}

function Core_ClientServerListener::onmapLoadFail(%this, %isFine)
function Core_ClientServerListener::onMapLoadFail(%this, %canContinueOnFail)
{
if (%isFine)
if (%canContinueOnFail)
{
%this.onMapLoadComplete();
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
// anything else will be sent back as an error to the client.
// All the connect args are passed also to onConnectRequest
//
function GameConnection::onConnectRequest( %client, %netAddress, %name )
function GameConnection::onConnectRequest( %this, %netAddress, %name )
{
echo("Connect request from: " @ %netAddress);
if($Server::PlayerCount >= $pref::Server::MaxPlayers)
Expand All @@ -47,11 +47,11 @@ function GameConnection::onConnect( %this, %clientData )
sendLoadInfoToClient(%this);

// Simulated client lag for testing...
// %client.setSimulatedNetParams(0.1, 30);
// %this.setSimulatedNetParams(0.1, 30);

// Get the client's unique id:
// %authInfo = %client.getAuthInfo();
// %client.guid = getField(%authInfo, 3);
// %authInfo = %this.getAuthInfo();
// %this.guid = getField(%authInfo, 3);
%this.guid = 0;
addToServerGuidList(%this.guid);

Expand Down Expand Up @@ -81,19 +81,194 @@ function GameConnection::onConnect( %this, %clientData )

%this.connectData = %clientData;

//Signal and listener logic for the spawn config/processing here
%this.GetEventManager().registerEvent("setSpawnObjectTypeComplete");
%this.GetEventManager().registerEvent("setSpawnObjectTypeFailed");
%this.GetEventManager().registerEvent("setSpawnPointComplete");
%this.GetEventManager().registerEvent("setSpawnPointFailed");
%this.GetEventManager().registerEvent("postSpawnComplete");

%this.listener = new ScriptMsgListener() {
class = GameConnectionListener;
};
%this.GetEventManager().subscribe( %this.listener, "setSpawnObjectTypeComplete" );
%this.GetEventManager().subscribe( %this.listener, "setSpawnObjectTypeFailed" );
%this.GetEventManager().subscribe( %this.listener, "setSpawnPointComplete" );
%this.GetEventManager().subscribe( %this.listener, "setSpawnPointFailed" );
%this.GetEventManager().subscribe( %this.listener, "postSpawnComplete" );

callGamemodeFunction("onClientConnect", %this);

$Server::PlayerCount++;
}

function GameConnection::GetEventManager(%this)
{
if( !isObject( %this.eventManager ) )
%this.eventManager = new EventManager() {
queue = "GameConnectionEventManager";
};

return %this.eventManager;
}

function GameConnection::spawnControlObject( %this )
{
//baseline controlObject spawn type with extention points
%this.spawnClass = "Camera";
%this.spawnDBType = "CameraData";
%this.spawnDataBlock = "Observer";

%this.numModsNeedingLoaded = 0;
%this.moduleLoadedDone = 0;
%modulesIDList = getModulesAndGameModesList(true, "Game");

%this.numModsNeedingLoaded = getNumCanCallOnObjectList("setSpawnObjectType", %modulesIDList);

if (%this.numModsNeedingLoaded)
callOnObjectList("setSpawnObjectType", %modulesIdList, %this);
else
%this.GetEventManager().onSetSpawnObjectTypeComplete(); //just jump to progress
}

function GameConnectionListener::onSetSpawnObjectTypeComplete( %this, %client )
{
%client.moduleLoadedDone++;

if (%client.moduleLoadedDone < %client.numModsNeedingLoaded)
return; //continue to wait

if (isObject(%client.player))
{
// The client should not already have a player. Assigning
// a new one could result in an uncontrolled player object.
error("Attempting to create a player for a client that already has one!");
}

// Spawn with the engine's Sim::spawnObject() function
%client.player = spawnObject(%client.spawnClass, %client.spawnDataBlock);

if (!%client.player.isMemberOfClass(%client.spawnClass))
warn("Trying to spawn a class that does not derive from "@ %client.spawnClass);

// Add the player object to MissionCleanup so that it
// won't get saved into the level files and will get
// cleaned up properly
MissionCleanup.add(%client.player);

// Store the client object on the player object for
// future reference
%client.player.client = %client;

%client.setSpawnPoint();

// Give the client control of the camera if in the editor
if( $startWorldEditor )
{
%control = %client.camera;
%control.mode = "Fly";
EditorGui.syncCameraGui();
}
else
%control = %client.player;

// Allow the player/camera to receive move data from the GameConnection. Without this
// the user is unable to control the player/camera.
if (!isDefined("%noControl"))
%client.setControlObject(%control);
}

function GameConnectionListener::onSetSpawnObjectTypeFailed( %this, %client, %canContinueOnFail )
{
errorf("Failed to properly set Spawn Object Type for client: " @ %client);
}

function GameConnection::setSpawnPoint( %this )
{
//baseline spawn point config rules with extention points
%this.playerSpawnGroups = "PlayerSpawnPoints PlayerDropPoints";
%this.spawnPoint = "";
%this.spawnLocation = "0 0 0";

%this.numModsNeedingLoaded = 0;
%this.moduleLoadedDone = 0;
%modulesIDList = getModulesAndGameModesList(true, "Game");

%this.numModsNeedingLoaded = getNumCanCallOnObjectList("setSpawnPoint", %modulesIDList);

if (%this.numModsNeedingLoaded)
callOnObjectList("setSpawnPoint", %modulesIdList, %this);
else
%this.GetEventManager().onSetSpawnPointComplete();
}

function GameConnectionListener::onSetSpawnPointComplete( %this, %client )
{
%client.moduleLoadedDone++;
if (%client.moduleLoadedDone < %client.numModsNeedingLoaded)
return; //continue to wait

if (isObject(%client.player))
%client.player.setTransform(%client.spawnLocation);
else
{
// If we weren't able to create the player object then warn the user
// When the player clicks OK in one of these message boxes, we will fall through
// to the "if (!isObject(%player))" check below.
if (isDefined("%this.spawnDataBlock"))
{
MessageBoxOK("Spawn Failed",
"Unable to create a player with class " @ %client.spawnClass @
" and datablock " @ %client.spawnDataBlock @ ".\n\nStarting as an Observer instead.",
"");
}
else
{
MessageBoxOK("Spawn Failed",
"Unable to create a player with class " @ %client.spawnClass @
".\n\nStarting as an Observer instead.",
"");
}
}
%client.onPostSpawn();
}

function GameConnectionListener::onSetSpawnPointFailed( %this, %client, %canContinueOnFail )
{
errorf("Failed to properly set Spawn Object Type for client: " @ %client);
}

function GameConnection::onPostSpawn( %this )
{
%this.numModsNeedingLoaded = 0;
%this.moduleLoadedDone = 0;
%modulesIDList = getModulesAndGameModesList(true, "Game");

%this.numModsNeedingLoaded = getNumCanCallOnObjectList("onPostSpawn", %modulesIDList);

if (%this.numModsNeedingLoaded)
callOnObjectList("onPostSpawn", %modulesIdList, %this);
else
%this.GetEventManager().onPostSpawnComplete();
}

function GameConnectionListener::onPostSpawnComplete(%this, %client)
{
%client.moduleLoadedDone++;
if (%client.moduleLoadedDone < %client.numModsNeedingLoaded)
return; //continue to wait

//Continue on. Room for special handling here if needbe but not expressly required
}

//-----------------------------------------------------------------------------
// A player's name could be obtained from the auth server, but for
// now we use the one passed from the client.
// %realName = getField( %authInfo, 0 );
//
function GameConnection::setPlayerName(%client,%name)
function GameConnection::setPlayerName(%this,%name)
{
%client.sendGuid = 0;
%this.sendGuid = 0;

// Minimum length requirements
%name = trim( strToPlayerName( %name ) );
Expand All @@ -112,8 +287,8 @@ function GameConnection::setPlayerName(%client,%name)
}

// Tag the name with the "smurf" color:
%client.nameBase = %name;
%client.playerName = addTaggedString("\cp\c8" @ %name @ "\co");
%this.nameBase = %name;
%this.playerName = addTaggedString("\cp\c8" @ %name @ "\co");
}

function isNameUnique(%name)
Expand All @@ -132,7 +307,7 @@ function isNameUnique(%name)
//-----------------------------------------------------------------------------
// This function is called when a client drops for any reason
//
function GameConnection::onDrop(%client, %reason)
function GameConnection::onDrop(%this, %reason)
{
%entityIds = parseMissionGroupForIds("Entity", "");
%entityCount = getWordCount(%entityIds);
Expand All @@ -148,15 +323,15 @@ function GameConnection::onDrop(%client, %reason)
%entityIds = %entityIds SPC %child.getID();
}

%entity.notify("onClientDisconnect", %client);
%entity.notify("onClientDisconnect", %this);
}

if($missionRunning)
{
%hasGameMode = callGamemodeFunction("onClientLeaveGame", %client);
%hasGameMode = callGamemodeFunction("onClientLeaveGame", %this);
}

removeFromServerGuidList( %client.guid );
removeFromServerGuidList( %this.guid );

$Server::PlayerCount--;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ function serverCmdMissionStartPhase3Ack(%client, %seq)
%client.currentPhase = 3;

%hasGameMode = callGamemodeFunction("onClientEnterGame", %client);

%client.spawnControlObject();

//if that also failed, just spawn a camera
if(%hasGameMode == 0)
Expand Down
Loading

0 comments on commit 8274bbb

Please sign in to comment.