(I'm not sure where you should post for SourceMod extension help, so I'm putting it in this forum. Feel free to move it if that's not the case.)
I'm having a pretty weird problem. I'm trying to hook two functions, SetWinningTeam and SetStalemate, which are both in CTFGameRules, and call forwards so that a plugin can modify the values. For SetWinningTeam, it's working perfectly fine, but for SetStalemate, it throws an exception "0xC0000005: Access violation writing location" when I modify the parameter. The extension and plugin both compile fine without errors, everything else is working without a hitch, and if I comment out the code changing the parameter, the SetStalemate forward seems to work perfectly fine. I have no idea why one function would work and the other wouldn't, since I don't think that there's a major difference between either that would make an impact. Of course, I may be dumb and missing a simple error, but I can't find it if I am.
Relevant part of IDA dump for CTFGameRules:
Quote:
// Auto reconstructed from vtable block @ 0x00EC18C0
// from "server_srv.so", by ida_vtables.idc
156 CTFGameRules::SetWinningTeam(int,int,bool,boo l,bool)
157 CTFGameRules::SetStalemate(int,bool,bool)
|
Code for creating forwards:
Code:
g_SetWinningTeamForward = forwards->CreateForward("CompCtrl_OnSetWinningTeam", ET_Hook, 5, NULL, Param_CellByRef, Param_CellByRef, Param_CellByRef, Param_CellByRef, Param_CellByRef);
g_SetStalemateForward = forwards->CreateForward("CompCtrl_OnSetStalemate", ET_Hook, 3, NULL, Param_CellByRef, Param_CellByRef, Param_CellByRef);
The code calling the forwards:
Code:
void GameRulesManager::Hook_CTFGameRules_SetWinningTeam(int team, int iWinReason, bool bForceMapReset, bool bSwitchTeams, bool bDontAddScore) {
cell_t forceMapReset = bForceMapReset;
cell_t switchTeams = bSwitchTeams;
cell_t dontAddScore = bDontAddScore;
g_SetWinningTeamForward->PushCellByRef(&team);
g_SetWinningTeamForward->PushCellByRef(&iWinReason);
g_SetWinningTeamForward->PushCellByRef(&forceMapReset);
g_SetWinningTeamForward->PushCellByRef(&switchTeams);
g_SetWinningTeamForward->PushCellByRef(&dontAddScore);
cell_t result = 0;
g_SetWinningTeamForward->Execute(&result);
if (result > Pl_Changed) {
RETURN_META(MRES_SUPERCEDE);
}
else if (result == Pl_Changed) {
RETURN_META_MNEWPARAMS(MRES_HANDLED, CTFGameRules_SetWinningTeam, (team, iWinReason, (bool)forceMapReset, (bool)switchTeams, (bool)dontAddScore));
}
else {
RETURN_META(MRES_IGNORED);
}
}
void GameRulesManager::Hook_CTFGameRules_SetStalemate(int iReason, bool bForceMapReset, bool bSwitchTeams) {
cell_t forceMapReset = bForceMapReset;
cell_t switchTeams = bSwitchTeams;
g_SetWinningTeamForward->PushCellByRef(&iReason);
g_SetWinningTeamForward->PushCellByRef(&forceMapReset);
g_SetWinningTeamForward->PushCellByRef(&switchTeams);
cell_t result = 0;
g_SetStalemateForward->Execute(&result);
if (result > Pl_Changed) {
RETURN_META(MRES_SUPERCEDE);
}
else if (result == Pl_Changed) {
RETURN_META_MNEWPARAMS(MRES_HANDLED, CTFGameRules_SetStalemate, (iReason, (bool)forceMapReset, (bool)switchTeams));
}
else {
RETURN_META(MRES_IGNORED);
}
}
The relevant forward definitions:
Code:
/**
* @brief When SetWinningTeam in CTFGameRules is called by the game.
*
* @param team The team that has won.
* @param reason The reason why the team is winning.
* @param forceMapReset Whether to reset the map (usually after a full round is completed).
* @param switchTeams Whether to switch teams.
* @param dontAddScore Whether to not score this round.
* @return Plugin_Continue to continue with original values, Plugin_Changed to use new values, Plugin_Handled or Plugin_Stop to stop the game call.
*/
forward Action:CompCtrl_OnSetWinningTeam(&TFTeam:team, &WinReason:reason, &bool:forceMapReset, &bool:switchTeams, &bool:dontAddScore);
/**
* @brief When SetStalemate in CTFGameRules is called by the game.
*
* @param reason The reason why the team is winning.
* @param forceMapReset Whether to reset the map (usually after a full round is completed).
* @param switchTeams Whether to switch teams.
* @return Plugin_Continue to continue with original values, Plugin_Changed to use new values, Plugin_Handled or Plugin_Stop to stop the game call.
*/
forward Action:CompCtrl_OnSetStalemate(&WinReason:reason, &bool:forceMapReset, &bool:switchTeams);
The relevant plugin code:
Code:
public Action:CompCtrl_OnSetWinningTeam(&TFTeam:team, &WinReason:reason, &bool:forceMapReset, &bool:switchTeams, &bool:dontAddScore) {
if (g_InMatch) {
if (g_SwitchTeams) {
if (GameRules_GetProp("m_bStopWatch", 1) && GetStopwatchStatus() == StopwatchStatus_ChaseTarget) {
switchTeams = false;
}
else {
switchTeams = true;
}
g_SwitchTeams = false;
return Plugin_Changed;
}
}
return Plugin_Continue;
}
public Action:CompCtrl_OnSetStalemate(&WinReason:reason, &bool:forceMapReset, &bool:switchTeams) {
if (g_InMatch) {
if (g_SwitchTeams) {
if (GameRules_GetProp("m_bStopWatch", 1) && GetStopwatchStatus() == StopwatchStatus_ChaseTarget) {
switchTeams = false;
}
else {
switchTeams = true;
}
g_SwitchTeams = false;
return Plugin_Changed;
}
}
return Plugin_Continue;
}
If anyone can shed some light into where the problem is occurring, that would be insanely helpful. Thanks in advance!