PHP-cli-factorio-updater/scripts/class.FactorioMod.php

377 lines
10 KiB
PHP
Raw Permalink Normal View History

<?php
/**
* Namespace for classes and functions related to the game Factorio.
* @package NAE\Factorio
*/
namespace NAE\Factorio;
/**
* Class for managing Factorio mods.
* @author "Marcel Naeve" <php@naeve.info>
* @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
}
}