////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Name: turret_manager_sup.sch // // Description: "Private" support methods for the turret management system. Mostly contains server-side // // methods to deal with client lock requests. // // See turret_manager_core.sch for more details. // // // // Written by: Online Technical Team: Orlando C-H // // Date: 05/09/2018 // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// USING "turret_manager_public.sch" USING "turret_manager_def.sch" USING "globals.sch" USING "script_network.sch" USING "net_include.sch" /// PURPOSE: /// Queries server data for a free turret index given a group and instance. /// No ordering is taken into account. /// /// Only guarenteed to be up to date for the freemode host. /// Request use of a turret with TURRET_MANAGER_CREATE_LOCK_REQUEST. /// PARAMS: /// ref_iTurretId - Set to the turret index. Only valid if the function returns true. /// RETURNS: /// FUNC BOOL GET_ANY_FREE_TURRET_ID(TURRET_GROUP_TYPE eGroupType, INT iInstanceId, INT& ref_iTurretId) INT iTurretCount = TURRET_GROUP_TURRET_COUNT(eGroupType) IF iTurretCount > ci_MAX_TURRET_GROUP_SIZE ASSERTLN("[ARENA_TURRET] GET_FIRST_FREE_TURRET_ID - INCREASE ci_MAX_TURRET_GROUP_SIZE") RETURN FALSE ENDIF BOOL bInUse[ci_MAX_TURRET_GROUP_SIZE] INT i REPEAT COUNT_OF(GlobalServerBD.turrets.players) i IF GlobalServerBD.turrets.players[i].iInstanceId = iInstanceId AND GlobalServerBD.turrets.players[i].groupType = eGroupType bInUse[GlobalServerBD.turrets.players[i].iTurretId] = TRUE ENDIF ENDREPEAT REPEAT COUNT_OF(bInUse) i IF NOT bInUse[i] ref_iTurretId = i CDEBUG1LN(DEBUG_NET_TURRET, "GET_ANY_FREE_TURRET_ID Found free turretId = ", ref_iTurretId) RETURN TRUE ENDIF ENDREPEAT RETURN FALSE ENDFUNC /// PURPOSE: /// Checks the serverBd to see if a turret is free. /// Only guarenteed to be up to date for the freemode host. /// Request use of a turret with TURRET_MANAGER_CREATE_LOCK_REQUEST. FUNC BOOL GET_NEXT_FREE_TURRET_ID(BOOL bForwards, TURRET_GROUP_TYPE eGroupType, INT iInstanceId, INT& ref_iTurretId) INT iTurretCount = TURRET_GROUP_TURRET_COUNT(eGroupType) IF iTurretCount > ci_MAX_TURRET_GROUP_SIZE ASSERTLN("[ARENA_TURRET] GET_FIRST_FREE_TURRET_ID - INCREASE ci_MAX_TURRET_GROUP_SIZE") RETURN FALSE ENDIF BOOL bInUse[ci_MAX_TURRET_GROUP_SIZE] INT i REPEAT COUNT_OF(GlobalServerBD.turrets.players) i IF GlobalServerBD.turrets.players[i].iInstanceId = iInstanceId AND GlobalServerBD.turrets.players[i].groupType = eGroupType bInUse[GlobalServerBD.turrets.players[i].iTurretId] = TRUE ENDIF ENDREPEAT INT iClosestId = ref_iTurretId INT iClosestDist = ci_MAX_TURRET_GROUP_SIZE IF bForwards REPEAT COUNT_OF(bInUse) i IF NOT bInUse[i] AND ref_iTurretId <> i INT iDist = i - ref_iTurretId // Wrap distance around 0->max IF iDist < 0 iDist += iTurretCount ENDIF IF iDist < iClosestDist iClosestId = i iClosestDist = iDist ENDIF ENDIF ENDREPEAT ELSE REPEAT COUNT_OF(bInUse) i IF NOT bInUse[i] AND ref_iTurretId <> i INT iDist = ref_iTurretId - i // Wrap distance around 0->max IF iDist < 0 iDist += iTurretCount ENDIF IF iDist < iClosestDist iClosestId = i iClosestDist = iDist ENDIF ENDIF ENDREPEAT ENDIF IF iClosestId = ref_iTurretId RETURN FALSE ELSE ref_iTurretId = iClosestId RETURN TRUE ENDIF ENDFUNC /// PURPOSE: /// Checks the serverBd to see if a turret is free. /// Only guarenteed to be up to date for the freemode host. /// Request use of a turret with TURRET_MANAGER_CREATE_LOCK_REQUEST. /// Returns -1 if turret is free. FUNC PLAYER_INDEX GET_PLAYER_IN_TURRET(TURRET_GROUP_TYPE eGroupType, INT iInstanceId, INT iTurretId) INT iPlayer REPEAT COUNT_OF(GlobalServerBD.turrets.players) iPlayer IF GlobalServerBD.turrets.players[iPlayer].groupType = eGroupType AND GlobalServerBD.turrets.players[iPlayer].iInstanceId = iInstanceId AND GlobalServerBD.turrets.players[iPlayer].iTurretId = iTurretId RETURN INT_TO_NATIVE(PLAYER_INDEX, iPlayer) ENDIF ENDREPEAT RETURN INT_TO_NATIVE(PLAYER_INDEX, -1) ENDFUNC /// PURPOSE: /// Checks the serverBd to see if a turret is free. /// Only guarenteed to be up to date for the freemode host. /// Request use of a turret with TURRET_MANAGER_CREATE_LOCK_REQUEST. FUNC BOOL IS_THIS_TURRET_ID_IS_FREE(TURRET_GROUP_TYPE eGroupType, INT iInstanceId, INT iTurretId) PLAYER_INDEX player = GET_PLAYER_IN_TURRET(eGroupType, iInstanceId, iTurretId) RETURN NATIVE_TO_INT(player) = -1 ENDFUNC /// PURPOSE: /// Returns FALSE if no turretId is free with matching eGroupType and iInstanceId. FUNC BOOL IS_TURRET_FREE(INT& ref_iTurretId, INT iInstanceId, TURRET_GROUP_TYPE eGroupType, TURRET_LOCK_SEARCH_TYPE eSearchType) CDEBUG1LN(DEBUG_NET_TURRET, "IS_TURRET_FREE eGroupType = ", ENUM_TO_INT(eGroupType), " iInstanceId = ",iInstanceId, " iTurretId = ", ref_iTurretId, " eSearchType = ", eSearchType) SWITCH eSearchType CASE TLST_THIS_TURRET_ONLY RETURN IS_THIS_TURRET_ID_IS_FREE(eGroupType, iInstanceId, ref_iTurretId) CASE TLST_ANY_TURRET RETURN GET_ANY_FREE_TURRET_ID(eGroupType, iInstanceId, ref_iTurretId) CASE TLST_ANY_TURRET_FORWARDS RETURN GET_NEXT_FREE_TURRET_ID(TRUE, eGroupType, iInstanceId, ref_iTurretId) CASE TLST_ANY_TURRET_BACKWARDS RETURN GET_NEXT_FREE_TURRET_ID(FALSE, eGroupType, iInstanceId, ref_iTurretId) DEFAULT RETURN FALSE ENDSWITCH ENDFUNC /// PURPOSE: /// Save the arguments into global broadcast data for the turret management system. PROC TURRET_MANAGER_SERVER_SET_DATA(PLAYER_INDEX player, TURRET_GROUP_TYPE eGroup, INT iInstanceId, INT iTurretId) INT iPlayerIndex = NATIVE_TO_INT(player) IF iPlayerIndex < 0 OR iPlayerIndex >= COUNT_OF(GlobalServerBD.turrets.players) PRINTLN("TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid player index in player: ", iPlayerIndex) SCRIPT_ASSERT("TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid player index in player") EXIT ENDIF INT iTurretGroupType = ENUM_TO_INT(eGroup) IF iTurretGroupType < 0 OR iTurretGroupType > ENUM_TO_INT(TGT_ARENA_CONTESTANT) CDEBUG1LN(DEBUG_NET_TURRET, "TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid TURRET_GROUP_TYPE in eGroup, expected value between 0 and TGT_ARENA_CONTESTANT, actual value: ", iTurretGroupType) SCRIPT_ASSERT("TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid TURRET_GROUP_TYPE in eGroup") EXIT ENDIF IF iTurretId < 0 OR iTurretId >= ci_MAX_TURRET_GROUP_SIZE CDEBUG1LN(DEBUG_NET_TURRET, "TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid value in iTurretId, expected value between 0 and (ci_MAX_TURRET_GROUP_SIZE-1), actual value: ", iTurretId) SCRIPT_ASSERT("TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid value in iTurretId") EXIT ENDIF GlobalServerBD.turrets.players[iPlayerIndex].groupType = eGroup GlobalServerBD.turrets.players[iPlayerIndex].iInstanceId = iInstanceId GlobalServerBD.turrets.players[iPlayerIndex].iTurretId = iTurretId ENDPROC /// PURPOSE: /// This proc takes data from a request "ref_iRequestArray" and populates "ref_iResponseArray" /// with data to send back to the player who requested a turret change. /// /// This should only be handled by the player owning the turret serverBd (GlobalServerBD.turrets - freemode host). PROC PROCESS_SERVER_RESPONSE_TO_TURRET_REQUEST(PLAYER_INDEX player, INT& ref_iRequestArray[], INT& ref_iResponseArray[]) CDEBUG1LN(DEBUG_NET_TURRET, "[SERVER] PROCESS_SERVER_RESPONSE_TO_TURRET_REQUEST for ", GET_PLAYER_NAME(player), " (", NATIVE_TO_INT(player),")") TURRET_GROUP_TYPE eGroupTypeRequest = INT_TO_ENUM(TURRET_GROUP_TYPE, ref_iRequestArray[ci_TURRET_RQST_GRP]) TURRET_LOCK_SEARCH_TYPE eSearchType = INT_TO_ENUM(TURRET_LOCK_SEARCH_TYPE, ref_iRequestArray[ci_TURRET_RQST_SEARCH]) TURRET_GROUP_TYPE eCurrentGroupType = TURRET_MANAGER_GET_GROUP(player) SWITCH eGroupTypeRequest CASE TGT_NONE CDEBUG1LN(DEBUG_NET_TURRET, "[SERVER] Setting player turret to TGT_NONE.") // To release a turret simply set the group type to tgt_none & copy other data. ref_iResponseArray[ci_TURRET_RQST_TURRET] = ref_iRequestArray[ci_TURRET_RQST_TURRET] ref_iResponseArray[ci_TURRET_RQST_INST] = ref_iRequestArray[ci_TURRET_RQST_INST] ref_iResponseArray[ci_TURRET_RQST_UID] = ref_iRequestArray[ci_TURRET_RQST_UID] ref_iResponseArray[ci_TURRET_RQST_SEARCH] = ref_iRequestArray[ci_TURRET_RQST_SEARCH] ref_iResponseArray[ci_TURRET_RQST_BS] = ref_iRequestArray[ci_TURRET_RQST_BS] ref_iResponseArray[ci_TURRET_RQST_GRP] = ENUM_TO_INT(TGT_NONE) BREAK DEFAULT // Defualt behaviour : Return requested turret details & set group type to TGT_NONE if // the turret isn't free. ref_iResponseArray[ci_TURRET_RQST_GRP] = ref_iRequestArray[ci_TURRET_RQST_GRP] ref_iResponseArray[ci_TURRET_RQST_TURRET] = ref_iRequestArray[ci_TURRET_RQST_TURRET] ref_iResponseArray[ci_TURRET_RQST_INST] = ref_iRequestArray[ci_TURRET_RQST_INST] ref_iResponseArray[ci_TURRET_RQST_UID] = ref_iRequestArray[ci_TURRET_RQST_UID] ref_iResponseArray[ci_TURRET_RQST_SEARCH] = ref_iRequestArray[ci_TURRET_RQST_SEARCH] ref_iResponseArray[ci_TURRET_RQST_BS] = ref_iRequestArray[ci_TURRET_RQST_BS] IF NOT IS_TURRET_FREE(ref_iResponseArray[ci_TURRET_RQST_TURRET], ref_iRequestArray[ci_TURRET_RQST_INST], eGroupTypeRequest, eSearchType) IF eCurrentGroupType <> TGT_NONE AND IS_BIT_SET(ref_iRequestArray[ci_TURRET_RQST_BS], ci_TURRET_LOCK_BS_DO_NOT_KICK) CDEBUG1LN(DEBUG_NET_TURRET, "[SERVER] ci_TURRET_LOCK_BS_DO_NOT_KICK - not kicking player from their current turret.") // Don't kick player form current turret on fail. ref_iResponseArray[ci_TURRET_RQST_TURRET] = TURRET_MANAGER_GET_TURRET_ID(player) ref_iResponseArray[ci_TURRET_RQST_GRP] = ENUM_TO_INT(eCurrentGroupType) ref_iResponseArray[ci_TURRET_RQST_INST] = TURRET_MANAGER_GET_INSTANCE_ID(player) ELSE // Respond with fail & kick from turret if they're in one. ref_iResponseArray[ci_TURRET_RQST_TURRET] = -1 ref_iResponseArray[ci_TURRET_RQST_GRP] = ENUM_TO_INT(TGT_NONE) ENDIF ENDIF BREAK ENDSWITCH // Assign response to serverBd PRINT_TURRET_RQST(ref_iResponseArray) TURRET_MANAGER_SERVER_SET_DATA(player, INT_TO_ENUM(TURRET_GROUP_TYPE, ref_iResponseArray[ci_TURRET_RQST_GRP]), ref_iResponseArray[ci_TURRET_RQST_INST], ref_iResponseArray[ci_TURRET_RQST_TURRET]) ENDPROC FUNC TURRET_OCCUPANCY_DATA CONVERT_TURRET_REQUEST_DATA(INT& ref_iRequestArray[]) TURRET_OCCUPANCY_DATA data IF COUNT_OF(ref_iRequestArray) < ci_TURRET_RQST_COUNT ASSERTLN("CONVERT_TURRET_REQUEST_DATA int array too small") RETURN data ENDIF data.iInstanceId = ref_iRequestArray[ci_TURRET_RQST_INST] data.groupType = INT_TO_ENUM(TURRET_GROUP_TYPE, ref_iRequestArray[ci_TURRET_RQST_GRP]) data.iTurretId = ref_iRequestArray[ci_TURRET_RQST_TURRET] RETURN data ENDFUNC PROC SAVE_TURRET_LOCK_RESPONSE(INT& ref_iResponseArray[]) IF COUNT_OF(ref_iResponseArray) < ci_TURRET_RQST_COUNT ASSERTLN("SET_TURRET_REQUEST_RESPONSE Response int array too small") EXIT ENDIF g_turretLockResponse = CONVERT_TURRET_REQUEST_DATA(ref_iResponseArray) g_iTurretLockResponseUid = INT_TO_ENUM(TURRET_LOCK_REQUEST_ID, ref_iResponseArray[ci_TURRET_RQST_UID]) // No need to save response search settings CDEBUG1LN(DEBUG_NET_TURRET, "SAVE_TURRET_LOCK_RESPONSE: ") PRINT_TURRET_RQST(ref_iResponseArray) ENDPROC /// PURPOSE: /// Fill "ref_iRequestArray" with the data required for a turret request event. /// PROC FILL_TURRET_REQUEST_DATA(TURRET_OCCUPANCY_DATA& ref_request, INT iUniqueId, TURRET_LOCK_SEARCH_TYPE eSearchType, INT iSettingsBs, INT& ref_iRequestArray[]) IF COUNT_OF(ref_iRequestArray) < ci_TURRET_RQST_COUNT ASSERTLN("SET_TURRET_REQUEST_RESPONSE Request int array too small") EXIT ENDIF ref_iRequestArray[ci_TURRET_RQST_UID] = iUniqueId ref_iRequestArray[ci_TURRET_RQST_INST] = ref_request.iInstanceId ref_iRequestArray[ci_TURRET_RQST_GRP] = ENUM_TO_INT(ref_request.groupType) ref_iRequestArray[ci_TURRET_RQST_TURRET] = ref_request.iTurretId ref_iRequestArray[ci_TURRET_RQST_SEARCH] = ENUM_TO_INT(eSearchType) ref_iRequestArray[ci_TURRET_RQST_BS] = iSettingsBs ENDPROC