diff --git a/app/main/controller/api/map.php b/app/main/controller/api/map.php index be714422..f8120ed4 100644 --- a/app/main/controller/api/map.php +++ b/app/main/controller/api/map.php @@ -17,6 +17,10 @@ use Model; */ class Map extends Controller\AccessController { + // cache keys + const CACHE_KEY_MAP_DATA = 'CACHED.MAP_DATA.%s'; + const CACHE_KEY_USER_DATA = 'CACHED.USER_DATA.%s_%s'; + /** * event handler * @param \Base $f3 @@ -27,6 +31,37 @@ class Map extends Controller\AccessController { parent::beforeroute($f3); } + /** + * get map data cache key + * @param Model\CharacterModel $character + * @return string + */ + protected function getMapDataCacheKey(Model\CharacterModel $character){ + return sprintf(self::CACHE_KEY_MAP_DATA, 'CHAR_' . $character->_id); + } + + /** + * clear map data caching + * -> cache timings are short, this will just increase update performance on map changes + * @param Model\CharacterModel $character + */ + protected function clearMapDataCache(Model\CharacterModel $character){ + $cacheKey = $this->getMapDataCacheKey($character); + if($this->getF3()->exists($cacheKey)){ + $this->getF3()->clear($cacheKey); + } + } + + /** + * get user data cache key + * @param int $mapId + * @param int $systemId + * @return string + */ + protected function getUserDataCacheKey($mapId, $systemId = 0){ + return sprintf(self::CACHE_KEY_USER_DATA, 'MAP_' . $mapId, 'SYS_' . $systemId); + } + /** * Get all required static config data for program initialization * @param \Base $f3 @@ -42,10 +77,10 @@ class Map extends Controller\AccessController { $return = (object) []; $return->error = []; - // static program data ------------------------------------------------ + // static program data ---------------------------------------------------------------------------------------- $return->timer = $f3->get('PATHFINDER.TIMER'); - // get all available map types ---------------------------------------- + // get all available map types -------------------------------------------------------------------------------- $mapType = Model\BasicModel::getNew('MapTypeModel'); $rows = $mapType->find('active = 1', null, $expireTimeSQL); @@ -62,7 +97,7 @@ class Map extends Controller\AccessController { } $return->mapTypes = $mapTypeData; - // get all available map scopes --------------------------------------- + // get all available map scopes ------------------------------------------------------------------------------- $mapScope = Model\BasicModel::getNew('MapScopeModel'); $rows = $mapScope->find('active = 1', null, $expireTimeSQL); $mapScopeData = []; @@ -75,7 +110,7 @@ class Map extends Controller\AccessController { } $return->mapScopes = $mapScopeData; - // get all available system status ------------------------------------ + // get all available system status ---------------------------------------------------------------------------- $systemStatus = Model\BasicModel::getNew('SystemStatusModel'); $rows = $systemStatus->find('active = 1', null, $expireTimeSQL); $systemScopeData = []; @@ -89,7 +124,7 @@ class Map extends Controller\AccessController { } $return->systemStatus = $systemScopeData; - // get all available system types ------------------------------------- + // get all available system types ----------------------------------------------------------------------------- $systemType = Model\BasicModel::getNew('SystemTypeModel'); $rows = $systemType->find('active = 1', null, $expireTimeSQL); $systemTypeData = []; @@ -102,7 +137,7 @@ class Map extends Controller\AccessController { } $return->systemType = $systemTypeData; - // get available connection scopes ------------------------------------ + // get available connection scopes ---------------------------------------------------------------------------- $connectionScope = Model\BasicModel::getNew('ConnectionScopeModel'); $rows = $connectionScope->find('active = 1', null, $expireTimeSQL); $connectionScopeData = []; @@ -116,7 +151,7 @@ class Map extends Controller\AccessController { } $return->connectionScopes = $connectionScopeData; - // get available character status ------------------------------------- + // get available character status ----------------------------------------------------------------------------- $characterStatus = Model\BasicModel::getNew('CharacterStatusModel'); $rows = $characterStatus->find('active = 1', null, $expireTimeSQL); $characterStatusData = []; @@ -130,7 +165,7 @@ class Map extends Controller\AccessController { } $return->characterStatus = $characterStatusData; - // get max number of shared entities per map -------------------------- + // get max number of shared entities per map ------------------------------------------------------------------ $maxSharedCount = [ 'character' => $f3->get('PATHFINDER.MAX_SHARED_CHARACTER'), 'corporation' => $f3->get('PATHFINDER.MAX_SHARED_CORPORATION'), @@ -138,12 +173,12 @@ class Map extends Controller\AccessController { ]; $return->maxSharedCount = $maxSharedCount; - // get program routes ------------------------------------------------- + // get program routes ----------------------------------------------------------------------------------------- $return->routes = [ 'ssoLogin' => $this->getF3()->alias( 'sso', ['action' => 'requestAuthorization'] ) ]; - // get SSO error messages that should be shown immediately ------------ + // get SSO error messages that should be shown immediately ---------------------------------------------------- // -> e.g. errors while character switch from previous HTTP requests if( $f3->exists(Controller\Ccp\Sso::SESSION_KEY_SSO_ERROR) ){ $ssoError = (object) []; @@ -493,15 +528,14 @@ class Map extends Controller\AccessController { $return->error = []; if($activeCharacter){ - - $cacheKey = 'user_map_data_' . $activeCharacter->_id; + $cacheKey = $this->getMapDataCacheKey($activeCharacter); // if there is any system/connection change data submitted -> save new data if( !empty($mapData) || !$f3->exists($cacheKey) ){ - // get current map data ======================================================== + // get current map data =============================================================================== $maps = $activeCharacter->getMaps(); // loop all submitted map data that should be saved @@ -527,12 +561,12 @@ class Map extends Controller\AccessController { count($connections) > 0 ){ - // map changes expected ============================================= + // map changes expected ======================================================================= // loop current user maps and check for changes foreach($maps as $map){ - // update system data ----------------------------------------------- + // update system data --------------------------------------------------------------------- foreach($systems as $i => $systemData){ // check if current system belongs to the current map @@ -561,7 +595,7 @@ class Map extends Controller\AccessController { } } - // update connection data ------------------------------------------- + // update connection data ----------------------------------------------------------------- foreach($connections as $i => $connectionData){ // check if the current connection belongs to the current map @@ -645,61 +679,61 @@ class Map extends Controller\AccessController { public function updateUserData(\Base $f3){ $return = (object) []; $return->error = []; - $activeCharacter = $this->getCharacter(0); - - if($activeCharacter){ - - if( !empty($f3->get('POST.mapIds')) ){ - $mapIds = (array)$f3->get('POST.mapIds'); - // check if data for specific system is requested - $systemData = (array)$f3->get('POST.systemData'); - // update current location - // -> suppress temporary timeout errors - $activeCharacter = $activeCharacter->updateLog(['suppressTimeoutErrors' => true]); - - // if data is requested extend the cache key in order to get new data - $requestSystemData = (object) []; - $requestSystemData->mapId = isset($systemData['mapId']) ? (int) $systemData['mapId'] : 0; - $requestSystemData->systemId = isset($systemData['systemData']['id']) ? (int) $systemData['systemData']['id'] : 0; + if( $activeCharacter = $this->getCharacter(0) ){ + $postData = $f3->get('POST'); + if( !empty($mapIds = (array)$postData['mapIds']) ){ // IMPORTANT for now -> just update a single map (save performance) - $mapIds = array_slice($mapIds, 0, 1); + $mapId = (int)reset($mapIds); + // get map and check map access + $map = $activeCharacter->getMap( (int)$mapId); - // the userMapData is cached per map (this must be changed if multiple maps - // will be allowed in future... - $tempId = (int)$mapIds[0]; - $cacheKey = 'user_data_' . $tempId . '_' . $requestSystemData->systemId; - if( !$f3->exists($cacheKey) ){ - foreach($mapIds as $mapId){ - $map = $activeCharacter->getMap( (int)$mapId); + if( !is_null($map) ){ + $characterMapData = (array)$postData['characterMapData']; - if( !is_null($map) ){ - $return->mapUserData[] = $map->getUserData(); + // check if data for specific system is requested + $systemData = (array)$postData['systemData']; + // if data is requested extend the cache key in order to get new data + $requestSystemData = (object) []; + $requestSystemData->mapId = isset($systemData['mapId']) ? (int) $systemData['mapId'] : 0; + $requestSystemData->systemId = isset($systemData['systemData']['id']) ? (int) $systemData['systemData']['id'] : 0; - // request signature data for a system if user has map access! - if( $map->id === $requestSystemData->mapId ){ - $system = $map->getSystemById( $requestSystemData->systemId ); + // update current location + // -> suppress temporary timeout errors + $activeCharacter = $activeCharacter->updateLog(['suppressTimeoutErrors' => true]); - if( !is_null($system) ){ - // data for currently selected system - $return->system = $system->getData(); - $return->system->signatures = $system->getSignaturesData(); - } - } - } + // check character log (current system) and manipulate map (e.g. add new system) + if( (bool)$characterMapData['mapTracking'] ){ + $map = $this->updateMapData($activeCharacter, $map); } - // cache time (seconds) should be equal or less than request trigger time - // prevent request flooding - $responseTTL = (int)$f3->get('PATHFINDER.TIMER.UPDATE_SERVER_USER_DATA.DELAY') / 1000; + $cacheKey = $this->getUserDataCacheKey($mapId, $requestSystemData->systemId); + if( !$f3->exists($cacheKey) ){ + $return->mapUserData[] = $map->getUserData(); - // cache response - $f3->set($cacheKey, $return, $responseTTL); - }else{ - // get from cache - // this should happen if a user has multiple program instances running - // with the same main char - $return = $f3->get($cacheKey); + // request signature data for a system if user has map access! + if( $mapId === $requestSystemData->mapId ){ + $system = $map->getSystemById( $requestSystemData->systemId ); + + if( !is_null($system) ){ + // data for currently selected system + $return->system = $system->getData(); + $return->system->signatures = $system->getSignaturesData(); + } + } + + // cache time (seconds) should be equal or less than request trigger time + // prevent request flooding + $responseTTL = (int)$f3->get('PATHFINDER.TIMER.UPDATE_SERVER_USER_DATA.DELAY') / 1000; + + // cache response + $f3->set($cacheKey, $return, $responseTTL); + }else{ + // get from cache + // this should happen if a user has multiple program instances running + // with the same main char + $return = $f3->get($cacheKey); + } } } @@ -714,6 +748,193 @@ class Map extends Controller\AccessController { echo json_encode( $return ); } + + /** + * + * @param Model\CharacterModel $character + * @param Model\MapModel $map + * @return Model\MapModel + */ + protected function updateMapData($character, $map){ + + // update "map data" cache in case of map (system/connection) changes + $clearMapDataCache = false; + + if( + ( $mapScope = $map->getScope() ) && + ( $mapScope->name != 'none' ) && // tracking is disabled for map + ( $log = $character->getLog() ) + ){ + // character is currently in a system + + $sameSystem = false; + $sourceExists = true; + $targetExists = true; + + // system coordinates + $systemOffsetX = 130; + $systemOffsetY = 0; + $systemPosX = 0; + $systemPosY = 30; + + $sourceSystemId = (int)$this->getF3()->get(User::SESSION_KEY_CHARACTER_PREV_SYSTEM_ID); + $targetSystemId = (int)$log->systemId; + + $sourceSystem = null; + $targetSystem = null; + + // check if source and target systems are equal + // -> NO target system available + if($sourceSystemId === $targetSystemId){ + // check if previous (solo) system is already on the map + $sourceSystem = $map->getSystemByCCPId($sourceSystemId); + $sameSystem = true; + }else{ + // check if previous (source) system is already on the map + $sourceSystem = $map->getSystemByCCPId($sourceSystemId); + + // -> check if system is already on this map + $targetSystem = $map->getSystemByCCPId( $targetSystemId ); + } + + // if systems don´t already exists on map -> get "blank" systems + // -> required for system type check (e.g. wormhole, k-space) + if( !$sourceSystem ){ + $sourceExists = false; + $sourceSystem = $map->getNewSystem($sourceSystemId); + }else{ + // system exists -> add target to the "right" + $systemPosX = $sourceSystem->posX + $systemOffsetX; + $systemPosY = $sourceSystem->posY + $systemOffsetY; + } + + if( + !$sameSystem && + !$targetSystem + ){ + $targetExists = false; + $targetSystem = $map->getNewSystem( $targetSystemId ); + } + + $addSourceSystem = false; + $addTargetSystem = false; + $addConnection = false; + + switch($mapScope->name){ + case 'all': + if($sameSystem){ + $addSourceSystem = true; + }else{ + $addSourceSystem = true; + $addTargetSystem = true; + $addConnection = true; + } + break; + case 'k-space': + if($sameSystem){ + if( !$sourceSystem->isWormhole() ){ + $addSourceSystem = true; + } + }elseif( + !$sourceSystem->isWormhole() || + !$targetSystem->isWormhole() + ){ + $addSourceSystem = true; + $addTargetSystem = true; + $addConnection = true; + } + break; + case 'wh': + default: + if($sameSystem){ + if( $sourceSystem->isWormhole() ){ + $addSourceSystem = true; + } + }elseif( + $sourceSystem->isWormhole() || + $targetSystem->isWormhole() + ){ + $addSourceSystem = true; + $addTargetSystem = true; + $addConnection = true; + }elseif( + !$sourceSystem->isWormhole() && + !$targetSystem->isWormhole() + ){ + // check distance between systems (in jumps) + // -> if > 1 it is !very likely! a wormhole + $routeController = new Route(); + $routeController->initJumpData(); + $route = $routeController->findRoute($sourceSystem->name, $targetSystem->name, 1); + + if( !$route['routePossible'] ){ + $addSourceSystem = true; + $addTargetSystem = true; + $addConnection = true; + } + } + break; + } + + // save source system ------------------------------------------------------------------------------------- + if( + $addSourceSystem && + $sourceSystem && + !$sourceExists + ){ + $sourceSystem = $map->saveSystem($sourceSystem, $systemPosX, $systemPosY, $character); + // get updated maps object + if($sourceSystem){ + $map = $sourceSystem->mapId; + $sourceExists = true; + $clearMapDataCache = true; + // increase system position (prevent overlapping) + $systemPosX = $sourceSystem->posX + $systemOffsetX; + $systemPosY = $sourceSystem->posY + $systemOffsetY; + } + } + + // save target system ------------------------------------------------------------------------------------- + if( + $addTargetSystem && + $targetSystem && + !$targetExists + ){ + $targetSystem = $map->saveSystem($targetSystem, $systemPosX, $systemPosY, $character); + // get updated maps object + if($targetSystem){ + $map = $targetSystem->mapId; + $clearMapDataCache = true; + $targetExists = true; + } + } + + // save connection ---------------------------------------------------------------------------------------- + if( + $addConnection && + $sourceExists && + $targetExists && + $sourceSystem && + $targetSystem && + !$map->searchConnection( $sourceSystem, $targetSystem ) + ){ + $connection = $map->getNewConnection($sourceSystem, $targetSystem); + $connection = $map->saveConnection($connection); + // get updated maps object + if($connection){ + $map = $connection->mapId; + $clearMapDataCache = true; + } + } + } + + if($clearMapDataCache){ + $this->clearMapDataCache($character); + } + + return $map; + } + } diff --git a/app/main/controller/api/system.php b/app/main/controller/api/system.php index 0f14b896..82cc9e21 100644 --- a/app/main/controller/api/system.php +++ b/app/main/controller/api/system.php @@ -98,7 +98,7 @@ class System extends \Controller\AccessController { * @return Model\SystemModel[] * @throws \Exception */ - protected function _getSystemModelByIds($columnIDs = [], $column = 'solarSystemID'){ + public function getSystemModelByIds($columnIDs = [], $column = 'solarSystemID'){ $systemModels = []; @@ -112,8 +112,7 @@ class System extends \Controller\AccessController { $rows = $ccpDB->exec($query, null, 60 * 60 * 24); // format result - $mapper = new Mapper\CcpSystemsMapper($rows); - $ccpSystemsData = $mapper->getData(); + $ccpSystemsData = (new Mapper\CcpSystemsMapper($rows))->getData(); foreach($ccpSystemsData as $ccpSystemData){ /** @@ -236,7 +235,7 @@ class System extends \Controller\AccessController { // --> (e.g. multiple simultaneously save() calls for the same system) if( is_null( $systemModel = $map->getSystemByCCPId($systemData['systemId']) ) ){ // system not found on map -> get static system data (CCP DB) - $systemModel = array_values( $this->_getSystemModelByIds([$systemData['systemId']]) )[0]; + $systemModel = $map->getNewSystem($systemData['systemId']); $systemModel->createdCharacterId = $activeCharacter; } @@ -332,7 +331,7 @@ class System extends \Controller\AccessController { $return->systemData = $f3->get($cacheKey); }else{ if($constellationId > 0){ - $systemModels = $this->_getSystemModelByIds([$constellationId], 'constellationID'); + $systemModels = $this->getSystemModelByIds([$constellationId], 'constellationID'); foreach($systemModels as $systemModel){ $return->systemData[] = $systemModel->getData(); diff --git a/app/main/controller/api/user.php b/app/main/controller/api/user.php index be9c5c35..ac219e10 100644 --- a/app/main/controller/api/user.php +++ b/app/main/controller/api/user.php @@ -29,6 +29,7 @@ class User extends Controller\Controller{ const SESSION_KEY_CHARACTER_ID = 'SESSION.CHARACTER.ID'; const SESSION_KEY_CHARACTER_NAME = 'SESSION.CHARACTER.NAME'; const SESSION_KEY_CHARACTER_TIME = 'SESSION.CHARACTER.TIME'; + const SESSION_KEY_CHARACTER_PREV_SYSTEM_ID = 'SESSION.CHARACTER.PREV_SYSTEM_ID'; const SESSION_KEY_CHARACTER_ACCESS_TOKEN = 'SESSION.CHARACTER.ACCESS_TOKEN'; const SESSION_KEY_CHARACTER_REFRESH_TOKEN = 'SESSION.CHARACTER.REFRESH_TOKEN'; diff --git a/app/main/controller/controller.php b/app/main/controller/controller.php index b4b415a5..28e7dac9 100644 --- a/app/main/controller/controller.php +++ b/app/main/controller/controller.php @@ -599,7 +599,7 @@ class Controller { } /** - * check weather the page is IGB trusted or not + * check whether the page is IGB trusted or not * @return boolean */ static function isIGBTrusted(){ diff --git a/app/main/model/basicmodel.php b/app/main/model/basicmodel.php index 1c776425..747d29a0 100644 --- a/app/main/model/basicmodel.php +++ b/app/main/model/basicmodel.php @@ -78,10 +78,12 @@ abstract class BasicModel extends \DB\Cortex { // events ----------------------------------------- $this->afterinsert(function($self){ + $self->afterinsertEvent($self); $self->clearCacheData(); }); $this->afterupdate( function($self){ + $self->afterupdateEvent($self); $self->clearCacheData(); }); @@ -317,7 +319,6 @@ abstract class BasicModel extends \DB\Cortex { if( $f3->exists($cacheKey) ){ $f3->clear($cacheKey); } - } } @@ -360,7 +361,7 @@ abstract class BasicModel extends \DB\Cortex { } /** - * checks weather this model is active or not + * checks whether this model is active or not * each model should have an "active" column * @return bool */ @@ -413,6 +414,24 @@ abstract class BasicModel extends \DB\Cortex { return true; } + /** + * Event "Hook" function + * can be overwritten + * return false will stop any further action + */ + public function afterinsertEvent(){ + return true; + } + + /** + * Event "Hook" function + * can be overwritten + * return false will stop any further action + */ + public function afterupdateEvent(){ + return true; + } + /** * Event "Hook" function * can be overwritten diff --git a/app/main/model/characterlogmodel.php b/app/main/model/characterlogmodel.php index ee7634c1..8cffef5f 100644 --- a/app/main/model/characterlogmodel.php +++ b/app/main/model/characterlogmodel.php @@ -8,6 +8,8 @@ namespace Model; +use Controller\Api\User; +use Controller\Controller; use DB\SQL\Schema; class CharacterLogModel extends BasicModel { @@ -190,4 +192,34 @@ class CharacterLogModel extends BasicModel { return $logData; } + public function set_systemId($systemId){ + if($systemId > 0){ + $this->updateCharacterSessionLocation($systemId); + } + return $systemId; + } + + /** + * update session data for active character + * @param int $systemId + */ + protected function updateCharacterSessionLocation($systemId){ + $controller = new Controller(); + $f3 = $this->getF3(); + $systemId = (int)$systemId; + + if( + ( $activeCharacter = $controller->getCharacter() ) && + ( $activeCharacter->_id === $this->characterId->_id ) + ){ + $prevSystemId = (int)$f3->get( User::SESSION_KEY_CHARACTER_PREV_SYSTEM_ID); + + if($prevSystemId === 0){ + $f3->set( User::SESSION_KEY_CHARACTER_PREV_SYSTEM_ID, $systemId); + }else{ + $f3->set( User::SESSION_KEY_CHARACTER_PREV_SYSTEM_ID, (int)$this->systemId); + } + } + } + } \ No newline at end of file diff --git a/app/main/model/charactermodel.php b/app/main/model/charactermodel.php index e1b1e5e5..fd233026 100644 --- a/app/main/model/charactermodel.php +++ b/app/main/model/charactermodel.php @@ -369,7 +369,7 @@ class CharacterModel extends BasicModel { } if($updateLogData == false){ - // ... IGB Header data not found OR character does not match current active character + // ... No IGB Header data found OR character does not match current active character // -> try to pull data from CREST $ssoController = new Sso(); @@ -533,12 +533,12 @@ class CharacterModel extends BasicModel { if($this->characterMaps){ $mapCountPrivate = 0; - foreach($this->characterMaps as &$characterMap){ + foreach($this->characterMaps as $characterMap){ if( $mapCountPrivate < self::getF3()->get('PATHFINDER.MAX_MAPS_PRIVATE') && $characterMap->mapId->isActive() ){ - $maps[] = &$characterMap->mapId; + $maps[] = $characterMap->mapId; $mapCountPrivate++; } } diff --git a/app/main/model/connectionmodel.php b/app/main/model/connectionmodel.php index c5dc133d..b3f1c222 100644 --- a/app/main/model/connectionmodel.php +++ b/app/main/model/connectionmodel.php @@ -8,6 +8,7 @@ namespace Model; +use Controller\Api\Route; use DB\SQL\Schema; class ConnectionModel extends BasicModel{ @@ -111,7 +112,37 @@ class ConnectionModel extends BasicModel{ } /** - * check weather this model is valid or not + * set default connection type by search route between endpoints + */ + public function setDefaultTypeData(){ + if( + is_object($this->source) && + is_object($this->target) + ){ + $routeController = new Route(); + $routeController->initJumpData(); + $route = $routeController->findRoute($this->source->name, $this->target->name, 1); + + if($route['routePossible']){ + $this->scope = 'stargate'; + $this->type = ['stargate']; + }else{ + $this->scope = 'wh'; + $this->type = ['wh_fresh']; + } + } + } + + /** + * check whether this connection is a wormhole or not + * @return bool + */ + public function isWormhole(){ + return ($this->scope === 'wh'); + } + + /** + * check whether this model is valid or not * @return bool */ public function isValid(){ @@ -120,6 +151,8 @@ class ConnectionModel extends BasicModel{ // check if source/target system are not equal // check if source/target belong to same map if( + is_object($this->source) && + is_object($this->target) && $this->source->_id === $this->target->_id || $this->source->mapId->_id !== $this->target->mapId->_id ){ @@ -129,6 +162,31 @@ class ConnectionModel extends BasicModel{ return $isValid; } + /** + * Event "Hook" function + * can be overwritten + * return false will stop any further action + */ + public function beforeInsertEvent(){ + // check for "default" connection type and add them if missing + if( + !$this->scope || + !$this->type + ){ + $this->setDefaultTypeData(); + } + + return true; + } + + /** + * save connection and check if obj is valid + * @return ConnectionModel|false + */ + public function save(){ + return ( $this->isValid() ) ? parent::save() : false; + } + /** * delete a connection * @param CharacterModel $characterModel diff --git a/app/main/model/mapmodel.php b/app/main/model/mapmodel.php index b66a6547..b4e71dd4 100644 --- a/app/main/model/mapmodel.php +++ b/app/main/model/mapmodel.php @@ -8,7 +8,7 @@ namespace Model; -use Controller\Api\User; +use Controller\Api\System; use DB\SQL\Schema; class MapModel extends BasicModel { @@ -209,59 +209,80 @@ class MapModel extends BasicModel { return $mapDataAll; } + /** + * get blank system model pre-filled with default SDE data + * @param int $systemId + * @return SystemModel + */ + public function getNewSystem($systemId){ + $systemController = new System(); + $system = reset($systemController->getSystemModelByIds([$systemId])); + $system->mapId = $this->id; + return $system; + } + + /** + * get blank connection model for given source/target systems + * @param SystemModel $sourceSystem + * @param SystemModel $targetSystem + * @return ConnectionModel + */ + public function getNewConnection(SystemModel $sourceSystem, SystemModel $targetSystem){ + /** + * @var $connection ConnectionModel + */ + $connection = $this->rel('connections'); + $connection->mapId = $this; + $connection->source = $sourceSystem; + $connection->target = $targetSystem; + return $connection; + } + + /** + * search for a system by id + * @param int $id + * @return null|SystemModel + */ + public function getSystemById($id){ + /** + * @var $system SystemModel + */ + $system = $this->rel('systems'); + $result = $system->findone([ + 'active = 1 AND mapId = :mapId AND id = :id', + ':mapId' => $this->id, + ':id' => $id + ]); + return is_object($result) ? $result : null; + } + /** * search for a system by CCPs systemId * @param int $systemId * @return null|SystemModel */ public function getSystemByCCPId($systemId){ - $system = null; - if( !empty($systems = $this->getSystems('systemId', (int)$systemId) ) ){ - $system = $systems[0]; - } - - return $system; - } - - /** - * search for a system by id - * @param int $systemId - * @return null|SystemModel - */ - public function getSystemById($systemId){ - $system = null; - if( !empty($systems = $this->getSystems('id', (int)$systemId) ) ){ - $system = $systems[0]; - } - - return $system; + /** + * @var $system SystemModel + */ + $system = $this->rel('systems'); + $result = $system->findone([ + 'active = 1 AND mapId = :mapId AND systemId = :systemId', + ':mapId' => $this->id, + ':systemId' => $systemId + ]); + return is_object($result) ? $result : null; } /** * get either all system models in this map - * -> or get a specific system by column filter - * @param string $column - * @param string $value * @return array|mixed */ - public function getSystems($column = '', $value = ''){ + public function getSystems(){ $systems = []; - $filterQuery = ['active = :active AND id > 0', - ':active' => 1 - ]; - - // add more filter options.... - if( - !empty($column) && - !empty($value) - ){ - $filterQuery[0] .= ' AND ' . $column . ' = :value'; - $filterQuery[':value'] = $value; - } - // orderBy x-Coordinate for smoother frontend animation (left to right) - $this->filter('systems', $filterQuery, + $this->filter('systems', ['active = 1'], ['order' => 'posX'] ); @@ -426,7 +447,7 @@ class MapModel extends BasicModel { } /** - * checks weather a character has access to this map or not + * checks whether a character has access to this map or not * @param CharacterModel $characterModel * @return bool */ @@ -588,7 +609,7 @@ class MapModel extends BasicModel { } /** - * checks weather this map is private map + * checks whether this map is private map * @return bool */ public function isPrivate(){ @@ -602,7 +623,7 @@ class MapModel extends BasicModel { } /** - * checks weather this map is corporation map + * checks whether this map is corporation map * @return bool */ public function isCorporation(){ @@ -616,7 +637,7 @@ class MapModel extends BasicModel { } /** - * checks weather this map is alliance map + * checks whether this map is alliance map * @return bool */ public function isAlliance(){ @@ -629,6 +650,81 @@ class MapModel extends BasicModel { return $isAlliance; } + /** + * + * @return mixed|null + */ + public function getScope(){ + $scope = null; + if( $this->scopeId->isActive() ){ + $scope = $this->scopeId; + } + return $scope; + } + + /** + * save a system to this map + * @param SystemModel $system + * @param int $posX + * @param int $posY + * @param null|CharacterModel $character + * @return mixed + */ + public function saveSystem( SystemModel $system, $posX = 10, $posY = 0, $character = null){ + $system->mapId = $this->id; + $system->posX = $posX; + $system->posY = $posY; + $system->createdCharacterId = $character; + $system->updatedCharacterId = $character; + return $system->save(); + } + + /** + * search for a connection by (source -> target) system ids + * -> this also searches the revers way (target -> source) + * @param SystemModel $sourceSystem + * @param SystemModel $targetSystem + * @return ConnectionModel|null + */ + public function searchConnection(SystemModel $sourceSystem, SystemModel $targetSystem){ + // check if both systems belong to this map + if( + $sourceSystem->mapId->id === $this->id && + $targetSystem->mapId->id === $this->id + ){ + $this->filter('connections', [ + 'active = :active AND + ( + ( + source = :sourceId AND + target = :targetId + ) OR ( + source = :targetId AND + target = :sourceId + ) + )', + ':active' => 1, + ':sourceId' => $sourceSystem->id, + ':targetId' => $targetSystem->id, + ], ['limit'=> 1]); + + return ($this->connections) ? reset($this->connections) : null; + }else{ + return null; + } + } + + /** + * save new connection + * -> connection scope/type is automatically added + * @param ConnectionModel $connection + * @return false|ConnectionModel + */ + public function saveConnection(ConnectionModel $connection){ + $connection->mapId = $this; + return $connection->save(); + } + /** * get all active characters (with active log) * grouped by systems diff --git a/app/main/model/mapscopemodel.php b/app/main/model/mapscopemodel.php index 91492f44..c0d78973 100644 --- a/app/main/model/mapscopemodel.php +++ b/app/main/model/mapscopemodel.php @@ -37,7 +37,19 @@ class MapScopeModel extends BasicModel{ [ 'id' => 1, 'name' => 'wh', - 'label' => 'w-space' + 'label' => 'wormholes' + ],[ + 'id' => 2, + 'name' => 'k-space', + 'label' => 'stargates' + ],[ + 'id' => 3, + 'name' => 'none', + 'label' => 'none' + ],[ + 'id' => 4, + 'name' => 'all', + 'label' => 'all' ] ]; diff --git a/app/main/model/systemmodel.php b/app/main/model/systemmodel.php index b33096c1..bd0aeb88 100644 --- a/app/main/model/systemmodel.php +++ b/app/main/model/systemmodel.php @@ -404,17 +404,11 @@ class SystemModel extends BasicModel { } /** - * checks weather this system is a wormhole + * check whether this system is a wormhole or not * @return bool */ - protected function isWormhole(){ - $isWormhole = false; - - if($this->typeId->id == 1){ - $isWormhole = true; - } - - return $isWormhole; + public function isWormhole(){ + return ($this->typeId->id === 1); } /** diff --git a/js/app.js b/js/app.js index e66abc0a..d4382a78 100644 --- a/js/app.js +++ b/js/app.js @@ -22,36 +22,36 @@ requirejs.config({ setup: './app/setup', // initial start "setup page" view jquery: 'lib/jquery-1.11.3.min', // v1.11.3 jQuery - bootstrap: 'lib/bootstrap.min', // v3.3.0 Bootstrap js code - http://getbootstrap.com/javascript/ + bootstrap: 'lib/bootstrap.min', // v3.3.0 Bootstrap js code - http://getbootstrap.com/javascript text: 'lib/requirejs/text', // v2.0.12 A RequireJS/AMD loader plugin for loading text resources. - mustache: 'lib/mustache.min', // v1.0.0 Javascript template engine - http://mustache.github.io/ - velocity: 'lib/velocity.min', // v1.2.2 animation engine - http://julian.com/research/velocity/ + mustache: 'lib/mustache.min', // v1.0.0 Javascript template engine - http://mustache.github.io + velocity: 'lib/velocity.min', // v1.2.2 animation engine - http://julian.com/research/velocity velocityUI: 'lib/velocity.ui.min', // v5.0.4 plugin for velocity - http://julian.com/research/velocity/#uiPack - slidebars: 'lib/slidebars', // v0.10 Slidebars - side menu plugin http://plugins.adchsm.me/slidebars/ - jsPlumb: 'lib/dom.jsPlumb-1.7.6', // v1.7.6 jsPlumb (Vanilla)- main map draw plugin https://jsplumbtoolkit.com/ + slidebars: 'lib/slidebars', // v0.10 Slidebars - side menu plugin http://plugins.adchsm.me/slidebars + jsPlumb: 'lib/dom.jsPlumb-1.7.6', // v1.7.6 jsPlumb (Vanilla)- main map draw plugin https://jsplumbtoolkit.com farahey: 'lib/farahey-0.5', // v0.5 jsPlumb "magnetizing" extension - https://github.com/jsplumb/farahey - customScrollbar: 'lib/jquery.mCustomScrollbar.concat.min', // v3.0.9 Custom scroll bars - http://manos.malihu.gr/ - datatables: 'lib/datatables/jquery.dataTables.min', // v1.10.7 DataTables - https://datatables.net/ + customScrollbar: 'lib/jquery.mCustomScrollbar.concat.min', // v3.1.3 Custom scroll bars - http://manos.malihu.gr + datatables: 'lib/datatables/jquery.dataTables.min', // v1.10.7 DataTables - https://datatables.net //datatablesBootstrap: 'lib/datatables/dataTables.bootstrap', // DataTables - not used (bootstrap style) - datatablesResponsive: 'lib/datatables/extensions/responsive/dataTables.responsive', // v1.0.6 TableTools (PlugIn) - https://datatables.net/extensions/responsive/ + datatablesResponsive: 'lib/datatables/extensions/responsive/dataTables.responsive', // v1.0.6 TableTools (PlugIn) - https://datatables.net/extensions/responsive - datatablesTableTools: 'lib/datatables/extensions/tabletools/js/dataTables.tableTools', // v2.2.3 TableTools (PlugIn) - https://datatables.net/extensions/tabletools/ + datatablesTableTools: 'lib/datatables/extensions/tabletools/js/dataTables.tableTools', // v2.2.3 TableTools (PlugIn) - https://datatables.net/extensions/tabletools xEditable: 'lib/bootstrap-editable.min', // v1.5.1 X-editable - in placed editing morris: 'lib/morris.min', // v0.5.1 Morris.js - graphs and charts raphael: 'lib/raphael-min', // v2.1.2 Raphaël - required for morris (dependency) - bootbox: 'lib/bootbox.min', // v4.4.0 Bootbox.js - custom dialogs - http://bootboxjs.com/ - easyPieChart: 'lib/jquery.easypiechart.min', // v2.1.6 Easy Pie Chart - HTML 5 pie charts - http://rendro.github.io/easy-pie-chart/ - dragToSelect: 'lib/jquery.dragToSelect', // v1.1 Drag to Select - http://andreaslagerkvist.com/jquery/drag-to-select/ + bootbox: 'lib/bootbox.min', // v4.4.0 Bootbox.js - custom dialogs - http://bootboxjs.com + easyPieChart: 'lib/jquery.easypiechart.min', // v2.1.6 Easy Pie Chart - HTML 5 pie charts - http://rendro.github.io/easy-pie-chart + dragToSelect: 'lib/jquery.dragToSelect', // v1.1 Drag to Select - http://andreaslagerkvist.com/jquery/drag-to-select hoverIntent: 'lib/jquery.hoverIntent.minified', // v1.8.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html fullScreen: 'lib/jquery.fullscreen.min', // v0.5.0 Full screen mode - https://github.com/private-face/jquery.fullscreen - select2: 'lib/select2.min', // v4.0.0 Drop Down customization - https://select2.github.io/ + select2: 'lib/select2.min', // v4.0.0 Drop Down customization - https://select2.github.io validator: 'lib/validator.min', // v0.10.1 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator - lazylinepainter: 'lib/jquery.lazylinepainter-1.5.1.min', // v1.5.1 SVG line animation plugin - http://lazylinepainter.info/ - blueImpGallery: 'lib/blueimp-gallery', // v2.15.2 Image Gallery - https://github.com/blueimp/Gallery/ + lazylinepainter: 'lib/jquery.lazylinepainter-1.5.1.min', // v1.5.1 SVG line animation plugin - http://lazylinepainter.info + blueImpGallery: 'lib/blueimp-gallery', // v2.15.2 Image Gallery - https://github.com/blueimp/Gallery blueImpGalleryHelper: 'lib/blueimp-helper', // helper function for Blue Imp Gallery - blueImpGalleryBootstrap: 'lib/bootstrap-image-gallery', // v3.1.1 Bootstrap extension for Blue Imp Gallery - https://blueimp.github.io/Bootstrap-Image-Gallery/ + blueImpGalleryBootstrap: 'lib/bootstrap-image-gallery', // v3.1.1 Bootstrap extension for Blue Imp Gallery - https://blueimp.github.io/Bootstrap-Image-Gallery bootstrapConfirmation: 'lib/bootstrap-confirmation', // v1.0.1 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation - bootstrapToggle: 'lib/bootstrap2-toggle.min', // v2.2.0 Bootstrap Toggle (Checkbox) - http://www.bootstraptoggle.com/ + bootstrapToggle: 'lib/bootstrap2-toggle.min', // v2.2.0 Bootstrap Toggle (Checkbox) - http://www.bootstraptoggle.com lazyload: 'lib/jquery.lazyload.min', // v1.9.5 LazyLoader images - http://www.appelsiini.net/projects/lazyload // header animation diff --git a/js/app/ccp.js b/js/app/ccp.js index 5fe8501e..6dd2186e 100644 --- a/js/app/ccp.js +++ b/js/app/ccp.js @@ -7,7 +7,7 @@ define(['jquery'], function($) { 'use strict'; /** - * checks weather the program URL is IGB trusted or not + * checks whether the program URL is IGB trusted or not * @returns {boolean} */ var isTrusted = function(){ diff --git a/js/app/map/map.js b/js/app/map/map.js index abf8234c..1176a388 100644 --- a/js/app/map/map.js +++ b/js/app/map/map.js @@ -30,7 +30,6 @@ define([ mapMagnetizer: false, // "Magnetizer" feature for drag&drop systems on map (optional) mapTabContentClass: 'pf-map-tab-content', // Tab-Content element (parent element) mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable) - headMapTrackingId: 'pf-head-map-tracking', // id for "map tracking" toggle (checkbox) mapClass: 'pf-map', // class for all maps mapGridClass: 'pf-grid-small', // class for map grid snapping @@ -82,10 +81,6 @@ define([ // active connections per map (cache object) var connectionCache = {}; - // characterID => systemIds are cached temporary where the active user character is in - // if a character switches/add system, establish connection with "previous" system - var activeSystemCache = ''; - // jsPlumb config var globalMapConfig = { source: { @@ -2911,7 +2906,7 @@ define([ // validate form form.validator('validate'); - // check weather the form is valid + // check whether the form is valid var formValid = form.isValidForm(); if(formValid === false){ @@ -3075,11 +3070,6 @@ define([ var mapElement = map.getContainer(); - // get map tracking toggle value - // if "false" -> new systems/connections will not automatically added - var mapTracking = $('#' + config.headMapTrackingId).is(':checked'); - - // container must exist! otherwise systems can not be updated if(mapElement !== undefined){ @@ -3149,76 +3139,12 @@ define([ // set current location data for header update headerUpdateData.currentSystemId = $(system).data('id'); headerUpdateData.currentSystemName = currentCharacterLog.system.name; - - // check connection exists between new and previous systems --------o------------------------------ - // e.g. a loop - if( - activeSystemCache && - mapTracking && - activeSystemCache.data('systemId') !== currentCharacterLog.system.id - ){ - // maybe a loop detected (both systems already on map -> connection missing - var connections = checkForConnection(map, activeSystemCache, system ); - - if(connections.length === 0){ - var connectionData = { - source: activeSystemCache.data('id') , - target: system.data('id'), - type: ['wh_fresh'] // default type. - }; - - var connection = drawConnection(map, connectionData); - saveConnection(connection); - } - - } - - // cache current location - activeSystemCache = system; } } system.updateSystemUserData(map, tempUserData, currentUserIsHere); } - // current user was not found on any map system -> add new system to map where the user is in ---------------- - // this is restricted to IGB-usage! CharacterLog data is always set through the IGB - // ->this prevent adding the same system multiple times, if a user is online with IGB AND OOG - if( - currentUserOnMap === false && - currentCharacterLog && - mapTracking - ){ - // add new system to the map - var requestData = { - systemData: { - systemId: currentCharacterLog.system.id - }, - mapData: { - id: userData.config.id - } - }; - - // check if a system jump is detected previous system !== current system - // and add a connection to the previous system as well - // hint: if a user just logged on -> there is no active system cached - var sourceSystem = false; - if( - activeSystemCache && - activeSystemCache.data('systemId') !== currentCharacterLog.system.id - ){ - - // draw new connection - sourceSystem = activeSystemCache; - // calculate new system coordinates - requestData.systemData.position = calculateNewSystemPosition(sourceSystem); - } - - mapElement.getMapOverlay('timer').startMapUpdateCounter(); - - saveSystem(map, requestData, sourceSystem, false); - } - // trigger document event -> update header $(document).trigger('pf:updateHeaderMapData', headerUpdateData); } diff --git a/js/app/mappage.js b/js/app/mappage.js index 16b8b6f8..c8cbcaf9 100644 --- a/js/app/mappage.js +++ b/js/app/mappage.js @@ -99,6 +99,8 @@ define([ userUpdate: 0 }; + var locationToggle = $('#' + Util.config.headMapTrackingId); + // ping for main map update ======================================================== var triggerMapUpdatePing = function(){ @@ -197,7 +199,10 @@ define([ var updatedUserData = { mapIds: mapIds, - systemData: Util.getCurrentSystemData() + systemData: Util.getCurrentSystemData(), + characterMapData: { + mapTracking: (locationToggle.is(':checked') ? 1 : 0) // location tracking + } }; Util.timeStart(logKeyServerUserData); diff --git a/js/app/ui/dialog/account_settings.js b/js/app/ui/dialog/account_settings.js index e6c2cbd1..da4f0dbe 100644 --- a/js/app/ui/dialog/account_settings.js +++ b/js/app/ui/dialog/account_settings.js @@ -76,7 +76,7 @@ define([ // validate form form.validator('validate'); - // check weather the form is valid + // check whether the form is valid var formValid = form.isValidForm(); if(formValid === true){ diff --git a/js/app/ui/dialog/map_settings.js b/js/app/ui/dialog/map_settings.js index 0a8cbf59..fcd6f865 100644 --- a/js/app/ui/dialog/map_settings.js +++ b/js/app/ui/dialog/map_settings.js @@ -218,7 +218,7 @@ define([ } }); - // check weather the form is valid + // check whether the form is valid var formValid = form.isValidForm(); if(formValid === true){ diff --git a/js/app/ui/system_route.js b/js/app/ui/system_route.js index be403943..3bc9085d 100644 --- a/js/app/ui/system_route.js +++ b/js/app/ui/system_route.js @@ -202,7 +202,7 @@ define([ // validate form form.validator('validate'); - // check weather the form is valid + // check whether the form is valid var formValid = form.isValidForm(); if(formValid === false){ diff --git a/js/app/util.js b/js/app/util.js index 2cb82160..92aa6dfc 100644 --- a/js/app/util.js +++ b/js/app/util.js @@ -31,6 +31,9 @@ define([ formWarningContainerClass: 'pf-dialog-warning-container', // class for "warning" containers in dialogs formInfoContainerClass: 'pf-dialog-info-container', // class for "info" containers in dialogs + // head + headMapTrackingId: 'pf-head-map-tracking', // id for "map tracking" toggle (checkbox) + settingsMessageVelocityOptions: { duration: 180 @@ -353,7 +356,7 @@ define([ }; /** - * checks weather a bootstrap form is valid or not + * checks whether a bootstrap form is valid or not * validation plugin does not provide a proper function for this * @returns {boolean} */ diff --git a/js/lib/jquery.mCustomScrollbar.concat.min.js b/js/lib/jquery.mCustomScrollbar.concat.min.js index f53d4b22..6d794180 100644 --- a/js/lib/jquery.mCustomScrollbar.concat.min.js +++ b/js/lib/jquery.mCustomScrollbar.concat.min.js @@ -1,5 +1,6 @@ -/* == jquery mousewheel plugin == Version: 3.1.12, License: MIT License (MIT) */ -!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})}); -/* == malihu jquery custom scrollbar plugin == Version: 3.0.9, License: MIT License (MIT) */ -!function(e){"undefined"!=typeof module&&module.exports?module.exports=e:e(jQuery,window,document)}(function(e){!function(t){var o="function"==typeof define&&define.amd,a="undefined"!=typeof module&&module.exports,n="https:"==document.location.protocol?"https:":"http:",i="cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.12/jquery.mousewheel.min.js";o||(a?require("jquery-mousewheel")(e):e.event.special.mousewheel||e("head").append(decodeURI("%3Cscript src="+n+"//"+i+"%3E%3C/script%3E"))),t()}(function(){var t,o="mCustomScrollbar",a="mCS",n=".mCustomScrollbar",i={setTop:0,setLeft:0,axis:"y",scrollbarPosition:"inside",scrollInertia:950,autoDraggerLength:!0,alwaysShowScrollbar:0,snapOffset:0,mouseWheel:{enable:!0,scrollAmount:"auto",axis:"y",deltaFactor:"auto",disableOver:["select","option","keygen","datalist","textarea"]},scrollButtons:{scrollType:"stepless",scrollAmount:"auto"},keyboard:{enable:!0,scrollType:"stepless",scrollAmount:"auto"},contentTouchScroll:25,advanced:{autoScrollOnFocus:"input,textarea,select,button,datalist,keygen,a[tabindex],area,object,[contenteditable='true']",updateOnContentResize:!0,updateOnImageLoad:!0,autoUpdateTimeout:60},theme:"light",callbacks:{onTotalScrollOffset:0,onTotalScrollBackOffset:0,alwaysTriggerOffsets:!0}},r=0,l={},s=window.attachEvent&&!window.addEventListener?1:0,c=!1,d=["mCSB_dragger_onDrag","mCSB_scrollTools_onDrag","mCS_img_loaded","mCS_disabled","mCS_destroyed","mCS_no_scrollbar","mCS-autoHide","mCS-dir-rtl","mCS_no_scrollbar_y","mCS_no_scrollbar_x","mCS_y_hidden","mCS_x_hidden","mCSB_draggerContainer","mCSB_buttonUp","mCSB_buttonDown","mCSB_buttonLeft","mCSB_buttonRight"],u={init:function(t){var t=e.extend(!0,{},i,t),o=f.call(this);if(t.live){var s=t.liveSelector||this.selector||n,c=e(s);if("off"===t.live)return void m(s);l[s]=setTimeout(function(){c.mCustomScrollbar(t),"once"===t.live&&c.length&&m(s)},500)}else m(s);return t.setWidth=t.set_width?t.set_width:t.setWidth,t.setHeight=t.set_height?t.set_height:t.setHeight,t.axis=t.horizontalScroll?"x":p(t.axis),t.scrollInertia=t.scrollInertia>0&&t.scrollInertia<17?17:t.scrollInertia,"object"!=typeof t.mouseWheel&&1==t.mouseWheel&&(t.mouseWheel={enable:!0,scrollAmount:"auto",axis:"y",preventDefault:!1,deltaFactor:"auto",normalizeDelta:!1,invert:!1}),t.mouseWheel.scrollAmount=t.mouseWheelPixels?t.mouseWheelPixels:t.mouseWheel.scrollAmount,t.mouseWheel.normalizeDelta=t.advanced.normalizeMouseWheelDelta?t.advanced.normalizeMouseWheelDelta:t.mouseWheel.normalizeDelta,t.scrollButtons.scrollType=g(t.scrollButtons.scrollType),h(t),e(o).each(function(){var o=e(this);if(!o.data(a)){o.data(a,{idx:++r,opt:t,scrollRatio:{y:null,x:null},overflowed:null,contentReset:{y:null,x:null},bindEvents:!1,tweenRunning:!1,sequential:{},langDir:o.css("direction"),cbOffsets:null,trigger:null});var n=o.data(a),i=n.opt,l=o.data("mcs-axis"),s=o.data("mcs-scrollbar-position"),c=o.data("mcs-theme");l&&(i.axis=l),s&&(i.scrollbarPosition=s),c&&(i.theme=c,h(i)),v.call(this),e("#mCSB_"+n.idx+"_container img:not(."+d[2]+")").addClass(d[2]),u.update.call(null,o)}})},update:function(t,o){var n=t||f.call(this);return e(n).each(function(){var t=e(this);if(t.data(a)){var n=t.data(a),i=n.opt,r=e("#mCSB_"+n.idx+"_container"),l=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")];if(!r.length)return;n.tweenRunning&&V(t),t.hasClass(d[3])&&t.removeClass(d[3]),t.hasClass(d[4])&&t.removeClass(d[4]),S.call(this),_.call(this),"y"===i.axis||i.advanced.autoExpandHorizontalScroll||r.css("width",x(r.children())),n.overflowed=B.call(this),O.call(this),i.autoDraggerLength&&b.call(this),C.call(this),k.call(this);var s=[Math.abs(r[0].offsetTop),Math.abs(r[0].offsetLeft)];"x"!==i.axis&&(n.overflowed[0]?l[0].height()>l[0].parent().height()?T.call(this):(Q(t,s[0].toString(),{dir:"y",dur:0,overwrite:"none"}),n.contentReset.y=null):(T.call(this),"y"===i.axis?M.call(this):"yx"===i.axis&&n.overflowed[1]&&Q(t,s[1].toString(),{dir:"x",dur:0,overwrite:"none"}))),"y"!==i.axis&&(n.overflowed[1]?l[1].width()>l[1].parent().width()?T.call(this):(Q(t,s[1].toString(),{dir:"x",dur:0,overwrite:"none"}),n.contentReset.x=null):(T.call(this),"x"===i.axis?M.call(this):"yx"===i.axis&&n.overflowed[0]&&Q(t,s[0].toString(),{dir:"y",dur:0,overwrite:"none"}))),o&&n&&(2===o&&i.callbacks.onImageLoad&&"function"==typeof i.callbacks.onImageLoad?i.callbacks.onImageLoad.call(this):3===o&&i.callbacks.onSelectorChange&&"function"==typeof i.callbacks.onSelectorChange?i.callbacks.onSelectorChange.call(this):i.callbacks.onUpdate&&"function"==typeof i.callbacks.onUpdate&&i.callbacks.onUpdate.call(this)),X.call(this)}})},scrollTo:function(t,o){if("undefined"!=typeof t&&null!=t){var n=f.call(this);return e(n).each(function(){var n=e(this);if(n.data(a)){var i=n.data(a),r=i.opt,l={trigger:"external",scrollInertia:r.scrollInertia,scrollEasing:"mcsEaseInOut",moveDragger:!1,timeout:60,callbacks:!0,onStart:!0,onUpdate:!0,onComplete:!0},s=e.extend(!0,{},l,o),c=Y.call(this,t),d=s.scrollInertia>0&&s.scrollInertia<17?17:s.scrollInertia;c[0]=j.call(this,c[0],"y"),c[1]=j.call(this,c[1],"x"),s.moveDragger&&(c[0]*=i.scrollRatio.y,c[1]*=i.scrollRatio.x),s.dur=d,setTimeout(function(){null!==c[0]&&"undefined"!=typeof c[0]&&"x"!==r.axis&&i.overflowed[0]&&(s.dir="y",s.overwrite="all",Q(n,c[0].toString(),s)),null!==c[1]&&"undefined"!=typeof c[1]&&"y"!==r.axis&&i.overflowed[1]&&(s.dir="x",s.overwrite="none",Q(n,c[1].toString(),s))},s.timeout)}})}},stop:function(){var t=f.call(this);return e(t).each(function(){var t=e(this);t.data(a)&&V(t)})},disable:function(t){var o=f.call(this);return e(o).each(function(){var o=e(this);if(o.data(a)){{o.data(a)}X.call(this,"remove"),M.call(this),t&&T.call(this),O.call(this,!0),o.addClass(d[3])}})},destroy:function(){var t=f.call(this);return e(t).each(function(){var n=e(this);if(n.data(a)){var i=n.data(a),r=i.opt,l=e("#mCSB_"+i.idx),s=e("#mCSB_"+i.idx+"_container"),c=e(".mCSB_"+i.idx+"_scrollbar");r.live&&m(r.liveSelector||e(t).selector),X.call(this,"remove"),M.call(this),T.call(this),n.removeData(a),Z(this,"mcs"),c.remove(),s.find("img."+d[2]).removeClass(d[2]),l.replaceWith(s.contents()),n.removeClass(o+" _"+a+"_"+i.idx+" "+d[6]+" "+d[7]+" "+d[5]+" "+d[3]).addClass(d[4])}})}},f=function(){return"object"!=typeof e(this)||e(this).length<1?n:this},h=function(t){var o=["rounded","rounded-dark","rounded-dots","rounded-dots-dark"],a=["rounded-dots","rounded-dots-dark","3d","3d-dark","3d-thick","3d-thick-dark","inset","inset-dark","inset-2","inset-2-dark","inset-3","inset-3-dark"],n=["minimal","minimal-dark"],i=["minimal","minimal-dark"],r=["minimal","minimal-dark"];t.autoDraggerLength=e.inArray(t.theme,o)>-1?!1:t.autoDraggerLength,t.autoExpandScrollbar=e.inArray(t.theme,a)>-1?!1:t.autoExpandScrollbar,t.scrollButtons.enable=e.inArray(t.theme,n)>-1?!1:t.scrollButtons.enable,t.autoHideScrollbar=e.inArray(t.theme,i)>-1?!0:t.autoHideScrollbar,t.scrollbarPosition=e.inArray(t.theme,r)>-1?"outside":t.scrollbarPosition},m=function(e){l[e]&&(clearTimeout(l[e]),Z(l,e))},p=function(e){return"yx"===e||"xy"===e||"auto"===e?"yx":"x"===e||"horizontal"===e?"x":"y"},g=function(e){return"stepped"===e||"pixels"===e||"step"===e||"click"===e?"stepped":"stepless"},v=function(){var t=e(this),n=t.data(a),i=n.opt,r=i.autoExpandScrollbar?" "+d[1]+"_expand":"",l=["
",""],s="yx"===i.axis?"mCSB_vertical_horizontal":"x"===i.axis?"mCSB_horizontal":"mCSB_vertical",c="yx"===i.axis?l[0]+l[1]:"x"===i.axis?l[1]:l[0],u="yx"===i.axis?"":"",f=i.autoHideScrollbar?" "+d[6]:"",h="x"!==i.axis&&"rtl"===n.langDir?" "+d[7]:"";i.setWidth&&t.css("width",i.setWidth),i.setHeight&&t.css("height",i.setHeight),i.setLeft="y"!==i.axis&&"rtl"===n.langDir?"989999px":i.setLeft,t.addClass(o+" _"+a+"_"+n.idx+f+h).wrapInner("- pathfinder supports 3 different types of maps. Each map contains several systems (more) - and connections (more). Maps are also referred to as "Chain Map" or "Chain". + pathfinder supports 3 different types of maps. Systems (more) + and connections (more) can be added to them. Maps are also referred to as "Chain Map" or "Chain":
Up to 5 different maps can be used simultaneously. Alliance maps require appropriate rules to be created.
++ Each map has a "scope" that affects how systems will be added automatically to it: +
+
+ If "map tracking" is on, new systems (more)
+ and connections (more)
+ will be automatically added to the current map (more).
+ This can only work if your current position is known by pathfinder.
+ The map scope (more) defines which systems are affected.
+ The connection scope (more) will be auto-detected (e.g. wormhole connection).
+ This is achieved by calculating the jump distance between your current system and system you came from.
+
right click somewhere on the map to open the context menu. @@ -64,24 +84,11 @@ 4 -
The "Update counter" starts counting backwards during map interaction. While the counter is active, no data is pushed to server.
Once the counter hits 0, all map date will be stored and active pilots will receive the map updates.
There is no need for any save/edit buttons.
- If "map tracking" is on, new systems (more)
- and connections (more)
- will be automatically added to the current map (more).
- This can only work if your current position is known by pathfinder. You have to use the IGB for this feature.
- The connection scope (more) will be auto-detected and can be changed afterwards.
- This is achieved by calculating the jump distance between your current system and system you came from.
-
+ Waypoints can be set to systems. Waypoint options are identical to their in game options. +
+Any system that is not "Locked" (more) can be deleted from a map. @@ -192,7 +209,7 @@
- Connections between systems are represented by solid curved lines. Any connection requires two systems that are connected. A connection can be a "Stargate" or "Wormhole". + Connections between systems are represented by solid lines. Any connection requires two systems that are connected together.
@@ -324,28 +341,21 @@
The concept of map sharing is pretty complex and powerful. By default all sharing options are disabled, so there is no reason to be concerned about map security.
All map types (more) can be temporary shared with allied entities e.g. for "Joint-Ops".
The map type is preserved for the period of sharing (private maps can be shared with other users, corporation maps can be shared with other corporations,..).
- For now you can not invite a single user to your corporation map.
Do the following steps to share your map with your friend/allied corporation/allied alliance: