2026-03-09 07:12:13 +01:00

747 lines
37 KiB
PHP

<?php
//include_once "../objects/db_table_object.php";
include_once '../objects/db_session.php';
include_once '../objects/db_user.php';
include_once '../objects/db_view_sessiondebrief_row.php';
include_once '../objects/stats_user_globals.php';
//include_once '../objects/stats_user_in_session_row.php';
class StatsObject extends DBTableObject
{
// database connection and table name
//protected $conn;
protected $array_key = "stats";
protected $elements = array();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected $excludeCalibrationSessionsFromStats = true;
protected function getCalibrationSessionsConstraint ($sessionsTableIndex="SD") : string
{
return $this->excludeCalibrationSessionsFromStats == true ? " AND " . $sessionsTableIndex . ".ScenarioName NOT LIKE '%Calibration%'" : "";
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected $minimumSessionDuration = 10;
protected function getSessionDurationConstraint ($sessionsTableIndex="SD", $allowZero=false) : string
{
return $this->minimumSessionDuration > 0 ? " AND (" . $sessionsTableIndex . ".timeToFinish > " . $this->minimumSessionDuration . ($allowZero ? " OR " . $sessionsTableIndex . ".timeToFinish = 0" : "") . ")" : "";
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected function getSessionsWithUserConstraint ($userId) : string
{
return $userId > 0 ? "SELECT DISTINCT UP.SessionId FROM " . PARTICIPATES_TABLE_NAME . " UP WHERE UP.userId=" . $userId : "";
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public function toArray () : array
{
return $this->elements;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// get users who took place in given session
public function fixDurations ()
{
$query = "SELECT S.id AS SessionId FROM " . SESSIONS_TABLE_NAME . " S, " . TRIGGEREVENTS_TABLE_NAME . " TE WHERE S.timeToFinish=0 AND S.id=TE.sessionId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
$nb = 0;
// get max time for trigger events in these sessions
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$subQuery = "SELECT COALESCE(MAX(TE.timeStamp),0) AS LastTriggerEvent FROM " . TRIGGEREVENTS_TABLE_NAME . " TE WHERE TE.sessionId=" . $row['SessionId'];
// prepare and execute query
$subStmt = $this->conn->prepare($subQuery);
$subStmt->execute();
while ($subRow = $subStmt->fetch(PDO::FETCH_ASSOC)) // should be only 1 row
{
if ($subRow['LastTriggerEvent'] != 0) // should always be true
{
$subQuery = "UPDATE " . SESSIONS_TABLE_NAME . " SET timeToFinish=" . $subRow['LastTriggerEvent'] . " WHERE id=" . $row['SessionId'];
// prepare and execute query
$subStmt = $this->conn->prepare($subQuery);
$subStmt->execute();
$nb++;
}
}
}
return $nb;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// get users who took place in given session
public function getRawUsers ($sessionId)
{
// Check if we are looking for a specific session
$sessionConstraint = $sessionId > 0 ? " AND P.sessionId=" . $sessionId : "";
$query = "SELECT DISTINCT U.* FROM " . USERS_TABLE_NAME . " U LEFT JOIN " . PARTICIPATES_TABLE_NAME . " P ON U.id = P.userId " .
"LEFT JOIN " . SESSIONS_TABLE_NAME . " SD ON P.sessionId=SD.id " .
"WHERE U.id > 0" . $sessionConstraint . $this->getSessionDurationConstraint("SD");
//$query = "SELECT DISTINCT U.* FROM " . USERS_TABLE_NAME . " U, " . PARTICIPATES_TABLE_NAME . " P WHERE U.id = P.userId AND U.id > 0" . $sessionConstraint;
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// get users who took place in given session
public function getUsersInSession ($sessionId)
{
// Check if we are looking for a specific session
$stmt = $this->getRawUsers($sessionId);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
//$sess = new GameSession($this->conn);
//$sess->readRow($row);
$user = User::withRow($this->conn, $row);
array_push( $this->elements, $user->toArray() );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// get sessions of given type that given user has taken part in
public function getRawSessions ($userId=-1, $typeId=-1)
{
// Check if we are looking for a specific user and/or type of session
$userConstraint = $userId > 0 ? " AND P.userId=" . $userId : "";
$typeConstraint = $typeId >= 0 ? " AND SD.sessionType=" . $typeId : "";
// Order results from newest to oldest session
$orderConstraint = " ORDER BY SD.id DESC";
//$query = "SELECT DISTINCT S.* FROM " . SESSIONS_TABLE_NAME . " S LEFT JOIN " . PARTICIPATES_TABLE_NAME . " P ON S.id = P.sessionId WHERE 1 " .
$query = "SELECT DISTINCT SD.* FROM " . SESSIONS_TABLE_NAME . " SD, " . PARTICIPATES_TABLE_NAME . " P WHERE SD.id = P.sessionId " .
$this->getCalibrationSessionsConstraint("SD") . $this->getSessionDurationConstraint("SD") . $userConstraint . $typeConstraint . $orderConstraint;
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// get sessions that given user has taken part in
public function getSessionsForUser ($userId, $typeId=-1)
{
// Check if we are looking for a specific user and/or session
$stmt = $this->getRawSessions($userId, $typeId);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
//$sess = new GameSession($this->conn);
//$sess->readRow($row);
$sess = GameSession::withRow($this->conn, $row);
array_push( $this->elements, $sess->toArray() );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debrief mission : get stats for given session
public function getRawStatsForSession ($sessionId, $userId, $fromUser=-1)
{
$sessionStats = array();
// first create expected rows for results, so that every user will get stats (even if user didn't fire or received any shot)
if ($sessionId > 0 && $userId > 0)
{
// we want stats for a specific user in a specific session
// => we only need to create one default row, just in case user didn't fire or received any shot
$defaultRow = new UserStatsInSessionRow();
$defaultRow->createSessionAndUser($this->conn, $sessionId, $userId);
array_push( $sessionStats, $defaultRow );
}
else if ($userId == -1)
{
// we want stats for all users in a specific session
// => we need to create one default row for each user
$stmt_usersInSession = $this->getRawUsers($sessionId);
while ($row = $stmt_usersInSession->fetch(PDO::FETCH_ASSOC))
{
$defaultRow = new UserStatsInSessionRow();
$defaultRow->createSessionAndUser($this->conn, $sessionId, $row['id']);
array_push( $sessionStats, $defaultRow );
}
}
else if ($sessionId == -1)
{
// we want stats for a specific user in all sessions he took place in
// => we need to create one default row for each user
$stmt_sessionsForUser = $this->getRawSessions($userId);
while ($row = $stmt_sessionsForUser->fetch(PDO::FETCH_ASSOC))
{
$defaultRow = new UserStatsInSessionRow();
$defaultRow->createSessionAndUser($this->conn, $row['id'], $userId);
array_push( $sessionStats, $defaultRow );
}
}
else
{
// both $sessionId and $userId are set to -1
// => do nothing, this will (should) not happen
}
// Get fired shots
$stmt_firedShots = $this->getShotsFiredByUser($sessionId, $userId, $fromUser);
while ($row = $stmt_firedShots->fetch(PDO::FETCH_ASSOC))
{
// Only create stats row for shooters with id > 0
if ((int)$row['UserId'] > 0)
{
$statsRow = $this->findStats( $sessionStats, (int)$row['UserId'], (int)$row['SessionId'] );
if ($statsRow == null)
{
$statsRow = UserStatsInSessionRow::withRow($this->conn, $row);
$statsRow->setFiredShots($row);
array_push( $sessionStats, $statsRow );
}
else
$statsRow->setFiredShots($row);
}
}
// Get received shots
$stmt_receivedShots = $this->getReceivedHitsForUser($sessionId, $userId, $fromUser);
while ($row = $stmt_receivedShots->fetch(PDO::FETCH_ASSOC))
{
// Only create stats row for hit users with id > 0
if ((int)$row['UserId'] > 0)
{
$statsRow = $this->findStats ( $sessionStats, (int)$row['UserId'], (int)$row['SessionId'] );
if ($statsRow == null)
{
$statsRow = UserStatsInSessionRow::withRow($this->conn, $row);
$statsRow->setReceivedHits($row);
array_push( $sessionStats, $statsRow );
}
else
$statsRow->setReceivedHits($row);
}
}
// Get average precision and reaction time
$stmt_averages = $this->getPrecisionAndReactionTimeForUser($sessionId, $userId, $fromUser);
while ($row = $stmt_averages->fetch(PDO::FETCH_ASSOC))
{
// Only create stats row for hit users with id > 0
if ((int)$row['UserId'] > 0)
{
$statsRow = $this->findStats ( $sessionStats, (int)$row['UserId'], (int)$row['SessionId'] );
if ($statsRow == null)
{
$statsRow = UserStatsInSessionRow::withRow($this->conn, $row);
$statsRow->setPrecisionAndReactionTime($row);
array_push( $sessionStats, $statsRow );
}
else
$statsRow->setPrecisionAndReactionTime($row);
}
}
// Get total of targets killed in the session
$stmt_targetKilled = $this->getTargetKilledInSession($sessionId);
while ($row = $stmt_targetKilled->fetch(PDO::FETCH_ASSOC))
{
// Add totals stats to all rows of the same session
foreach ($sessionStats as $statsRow)
{
if ($statsRow->sessionId == (int)$row['SessionId'])
$statsRow->setTotalKills($row);
}
}
return $sessionStats;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debrief mission : get stats for given session
public function getStatsForSession ($sessionId, $userId, $fromUser=-1)
{
$sessionStats = $this->getRawStatsForSession($sessionId, $userId, $fromUser);
// Parse workingStats array to output results
foreach ($sessionStats as $outputStats)
array_push( $this->elements, $outputStats->toArray() );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// find a row of stats for given user and stats
function findStats (array $statsArray, int $userId, int $sessionId)
{
foreach ($statsArray as $row)
{
if (call_user_func_array(array($row, 'isForUserInSession'), array($userId, $sessionId)) === true)
return $row;
}
return null;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// get stats : main call for getting stats from Unreal
public function get ($sessionId, $userId, $sessionType, $fromUserId=-1)
{
if ($sessionType == 0 || $sessionType == 1 || $sessionType == 7) // Firerange, Challenge or Long Range
$this->getResultsForSession ($sessionId, $userId, $fromUserId);
else if ($sessionId > 0 || $userId > 0)
$this->getStatsForSession ($sessionId, $userId, $fromUserId);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// user history : get user "all-time" totals
public function getUserHistory ($userId, $sessionId, $quickMode)
{
$userGlobals = new UserGlobalStats();
if ($quickMode == 1 && $userId > 0)
{
$userGlobals->totals->createSessionAndUser($this->conn, $sessionId, $userId);
$userGlobals->totals->averagePrecision = $userGlobals->totals->user->avgPrecision;
$userGlobals->totals->averageReactionTime = $userGlobals->totals->user->avgReaction;
$userSubConstraint = $userId >= 0 ? " AND P.UserId = " . $userId : ""; // always true
// Calculate date of first and last sessions
$query = "SELECT P.userID AS UserId, MIN(SD.SessionDate) AS MinDate, MAX(SD.SessionDate) AS MaxDate, " . "
COUNT(DISTINCT P.UserId, P.sessionId) AS NbSessions, SUM(SD.timeToFinish) AS TotalDuration " . "
FROM " . PARTICIPATES_TABLE_NAME . " P, " . SESSIONS_TABLE_NAME . " SD WHERE SD.id=P.sessionId " . $this->getCalibrationSessionsConstraint("SD") . $this->getSessionDurationConstraint("SD") . $userSubConstraint . " GROUP BY P.UserId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) // should be only 1 row
{
$userGlobals->setSessionTotals($row);
//$userGlobals->nbSessions = $row['NbSessions'];
//$userGlobals->totalDuration = $row['TotalDuration'];
//$userGlobals->firstSession = $row['MinDate'];
//$userGlobals->lastSession = $row['MaxDate'];
}
// Calculate shots fired
$userConstraint = $userId > 0 ? " AND SDTE.srcUserId=" . $userId : "";
$query = "SELECT COALESCE(SDTE.srcUserId,-1) AS UserId,
COALESCE(X.NbShotsFired,0) AS NbShotsFired,
COALESCE(X.NbShotsFired,0) - COALESCE(SUM(CASE WHEN Y.ReactTypeId>=0 AND Y.ReactTypeId<6 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END),0) AS NbMissedShots,
SUM(CASE WHEN Y.ReactTypeId=0 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbEnemyHits,
SUM(CASE WHEN Y.ReactTypeId=1 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbCivilHits,
SUM(CASE WHEN Y.ReactTypeId=2 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbPoliceHits,
SUM(CASE WHEN (Y.ReactTypeId=4 OR Y.ReactTypeId=5) AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbObjectHits,
SUM(CASE WHEN Y.ReactTypeId=6 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbDeadBodyHits
FROM " . SESSIONS_TABLE_NAME . " SD LEFT JOIN " . TRIGGEREVENTS_TABLE_NAME . " SDTE ON (SDTE.sessionId=SD.id)
LEFT JOIN " . REACTEVENTS_TABLE_NAME . " SDRE ON (SDTE.sessionId=SDRE.srcEventSessionId AND SDTE.indexCount=SDRE.srcEventIndex)
LEFT JOIN " . "
(SELECT TE.srcUserId AS ShooterId, COUNT(DISTINCT TE.sessionId, TE.indexCount) AS NbShotsFired FROM " . TRIGGEREVENTS_TABLE_NAME . " TE GROUP BY TE.srcUserId) AS X
ON X.ShooterId=SDTE.srcUserId
LEFT JOIN " . "
(SELECT TE.srcUserId AS ShooterId, RE.ReactType AS ReactTypeId, COUNT(DISTINCT TE.sessionId, TE.indexCount, RE.hitTargetName) AS NbHits, RE.id AS ReactId, RE.hitPrecision AS ReactPrecision
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE, " . REACTEVENTS_TABLE_NAME . " RE
WHERE TE.sessionId = RE.srcEventSessionId AND TE.indexCount = RE.srcEventIndex AND TE.indexCount!=-1 AND RE.ReactType!=-1 GROUP BY ShooterId, ReactTypeId, ReactID) AS Y
ON (Y.ShooterId=SDTE.srcUserId AND Y.ReactId=SDRE.id)
LEFT JOIN " . "
(SELECT TE1.srcUserId AS ShooterId, COALESCE(COUNT(DISTINCT TE1.sessionId, TE1.indexCount),0) AS NbMissedShots FROM " . TRIGGEREVENTS_TABLE_NAME . " TE1, " . REACTEVENTS_TABLE_NAME . " RE1
WHERE TE1.sessionId=RE1.srcEventSessionId AND TE1.indexCount NOT IN (SELECT RE2.srcEventIndex FROM " . REACTEVENTS_TABLE_NAME . " RE2 WHERE RE2.srcEventSessionId=RE1.srcEventSessionId)) AS Z
ON (Z.ShooterId=SDTE.srcUserId) " . "
WHERE 1 " . $this->getCalibrationSessionsConstraint("SD") . $this->getSessionDurationConstraint("SD") . $userConstraint . " GROUP BY SDTE.srcUserId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$userGlobals->totals->setFiredShots($row);
//$userGlobals->totals->nbFiredShotsByUser = $row['NbShotsFired'];
//$userGlobals->totals->nbMissedShotsByUser = $row['NbMissedShots'];
//$userGlobals->totals->nbEnemyHitsByUser = $row['NbEnemyHits'];
//$userGlobals->totals->nbCivilHitsByUser = $row['NbCivilHits'];
//$userGlobals->totals->nbPoliceHitsByUser = $row['NbPoliceHits'];
//$userGlobals->totals->nbObjectHitsByUser = $row['NbObjectHits'];
//$userGlobals->totals->nbDeadBodyHitsByUser = $row['NbDeadBodyHits'];
}
// Calculate received hits
$userConstraint = $userId > 0 ? " AND X.TargetUserId=" . $userId : "";
$query = "SELECT COALESCE(X.TargetUserId, -1) AS UserId,
SUM(CASE WHEN X.ShooterRoleId=3 THEN X.NbHits ELSE 0 END) AS NbEnemyShotsIA,
SUM(CASE WHEN X.ShooterRoleId=1 THEN X.NbHits ELSE 0 END) AS NbEnemyShotsUser,
SUM(CASE WHEN X.ShooterRoleId=0 THEN X.NbHits ELSE 0 END) AS NbPoliceHits
FROM (SELECT TE.SessionId AS SessionId, RE.hitUserId AS TargetUserId,
(SELECT IFNULL((SELECT P.role FROM " . PARTICIPATES_TABLE_NAME . " P WHERE P.sessionId=TE.sessionId AND P.userId=TE.srcUserId),3)) AS ShooterRoleId,
COUNT(DISTINCT TE.indexCount, RE.hitTargetName) AS NbHits
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE, " . REACTEVENTS_TABLE_NAME . " RE, " . SESSIONS_TABLE_NAME . " SD " .
"WHERE SD.id=TE.sessionId AND TE.sessionId = RE.srcEventSessionId AND TE.indexCount = RE.srcEventIndex AND TE.indexCount!=-1 AND RE.ReactType!=-1 " .
$this->getCalibrationSessionsConstraint("SD") . $this->getSessionDurationConstraint("SD") .
"GROUP BY SessionId, TargetUserId, ShooterRoleId) AS X
WHERE 1 " . $userConstraint . " GROUP BY X.TargetUserId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$userGlobals->totals->setReceivedHits($row);
}
// Calculate totals hits by type
$sessionConstraint = $sessionId > 0 ? " AND SDTE.SessionId = " . $sessionId : "";
$userConstraint = $userId > 0 ? " AND SDTE.SessionId IN (" . $this->getSessionsWithUserConstraint($userId) . ")" : "";
$query = "SELECT SUM(CASE WHEN X.ReactTypeId=0 THEN X.NbHits ELSE 0 END) AS NbEnemyKilled,
SUM(CASE WHEN X.ReactTypeId=1 THEN X.NbHits ELSE 0 END) AS NbCivilKilled,
SUM(CASE WHEN X.ReactTypeId=2 THEN X.NbHits ELSE 0 END) AS NbPoliceKilled
FROM " . SESSIONS_TABLE_NAME . " SD LEFT JOIN " . TRIGGEREVENTS_TABLE_NAME . " SDTE ON (SD.id = SDTE.sessionId)
LEFT JOIN
(SELECT TE.SessionId AS SessionId, RE.hitUserId AS TargetUserId, TE.srcUserId AS ShooterRoleId, COUNT(DISTINCT TE.indexCount, RE.hitTargetName) AS NbHits, RE.srcEventIndex AS TriggerIndex, RE.ReactType AS ReactTypeId
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE, " . REACTEVENTS_TABLE_NAME . " RE WHERE TE.sessionId = RE.srcEventSessionId AND TE.indexCount = RE.srcEventIndex AND TE.indexCount!=-1 AND RE.ReactType!=-1 AND RE.TargetKilled=1
GROUP BY SessionId, TargetUserId, ShooterRoleId, ReactTypeId) AS X
ON (X.SessionId=SDTE.SessionId AND X.TriggerIndex=SDTE.indexCount)
WHERE 1 " . $this->getCalibrationSessionsConstraint("SD") . $this->getSessionDurationConstraint("SD") . $userConstraint;
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$userGlobals->totals->setTotalKills($row);
}
$query = "SELECT X.*, " .
"SUM(X.HitPrecision)/COALESCE(COUNT(DISTINCT X.SessionId, X.ShotIndex),1) AS AvgPrecision, " .
"SUM(X.ReactionTime)/COALESCE(SUM(CASE WHEN X.ReactionTime > 0 THEN CEILING(X.HitPrecision) ELSE 0 END),1) AS AvgReactTime " .
"FROM " .
"(SELECT TE.sessionId AS SessionId, S.sessionType AS SessionTypeId, ST.displayName AS SessionType, S.sessionName AS SessionName, S.sessionDate AS SessionDate, S.mapName AS MapName, S.scenarioName AS ScenarioName, " .
"S.success AS SessionSuccessful, S.timeToFinish AS SessionDuration, 0 AS TriggerTypeId, 'Fire' AS TriggerType, TE.srcUserId AS ShooterId, '' AS ShooterName, -1 AS ShooterRoleId, '' AS ShooterRole, " .
"TE.indexCount AS ShotIndex, RE.id AS ReactId, -1 AS ReactModeId, '' AS ReactMode, -1 AS ReactTypeId, '' AS ReactType, RE.hitUserId AS TargetUserId, " .
"'' AS TargetUserName, -1 AS TargetRoleId, '' AS TargetRole, RE.hitTargetName AS TargetName, RE.hitBoneName AS TargetBoneName, 0 AS TargetKilled, 0 AS HitLocationX, 0 AS HitLocationY, " .
"'' AS HitLocationTag, RE.hitPrecision AS HitPrecision, 0 AS HitTargetDistance, RE.reactTime as ReactionTime, 0 AS TimeStamp, 0 AS NbHit, 0 AS NbKilled " .
"FROM " . SESSIONS_TABLE_NAME . " S " .
"LEFT JOIN " . TRIGGEREVENTS_TABLE_NAME . " TE ON (S.id=TE.sessionId) " .
"LEFT JOIN " . REACTEVENTS_TABLE_NAME . " RE ON (TE.sessionId=RE.srcEventSessionId AND TE.indexCount=RE.srcEventIndex) " .
"LEFT JOIN " . SESSIONTYPES_TABLE_NAME . " ST ON (S.sessionType=ST.id) " .
"WHERE 1 " . $this->getSessionDurationConstraint("S") . $this->getCalibrationSessionsConstraint("S") .
" GROUP BY ShooterId, SessionId, TE.indexCount) AS X " .
"WHERE X.ShooterId = " . $userId . " AND X.SessionId IN (" . $this->getSessionsWithUserConstraint($userId) . ") GROUP BY X.ShooterId, X.SessionId ORDER BY X.SessionId ASC";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$row['HitPrecision'] = $row['AvgPrecision'];
$row['ReactionTime'] = $row['AvgReactTime'];
$stats = SessionDebriefRow::withRow($row);
array_push( $userGlobals->sessionDebriefRows, $stats->toArray() );
}
}
else
{
// create SQL constraints for query
$sessionConstraint = $sessionId > 0 ? " AND SD.SessionId = " . $sessionId : "";
$userConstraint = $userId >= 0 ? " AND SD.ShooterId = " . $userId : "";
$userSubConstraint = $userId >= 0 ? " AND P.UserId = " . $userId : "";
// get raw results from query
$sessionStats = $this->getRawStatsForSession ($sessionId, $userId, -1);
$newNbFiredShotsForReactionTime = 0;
$nbSessions = 0;
foreach ($sessionStats as $row)
{
if ( ($userId == -1 || $row->userId == $userId) && ($sessionId == -1 || $row->sessionId == $sessionId) )
{
// Increase number of sessions for this user
$nbSessions++;
// Update precision average
$newPrecision = $userGlobals->totals->averagePrecision*$userGlobals->totals->nbFiredShotsByUser + $row->averagePrecision*$row->nbFiredShotsByUser;
$userGlobals->totals->averagePrecision = $newPrecision/max($userGlobals->totals->nbFiredShotsByUser + $row->nbFiredShotsByUser, 1.0);
// Update reactionTime average
if ($row->averageReactionTime > 0)
{
$newReactionTime = $userGlobals->totals->averageReactionTime*$newNbFiredShotsForReactionTime + $row->averageReactionTime*$row->nbFiredShotsByUser;
$newNbFiredShotsForReactionTime += $row->nbFiredShotsByUser;
$userGlobals->totals->averageReactionTime = $newReactionTime/max($newNbFiredShotsForReactionTime, 1.0);
}
// Update other fields
$userGlobals->totals->nbFiredShotsByUser = $userGlobals->totals->nbFiredShotsByUser + $row->nbFiredShotsByUser;
$userGlobals->totals->nbEnemyHitsByUser += $row->nbEnemyHitsByUser;
$userGlobals->totals->nbCivilHitsByUser += $row->nbCivilHitsByUser;
$userGlobals->totals->nbPoliceHitsByUser += $row->nbPoliceHitsByUser;
$userGlobals->totals->nbObjectHitsByUser += $row->nbObjectHitsByUser;
$userGlobals->totals->nbMissedShotsByUser += $row->nbMissedShotsByUser;
$userGlobals->totals->nbDeadBodyHitsByUser += $row->nbDeadBodyHitsByUser;
$userGlobals->totals->nbReceivedHitsFromEnemyIA += $row->nbReceivedHitsFromEnemyIA;
$userGlobals->totals->nbReceivedHitsFromEnemyUser += $row->nbReceivedHitsFromEnemyUser;
$userGlobals->totals->nbReceivedHitsFromPoliceUser +=$row->nbReceivedHitsFromPoliceUser;
$userGlobals->totals->totalEnemyKilled += $row->totalEnemyKilled;
$userGlobals->totals->totalCivilKilled += $row->totalCivilKilled;
$userGlobals->totals->totalPoliceKilled += $row->totalPoliceKilled;
// Update duration
$userGlobals->totalDuration += $row->session->timeToFinish;
// Update user and session ids
$userGlobals->totals->userId = $row->userId;
$userGlobals->totals->sessionId = $row->sessionId;
}
}
// Get number of sessions user took part in
$userGlobals->nbSessions = $nbSessions;
// Calculate averages for precision and reaction time
$query = "SELECT SD.*, SUM(SD.HitPrecision) AS TotalPrecision, COUNT(DISTINCT SD.ShotIndex, SD.TargetName) AS TotalShots" .
", SUM(SD.ReactionTime) AS TotalReactionTime, SUM(CEILING(SD.HitPrecision)) AS TotalHits, X.MinDate AS MinDate, X.MaxDate AS MaxDate" .
" FROM " . SESSIONDEBRIEFS_VIEW_NAME . " SD, " .
" (SELECT P.userID AS UserId, MIN(S.SessionDate) AS MinDate, MAX(S.SessionDate) AS MaxDate" .
//" FROM " . PARTICIPATES_TABLE_NAME . " P INNER JOIN " . SESSIONS_TABLE_NAME . " S ON S.id=P.sessionId WHERE 1 " . $userSubConstraint . " GROUP BY P.userId) AS X" .
" FROM " . PARTICIPATES_TABLE_NAME . " P, " . SESSIONS_TABLE_NAME . " S WHERE S.id=P.sessionId " . $userSubConstraint . " GROUP BY P.userId) AS X" .
" WHERE 1 " . $sessionConstraint . $userConstraint . " GROUP BY SD.SessionId, SD.ShooterId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
// read MIN and MAX dates
$userGlobals->firstSession = $row['MinDate'];
$userGlobals->lastSession = $row['MaxDate'];
// replace HitPrecision, ReactionTime and NbHit fields so that we don't have to create a new type for returning the results
$row['HitPrecision'] = (float)(($row['TotalPrecision'] ?? 0.0) / max(($row['TotalShots'] ?? 1.0), 1.0) );
$row['ReactionTime'] = (float)(($row['TotalReactionTime'] ?? 0.0) / max(($row['TotalHits'] ?? 1.0), 1.0) );
$row['NbHit'] = $row['TotalHits'] ?? 0;
$stats = SessionDebriefRow::withRow($row);
array_push( $userGlobals->sessionDebriefRows, $stats->toArray() );
//array_push( $this->elements, $stats->toArray() ); // old
}
if ($userGlobals->nbSessions == 1)
{
$userGlobals->firstSession = $sessionStats[0]->session->sessionDate;
$userGlobals->lastSession = $userGlobals->firstSession;
}
}
array_push( $this->elements, $userGlobals->toArray() ); // new
//return $userGlobals->toArray();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debrief mission : get totals for given session and/or user
public function getReceivedHitsForUser ($sessionId, $userId, $fromUser=-1)
{
// create SQL constraints for query
$sessionConstraint = $sessionId > 0 ? " AND SDRE.srcEventSessionId = " . $sessionId : "";
$userConstraint = $userId > 0 ? " AND SDRE.hitUserId=" . $userId : "";
$query = "SELECT SDRE.srcEventSessionId AS SessionId, COALESCE(SDRE.hitUserId, -1) AS UserId,
SUM(CASE WHEN X.ShooterRoleId=3 THEN X.NbHits ELSE 0 END) AS NbEnemyShotsIA,
SUM(CASE WHEN X.ShooterRoleId=1 THEN X.NbHits ELSE 0 END) AS NbEnemyShotsUser,
SUM(CASE WHEN X.ShooterRoleId=0 THEN X.NbHits ELSE 0 END) AS NbPoliceHits
FROM " . REACTEVENTS_TABLE_NAME . " SDRE LEFT JOIN
(SELECT TE.SessionId AS SessionId, RE.hitUserId AS TargetUserId, TE.srcUserId AS ShooterRoleId, COUNT(DISTINCT TE.indexCount, RE.hitTargetName) AS NbHits, RE.id AS ReactId
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE, " . REACTEVENTS_TABLE_NAME . " RE WHERE TE.sessionId = RE.srcEventSessionId AND TE.indexCount = RE.srcEventIndex AND TE.indexCount!=-1 AND RE.ReactType!=-1 GROUP BY SessionId, TargetUserId, ShooterRoleId) AS X
ON (X.SessionId=SDRE.srcEventSessionId AND X.TargetUserId=SDRE.hitUserId AND X.ReactId=SDRE.id) " .
" LEFT JOIN " . SESSIONS_TABLE_NAME . " SD ON (SD.id=SDRE.srcEventSessionId) " .
"WHERE 1 " . $sessionConstraint . $userConstraint . $this->getSessionDurationConstraint("SD") . " GROUP BY SDRE.srcEventSessionId, SDRE.hitUserId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debrief mission : get totals for given session and/or user
public function getShotsFiredByUser ($sessionId, $userId, $fromUser=-1)
{
// create SQL constraints for query
$sessionConstraint = $sessionId > 0 ? " AND SDTE.SessionId = " . $sessionId : "";
$userConstraint = $userId > 0 ? " AND SDTE.srcUserId=" . $userId : "";
$query = "SELECT SDTE.SessionId AS SessionId, SDTE.srcUserId AS UserId,
COALESCE(X.NbShotsFired,0) AS NbShotsFired,
COALESCE(X.NbShotsFired,0) - COALESCE(SUM(CASE WHEN Y.ReactTypeId>=0 AND Y.ReactTypeId<6 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END),0) AS NbMissedShots,
SUM(CASE WHEN Y.ReactTypeId=0 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbEnemyHits,
SUM(CASE WHEN Y.ReactTypeId=1 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbCivilHits,
SUM(CASE WHEN Y.ReactTypeId=2 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbPoliceHits,
SUM(CASE WHEN (Y.ReactTypeId=4 OR Y.ReactTypeId=5) AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbObjectHits,
SUM(CASE WHEN Y.ReactTypeId=6 AND Y.ReactPrecision>0 THEN Y.NbHits ELSE 0 END) AS NbDeadBodyHits
FROM " . SESSIONS_TABLE_NAME . " SD LEFT JOIN " . TRIGGEREVENTS_TABLE_NAME . " SDTE ON (SD.id = SDTE.sessionId)
LEFT JOIN " . REACTEVENTS_TABLE_NAME . " SDRE ON (SDTE.sessionId=SDRE.srcEventSessionId AND SDTE.indexCount=SDRE.srcEventIndex)
LEFT JOIN
(SELECT TE.sessionId AS SessionId, TE.srcUserId AS ShooterId, COUNT(DISTINCT TE.indexCount) AS NbShotsFired
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE GROUP BY TE.sessionId, TE.srcUserId) AS X
ON (X.SessionId=SDTE.SessionId AND X.ShooterId=SDTE.srcUserId)
LEFT JOIN
(SELECT TE.sessionId AS SessionId, TE.srcUserId AS ShooterId, RE.ReactType AS ReactTypeId, COUNT(DISTINCT TE.indexCount, RE.hitTargetName) AS NbHits, RE.id AS ReactId, RE.hitPrecision AS ReactPrecision
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE, " . REACTEVENTS_TABLE_NAME . " RE
WHERE TE.sessionId = RE.srcEventSessionId AND TE.indexCount = RE.srcEventIndex AND TE.indexCount!=-1 AND RE.ReactType!=-1 GROUP BY SessionId, ShooterId, ReactTypeId, ReactID) AS Y
ON (Y.SessionId=SDTE.SessionId AND Y.ShooterId=SDTE.srcUserId AND Y.ReactId=SDRE.id)
LEFT JOIN
(SELECT TE1.sessionId AS SessionId, TE1.srcUserId AS ShooterId, COALESCE(COUNT(DISTINCT TE1.sessionId, TE1.indexCount),0) AS NbMissedShots
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE1, " . REACTEVENTS_TABLE_NAME . " RE1
WHERE TE1.sessionId=RE1.srcEventSessionId AND TE1.indexCount NOT IN (SELECT RE2.srcEventIndex FROM " . REACTEVENTS_TABLE_NAME . " RE2 WHERE RE2.srcEventSessionId=RE1.srcEventSessionId)) AS Z
ON (Z.SessionId=SDTE.SessionId AND Z.ShooterId=SDTE.srcUserId)
WHERE 1 " . $this->getCalibrationSessionsConstraint("SD") . $this->getSessionDurationConstraint("SD") . $sessionConstraint . $userConstraint . " GROUP BY SDTE.SessionId, SDTE.srcUserId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debrief mission : get totals for given session and/or user
public function getTargetKilledInSession ($sessionId)
{
// create SQL constraints for query
$sessionConstraint = $sessionId > 0 ? " AND SDTE.SessionId = " . $sessionId : "";
$query = "SELECT SDTE.SessionId AS SessionId, COALESCE(SDTE.srcUserId,-1) AS UserId,
SUM(CASE WHEN X.ReactTypeId=0 THEN X.NbHits ELSE 0 END) AS NbEnemyKilled,
SUM(CASE WHEN X.ReactTypeId=1 THEN X.NbHits ELSE 0 END) AS NbCivilKilled,
SUM(CASE WHEN X.ReactTypeId=2 THEN X.NbHits ELSE 0 END) AS NbPoliceKilled
FROM " . SESSIONS_TABLE_NAME . " SD LEFT JOIN " . TRIGGEREVENTS_TABLE_NAME . " SDTE ON (SD.id = SDTE.sessionId)
LEFT JOIN " . REACTEVENTS_TABLE_NAME . " SDRE ON (SDTE.sessionId=SDRE.srcEventSessionId AND SDTE.indexCount=SDRE.srcEventIndex)
LEFT JOIN
(SELECT TE.SessionId AS SessionId, RE.hitUserId AS TargetUserId, TE.srcUserId AS ShooterRoleId, COUNT(DISTINCT TE.indexCount, RE.hitTargetName) AS NbHits, RE.id AS ReactId, RE.ReactType AS ReactTypeId
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE, " . REACTEVENTS_TABLE_NAME . " RE WHERE TE.sessionId = RE.srcEventSessionId AND TE.indexCount = RE.srcEventIndex AND TE.indexCount!=-1 AND RE.ReactType!=-1 AND RE.TargetKilled=1
GROUP BY SessionId, TargetUserId, ShooterRoleId, ReactTypeId) AS X
ON (X.SessionId=SDTE.SessionId AND X.TargetUserId=SDRE.hitUserId AND X.ReactId=SDRE.id)
WHERE 1 " . $this->getCalibrationSessionsConstraint("SD") . $this->getSessionDurationConstraint("SD") . $sessionConstraint . " GROUP BY SDTE.SessionId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debrief mission : get averages for given session and/or user
public function getPrecisionAndReactionTimeForUser ($sessionId, $userId, $fromUser=-1)
{
// create SQL constraints for query
$sessionConstraint = $sessionId > 0 ? " AND SDTE.SessionId = " . $sessionId : "";
$query = "SELECT SDTE.SessionId AS SessionId, SDTE.srcUserId AS UserId, AVG(X.AvgHitPrec) AS AveragePrecision,
AVG(CASE WHEN X.HitPrecision > 0 AND X.ReactId > 0 THEN X.AvgReactTime END) AS AverageReactionTime
FROM " . SESSIONS_TABLE_NAME . " SD LEFT JOIN " . TRIGGEREVENTS_TABLE_NAME . " SDTE ON (SD.id = SDTE.sessionId)
LEFT JOIN " . REACTEVENTS_TABLE_NAME . " SDRE ON SDTE.sessionId=SDRE.srcEventSessionId AND SDTE.indexCount=SDRE.srcEventIndex
LEFT JOIN
(SELECT DISTINCT TE.SessionId AS SessionId, TE.srcUserId AS ShooterId, TE.indexCount, RE.hitTargetName, COALESCE(AVG(RE.hitPrecision),0) AS AvgHitPrec, COALESCE(AVG(RE.reactTime),0) AS AvgReactTime, COALESCE(RE.id,-1) AS ReactId, COALESCE(RE.hitPrecision,0) AS HitPrecision
FROM " . TRIGGEREVENTS_TABLE_NAME . " TE LEFT JOIN " . REACTEVENTS_TABLE_NAME . " RE ON TE.indexCount=RE.srcEventIndex AND TE.sessionId=RE.srcEventSessionId GROUP BY TE.SessionId, TE.srcUserId, TE.indexCount, RE.id, RE.hitTargetName) AS X
ON X.SessionId=SDTE.SessionId AND X.ShooterId=SDTE.srcUserId
WHERE 1 " . $this->getCalibrationSessionsConstraint("SD") . $this->getSessionDurationConstraint("SD") . $sessionConstraint . " GROUP BY SDTE.SessionId, SDTE.srcUserId";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debrief mission : get given users results in given session
public function getResultsForSession ($sessionId, $userId, $fromUserId=-1)
{
$userConstraint = $userId > 0 ? " AND SD.ShooterId=" . $userId : "";
$sessionConstraint = $sessionId > 0 ? " AND SD.SessionId=" . $sessionId : "";
$query = "SELECT SD.* FROM " . SESSIONDEBRIEFS_VIEW_NAME . " SD WHERE 1 " . $this->getCalibrationSessionsConstraint() . $userConstraint . $sessionConstraint . " GROUP BY SD.SessionId, SD.ShooterId, SD.ShotIndex";
//$query = "SELECT SD.* FROM (" . SESSIONDEBRIEFS_VIEW_QUERY . ") AS SD WHERE 1 " . $userConstraint . $sessionConstraint . " GROUP BY SD.SessionId, SD.ShooterId, SD.ShotIndex";
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$shot = SessionDebriefRow::withRow($row);
array_push( $this->elements, $shot->toArray() );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debrief mission : get stats for given session and/or user
/*public function getSessionDebrief ($sessionId, $userId, $fromUser=-1)
{
// prepare and execute query
$stmt = $this->getDebriefRows($sessionId, $userId);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
// create a SessionDebriefRow with this data
$stats = SessionDebriefRow::withRow($row);
array_push( $this->elements, $stats->toArray() );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public function getDebriefRows ($sessionId, $userId)
{
// create SQL constraints for query
$sessionConstraint = $sessionId > 0 ? " AND SD.SessionId = " . $sessionId : "";
$userConstraint = $userId >= 0 ? " AND (SD.ShooterId = " . $userId . " OR SD.TargetUserId = " . $userId . ")" : "";
//$query = "SELECT SD.* FROM " . SESSIONDEBRIEFS_VIEW_NAME . " SD WHERE 1 " . $sessionConstraint . $userConstraint;
$query = "SELECT SD.* FROM (" . SESSIONDEBRIEFS_VIEW_QUERY . ") AS SD WHERE 1 " . $sessionConstraint . $userConstraint;
// prepare and execute query
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}*/
}
?>