logText("gs job: port: {$Port}, placeId: {$placeId}, soapPort: {$soapPort}, clientYear: {$clientYear}"); if (self::isPortInUse($soapPort) || self::isPortInUse($Port)) { exit("Port already in use."); } if ($clientYear === 2016) { error_log("client is 2016"); $gsScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/gameserver16.txt"); } else { $gsScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/gameserver.txt"); } $gsScript = str_replace( ["%placeId%", "%port%", "%url%", "%domain%", "%creatorid%"], [$placeId, $Port, "aftwld.com", "aftwld.com", $creatorid], $gsScript ); $jobId = jobId(); $pidFile = "C:\\temp\\rcc_$soapPort.pid"; if (!file_exists("C:\\temp")) { mkdir("C:\\temp", 0777, true); } if ($clientYear === 2016) { $psCommand = "powershell -Command \"Start-Process -FilePath 'C:\\\\RCC\\\\2016\\\\RCCService.exe' -ArgumentList '-console $soapPort' -PassThru | Select-Object -ExpandProperty Id | Out-File -Encoding ASCII -FilePath '$pidFile'\""; } else { $psCommand = "powershell -Command \"Start-Process -FilePath 'C:\\\\RCC\\\\RCCService.exe' -ArgumentList '-console $soapPort' -PassThru | Select-Object -ExpandProperty Id | Out-File -Encoding ASCII -FilePath '$pidFile'\""; } exec($psCommand); $retries = 0; while (!self::isPortInUse($soapPort) && $retries++ < 20) { sleep(1); } // Read PID from file $pid = null; if (file_exists($pidFile)) { $pid = (int)trim(file_get_contents($pidFile)); } if (!$pid) { exit("Failed to obtain RCCService PID."); } // Try connecting to the RCCService $rccSoap = new RCCServiceSoap("127.0.0.1", $soapPort); if ($rccSoap instanceof \SoapFault) { self::killRcc($pid); exit("Failed to start RCCService."); } $job = new Job($jobId, 9999999999999); $gsScript = new ScriptExecution($jobId . "-Script", $gsScript); $result = $rccSoap->OpenJobEx($job, $gsScript); return [ "JobId" => $jobId, "isRunning" => true, "soapport" => $soapPort, "pid" => $pid ]; } public function renderUser($userId) { global $pdo; $this->logText("render user"); $port = rand(6500, 7000); while (self::isPortInUse($port)) { $port = rand(6500, 7000); } $jobId = jobId(); if (!self::isPortInUse($port)) { // Define where to store the PID $pidFile = "C:\\temp\\rcc_user_$port.pid"; // Make sure the directory exists if (!file_exists("C:\\temp")) { mkdir("C:\\temp", 0777, true); } // Start RCCService using PowerShell and capture the PID $psCommand = "powershell -Command \"Start-Process -FilePath 'C:\\\\RCC\\\\RCCService.exe' -ArgumentList '-console $port' -PassThru | Select-Object -ExpandProperty Id | Out-File -Encoding ASCII -FilePath '$pidFile'\""; exec($psCommand); // Wait until the port is available $retries = 0; while (!self::isPortInUse($port) && $retries++ < 20) { sleep(1); } // Read PID from file $pid = null; if (file_exists($pidFile)) { $pid = (int)trim(file_get_contents($pidFile)); } if (!$pid) { exit("Failed to obtain RCCService PID for renderUser."); } $stmt = $pdo->prepare("INSERT INTO jobs (`jobid`, `placeId`, `soapport`, `port`, `isRunning`, `startTime`, `pid`, `playerList`, `isRenderer`) VALUE (:jobId, 0, :soapPort, 0, 1, :startTime, :pid, \"[]\", 1)"); $stmt->bindParam(":jobId", $jobId, PDO::PARAM_STR); $stmt->bindParam(":soapPort", $port, PDO::PARAM_INT); $startTime = time(); $stmt->bindParam(":startTime", $startTime, PDO::PARAM_INT); $stmt->bindParam(":pid", $pid, PDO::PARAM_INT); $stmt->execute(); $rccSoap = new RCCServiceSoap("127.0.0.1", $port); $job = new Job($jobId, 99999999); $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/avatar.lua"); $avatarScript = str_replace("%userid%", $userId, $avatarScript); $avatarScript = str_replace("%url%", "aftwld.com", $avatarScript); $avatarScript = new ScriptExecution($jobId, $avatarScript); $avatarResult = $rccSoap->BatchJobEx($job, $avatarScript); while (empty($avatarResult)) { sleep(1); } // Clean up the RCC process by PID self::killRcc($pid); $stmt = $pdo->prepare("DELETE FROM `jobs` WHERE `jobid` = :jobId"); $stmt->bindParam(":jobId", $jobId, PDO::PARAM_STR); $stmt->execute(); return $avatarResult; } } public function renderAsset($assetid, $assettype) { global $pdo; $this->logText("render asset"); $port = rand(6500, 7000); while (self::isPortInUse($port)) { $port = rand(6500, 7000); } $jobId = jobId(); if (!self::isPortInUse($port)) { $pidFile = "C:\\temp\\rcc_user_$port.pid"; if (!file_exists("C:\\temp")) { mkdir("C:\\temp", 0777, true); } $psCommand = "powershell -Command \"Start-Process -FilePath 'C:\\\\RCC\\\\RCCService.exe' -ArgumentList '-console $port' -PassThru | Select-Object -ExpandProperty Id | Out-File -Encoding ASCII -FilePath '$pidFile'\""; exec($psCommand); $retries = 0; while (!self::isPortInUse($port) && $retries++ < 20) { sleep(1); } $pid = null; if (file_exists($pidFile)) { $pid = (int)trim(file_get_contents($pidFile)); } if (!$pid) { exit("Failed to obtain RCCService PID for renderUser."); } $stmt = $pdo->prepare("INSERT INTO jobs (`jobid`, `placeId`, `soapport`, `port`, `isRunning`, `startTime`, `pid`, `playerList`, `isRenderer`) VALUE (:jobId, 0, :soapPort, 0, 1, :startTime, :pid, \"[]\", 1)"); $stmt->bindParam(":jobId", $jobId, PDO::PARAM_STR); $stmt->bindParam(":soapPort", $port, PDO::PARAM_INT); $startTime = time(); $stmt->bindParam(":startTime", $startTime, PDO::PARAM_INT); $stmt->bindParam(":pid", $pid, PDO::PARAM_INT); $stmt->execute(); $rccSoap = new RCCServiceSoap("127.0.0.1", $port); $job = new Job($jobId, 99999999); $baseurl = "http://www.aftwld.com"; switch ($assettype) { case 8: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Hat.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; case 9: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Place.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; case 10: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Model.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; case 11: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Shirt.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; case 12: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Pants.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; case 13: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Decal.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; case 17: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Head.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; case 18: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Decal.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; case 19: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/Gear.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; default: $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/BodyPart.lua"); $avatarScript = str_replace("%assetid%", $assetid, $avatarScript); $avatarScript = str_replace("%url%", $baseurl, $avatarScript); break; } $avatarScript = new ScriptExecution($jobId, $avatarScript); $avatarResult = $rccSoap->BatchJobEx($job, $avatarScript); while (empty($avatarResult)) { sleep(1); } self::killRcc($pid); $stmt = $pdo->prepare("DELETE FROM `jobs` WHERE `jobid` = :jobId "); $stmt->bindParam(":jobId", $jobId, PDO::PARAM_STR); $stmt->execute(); return $avatarResult; } } public function renderUser3D($userId) { global $pdo; $this->logText("render user 3d"); $port = rand(6500, 7000); while (self::isPortInUse($port)) { $port = rand(6500, 7000); } $jobId = jobId(); if (!self::isPortInUse($port)) { // Define where to store the PID $pidFile = "C:\\temp\\rcc_user_$port.pid"; // Make sure the directory exists if (!file_exists("C:\\temp")) { mkdir("C:\\temp", 0777, true); } // Start RCCService using PowerShell and capture the PID $psCommand = "powershell -Command \"Start-Process -FilePath 'C:\\\\RCC\\\\RCCService.exe' -ArgumentList '-console $port' -PassThru | Select-Object -ExpandProperty Id | Out-File -Encoding ASCII -FilePath '$pidFile'\""; exec($psCommand); // Wait until the port is available $retries = 0; while (!self::isPortInUse($port) && $retries++ < 20) { sleep(1); } // Read PID from file $pid = null; if (file_exists($pidFile)) { $pid = (int)trim(file_get_contents($pidFile)); } if (!$pid) { exit("Failed to obtain RCCService PID for renderUser."); } $stmt = $pdo->prepare("INSERT INTO jobs (`jobid`, `placeId`, `soapport`, `port`, `isRunning`, `startTime`, `pid`, `playerList`, `isRenderer`) VALUE (:jobId, 0, :soapPort, 0, 1, :startTime, :pid, \"[]\", 1)"); $stmt->bindParam(":jobId", $jobId, PDO::PARAM_STR); $stmt->bindParam(":soapPort", $port, PDO::PARAM_INT); $startTime = time(); $stmt->bindParam(":startTime", $startTime, PDO::PARAM_INT); $stmt->bindParam(":pid", $pid, PDO::PARAM_INT); $stmt->execute(); $rccSoap = new RCCServiceSoap("127.0.0.1", $port); $job = new Job($jobId, 99999999); $avatarScript = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/config/classes/includes/avatar3D.lua"); $avatarScript = str_replace("%userid%", $userId, $avatarScript); $avatarScript = str_replace("%url%", "aftwld.com", $avatarScript); $avatarScript = new ScriptExecution($jobId, $avatarScript); $avatarResult = $rccSoap->BatchJobEx($job, $avatarScript); while (empty($avatarResult)) { sleep(1); } // Clean up the RCC process by PID self::killRcc($pid); $stmt = $pdo->prepare("DELETE FROM `jobs` WHERE `jobid` = :jobId "); $stmt->bindParam(":jobId", $jobId, PDO::PARAM_STR); $stmt->execute(); return $avatarResult; } } public function killRcc(int $pid) { $this->logText("kill rcc"); if ($pid > 0) { exec("taskkill /f /PID $pid"); } } public function getPlayerCount(int $soapPort, string $jobId) { $rccSoap = new RCCServiceSoap("127.0.0.1", $soapPort); $script = "return #game:GetService(\"Players\"):GetPlayers()"; $script = new ScriptExecution($jobId, $script); $scriptResult = $rccSoap->ExecuteEx($jobId, $script); if (isset($scriptResult->LuaValue)) { return $scriptResult->LuaValue->value; } } public function getAllRccs() { exec("tasklist /FI \"IMAGENAME eq RCCService.exe\"", $output); $processes = []; foreach ($output as $line) { if (stripos($line, "RCCService.exe") !== false) { $parts = preg_split('/\s+/', $line); if (count($parts) >= 2) { $processes[] = [ "name" => $parts[0] ?? "", "pid" => $parts[1] ?? 0 ]; } } } return $processes; } }