* @license MIT License (http://www.opensource.org/licenses/mit) */ class FactorioMod { /** * @var int INIT_TYPE_PATH - Mod is initialized from a zip file. */ const INIT_TYPE_PATH = 1; /** * @var int INIT_TYPE_NAME - Mod is initialized from a mod name. */ const INIT_TYPE_NAME = 3; /** * @var object|null $info - Mod information from Zip file. */ private $info = null; /** * @var object|null $api - Mod information from Factorio API. */ private $api = null; /** * @var object|null $mod_settings - Mod settings enabled/disabled from json in mods folder. */ private $mod_settings = null; /** * @var string|null $mod_folder - Path to the mods folder. */ private $mod_folder = null; /** * @var string $game_folder - Path to the Factorio game folder. */ private $game_folder = "factorio"; /** * Reads all Mods as FactorioMod objects to an array. * @param string $modFolder Path to the mods folder. * @return array Array of FactorioMod objects. */ static function readModFolder(string $modFolder) : array { $mods = []; $dh = opendir($modFolder); // open the directory handle while ( false !== ($entry = readdir($dh)) ) { // read directory entries if(preg_match("/\.zip$/ui", $entry)) { // if the file is a zip file $mods[] = new FactorioMod( $modFolder. "/". $entry, FactorioMod::INIT_TYPE_PATH ); } } closedir($dh); // close the directory handle return $mods; } /** * Reads mod information from info.json file in mod Zip file. * @param string $zipPath Path to the mod Zip file. * @return object|null Mod information from info.json file. */ private function readInfo(string $zipPath) : ?object { if(!file_exists($zipPath)) { // file does not exist? return null; } $za = new \ZipArchive(); $res = $za->open($zipPath); // open the zip file if($res !== true) { // open the zip file failed? return null; } $c = null; for( $i = 0; $i < $za->numFiles; $i++ ){ // Iterate over all files in the zip file $name = $za->getNameIndex( $i ); // get the name of current file if(basename($name) == "info.json") { // if the file is info.json $c = $za->getFromIndex($i); // get the content of info.json $i = $za->numFiles; // break the loop by condition break; // break the loop by force (double tap) } } $za->close(); // close the zip file return json_decode( $c, false ); // return decoded json object or null on failure } /** * Sends a GET request to Factorio API to get mod information. * @param string $name Mod name to get information from Factorio API. * @return object|null Mod information from Factorio API. */ private function callApi(string $name="") : ?object { if($name === "") { // no name given? if($this->info === null) { // also no path to module for info.json? return null; } $name = $this->info->name; // get name from info.json } $api = "https://mods.factorio.com/api/mods/" . $name; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $api); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $response = curl_exec($curl); $cri = curl_getinfo($curl); curl_close($curl); if($cri["http_code"] != 200) { // request failed? return null; } if(trim($response) < 1) { // response body empty? return null; } $r = json_decode($response, false); // decode json object or null on failure return $r; } /** * Constructor. * @param string $init Path to the mod Zip file or mod name. * @param int $init_type Initialization type (FactorioMod::INIT_TYPE_PATH or FactorioMod::INIT_TYPE_NAME). * @param string $mod_folder Path to the mods folder. */ public function __construct(string $init, int $init_type=self::INIT_TYPE_PATH, string $mod_folder="") { if($init_type === self::INIT_TYPE_PATH) { $this->info = $this->readInfo($init); if($this->info !== null) { $this->mod_folder = dirname($init); $this->callApi(); } } if($init_type === self::INIT_TYPE_NAME) { $this->mod_folder = $mod_folder; $this->callApi($init); // TODO: look if mod is installed.. } } /** * Returns last release version information of the mod. * @return object|null Last release version information of the mod. */ public function getLastVersionInfo() : ?object { $target = count($this->api->releases) - 1; return $this->api->releases[ $target ]; } /** * Checks if the latest release mod version is newer than the installed version. * @return bool True if the latest release mod version is newer, false otherwise. */ public function isUpdateable() : bool { $lv = new \NAE\Factorio\FactorioVersion( $this->getLastVersionInfo()->version ); $cv = new \NAE\Factorio\FactorioVersion( $this->info->version ); return $lv->isNewer($cv); } /** * Deletes the mod from the mods folder file. * @return bool True if the mod was deleted, false otherwise. */ private function delete() : bool { // TODO: implement return false; } /** * Downloads the latest release mod version to the mods folder. * @return bool True if the mod was downloaded, false otherwise. */ private function download() : bool { // TODO: continue implementing.. where player-data.json.. $player_data = json_decode(file_get_contents($this->game_folder. "/player-data.json"), true); $token = $player_data["service-token"]; $username = $player_data["service-username"]; $url = "https://mods.factorio.com" . $this->getLastVersionInfo()->download_url . "?username=$username&token=$token"; return false; } /** * Uninstalls the mod from the mods folder and the settings.json file. * @return bool True if the mod was uninstalled, false otherwise. */ public function uninstall() : bool { // TODO: implement return false; } /** * Installs the mod in the mods folder and adds it to the settings.json file as enabled. * @return bool True if the mod was installed, false otherwise. */ public function install() : bool { // TODO: implement return false; } /** * Updates the mod to the latest release mod version. * @return bool True if the mod was updated, false otherwise. */ public function update() : bool { // TODO: implement return false; } /** * Loads the mod settings for all mods (enabled/disabled) from the settings.json file. * @return bool True if the mod settings have been loaded successfully, false otherwise. */ private function loadModSettings() : bool { $this->mod_settings = json_decode( file_get_contents($this->mod_folder. "/settings.json") ); return false; } /** * Returns the mod settings for all mods (enabled/disabled) from settings.json. * @return object|null Mod settings for all mods. */ public function getModSettings() :?object { return $this->mod_settings; } /** * Sets the path to the game folder. * @param string $game_folder Path to the game folder. * @return FactorioMod The instance of FactorioMod for chaining. */ public function setGameFolder(string $game_folder) : FactorioMod { $this->game_folder = $game_folder; return $this; } /** * Returns the path to the game folder. * @return string Path to the game folder. */ public function getGameFolder() : string { return $this->game_folder; } /** * Saves the changes in the mod settings for all mods (enabled/disabled) to the settings.json file. * @return bool True if the mod settings have been saved successfully, false otherwise. */ private function saveModSettings() : bool { $j = json_encode($this->mod_settings); $r = file_put_contents($this->mod_folder. "/settings.json", $j); if($r === false) { return false; } return ( $r === strlen($j) ); } /** * Sets the mod settings for all mods (enabled/disabled) in the settings.json file. * @param object $mod_settings Mod settings for all mods. * @return FactorioMod The instance of FactorioMod for chaining. */ public function setModSettings(object $mod_settings) : FactorioMod { $this->mod_settings = $mod_settings; return $this; } /** * Checks if this mod is enabled in the settings.json. * @return bool True if this mod is enabled, false otherwise. */ public function isEnabled() : bool { // TODO: implement return false; } /** * Checks if this mod is disabled in the settings.json. * @return bool True if this mod is disabled, false otherwise. */ public function isDisabled() : bool { // TODO: implement return false; } /** * Sets this mod to enabled in the settings.json */ public function enable() { // TODO: implement } /** * Sets this mod to disabled in the settings.json */ public function disable() { // TODO: implement } }