Files
aowow/includes/types/guild.class.php
Sarjuuk cd94a2fa4e Profiler/Misc
* fix realm selection in profiler filters
 * minor cleanup of prQueue
2025-06-17 17:45:49 +02:00

316 lines
11 KiB
PHP

<?php
namespace Aowow;
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
{
use TrProfilerFilter;
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;
}
}
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('RemoteGuildList::__construct - cannot access any realm.', 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']]++;
}
foreach ($conditions as $c)
if (is_int($c))
$limit = $c;
$limit ??= Cfg::get('SQL_LIMIT_DEFAULT');
if (!$limit) // int:0 means unlimited, so skip early
return;
$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 = [])
{
$realms = Profiler::getRealms();
// graft realm selection from miscData onto conditions
if (isset($miscData['sv']))
$realms = array_filter($realms, fn($x) => Profiler::urlize($x['name']) == Profiler::urlize($miscData['sv']));
if (isset($miscData['rg']))
$realms = array_filter($realms, fn($x) => $x['region'] == $miscData['rg']);
if (!$realms)
{
trigger_error('LocalGuildList::__construct - cannot access any realm.', E_USER_WARNING);
return;
}
if ($conditions)
{
array_unshift($conditions, 'AND');
$conditions = ['AND', ['realm', array_keys($realms)], $conditions];
}
else
$conditions = [['realm', array_keys($realms)]];
parent::__construct($conditions, $miscData);
if ($this->error)
return;
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'))
));
}
}
?>