mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
* followup on 748a78c3c7
* fix return type of criteria filter callbacks (mostly in case of faulty input)
* spread the criteria var into criteria filter callbacks
* some magic numbers to constants and type declarations for params/return types
315 lines
11 KiB
PHP
315 lines
11 KiB
PHP
<?php
|
|
|
|
if (!defined('AOWOW_REVISION'))
|
|
die('illegal access');
|
|
|
|
|
|
class GuildList extends BaseType
|
|
{
|
|
use profilerHelper, listviewHelper;
|
|
|
|
public static $contribute = CONTRIBUTE_NONE;
|
|
|
|
public function getListviewData()
|
|
{
|
|
$this->getGuildScores();
|
|
|
|
$data = [];
|
|
foreach ($this->iterate() as $__)
|
|
{
|
|
$data[$this->id] = array(
|
|
'name' => '$"'.str_replace ('"', '', $this->curTpl['name']).'"', // MUST be a string, omit any quotes in name
|
|
'members' => $this->curTpl['members'],
|
|
'faction' => $this->curTpl['faction'],
|
|
'achievementpoints' => $this->getField('achievementpoints'),
|
|
'gearscore' => $this->getField('gearscore'),
|
|
'realm' => Profiler::urlize($this->curTpl['realmName'], true),
|
|
'realmname' => $this->curTpl['realmName'],
|
|
// 'battlegroup' => Profiler::urlize($this->curTpl['battlegroup']), // was renamed to subregion somewhere around cata release
|
|
// 'battlegroupname' => $this->curTpl['battlegroup'],
|
|
'region' => Profiler::urlize($this->curTpl['region'])
|
|
);
|
|
}
|
|
|
|
return array_values($data);
|
|
}
|
|
|
|
private function getGuildScores()
|
|
{
|
|
/*
|
|
Guild gear scores and achievement points are derived using a weighted average of all of the known characters in that guild.
|
|
Guilds with at least 25 level 80 players receive full benefit of the top 25 characters' gear scores, while guilds with at least 10 level 80 characters receive a slight penalty,
|
|
at least 1 level 80 a moderate penalty, and no level 80 characters a severe penalty. [...]
|
|
Instead of being based on level, achievement point averages are based around 1,500 points, but the same penalties apply.
|
|
*/
|
|
$guilds = array_column($this->templates, 'id');
|
|
if (!$guilds)
|
|
return;
|
|
|
|
$stats = DB::Aowow()->select('SELECT `guild` AS ARRAY_KEY, `id` AS ARRAY_KEY2, `level`, `gearscore`, `achievementpoints`, IF(`cuFlags` & ?d, 0, 1) AS "synced" FROM ?_profiler_profiles WHERE `guild` IN (?a) ORDER BY `gearscore` DESC', PROFILER_CU_NEEDS_RESYNC, $guilds);
|
|
foreach ($this->iterate() as &$_curTpl)
|
|
{
|
|
$id = $_curTpl['id'];
|
|
if (empty($stats[$id]))
|
|
continue;
|
|
|
|
$guildStats = array_filter($stats[$id], function ($x) { return $x['synced']; } );
|
|
if (!$guildStats)
|
|
continue;
|
|
|
|
$nMaxLevel = count(array_filter($stats[$id], function ($x) { return $x['level'] >= MAX_LEVEL; } ));
|
|
$levelMod = 1.0;
|
|
|
|
if ($nMaxLevel < 25)
|
|
$levelMod = 0.85;
|
|
if ($nMaxLevel < 10)
|
|
$levelMod = 0.66;
|
|
if ($nMaxLevel < 1)
|
|
$levelMod = 0.20;
|
|
|
|
$totalGS = $totalAP = $nMembers = 0;
|
|
foreach ($guildStats as $gs)
|
|
{
|
|
$totalGS += $gs['gearscore'] * $levelMod * min($gs['level'], MAX_LEVEL) / MAX_LEVEL;
|
|
$totalAP += $gs['achievementpoints'] * $levelMod * min($gs['achievementpoints'], 1500) / 1500;
|
|
$nMembers += min($gs['level'], MAX_LEVEL) / MAX_LEVEL;
|
|
}
|
|
|
|
$_curTpl['gearscore'] = intval($totalGS / $nMembers);
|
|
$_curTpl['achievementpoints'] = intval($totalAP / $nMembers);
|
|
}
|
|
}
|
|
|
|
public function renderTooltip() {}
|
|
public function getJSGlobals($addMask = 0) {}
|
|
}
|
|
|
|
|
|
class GuildListFilter extends Filter
|
|
{
|
|
public $extraOpts = [];
|
|
protected $genericFilter = [];
|
|
|
|
protected $inputFields = array(
|
|
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
|
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
|
'ex' => [parent::V_EQUAL, 'on', false], // only match exact
|
|
'si' => [parent::V_LIST, [SIDE_ALLIANCE, SIDE_HORDE], false], // side
|
|
'rg' => [parent::V_CALLBACK, 'cbRegionCheck', false], // region
|
|
'sv' => [parent::V_CALLBACK, 'cbServerCheck', false], // server
|
|
);
|
|
|
|
protected function createSQLForValues()
|
|
{
|
|
$parts = [];
|
|
$_v = $this->fiData['v'];
|
|
|
|
// region (rg), battlegroup (bg) and server (sv) are passed to GuildList as miscData and handled there
|
|
|
|
// name [str]
|
|
if (!empty($_v['na']))
|
|
if ($_ = $this->modularizeString(['g.name'], $_v['na'], !empty($_v['ex']) && $_v['ex'] == 'on'))
|
|
$parts[] = $_;
|
|
|
|
// side [list]
|
|
if (!empty($_v['si']))
|
|
{
|
|
if ($_v['si'] == SIDE_ALLIANCE)
|
|
$parts[] = ['c.race', ChrRace::fromMask(ChrRace::MASK_ALLIANCE)];
|
|
else if ($_v['si'] == SIDE_HORDE)
|
|
$parts[] = ['c.race', ChrRace::fromMask(ChrRace::MASK_HORDE)];
|
|
}
|
|
|
|
return $parts;
|
|
}
|
|
|
|
protected function cbRegionCheck(string &$v) : bool
|
|
{
|
|
if (in_array($v, Util::$regions))
|
|
{
|
|
$this->parentCats[0] = $v; // directly redirect onto this region
|
|
$v = ''; // remove from filter
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected function cbServerCheck(string &$v) : bool
|
|
{
|
|
foreach (Profiler::getRealms() as $realm)
|
|
if ($realm['name'] == $v)
|
|
{
|
|
$this->parentCats[1] = Profiler::urlize($v);// directly redirect onto this server
|
|
$v = ''; // remove from filter
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
class RemoteGuildList extends GuildList
|
|
{
|
|
protected $queryBase = 'SELECT `g`.*, `g`.`guildid` AS ARRAY_KEY FROM guild g';
|
|
protected $queryOpts = array(
|
|
'g' => [['gm', 'c'], 'g' => 'ARRAY_KEY'],
|
|
'gm' => ['j' => 'guild_member gm ON gm.guildid = g.guildid', 's' => ', COUNT(1) AS members'],
|
|
'c' => ['j' => 'characters c ON c.guid = gm.guid', 's' => ', BIT_OR(IF(c.race IN (1, 3, 4, 7, 11), 1, 2)) - 1 AS faction']
|
|
);
|
|
|
|
public function __construct(array $conditions = [], array $miscData = [])
|
|
{
|
|
// select DB by realm
|
|
if (!$this->selectRealms($miscData))
|
|
{
|
|
trigger_error('no access to auth-db or table realmlist is empty', E_USER_WARNING);
|
|
return;
|
|
}
|
|
|
|
parent::__construct($conditions, $miscData);
|
|
|
|
if ($this->error)
|
|
return;
|
|
|
|
reset($this->dbNames); // only use when querying single realm
|
|
$realmId = key($this->dbNames);
|
|
$realms = Profiler::getRealms();
|
|
$distrib = [];
|
|
|
|
// post processing
|
|
foreach ($this->iterate() as $guid => &$curTpl)
|
|
{
|
|
// battlegroup
|
|
$curTpl['battlegroup'] = Cfg::get('BATTLEGROUP');
|
|
|
|
$r = explode(':', $guid)[0];
|
|
if (!empty($realms[$r]))
|
|
{
|
|
$curTpl['realm'] = $r;
|
|
$curTpl['realmName'] = $realms[$r]['name'];
|
|
$curTpl['region'] = $realms[$r]['region'];
|
|
}
|
|
else
|
|
{
|
|
trigger_error('guild #'.$guid.' belongs to nonexistant realm #'.$r, E_USER_WARNING);
|
|
unset($this->templates[$guid]);
|
|
continue;
|
|
}
|
|
|
|
// empty name
|
|
if (!$curTpl['name'])
|
|
{
|
|
trigger_error('guild #'.$guid.' on realm #'.$r.' has empty name.', E_USER_WARNING);
|
|
unset($this->templates[$guid]);
|
|
continue;
|
|
}
|
|
|
|
// equalize distribution
|
|
if (empty($distrib[$curTpl['realm']]))
|
|
$distrib[$curTpl['realm']] = 1;
|
|
else
|
|
$distrib[$curTpl['realm']]++;
|
|
}
|
|
|
|
$limit = Cfg::get('SQL_LIMIT_DEFAULT');
|
|
foreach ($conditions as $c)
|
|
if (is_int($c))
|
|
$limit = $c;
|
|
|
|
$total = array_sum($distrib);
|
|
foreach ($distrib as &$d)
|
|
$d = ceil($limit * $d / $total);
|
|
|
|
foreach ($this->iterate() as $guid => &$curTpl)
|
|
{
|
|
if ($limit <= 0 || $distrib[$curTpl['realm']] <= 0)
|
|
{
|
|
unset($this->templates[$guid]);
|
|
continue;
|
|
}
|
|
|
|
$distrib[$curTpl['realm']]--;
|
|
$limit--;
|
|
}
|
|
}
|
|
|
|
public function initializeLocalEntries()
|
|
{
|
|
$data = [];
|
|
foreach ($this->iterate() as $guid => $__)
|
|
{
|
|
$data[$guid] = array(
|
|
'realm' => $this->getField('realm'),
|
|
'realmGUID' => $this->getField('guildid'),
|
|
'name' => $this->getField('name'),
|
|
'nameUrl' => Profiler::urlize($this->getField('name')),
|
|
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
|
);
|
|
}
|
|
|
|
// basic guild data
|
|
foreach (Util::createSqlBatchInsert($data) as $ins)
|
|
DB::Aowow()->query('INSERT INTO ?_profiler_guild (?#) VALUES '.$ins.' ON DUPLICATE KEY UPDATE `id` = `id`', array_keys(reset($data)));
|
|
|
|
// merge back local ids
|
|
$localIds = DB::Aowow()->selectCol(
|
|
'SELECT CONCAT(realm, ":", realmGUID) AS ARRAY_KEY, id FROM ?_profiler_guild WHERE realm IN (?a) AND realmGUID IN (?a)',
|
|
array_column($data, 'realm'),
|
|
array_column($data, 'realmGUID')
|
|
);
|
|
|
|
foreach ($this->iterate() as $guid => &$_curTpl)
|
|
if (isset($localIds[$guid]))
|
|
$_curTpl['id'] = $localIds[$guid];
|
|
}
|
|
}
|
|
|
|
|
|
class LocalGuildList extends GuildList
|
|
{
|
|
protected $queryBase = 'SELECT g.*, g.id AS ARRAY_KEY FROM ?_profiler_guild g';
|
|
|
|
public function __construct(array $conditions = [], array $miscData = [])
|
|
{
|
|
parent::__construct($conditions, $miscData);
|
|
|
|
if ($this->error)
|
|
return;
|
|
|
|
$realms = Profiler::getRealms();
|
|
|
|
foreach ($this->iterate() as $id => &$curTpl)
|
|
{
|
|
if ($curTpl['realm'] && !isset($realms[$curTpl['realm']]))
|
|
continue;
|
|
|
|
if (isset($realms[$curTpl['realm']]))
|
|
{
|
|
$curTpl['realmName'] = $realms[$curTpl['realm']]['name'];
|
|
$curTpl['region'] = $realms[$curTpl['realm']]['region'];
|
|
}
|
|
|
|
// battlegroup
|
|
$curTpl['battlegroup'] = Cfg::get('BATTLEGROUP');
|
|
}
|
|
}
|
|
|
|
public function getProfileUrl()
|
|
{
|
|
$url = '?guild=';
|
|
|
|
return $url.implode('.', array(
|
|
Profiler::urlize($this->getField('region')),
|
|
Profiler::urlize($this->getField('realmName')),
|
|
Profiler::urlize($this->getField('name'))
|
|
));
|
|
}
|
|
}
|
|
|
|
|
|
?>
|