mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Profiler/Backend
* added core functions nessecary for profiler
This commit is contained in:
@@ -10,6 +10,10 @@ Order Deny,Allow
|
||||
ForceType application/x-httpd-php
|
||||
</Files>
|
||||
|
||||
<Files "prQueue">
|
||||
ForceType application/x-httpd-php
|
||||
</Files>
|
||||
|
||||
# Block view of some folders
|
||||
Options -Indexes
|
||||
DirectoryIndex index.php
|
||||
|
||||
@@ -7,12 +7,15 @@ class AjaxAccount extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['exclude', 'weightscales'];
|
||||
protected $_post = array(
|
||||
// 'groups' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkInt']],
|
||||
'groups' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'save' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'delete' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'id' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkIdList']],
|
||||
'name' => [FILTER_CALLBACK, ['options' => 'AjaxAccount::checkName']],
|
||||
'scale' => [FILTER_CALLBACK, ['options' => 'AjaxAccount::checkScale']],
|
||||
'reset' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'mode' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'type' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
);
|
||||
protected $_get = array(
|
||||
'locale' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkLocale']]
|
||||
@@ -37,10 +40,41 @@ class AjaxAccount extends AjaxHandler
|
||||
|
||||
protected function handleExclude()
|
||||
{
|
||||
// profiler completion exclude handler
|
||||
// $this->_post['groups'] = bitMask of excludeGroupIds when using .. excludeGroups .. duh
|
||||
// should probably occur in g_user.excludegroups (dont forget to also set g_users.settings = {})
|
||||
return '';
|
||||
if (!User::$id)
|
||||
return;
|
||||
|
||||
if ($this->_post['mode'] == 1) // directly set exludes
|
||||
{
|
||||
$type = $this->_post['type'];
|
||||
$ids = $this->_post['id'];
|
||||
|
||||
if (!isset(Util::$typeStrings[$type]) || empty($ids))
|
||||
return;
|
||||
|
||||
// ready for some bullshit? here it comes!
|
||||
// we don't get signaled whether an id should be added to or removed from either includes or excludes
|
||||
// so we throw everything into one table and toggle the mode if its already in here
|
||||
|
||||
$includes = DB::Aowow()->selectCol('SELECT typeId FROM ?_profiler_excludes WHERE type = ?d AND typeId IN (?a)', $type, $ids);
|
||||
|
||||
foreach ($ids as $typeId)
|
||||
DB::Aowow()->query('INSERT INTO ?_account_excludes (`userId`, `type`, `typeId`, `mode`) VALUES (?a) ON DUPLICATE KEY UPDATE mode = (mode ^ 0x3)', array(
|
||||
User::$id, $type, $typeId, in_array($includes, $typeId) ? 2 : 1
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
else if ($this->_post['reset'] == 1) // defaults to unavailable
|
||||
{
|
||||
$mask = PR_EXCLUDE_GROUP_UNAVAILABLE;
|
||||
DB::Aowow()->query('DELETE FROM ?_account_excludes WHERE userId = ?d', User::$id);
|
||||
}
|
||||
else // clamp to real groups
|
||||
$mask = $this->_post['groups'] & PR_EXCLUDE_GROUP_ANY;
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account SET excludeGroups = ?d WHERE id = ?d', $mask, User::$id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
protected function handleWeightscales()
|
||||
|
||||
82
includes/ajaxHandler/arenateam.class.php
Normal file
82
includes/ajaxHandler/arenateam.class.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('invalid access');
|
||||
|
||||
class AjaxArenaTeam extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['resync', 'status'];
|
||||
protected $_get = array(
|
||||
'id' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkIdList']],
|
||||
'profile' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkEmptySet']],
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params)
|
||||
return;
|
||||
|
||||
switch ($this->params[0])
|
||||
{
|
||||
case 'resync':
|
||||
$this->handler = 'handleResync';
|
||||
break;
|
||||
case 'status':
|
||||
$this->handler = 'handleStatus';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional, not used]
|
||||
profile: <empty> [optional, also get related chars]
|
||||
return: 1
|
||||
*/
|
||||
protected function handleResync()
|
||||
{
|
||||
if ($teams = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_arena_team WHERE id IN (?a)', $this->_get['id']))
|
||||
foreach ($teams as $t)
|
||||
Profiler::scheduleResync(TYPE_ARENA_TEAM, $t['realm'], $t['realmGUID']);
|
||||
|
||||
if ($this->_get['profile'])
|
||||
if ($chars = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_profiles p JOIN ?_profiler_arena_team_member atm ON atm.profileId = p.id WHERE atm.arenaTeamId IN (?a)', $this->_get['id']))
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(TYPE_PROFILE, $c['realm'], $c['realmGUID']);
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
<status object>
|
||||
[
|
||||
nQueueProcesses,
|
||||
[statusCode, timeToRefresh, curQueuePos, errorCode, nResyncTries],
|
||||
[<anotherStatus>]
|
||||
...
|
||||
]
|
||||
|
||||
not all fields are required, if zero they are omitted
|
||||
statusCode:
|
||||
0: end the request
|
||||
1: waiting
|
||||
2: working...
|
||||
3: ready; click to view
|
||||
4: error / retry
|
||||
errorCode:
|
||||
0: unk error
|
||||
1: char does not exist
|
||||
2: armory gone
|
||||
*/
|
||||
protected function handleStatus()
|
||||
{
|
||||
$response = Profiler::resyncStatus(TYPE_ARENA_TEAM, $this->_get['id']);
|
||||
return Util::toJSON($response);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -62,6 +62,15 @@ class AjaxFilter extends AjaxHandler
|
||||
case 'spells':
|
||||
$this->filter = (new SpellListFilter(true, $opts));
|
||||
break;
|
||||
case 'profiles':
|
||||
$this->filter = (new ProfileListFilter(true, $opts));
|
||||
break;
|
||||
case 'guilds':
|
||||
$this->filter = (new GuildListFilter(true, $opts));
|
||||
break;
|
||||
case 'arena-teams':
|
||||
$this->filter = (new ArenaTeamListFilter(true, $opts));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
82
includes/ajaxHandler/guild.class.php
Normal file
82
includes/ajaxHandler/guild.class.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('invalid access');
|
||||
|
||||
class AjaxGuild extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['resync', 'status'];
|
||||
protected $_get = array(
|
||||
'id' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkIdList']],
|
||||
'profile' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkEmptySet']],
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params)
|
||||
return;
|
||||
|
||||
switch ($this->params[0])
|
||||
{
|
||||
case 'resync':
|
||||
$this->handler = 'handleResync';
|
||||
break;
|
||||
case 'status':
|
||||
$this->handler = 'handleStatus';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional, not used]
|
||||
profile: <empty> [optional, also get related chars]
|
||||
return: 1
|
||||
*/
|
||||
protected function handleResync()
|
||||
{
|
||||
if ($guilds = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_guild WHERE id IN (?a)', $this->_get['id']))
|
||||
foreach ($guilds as $g)
|
||||
Profiler::scheduleResync(TYPE_GUILD, $g['realm'], $g['realmGUID']);
|
||||
|
||||
if ($this->_get['profile'])
|
||||
if ($chars = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_profiles WHERE guild IN (?a)', $this->_get['id']))
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(TYPE_PROFILE, $c['realm'], $c['realmGUID']);
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
<status object>
|
||||
[
|
||||
nQueueProcesses,
|
||||
[statusCode, timeToRefresh, curQueuePos, errorCode, nResyncTries],
|
||||
[<anotherStatus>]
|
||||
...
|
||||
]
|
||||
|
||||
not all fields are required, if zero they are omitted
|
||||
statusCode:
|
||||
0: end the request
|
||||
1: waiting
|
||||
2: working...
|
||||
3: ready; click to view
|
||||
4: error / retry
|
||||
errorCode:
|
||||
0: unk error
|
||||
1: char does not exist
|
||||
2: armory gone
|
||||
*/
|
||||
protected function handleStatus()
|
||||
{
|
||||
$response = Profiler::resyncStatus(TYPE_GUILD, $this->_get['id']);
|
||||
return Util::toJSON($response);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -5,11 +5,39 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class AjaxProfile extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['link', 'unlink', 'pin', 'unpin', 'public', 'private', 'avatar', 'resync', 'status', 'delete', 'purge', 'summary', 'load'];
|
||||
private $undo = false;
|
||||
|
||||
protected $validParams = ['link', 'unlink', 'pin', 'unpin', 'public', 'private', 'avatar', 'resync', 'status', 'save', 'delete', 'purge', 'summary', 'load'];
|
||||
protected $_get = array(
|
||||
'id' => [FILTER_CALLBACK, ['options' => 'AjaxProfile::checkId']],
|
||||
// 'items' => [FILTER_CALLBACK, ['options' => 'AjaxProfile::checkItems']],
|
||||
'id' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkIdList']],
|
||||
'items' => [FILTER_CALLBACK, ['options' => 'AjaxProfile::checkItemList']],
|
||||
'size' => [FILTER_SANITIZE_STRING, 0xC], // FILTER_FLAG_STRIP_LOW | *_HIGH
|
||||
'guild' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkEmptySet']],
|
||||
'arena-team' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkEmptySet']],
|
||||
);
|
||||
|
||||
protected $_post = array(
|
||||
'name' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkFulltext']],
|
||||
'level' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'class' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'race' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'gender' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'nomodel' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'talenttree1' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'talenttree2' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'talenttree3' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'activespec' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'talentbuild1' => [FILTER_SANITIZE_STRING, 0xC],// FILTER_FLAG_STRIP_LOW | *_HIGH
|
||||
'glyphs1' => [FILTER_SANITIZE_STRING, 0xC],
|
||||
'talentbuild2' => [FILTER_SANITIZE_STRING, 0xC],
|
||||
'glyphs2' => [FILTER_SANITIZE_STRING, 0xC],
|
||||
'icon' => [FILTER_SANITIZE_STRING, 0xC],
|
||||
'description' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkFulltext']],
|
||||
'source' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'copy' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'public' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'gearscore' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'inv' => [FILTER_CALLBACK, ['options' => 'AjaxProfile::checkItemString', 'flags' => FILTER_REQUIRE_ARRAY]],
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
@@ -21,24 +49,29 @@ class AjaxProfile extends AjaxHandler
|
||||
|
||||
switch ($this->params[0])
|
||||
{
|
||||
case 'link':
|
||||
case 'unlink':
|
||||
$this->undo = true;
|
||||
case 'link':
|
||||
$this->handler = 'handleLink'; // always returns null
|
||||
break;
|
||||
case 'pin':
|
||||
case 'unpin':
|
||||
$this->undo = true;
|
||||
case 'pin':
|
||||
$this->handler = 'handlePin'; // always returns null
|
||||
break;
|
||||
case 'public':
|
||||
case 'private':
|
||||
$this->undo = true;
|
||||
case 'public':
|
||||
$this->handler = 'handlePrivacy'; // always returns null
|
||||
break;
|
||||
case 'avatar':
|
||||
$this->handler = 'handleAvatar'; // sets an image header
|
||||
break; // so it has to die here or another header will be set
|
||||
case 'resync':
|
||||
$this->handler = 'handleResync'; // always returns "1"
|
||||
break;
|
||||
case 'status':
|
||||
$this->handler = 'handleResync';
|
||||
$this->handler = 'handleStatus'; // returns status object
|
||||
break;
|
||||
case 'save':
|
||||
$this->handler = 'handleSave';
|
||||
@@ -57,33 +90,86 @@ class AjaxProfile extends AjaxHandler
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleLink($id, $mode) // links char with account
|
||||
{
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handleLink() // links char with account
|
||||
{
|
||||
if (!User::$id || empty($this->_get['id']))
|
||||
return;
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$uid = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $this->_get['user']);
|
||||
else if ($this->_get['user'])
|
||||
return;
|
||||
|
||||
if ($this->undo)
|
||||
DB::Aowow()->query('DELETE FROM ?_account_profiles WHERE accountId = ?d AND profileId IN (?a)', $uid, $this->_get['id']);
|
||||
else
|
||||
foreach ($this->_get['id'] as $prId) // only link characters, not custom profiles
|
||||
if ($prId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE id = ?d AND realm IS NOT NULL', $prId))
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_account_profiles VALUES (?d, ?d, 0)', $uid, $prId);
|
||||
}
|
||||
|
||||
protected function handlePin($id, $mode) // (un)favorite
|
||||
{
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handlePin() // (un)favorite
|
||||
{
|
||||
if (!User::$id || empty($this->_get['id'][0]))
|
||||
return;
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$uid = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $this->_get['user']);
|
||||
else if ($this->_get['user'])
|
||||
return;
|
||||
|
||||
// since only one character can be pinned at a time we can reset everything
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET extraFlags = extraFlags & ?d WHERE accountId = ?d', ~PROFILER_CU_PINNED, $uid);
|
||||
// and set a single char if nesecary
|
||||
if (!$this->undo)
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET extraFlags = extraFlags | ?d WHERE profileId = ?d AND accountId = ?d', PROFILER_CU_PINNED, $this->_get['id'][0], $uid);
|
||||
}
|
||||
|
||||
protected function handlePrivacy($id, $mode) // public visibility
|
||||
{
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handlePrivacy() // public visibility
|
||||
{
|
||||
if (!User::$id || empty($this->_get['id'][0]))
|
||||
return;
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$uid = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $this->_get['user']);
|
||||
else if ($this->_get['user'])
|
||||
return;
|
||||
|
||||
if ($this->undo)
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET extraFlags = extraFlags & ?d WHERE profileId IN (?a) AND accountId = ?d', ~PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET cuFlags = cuFlags & ?d WHERE id IN (?a) AND user = ?d', ~PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET extraFlags = extraFlags | ?d WHERE profileId IN (?a) AND accountId = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET cuFlags = cuFlags | ?d WHERE id IN (?a) AND user = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId>
|
||||
size: <string> [optional]
|
||||
return: image-header
|
||||
*/
|
||||
protected function handleAvatar() // image
|
||||
{
|
||||
// something happened in the last years: those textures do not include tiny icons
|
||||
@@ -125,21 +211,31 @@ class AjaxProfile extends AjaxHandler
|
||||
return;
|
||||
}
|
||||
|
||||
protected function handleResync() // resync init and status requests
|
||||
{
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return
|
||||
null [onOK]
|
||||
int or str [onError]
|
||||
user: <string> [optional, not used]
|
||||
return: 1
|
||||
*/
|
||||
|
||||
if ($this->params[0] == 'resync')
|
||||
return '1';
|
||||
else // $this->params[0] == 'status'
|
||||
protected function handleResync()
|
||||
{
|
||||
/*
|
||||
if ($chars = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_profiles WHERE id IN (?a)', $this->_get['id']))
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(TYPE_PROFILE, $c['realm'], $c['realmGUID']);
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
<status object>
|
||||
[
|
||||
nQueueProcesses,
|
||||
[statusCode, timeToRefresh, curQueuePos, errorCode, nResyncTries],
|
||||
[<anotherStatus>]
|
||||
...
|
||||
]
|
||||
|
||||
not all fields are required, if zero they are omitted
|
||||
statusCode:
|
||||
0: end the request
|
||||
@@ -151,59 +247,175 @@ class AjaxProfile extends AjaxHandler
|
||||
0: unk error
|
||||
1: char does not exist
|
||||
2: armory gone
|
||||
|
||||
[
|
||||
processId,
|
||||
[StatusCode, timeToRefresh, iCount, errorCode, iNResyncs],
|
||||
[<anotherStatus>]...
|
||||
]
|
||||
*/
|
||||
return '[0, [4, 10000, 1, 2]]';
|
||||
}
|
||||
protected function handleStatus()
|
||||
{
|
||||
// roster resync for this guild was requested -> get char list
|
||||
if ($this->_get['guild'])
|
||||
$ids = DB::Aowow()->selectCol('SELECT id FROM ?_profiler_profiles WHERE guild IN (?a)', $this->_get['id']);
|
||||
else if ($this->_get['arena-team'])
|
||||
$ids = DB::Aowow()->selectCol('SELECT profileId FROM ?_profiler_arena_team_member WHERE arenaTeamId IN (?a)', $this->_get['id']);
|
||||
else
|
||||
$ids = $this->_get['id'];
|
||||
|
||||
$response = Profiler::resyncStatus(TYPE_PROFILE, $ids);
|
||||
return Util::toJSON($response);
|
||||
}
|
||||
|
||||
/* params (get))
|
||||
id: <prId1,0> [0: new profile]
|
||||
params (post)
|
||||
<various char data> [see below]
|
||||
return:
|
||||
proileId [onSuccess]
|
||||
-1 [onError]
|
||||
*/
|
||||
protected function handleSave() // unKill a profile
|
||||
{
|
||||
/* params GET
|
||||
// todo (med): detail check this post-data
|
||||
$cuProfile = array(
|
||||
'user' => User::$id,
|
||||
// 'userName' => User::$displayName,
|
||||
'name' => $this->_post['name'],
|
||||
'level' => $this->_post['level'],
|
||||
'class' => $this->_post['class'],
|
||||
'race' => $this->_post['race'],
|
||||
'gender' => $this->_post['gender'],
|
||||
'nomodelMask' => $this->_post['nomodel'],
|
||||
'talenttree1' => $this->_post['talenttree1'],
|
||||
'talenttree2' => $this->_post['talenttree2'],
|
||||
'talenttree3' => $this->_post['talenttree3'],
|
||||
'talentbuild1' => $this->_post['talentbuild1'],
|
||||
'talentbuild2' => $this->_post['talentbuild2'],
|
||||
'activespec' => $this->_post['activespec'],
|
||||
'glyphs1' => $this->_post['glyphs1'],
|
||||
'glyphs2' => $this->_post['glyphs2'],
|
||||
'gearscore' => $this->_post['gearscore'],
|
||||
'icon' => $this->_post['icon'],
|
||||
'cuFlags' => PROFILER_CU_PROFILE | ($this->_post['public'] ? PROFILER_CU_PUBLISHED : 0)
|
||||
);
|
||||
|
||||
if (strstr($cuProfile['icon'], 'profile=avatar')) // how the profiler is supposed to handle icons is beyond me
|
||||
$cuProfile['icon'] = '';
|
||||
|
||||
if ($_ = $this->_post['description'])
|
||||
$cuProfile['description'] = $_;
|
||||
|
||||
if ($_ = $this->_post['source']) // should i also set sourcename?
|
||||
$cuProfile['sourceId'] = $_;
|
||||
|
||||
if ($_ = $this->_post['copy']) // gets set to source profileId when "save as" is clicked. Whats the difference to 'source' though?
|
||||
{
|
||||
// get character origin info if possible
|
||||
if ($r = DB::Aowow()->selectCell('SELECT realm FROM ?_profiler_profiles WHERE id = ?d AND realm IS NOT NULL', $_))
|
||||
$cuProfile['realm'] = $r;
|
||||
|
||||
$cuProfile['sourceId'] = $_;
|
||||
}
|
||||
|
||||
if ($cuProfile['sourceId'])
|
||||
$cuProfile['sourceName'] = DB::Aowow()->selectCell('SELECT name FROM ?_profiler_profiles WHERE id = ?d', $cuProfile['sourceId']);
|
||||
|
||||
$charId = -1;
|
||||
if ($id = $this->_get['id'][0]) // update
|
||||
{
|
||||
if ($charId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE id = ?d', $id))
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET ?a WHERE id = ?d', $cuProfile, $id);
|
||||
}
|
||||
else // new
|
||||
{
|
||||
$nProfiles = DB::Aowow()->selectCell('SELECT COUNT(*) FROM ?_profiler_profiles WHERE user = ?d AND realmGUID IS NULL', User::$id);
|
||||
if ($nProfiles < 10 || User::isPremium())
|
||||
if ($newId = DB::Aowow()->query('INSERT INTO ?_profiler_profiles (?#) VALUES (?a)', array_keys($cuProfile), array_values($cuProfile)))
|
||||
$charId = $newId;
|
||||
}
|
||||
|
||||
// update items
|
||||
if ($charId != -1)
|
||||
{
|
||||
// ok, 'funny' thing: wether an item has en extra prismatic sockel is determined contextual
|
||||
// either the socket is -1 or it has an itemId in a socket where there shouldn't be one
|
||||
$keys = ['id', 'slot', 'item', 'subitem', 'permEnchant', 'tempEnchant', 'gem1', 'gem2', 'gem3', 'gem4'];
|
||||
|
||||
// validate Enchantments
|
||||
$enchIds = array_merge(
|
||||
array_column($this->_post['inv'], 3), // perm enchantments
|
||||
array_column($this->_post['inv'], 4) // temp enchantments (not used..?)
|
||||
);
|
||||
$enchs = new EnchantmentList(array(['id', $enchIds]));
|
||||
|
||||
// validate items
|
||||
$itemIds = array_merge(
|
||||
array_column($this->_post['inv'], 1), // base item
|
||||
array_column($this->_post['inv'], 5), // gem slot 1
|
||||
array_column($this->_post['inv'], 6), // gem slot 2
|
||||
array_column($this->_post['inv'], 7), // gem slot 3
|
||||
array_column($this->_post['inv'], 8) // gem slot 4
|
||||
);
|
||||
|
||||
$items = new ItemList(array(['id', $itemIds]));
|
||||
if (!$items->error)
|
||||
{
|
||||
foreach ($this->_post['inv'] as $slot => $itemData)
|
||||
{
|
||||
if ($slot + 1 == array_sum($itemData)) // only slot definition set => empty slot
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_items WHERE id = ?d AND slot = ?d', $charId, $itemData[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// item does not exist
|
||||
if (!$items->getEntry($itemData[1]))
|
||||
continue;
|
||||
|
||||
// sub-item check
|
||||
if (!$items->getRandEnchantForItem($itemData[1]))
|
||||
$itemData[2] = 0;
|
||||
|
||||
// item sockets are fubar
|
||||
$nSockets = $items->json[$itemData[1]]['nsockets'];
|
||||
$nSockets += in_array($slot, [SLOT_WAIST, SLOT_WRISTS, SLOT_HANDS]) ? 1 : 0;
|
||||
for ($i = 5; $i < 9; $i++)
|
||||
if ($itemData[$i] > 0 && (!$items->getEntry($itemData[$i]) || $i >= (5 + $nSockets)))
|
||||
$itemData[$i] = 0;
|
||||
|
||||
// item enchantments are borked
|
||||
if ($itemData[3] && !$enchs->getEntry($itemData[3]))
|
||||
$itemData[3] = 0;
|
||||
|
||||
if ($itemData[4] && !$enchs->getEntry($itemData[4]))
|
||||
$itemData[4] = 0;
|
||||
|
||||
// looks good
|
||||
array_unshift($itemData, $charId);
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_items (?#) VALUES (?a)', $keys, $itemData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $charId;
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
params POST
|
||||
name, level, class, race, gender, nomodel, talenttree1, talenttree2, talenttree3, activespec, talentbuild1, glyphs1, talentbuild2, glyphs2, gearscore, icon, public [always]
|
||||
description, source, copy, inv { inventory: array containing itemLinks } [optional]
|
||||
}
|
||||
return
|
||||
int > 0 [profileId, if we came from an armoryProfile create a new one]
|
||||
int < 0 [onError]
|
||||
str [onError]
|
||||
null
|
||||
*/
|
||||
|
||||
return 'NYI';
|
||||
}
|
||||
|
||||
protected function handleDelete() // kill a profile
|
||||
{
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
null
|
||||
*/
|
||||
if (!$this->_get['id'])
|
||||
return;
|
||||
|
||||
return 'NYI';
|
||||
// only flag as deleted; only custom profiles
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_profiler_profiles SET cuFlags = cuFlags | ?d WHERE id IN (?a) AND cuFlags & ?d {AND user = ?d}',
|
||||
PROFILER_CU_DELETED,
|
||||
$this->_get['id'],
|
||||
PROFILER_CU_PROFILE,
|
||||
User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
}
|
||||
|
||||
protected function handlePurge() // removes certain saved information but not the entire character
|
||||
{
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
data: <mode> [string, tabName?]
|
||||
return
|
||||
null
|
||||
*/
|
||||
|
||||
return 'NYI';
|
||||
}
|
||||
|
||||
protected function handleLoad()
|
||||
{
|
||||
/* params
|
||||
id: profileId
|
||||
items: string [itemIds.join(':')]
|
||||
@@ -211,109 +423,290 @@ class AjaxProfile extends AjaxHandler
|
||||
return
|
||||
lots...
|
||||
*/
|
||||
|
||||
// titles, achievements, characterData, talents (, pets)
|
||||
protected function handleLoad()
|
||||
{
|
||||
// titles, achievements, characterData, talents, pets
|
||||
// and some onLoad-hook to .. load it registerProfile($data)
|
||||
// everything else goes through data.php .. strangely enough
|
||||
|
||||
if (!$this->_get['id'])
|
||||
return;
|
||||
|
||||
$char = new ProfileList(array(['id', $this->_get['id'][0]])); // or string or whatever
|
||||
$pBase = DB::Aowow()->selectRow('SELECT pg.name AS guildname, p.* FROM ?_profiler_profiles p LEFT JOIN ?_profiler_guild pg ON pg.id = p.guild WHERE p.id = ?d', $this->_get['id'][0]);
|
||||
if (!$pBase)
|
||||
{
|
||||
trigger_error('Profiler::handleLoad() - called with invalid profileId #'.$this->_get['id'][0], E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (($pBase['cuFlags'] & PROFILER_CU_DELETED) && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
return;
|
||||
|
||||
|
||||
$rData = [];
|
||||
foreach (Profiler::getRealms() as $rId => $rData)
|
||||
if ($rId == $pBase['realm'])
|
||||
break;
|
||||
|
||||
$profile = array(
|
||||
'id' => $pBase['id'],
|
||||
'source' => $pBase['id'],
|
||||
'level' => $pBase['level'],
|
||||
'classs' => $pBase['class'],
|
||||
'race' => $pBase['race'],
|
||||
'faction' => Game::sideByRaceMask(1 << ($pBase['race'] - 1)) - 1,
|
||||
'gender' => $pBase['gender'],
|
||||
'skincolor' => $pBase['skincolor'],
|
||||
'hairstyle' => $pBase['hairstyle'],
|
||||
'haircolor' => $pBase['haircolor'],
|
||||
'facetype' => $pBase['facetype'],
|
||||
'features' => $pBase['features'],
|
||||
'title' => $pBase['title'],
|
||||
'name' => $pBase['name'],
|
||||
'guild' => "$'".$pBase['guildname']."'",
|
||||
'published' => !!($pBase['cuFlags'] & PROFILER_CU_PUBLISHED),
|
||||
'pinned' => !!($pBase['cuFlags'] & PROFILER_CU_PINNED),
|
||||
'nomodel' => $pBase['nomodelMask'],
|
||||
'playedtime' => $pBase['playedtime'],
|
||||
'lastupdated' => $pBase['lastupdated'] * 1000,
|
||||
'talents' => array(
|
||||
'builds' => array( // notice the bullshit to prevent the talent-string from becoming a float! NOTICE IT!!
|
||||
['talents' => '$"'.$pBase['talentbuild1'].'"', 'glyphs' => $pBase['glyphs1']],
|
||||
['talents' => '$"'.$pBase['talentbuild2'].'"', 'glyphs' => $pBase['glyphs2']]
|
||||
),
|
||||
'active' => $pBase['activespec']
|
||||
),
|
||||
// set later
|
||||
'inventory' => [],
|
||||
'bookmarks' => [], // list of userIds who claimed this profile (claiming and owning are two different things)
|
||||
|
||||
// completion lists: [subjectId => amount/timestamp/1]
|
||||
'skills' => [], // skillId => [curVal, maxVal]
|
||||
'reputation' => [], // factionId => curVal
|
||||
'titles' => [], // titleId => 1
|
||||
'spells' => [], // spellId => 1; recipes, vanity pets, mounts
|
||||
'achievements' => [], // achievementId => timestamp
|
||||
'quests' => [], // questId => 1
|
||||
'achievementpoints' => 0, // max you have
|
||||
'statistics' => [], // all raid activity [achievementId => killCount]
|
||||
'activity' => [], // recent raid activity [achievementId => 1] (is a subset of statistics)
|
||||
);
|
||||
|
||||
if ($pBase['cuFlags'] & PROFILER_CU_PROFILE)
|
||||
{
|
||||
// this parameter is _really_ strange .. probably still not doing this right
|
||||
$profile['source'] = $pBase['realm'] ? $pBase['sourceId'] : 0;
|
||||
|
||||
$profile['sourcename'] = $pBase['sourceName'];
|
||||
$profile['description'] = $pBase['description'];
|
||||
$profile['user'] = $pBase['user'];
|
||||
$profile['username'] = DB::Aowow()->selectCell('SELECT displayName FROM ?_account WHERE id = ?d', $pBase['user']);
|
||||
}
|
||||
|
||||
// custom profiles inherit this when copied from real char :(
|
||||
if ($pBase['realm'])
|
||||
{
|
||||
$profile['region'] = [$rData['region'], Lang::profiler('regions', $rData['region'])];
|
||||
$profile['battlegroup'] = [Profiler::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP];
|
||||
$profile['realm'] = [Profiler::urlize($rData['name']), $rData['name']];
|
||||
}
|
||||
|
||||
// bookmarks
|
||||
if ($_ = DB::Aowow()->selectCol('SELECT accountId FROM ?_account_profiles WHERE profileId = ?d', $pBase['id']))
|
||||
$profile['bookmarks'] = $_;
|
||||
|
||||
// arena teams - [size(2|3|5) => DisplayName]; DisplayName gets urlized to use as link
|
||||
if ($at = DB::Aowow()->selectCol('SELECT type AS ARRAY_KEY, name FROM ?_profiler_arena_team at JOIN ?_profiler_arena_team_member atm ON atm.arenaTeamId = at.id WHERE atm.profileId = ?d', $pBase['id']))
|
||||
$profile['arenateams'] = $at;
|
||||
|
||||
// pets if hunter fields: [name:name, family:petFamily, npc:npcId, displayId:modelId, talents:talentString]
|
||||
if ($pets = DB::Aowow()->select('SELECT name, family, npc, displayId, talents FROM ?_profiler_pets WHERE owner = ?d', $pBase['id']))
|
||||
$profile['pets'] = $pets;
|
||||
|
||||
// source for custom profiles; profileId => [name, ownerId, iconString(optional)]
|
||||
if ($customs = DB::Aowow()->select('SELECT id AS ARRAY_KEY, name, user, icon FROM ?_profiler_profiles WHERE sourceId = ?d AND sourceId <> id', $pBase['id']))
|
||||
{
|
||||
foreach ($customs as $id => $cu)
|
||||
{
|
||||
if (!$cu['icon'])
|
||||
unset($cu['icon']);
|
||||
|
||||
$profile['customs'][$id] = array_values($cu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* $profile[]
|
||||
// CUSTOM
|
||||
'auras' => [], // custom list of buffs, debuffs [spellId]
|
||||
|
||||
// UNUSED
|
||||
'glyphs' => [], // provided list of already known glyphs (post cataclysm feature)
|
||||
*/
|
||||
|
||||
|
||||
$completion = DB::Aowow()->select('SELECT type AS ARRAY_KEY, typeId AS ARRAY_KEY2, cur, max FROM ?_profiler_completion WHERE id = ?d', $pBase['id']);
|
||||
foreach ($completion as $type => $data)
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case TYPE_FACTION: // factionId => amount
|
||||
$profile['reputation'] = array_combine(array_keys($data), array_column($data, 'cur'));
|
||||
break;
|
||||
case TYPE_TITLE:
|
||||
foreach ($data as &$d)
|
||||
$d = 1;
|
||||
|
||||
$profile['titles'] = $data;
|
||||
break;
|
||||
case TYPE_QUEST:
|
||||
foreach ($data as &$d)
|
||||
$d = 1;
|
||||
|
||||
$profile['quests'] = $data;
|
||||
break;
|
||||
case TYPE_SPELL:
|
||||
foreach ($data as &$d)
|
||||
$d = 1;
|
||||
|
||||
$profile['spells'] = $data;
|
||||
break;
|
||||
case TYPE_ACHIEVEMENT:
|
||||
$achievements = array_filter($data, function ($x) { return $x['max'] === null; });
|
||||
$statistics = array_filter($data, function ($x) { return $x['max'] !== null; });
|
||||
|
||||
// achievements
|
||||
$profile['achievements'] = array_combine(array_keys($achievements), array_column($achievements, 'cur'));
|
||||
$profile['achievementpoints'] = DB::Aowow()->selectCell('SELECT SUM(points) FROM ?_achievement WHERE id IN (?a)', array_keys($achievements));
|
||||
|
||||
// raid progression
|
||||
$activity = array_filter($statistics, function ($x) { return $x['cur'] > (time() - MONTH); });
|
||||
foreach ($activity as &$r)
|
||||
$r = 1;
|
||||
|
||||
// ony .. subtract 10-man from 25-man
|
||||
|
||||
$profile['statistics'] = array_combine(array_keys($statistics), array_column($statistics, 'max'));
|
||||
$profile['activity'] = $activity;
|
||||
break;
|
||||
case TYPE_SKILL:
|
||||
foreach ($data as &$d)
|
||||
$d = [$d['cur'], $d['max']];
|
||||
|
||||
$profile['skills'] = $data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$buff = '';
|
||||
|
||||
if ($it = array_column($char->getField('inventory'), 0))
|
||||
$usedSlots = [];
|
||||
if ($this->_get['items'])
|
||||
{
|
||||
$phItems = new ItemList(array(['id', $this->_get['items']], ['slot', INVTYPE_NON_EQUIP, '!']));
|
||||
if (!$phItems->error)
|
||||
{
|
||||
$data = $phItems->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
|
||||
foreach ($phItems->iterate() as $iId => $__)
|
||||
{
|
||||
$sl = $phItems->getField('slot');
|
||||
foreach (Profiler::$slot2InvType as $slot => $invTypes)
|
||||
{
|
||||
if (in_array($sl, $invTypes) && !in_array($slot, $usedSlots))
|
||||
{
|
||||
// get and apply inventory
|
||||
$buff .= 'g_items.add('.$iId.', {name_'.User::$localeString.":'".Util::jsEscape($phItems->getField('name', true))."', quality:".$phItems->getField('quality').", icon:'".$phItems->getField('iconString')."', jsonequip:".Util::toJSON($data[$iId])."});\n";
|
||||
$profile['inventory'][$slot] = [$iId, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
$usedSlots[] = $slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($items = DB::Aowow()->select('SELECT * FROM ?_profiler_items WHERE id = ?d', $pBase['id']))
|
||||
{
|
||||
$itemz = new ItemList(array(['id', array_column($items, 'item')], CFG_SQL_LIMIT_NONE));
|
||||
if (!$itemz->error)
|
||||
{
|
||||
$itemz = new ItemList(array(['id', $it, CFG_SQL_LIMIT_NONE]));
|
||||
$data = $itemz->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
|
||||
|
||||
foreach ($items as $i)
|
||||
{
|
||||
if ($itemz->getEntry($i['item']) && !in_array($i['slot'], $usedSlots))
|
||||
{
|
||||
// get and apply inventory
|
||||
foreach ($itemz->iterate() as $iId => $__)
|
||||
$buff .= 'g_items.add('.$iId.', {name_'.User::$localeString.":'".Util::jsEscape($itemz->getField('name', true))."', quality:".$itemz->getField('quality').", icon:'".$itemz->getField('iconString')."', jsonequip:".Util::toJSON($data[$iId])."});\n";
|
||||
$buff .= 'g_items.add('.$i['item'].', {name_'.User::$localeString.":'".Util::jsEscape($itemz->getField('name', true))."', quality:".$itemz->getField('quality').", icon:'".$itemz->getField('iconString')."', jsonequip:".Util::toJSON($data[$i['item']])."});\n";
|
||||
$profile['inventory'][$i['slot']] = [$i['item'], $i['subItem'], $i['permEnchant'], $i['tempEnchant'], $i['gem1'], $i['gem2'], $i['gem3'], $i['gem4']];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($buff)
|
||||
$buff .= "\n";
|
||||
}
|
||||
|
||||
if ($au = $char->getField('auras'))
|
||||
{
|
||||
$auraz = new SpellList(array(['id', $char->getField('auras')], CFG_SQL_LIMIT_NONE));
|
||||
$dataz = $auraz->getListviewData();
|
||||
$modz = $auraz->getProfilerMods();
|
||||
|
||||
// get and apply aura-mods
|
||||
foreach ($dataz as $id => $data)
|
||||
{
|
||||
$mods = [];
|
||||
if (!empty($modz[$id]))
|
||||
{
|
||||
foreach ($modz[$id] as $k => $v)
|
||||
{
|
||||
if (is_array($v))
|
||||
$mods[] = $v;
|
||||
else if ($str = @Game::$itemMods[$k])
|
||||
$mods[$str] = $v;
|
||||
}
|
||||
}
|
||||
// if ($au = $char->getField('auras'))
|
||||
// {
|
||||
// $auraz = new SpellList(array(['id', $char->getField('auras')], CFG_SQL_LIMIT_NONE));
|
||||
// $dataz = $auraz->getListviewData();
|
||||
// $modz = $auraz->getProfilerMods();
|
||||
|
||||
$buff .= 'g_spells.add('.$id.", {id:".$id.", name:'".Util::jsEscape(mb_substr($data['name'], 1))."', icon:'".$data['icon']."', modifier:".Util::toJSON($mods)."});\n";
|
||||
}
|
||||
$buff .= "\n";
|
||||
}
|
||||
// // get and apply aura-mods
|
||||
// foreach ($dataz as $id => $data)
|
||||
// {
|
||||
// $mods = [];
|
||||
// if (!empty($modz[$id]))
|
||||
// {
|
||||
// foreach ($modz[$id] as $k => $v)
|
||||
// {
|
||||
// if (is_array($v))
|
||||
// $mods[] = $v;
|
||||
// else if ($str = @Game::$itemMods[$k])
|
||||
// $mods[$str] = $v;
|
||||
// }
|
||||
// }
|
||||
|
||||
// $buff .= 'g_spells.add('.$id.", {id:".$id.", name:'".Util::jsEscape(mb_substr($data['name'], 1))."', icon:'".$data['icon']."', modifier:".Util::toJSON($mods)."});\n";
|
||||
// }
|
||||
// $buff .= "\n";
|
||||
// }
|
||||
|
||||
/* depending on progress-achievements
|
||||
// required by progress in JScript move to handleLoad()?
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_NPC, [29120, 31134, 29306, 29311, 23980, 27656, 26861, 26723, 28923, 15991]);
|
||||
*/
|
||||
|
||||
// load available titles
|
||||
Util::loadStaticFile('p-titles-'.$char->getField('gender'), $buff, true);
|
||||
|
||||
// load available achievements
|
||||
if (!Util::loadStaticFile('p-achievements', $buff, true))
|
||||
{
|
||||
$buff .= "\n\ng_achievement_catorder = [];";
|
||||
$buff .= "\n\ng_achievement_points = [0];";
|
||||
}
|
||||
|
||||
// excludes; structure UNK type => [maskBit => [typeIds]] ?
|
||||
/*
|
||||
g_user.excludes = [type:[typeIds]]
|
||||
g_user.includes = [type:[typeIds]]
|
||||
g_user.excludegroups = groupMask // requires g_user.settings != null
|
||||
|
||||
maskBit are matched against fieldId from excludeGroups
|
||||
id: 1, label: LANG.dialog_notavail
|
||||
id: 2, label: LANG.dialog_tcg
|
||||
id: 4, label: LANG.dialog_collector
|
||||
id: 8, label: LANG.dialog_promo
|
||||
id: 16, label: LANG.dialog_nonus
|
||||
id: 96, label: LANG.dialog_faction
|
||||
id: 896, label: LANG.dialog_profession
|
||||
id: 1024, label: LANG.dialog_noexalted
|
||||
*/
|
||||
// $buff .= "\n\ng_excludes = {};";
|
||||
Util::loadStaticFile('p-titles-'.$pBase['gender'], $buff, true);
|
||||
|
||||
// add profile to buffer
|
||||
$buff .= "\n\n\$WowheadProfiler.registerProfile(".Util::toJSON($char->getEntry(2)).");"; // can't use JSON_NUMERIC_CHECK or the talent-string becomes a float
|
||||
$buff .= "\n\n\$WowheadProfiler.registerProfile(".Util::toJSON($profile).");";
|
||||
|
||||
return $buff."\n";
|
||||
}
|
||||
|
||||
protected function checkId($val)
|
||||
/* params
|
||||
id: <prId>
|
||||
data: <mode> [string, tabName]
|
||||
return
|
||||
null
|
||||
*/
|
||||
protected function handlePurge() { } // removes completion data (as uploaded by the wowhead client) Just fail silently if someone triggers this manually
|
||||
|
||||
protected function checkItemList($val)
|
||||
{
|
||||
// expecting id-list
|
||||
if (preg_match('/\d+(,\d+)*/', $val))
|
||||
return array_map('intVal', explode(',', $val));
|
||||
// expecting item-list
|
||||
if (preg_match('/\d+(:\d+)*/', $val))
|
||||
return array_map('intval', explode(':', $val));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function checkItems($val)
|
||||
protected function checkItemString($val)
|
||||
{
|
||||
// expecting item-list
|
||||
if (preg_match('/\d+(:\d+)*/', $val))
|
||||
return array_map('intVal', explode(': ', $val));
|
||||
if (preg_match('/\d+(,\d+)*/', $val))
|
||||
return array_map('intval', explode(',', $val));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -222,8 +222,8 @@ abstract class BaseType
|
||||
if (!in_array($k, $prefixes))
|
||||
unset($this->queryOpts[$k]);
|
||||
|
||||
// prepare usage of guids if using multiple DBs
|
||||
if (count($this->dbNames) > 1)
|
||||
// prepare usage of guids if using multiple realms (which have non-zoro indizes)
|
||||
if (key($this->dbNames) != 0)
|
||||
$this->queryBase = preg_replace('/\s([^\s]+)\sAS\sARRAY_KEY/i', ' CONCAT("DB_IDX", ":", \1) AS ARRAY_KEY', $this->queryBase);
|
||||
|
||||
// insert additional selected fields
|
||||
@@ -278,10 +278,6 @@ abstract class BaseType
|
||||
if (!$this->templates)
|
||||
return;
|
||||
|
||||
// assign query results to template
|
||||
foreach ($rows as $k => $tpl)
|
||||
$this->templates[$k] = $tpl;
|
||||
|
||||
// push first element for instant use
|
||||
$this->reset();
|
||||
|
||||
@@ -388,12 +384,8 @@ abstract class BaseType
|
||||
|
||||
protected function extendQueryOpts($extra) // needs to be called from __construct
|
||||
{
|
||||
|
||||
foreach ($extra as $tbl => $sets)
|
||||
{
|
||||
if (!isset($this->queryOpts[$tbl])) // allow adding only to known tables
|
||||
continue;
|
||||
|
||||
foreach ($sets as $module => $value)
|
||||
{
|
||||
if (!$value || !is_array($value))
|
||||
@@ -419,7 +411,7 @@ abstract class BaseType
|
||||
break;
|
||||
// additional (arr)
|
||||
case 'j': // join
|
||||
if (is_array($this->queryOpts[$tbl][$module]))
|
||||
if (!empty($this->queryOpts[$tbl][$module]) && is_array($this->queryOpts[$tbl][$module]))
|
||||
$this->queryOpts[$tbl][$module][0][] = $value;
|
||||
else
|
||||
$this->queryOpts[$tbl][$module] = $value;
|
||||
@@ -744,6 +736,32 @@ trait spawnHelper
|
||||
}
|
||||
}
|
||||
|
||||
trait profilerHelper
|
||||
{
|
||||
public static $type = 0; // arena teams dont actually have one
|
||||
public static $brickFile = 'profile'; // profile is multipurpose
|
||||
|
||||
private static $subjectGUID = 0;
|
||||
|
||||
public function selectRealms($fi)
|
||||
{
|
||||
$this->dbNames = [];
|
||||
|
||||
foreach(Profiler::getRealms() as $idx => $r)
|
||||
{
|
||||
if (!empty($fi['sv']) && Profiler::urlize($r['name']) != Profiler::urlize($fi['sv']) && intVal($fi['sv']) != $idx)
|
||||
continue;
|
||||
|
||||
if (!empty($fi['rg']) && Profiler::urlize($r['region']) != Profiler::urlize($fi['rg']))
|
||||
continue;
|
||||
|
||||
$this->dbNames[$idx] = 'Characters';
|
||||
}
|
||||
|
||||
return !!$this->dbNames;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
roight!
|
||||
just noticed, that the filters on pages originally pointed to ?filter=<pageName>
|
||||
|
||||
@@ -28,7 +28,10 @@ define('TYPE_SKILL', 15);
|
||||
define('TYPE_CURRENCY', 17);
|
||||
define('TYPE_SOUND', 19);
|
||||
define('TYPE_ICON', 29);
|
||||
define('TYPE_PROFILE', 100);
|
||||
// internal types (not published to js)
|
||||
define('TYPE_GUILD', 101);
|
||||
define('TYPE_ARENA_TEAM', 102);
|
||||
define('TYPE_USER', 500);
|
||||
define('TYPE_EMOTE', 501);
|
||||
define('TYPE_ENCHANTMENT', 502);
|
||||
@@ -165,6 +168,7 @@ define('BUTTON_FORUM', 5);
|
||||
define('BUTTON_TALENT', 6);
|
||||
define('BUTTON_EQUIP', 7);
|
||||
define('BUTTON_PLAYLIST', 8);
|
||||
define('BUTTON_RESYNC', 9);
|
||||
|
||||
// generic filter handler
|
||||
define('FILTER_CR_BOOLEAN', 1);
|
||||
@@ -204,11 +208,17 @@ define('NPCINFO_REP', 0x4);
|
||||
|
||||
define('ACHIEVEMENTINFO_PROFILE', 0x1);
|
||||
|
||||
define('PROFILEINFO_PROFILE', 0x1);
|
||||
define('PROFILEINFO_CHARACTER', 0x2);
|
||||
define('PROFILEINFO_GUILD', 0x10); // like &roster
|
||||
define('PROFILEINFO_ARENA', 0x20);
|
||||
|
||||
define('SPAWNINFO_ZONES', 1); // not a mask, mutually exclusive
|
||||
define('SPAWNINFO_SHORT', 2);
|
||||
define('SPAWNINFO_FULL', 3);
|
||||
define('SPAWNINFO_QUEST', 4);
|
||||
|
||||
|
||||
// Community Content
|
||||
define('CC_FLAG_STICKY', 0x1);
|
||||
define('CC_FLAG_DELETED', 0x2);
|
||||
@@ -287,6 +297,12 @@ define('QUEST_CU_SKIP_LOG', 0x10);
|
||||
define('QUEST_CU_AUTO_ACCEPT', 0x20);
|
||||
define('QUEST_CU_PVP_ENABLED', 0x40);
|
||||
|
||||
define('PROFILER_CU_PUBLISHED', 0x01);
|
||||
define('PROFILER_CU_PINNED', 0x02);
|
||||
define('PROFILER_CU_DELETED', 0x04);
|
||||
define('PROFILER_CU_PROFILE', 0x08);
|
||||
define('PROFILER_CU_NEEDS_RESYNC', 0x10);
|
||||
|
||||
define('MAX_LEVEL', 80);
|
||||
define('WOW_BUILD', 12340);
|
||||
|
||||
@@ -869,4 +885,31 @@ define('CND_DISTANCE_TO', 35); // distance to targe
|
||||
define('CND_ALIVE', 36); // target is alive: NULL, NULL, NULL
|
||||
define('CND_HP_VAL', 37); // targets absolute health: amount, operator, NULL
|
||||
define('CND_HP_PCT', 38); // targets relative health: amount, operator, NULL
|
||||
|
||||
// profiler queue interactions
|
||||
define('PR_QUEUE_STATUS_ENDED', 0);
|
||||
define('PR_QUEUE_STATUS_WAITING', 1);
|
||||
define('PR_QUEUE_STATUS_WORKING', 2);
|
||||
define('PR_QUEUE_STATUS_READY', 3);
|
||||
define('PR_QUEUE_STATUS_ERROR', 4);
|
||||
define('PR_QUEUE_ERROR_UNK', 0);
|
||||
define('PR_QUEUE_ERROR_CHAR', 1);
|
||||
define('PR_QUEUE_ERROR_ARMORY', 2);
|
||||
|
||||
// profiler completion manager
|
||||
define('PR_EXCLUDE_GROUP_UNAVAILABLE', 0x001);
|
||||
define('PR_EXCLUDE_GROUP_TCG', 0x002);
|
||||
define('PR_EXCLUDE_GROUP_COLLECTORS_EDITION', 0x004);
|
||||
define('PR_EXCLUDE_GROUP_PROMOTION', 0x008);
|
||||
define('PR_EXCLUDE_GROUP_WRONG_REGION', 0x010);
|
||||
define('PR_EXCLUDE_GROUP_REQ_ALLIANCE', 0x020);
|
||||
define('PR_EXCLUDE_GROUP_REQ_HORDE', 0x040);
|
||||
define('PR_EXCLUDE_GROUP_OTHER_FACTION', PR_EXCLUDE_GROUP_REQ_ALLIANCE | PR_EXCLUDE_GROUP_REQ_HORDE);
|
||||
define('PR_EXCLUDE_GROUP_REQ_FISHING', 0x080);
|
||||
define('PR_EXCLUDE_GROUP_REQ_ENGINEERING', 0x100);
|
||||
define('PR_EXCLUDE_GROUP_REQ_TAILORING', 0x200);
|
||||
define('PR_EXCLUDE_GROUP_WRONG_PROFESSION', PR_EXCLUDE_GROUP_REQ_FISHING | PR_EXCLUDE_GROUP_REQ_ENGINEERING | PR_EXCLUDE_GROUP_REQ_TAILORING);
|
||||
define('PR_EXCLUDE_GROUP_REQ_CANT_BE_EXALTED', 0x400);
|
||||
define('PR_EXCLUDE_GROUP_ANY', 0x7FF);
|
||||
|
||||
?>
|
||||
|
||||
@@ -20,6 +20,7 @@ require_once 'includes/defines.php';
|
||||
require_once 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master)
|
||||
require_once 'includes/utilities.php'; // helper functions
|
||||
require_once 'includes/game.php'; // game related data & functions
|
||||
require_once 'includes/profiler.class.php';
|
||||
require_once 'includes/user.class.php';
|
||||
require_once 'includes/markup.class.php'; // manipulate markup text
|
||||
require_once 'includes/database.class.php'; // wrap DBSimple
|
||||
@@ -43,10 +44,18 @@ spl_autoload_register(function ($class) {
|
||||
{
|
||||
require_once 'includes/basetype.class.php';
|
||||
|
||||
if (file_exists('includes/types/'.strtr($class, ['list' => '']).'.class.php'))
|
||||
require_once 'includes/types/'.strtr($class, ['list' => '']).'.class.php';
|
||||
$cl = strtr($class, ['list' => '']);
|
||||
if ($cl == 'remoteprofile' || $cl == 'localprofile')
|
||||
$cl = 'profile';
|
||||
if ($cl == 'remotearenateam' || $cl == 'localarenateam')
|
||||
$cl = 'arenateam';
|
||||
if ($cl == 'remoteguild' || $cl == 'localguild')
|
||||
$cl = 'guild';
|
||||
|
||||
if (file_exists('includes/types/'.$cl.'.class.php'))
|
||||
require_once 'includes/types/'.$cl.'.class.php';
|
||||
else
|
||||
throw new Exception('could not register type class: '.$class);
|
||||
throw new Exception('could not register type class: '.$cl);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -206,7 +215,7 @@ if (!CLI)
|
||||
die('error: SITE_HOST or STATIC_HOST not configured');
|
||||
|
||||
// Setup Session
|
||||
if (CFG_SESSION_CACHE_DIR && Util::checkOrCreateDirectory(CFG_SESSION_CACHE_DIR))
|
||||
if (CFG_SESSION_CACHE_DIR && Util::writeDir(CFG_SESSION_CACHE_DIR))
|
||||
session_save_path(getcwd().'/'.CFG_SESSION_CACHE_DIR);
|
||||
|
||||
session_set_cookie_params(15 * YEAR, '/', '', $secure, true);
|
||||
|
||||
828
includes/profiler.class.php
Normal file
828
includes/profiler.class.php
Normal file
@@ -0,0 +1,828 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class Profiler
|
||||
{
|
||||
const PID_FILE = 'config/pr-queue-pid';
|
||||
const CHAR_GMFLAGS = 0x1 | 0x8 | 0x10 | 0x20; // PLAYER_EXTRA_ :: GM_ON | TAXICHEAT | GM_INVISIBLE | GM_CHAT
|
||||
|
||||
private static $realms = [];
|
||||
|
||||
public static $slot2InvType = array(
|
||||
1 => [INVTYPE_HEAD], // head
|
||||
2 => [INVTYPE_NECK], // neck
|
||||
3 => [INVTYPE_SHOULDERS], // shoulder
|
||||
4 => [INVTYPE_BODY], // shirt
|
||||
5 => [INVTYPE_CHEST, INVTYPE_ROBE], // chest
|
||||
6 => [INVTYPE_WAIST], // waist
|
||||
7 => [INVTYPE_LEGS], // legs
|
||||
8 => [INVTYPE_FEET], // feet
|
||||
9 => [INVTYPE_WRISTS], // wrists
|
||||
10 => [INVTYPE_HANDS], // hands
|
||||
11 => [INVTYPE_FINGER], // finger1
|
||||
12 => [INVTYPE_FINGER], // finger2
|
||||
13 => [INVTYPE_TRINKET], // trinket1
|
||||
14 => [INVTYPE_TRINKET], // trinket2
|
||||
15 => [INVTYPE_CLOAK], // chest
|
||||
16 => [INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPON, INVTYPE_2HWEAPON], // mainhand
|
||||
17 => [INVTYPE_WEAPONOFFHAND, INVTYPE_WEAPON, INVTYPE_HOLDABLE, INVTYPE_SHIELD], // offhand
|
||||
18 => [INVTYPE_RANGED, INVTYPE_THROWN, INVTYPE_RELIC], // ranged + relic
|
||||
19 => [INVTYPE_TABARD], // tabard
|
||||
);
|
||||
|
||||
public static $raidProgression = array( // statisticAchievement => relevantCriterium
|
||||
1098 => 3271, // Onyxia's Lair 10
|
||||
1756 => 13345, // Onyxia's Lair 25
|
||||
4031 => 12230, 4034 => 12234, 4038 => 12238, 4042 => 12242, 4046 => 12246, // Trial of the Crusader 25 nh
|
||||
4029 => 12231, 4035 => 12235, 4039 => 12239, 4043 => 12243, 4047 => 12247, // Trial of the Crusader 25 hc
|
||||
4030 => 12229, 4033 => 12233, 4037 => 12237, 4041 => 12241, 4045 => 12245, // Trial of the Crusader 10 hc
|
||||
4028 => 12228, 4032 => 12232, 4036 => 12236, 4040 => 12240, 4044 => 12244, // Trial of the Crusader 10 nh
|
||||
4642 => 13091, 4656 => 13106, 4661 => 13111, 4664 => 13114, 4667 => 13117, 4670 => 13120, 4673 => 13123, 4676 => 13126, 4679 => 13129, 4682 => 13132, 4685 => 13135, 4688 => 13138, // Icecrown Citadel 25 hc
|
||||
4641 => 13092, 4655 => 13105, 4660 => 13109, 4663 => 13112, 4666 => 13115, 4669 => 13118, 4672 => 13121, 4675 => 13124, 4678 => 13127, 4681 => 13130, 4683 => 13133, 4687 => 13136, // Icecrown Citadel 25 nh
|
||||
4640 => 13090, 4654 => 13104, 4659 => 13110, 4662 => 13113, 4665 => 13116, 4668 => 13119, 4671 => 13122, 4674 => 13125, 4677 => 13128, 4680 => 13131, 4684 => 13134, 4686 => 13137, // Icecrown Citadel 10 hc
|
||||
4639 => 13089, 4643 => 13093, 4644 => 13094, 4645 => 13095, 4646 => 13096, 4647 => 13097, 4648 => 13098, 4649 => 13099, 4650 => 13100, 4651 => 13101, 4652 => 13102, 4653 => 13103, // Icecrown Citadel 10 nh
|
||||
// 4823 => 13467, // Ruby Sanctum 25 hc
|
||||
// 4820 => 13465, // Ruby Sanctum 25 nh
|
||||
// 4822 => 13468, // Ruby Sanctum 10 hc
|
||||
// 4821 => 13466, // Ruby Sanctum 10 nh
|
||||
);
|
||||
|
||||
public static function getBuyoutForItem($itemId)
|
||||
{
|
||||
if (!$itemId)
|
||||
return 0;
|
||||
|
||||
// try, when having filled char-DB at hand
|
||||
// return DB::Characters()->selectCell('SELECT SUM(a.buyoutprice) / SUM(ii.count) FROM auctionhouse a JOIN item_instance ii ON ii.guid = a.itemguid WHERE ii.itemEntry = ?d', $itemId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function queueStart(&$msg = '')
|
||||
{
|
||||
$queuePID = self::queueStatus();
|
||||
|
||||
if ($queuePID)
|
||||
{
|
||||
$msg = 'queue already running';
|
||||
return true;
|
||||
}
|
||||
|
||||
if (OS_WIN) // here be gremlins! .. suggested was "start /B php prQueue" as background process. but that closes itself
|
||||
pclose(popen('start php prQueue --log=cache/profiling.log', 'r'));
|
||||
else
|
||||
exec('php prQueue --log=cache/profiling.log > /dev/null 2>/dev/null &');
|
||||
|
||||
usleep(500000);
|
||||
if (self::queueStatus())
|
||||
return true;
|
||||
else
|
||||
{
|
||||
$msg = 'failed to start queue';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function queueStatus()
|
||||
{
|
||||
if (!file_exists(self::PID_FILE))
|
||||
return 0;
|
||||
|
||||
$pid = file_get_contents(self::PID_FILE);
|
||||
$cmd = OS_WIN ? 'tasklist /NH /FO CSV /FI "PID eq %d"' : 'ps --no-headers p %d';
|
||||
|
||||
exec(sprintf($cmd, $pid), $out);
|
||||
if ($out && stripos($out[0], $pid) !== false)
|
||||
return $pid;
|
||||
|
||||
// have pidFile but no process with this pid
|
||||
self::queueFree();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function queueLock($pid)
|
||||
{
|
||||
$queuePID = self::queueStatus();
|
||||
if ($queuePID && $queuePID != $pid)
|
||||
{
|
||||
trigger_error('pSync - another queue with PID #'.$queuePID.' is already running', E_USER_ERROR);
|
||||
CLI::write('Profiler::queueLock() - another queue with PID #'.$queuePID.' is already runnung', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// no queue running; create or overwrite pidFile
|
||||
$ok = false;
|
||||
if ($fh = fopen(self::PID_FILE, 'w'))
|
||||
{
|
||||
if (fwrite($fh, $pid))
|
||||
$ok = true;
|
||||
|
||||
fclose($fh);
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
public static function queueFree()
|
||||
{
|
||||
unlink(self::PID_FILE);
|
||||
}
|
||||
|
||||
public static function urlize($str, $allowLocales = false, $profile = false)
|
||||
{
|
||||
$search = ['<', '>', ' / ', "'"];
|
||||
$replace = ['<', '>', '-', '' ];
|
||||
$str = str_replace($search, $replace, $str);
|
||||
|
||||
if ($profile)
|
||||
{
|
||||
$str = str_replace(['(', ')'], ['', ''], $str);
|
||||
$accents = array(
|
||||
"ß" => "ss",
|
||||
"á" => "a", "ä" => "a", "à" => "a", "â" => "a",
|
||||
"è" => "e", "ê" => "e", "é" => "e", "ë" => "e",
|
||||
"í" => "i", "î" => "i", "ì" => "i", "ï" => "i",
|
||||
"ñ" => "n",
|
||||
"ò" => "o", "ó" => "o", "ö" => "o", "ô" => "o",
|
||||
"ú" => "u", "ü" => "u", "û" => "u", "ù" => "u",
|
||||
"œ" => "oe",
|
||||
"Á" => "A", "Ä" => "A", "À" => "A", "Â" => "A",
|
||||
"È" => "E", "Ê" => "E", "É" => "E", "Ë" => "E",
|
||||
"Í" => "I", "Î" => "I", "Ì" => "I", "Ï" => "I",
|
||||
"Ñ" => "N",
|
||||
"Ò" => "O", "Ó" => "O", "Ö" => "O", "Ô" => "O",
|
||||
"Ú" => "U", "Ü" => "U", "Û" => "U", "Ù" => "U",
|
||||
"Œ" => "Oe"
|
||||
);
|
||||
$str = strtr($str, $accents);
|
||||
}
|
||||
|
||||
$str = trim($str);
|
||||
|
||||
if ($allowLocales)
|
||||
$str = str_replace(' ', '-', $str);
|
||||
else
|
||||
$str = preg_replace('/[^a-z0-9]/i', '-', $str);
|
||||
|
||||
$str = str_replace('--', '-', $str);
|
||||
$str = str_replace('--', '-', $str);
|
||||
|
||||
$str = rtrim($str, '-');
|
||||
$str = strtolower($str);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
public static function getRealms()
|
||||
{
|
||||
if (DB::isConnectable(DB_AUTH) && !self::$realms)
|
||||
{
|
||||
self::$realms = DB::Auth()->select('SELECT id AS ARRAY_KEY, name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0 AND gamebuild = ?d', WOW_BUILD);
|
||||
foreach (self::$realms as $rId => $rData)
|
||||
{
|
||||
if (DB::isConnectable(DB_CHARACTERS . $rId))
|
||||
continue;
|
||||
|
||||
// realm in db but no connection info set
|
||||
unset(self::$realms[$rId]);
|
||||
}
|
||||
}
|
||||
|
||||
return self::$realms;
|
||||
}
|
||||
|
||||
private static function queueInsert($realmId, $guid, $type, $localId)
|
||||
{
|
||||
if ($rData = DB::Aowow()->selectRow('SELECT requestTime AS time, status FROM ?_profiler_sync WHERE realm = ?d AND realmGUID = ?d AND `type` = ?d AND typeId = ?d AND status <> ?d', $realmId, $guid, $type, $localId, PR_QUEUE_STATUS_WORKING))
|
||||
{
|
||||
// not on already scheduled - recalc time and set status to PR_QUEUE_STATUS_WAITING
|
||||
if ($rData['status'] != PR_QUEUE_STATUS_WAITING)
|
||||
{
|
||||
$newTime = CFG_DEBUG ? time() : max($rData['time'] + CFG_PROFILER_RESYNC_DELAY, time());
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET requestTime = ?d, status = ?d, errorCode = 0 WHERE realm = ?d AND realmGUID = ?d AND `type` = ?d AND typeId = ?d', $newTime, PR_QUEUE_STATUS_WAITING, $realmId, $guid, $type, $localId);
|
||||
}
|
||||
}
|
||||
else
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_sync (realm, realmGUID, `type`, typeId, requestTime, status, errorCode) VALUES (?d, ?d, ?d, ?d, UNIX_TIMESTAMP(), ?d, 0)', $realmId, $guid, $type, $localId, PR_QUEUE_STATUS_WAITING);
|
||||
}
|
||||
|
||||
public static function scheduleResync($type, $realmId, $guid)
|
||||
{
|
||||
$newId = 0;
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case TYPE_PROFILE:
|
||||
if ($newId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID = ?d', $realmId, $guid))
|
||||
self::queueInsert($realmId, $guid, TYPE_PROFILE, $newId);
|
||||
|
||||
break;
|
||||
case TYPE_GUILD:
|
||||
if ($newId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_guild WHERE realm = ?d AND realmGUID = ?d', $realmId, $guid))
|
||||
self::queueInsert($realmId, $guid, TYPE_GUILD, $newId);
|
||||
|
||||
break;
|
||||
case TYPE_ARENA_TEAM:
|
||||
if ($newId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_arena_team WHERE realm = ?d AND realmGUID = ?d', $realmId, $guid))
|
||||
self::queueInsert($realmId, $guid, TYPE_ARENA_TEAM, $newId);
|
||||
|
||||
break;
|
||||
default:
|
||||
trigger_error('scheduling resync for unknown type #'.$type.' omiting..', E_USER_WARNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!$newId)
|
||||
trigger_error('Profiler::scheduleResync() - tried to resync type #'.$type.' guid #'.$guid.' from realm #'.$realmId.' without preloaded data', E_USER_ERROR);
|
||||
else if (!self::queueStart($msg))
|
||||
trigger_error('Profiler::scheduleResync() - '.$msg, E_USER_ERROR);
|
||||
|
||||
return $newId;
|
||||
}
|
||||
|
||||
public static function resyncStatus($type, array $subjectGUIDs)
|
||||
{
|
||||
$response = [CFG_PROFILER_QUEUE ? 2 : 0]; // in theory you could have multiple queues; used as divisor for: (15 / x) + 2
|
||||
if (!$subjectGUIDs)
|
||||
$response[] = [PR_QUEUE_STATUS_ENDED, 0, 0, PR_QUEUE_ERROR_CHAR];
|
||||
else
|
||||
{
|
||||
// error out all profiles with status WORKING, that are older than 60sec
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET status = ?d, errorCode = ?d WHERE status = ?d AND requestTime < ?d', PR_QUEUE_STATUS_ERROR, PR_QUEUE_ERROR_UNK, PR_QUEUE_STATUS_WORKING, time() - MINUTE);
|
||||
|
||||
$subjectStatus = DB::Aowow()->select('SELECT typeId AS ARRAY_KEY, status, realm FROM ?_profiler_sync WHERE `type` = ?d AND typeId IN (?a)', $type, $subjectGUIDs);
|
||||
$queue = DB::Aowow()->selectCol('SELECT CONCAT(type, ":", typeId) FROM ?_profiler_sync WHERE status = ?d AND requestTime < UNIX_TIMESTAMP() ORDER BY requestTime ASC', PR_QUEUE_STATUS_WAITING);
|
||||
foreach ($subjectGUIDs as $guid)
|
||||
{
|
||||
if (empty($subjectStatus[$guid])) // whelp, thats some error..
|
||||
$response[] = [PR_QUEUE_STATUS_ERROR, 0, 0, PR_QUEUE_ERROR_UNK];
|
||||
else if ($subjectStatus[$guid]['status'] == PR_QUEUE_STATUS_ERROR)
|
||||
$response[] = [PR_QUEUE_STATUS_ERROR, 0, 0, $subjectStatus[$guid]['errCode']];
|
||||
else
|
||||
$response[] = array(
|
||||
$subjectStatus[$guid]['status'],
|
||||
$subjectStatus[$guid]['status'] != PR_QUEUE_STATUS_READY ? CFG_PROFILER_RESYNC_PING : 0,
|
||||
array_search($type.':'.$guid, $queue) + 1,
|
||||
0,
|
||||
1 // nResycTries - unsure about this one
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public static function getCharFromRealm($realmId, $charGuid)
|
||||
{
|
||||
$char = DB::Characters($realmId)->selectRow('SELECT c.* FROM characters c WHERE c.guid = ?d', $charGuid);
|
||||
if (!$char)
|
||||
return false;
|
||||
|
||||
// reminder: this query should not fail: a placeholder entry is created as soon as a char listview is created or profile detail page is called
|
||||
$profileId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID = ?d', $realmId, $char['guid']);
|
||||
|
||||
CLI::write('fetching char #'.$charGuid.' from realm #'.$realmId);
|
||||
CLI::write('writing...');
|
||||
|
||||
|
||||
/*************/
|
||||
/* equipment */
|
||||
/*************/
|
||||
|
||||
/* enchantment-Indizes
|
||||
* 0: permEnchant
|
||||
* 3: tempEnchant
|
||||
* 6: gem1
|
||||
* 9: gem2
|
||||
* 12: gem3
|
||||
* 15: socketBonus [not used]
|
||||
* 18: extraSocket [only check existance]
|
||||
* 21 - 30: randomProp enchantments
|
||||
*/
|
||||
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_items WHERE id = ?d', $profileId);
|
||||
$items = DB::Characters($realmId)->select('SELECT ci.slot AS ARRAY_KEY, ii.itemEntry, ii.enchantments, ii.randomPropertyId FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ?d AND bag = 0 AND slot BETWEEN 0 AND 18', $char['guid']);
|
||||
|
||||
$gemItems = [];
|
||||
$permEnch = [];
|
||||
$mhItem = 0;
|
||||
$ohItem = 0;
|
||||
|
||||
foreach ($items as $slot => $item)
|
||||
{
|
||||
$ench = explode(' ', $item['enchantments']);
|
||||
$gEnch = [];
|
||||
foreach ([6, 9, 12] as $idx)
|
||||
if ($ench[$idx])
|
||||
$gEnch[$idx] = $ench[$idx];
|
||||
|
||||
if ($gEnch)
|
||||
{
|
||||
$gi = DB::Aowow()->selectCol('SELECT gemEnchantmentId AS ARRAY_KEY, id FROM ?_items WHERE class = 3 AND gemEnchantmentId IN (?a)', $gEnch);
|
||||
foreach ($gEnch as $eId)
|
||||
{
|
||||
if (isset($gemItems[$eId]))
|
||||
$gemItems[$eId][1]++;
|
||||
else
|
||||
$gemItems[$eId] = [$gi[$eId], 1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($slot + 1 == 16)
|
||||
$mhItem = $item['itemEntry'];
|
||||
if ($slot + 1 == 17)
|
||||
$ohItem = $item['itemEntry'];
|
||||
|
||||
if ($ench[0])
|
||||
$permEnch[$slot] = $ench[0];
|
||||
|
||||
$data = array(
|
||||
'id' => $profileId,
|
||||
'slot' => $slot + 1,
|
||||
'item' => $item['itemEntry'],
|
||||
'subItem' => $item['randomPropertyId'],
|
||||
'permEnchant' => $ench[0],
|
||||
'tempEnchant' => $ench[3],
|
||||
'extraSocket' => (int)!!$ench[18],
|
||||
'gem1' => isset($gemItems[$ench[6]]) ? $gemItems[$ench[6]][0] : 0,
|
||||
'gem2' => isset($gemItems[$ench[9]]) ? $gemItems[$ench[9]][0] : 0,
|
||||
'gem3' => isset($gemItems[$ench[12]]) ? $gemItems[$ench[12]][0] : 0,
|
||||
'gem4' => 0 // serverside items cant have more than 3 sockets. (custom profile thing)
|
||||
);
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_items (?#) VALUES (?a)', array_keys($data), array_values($data));
|
||||
}
|
||||
|
||||
CLI::write(' ..inventory');
|
||||
|
||||
|
||||
/**************/
|
||||
/* basic info */
|
||||
/**************/
|
||||
|
||||
$data = array(
|
||||
'realm' => $realmId,
|
||||
'realmGUID' => $charGuid,
|
||||
'name' => $char['name'],
|
||||
'race' => $char['race'],
|
||||
'class' => $char['class'],
|
||||
'level' => $char['level'],
|
||||
'gender' => $char['gender'],
|
||||
'skincolor' => $char['playerBytes'] & 0xFF,
|
||||
'facetype' => ($char['playerBytes'] >> 8) & 0xFF, // maybe features
|
||||
'hairstyle' => ($char['playerBytes'] >> 16) & 0xFF,
|
||||
'haircolor' => ($char['playerBytes'] >> 24) & 0xFF,
|
||||
'features' => $char['playerBytes2'] & 0xFF, // maybe facetype
|
||||
'title' => $char['chosenTitle'] ? DB::Aowow()->selectCell('SELECT id FROM ?_titles WHERE bitIdx = ?d', $char['chosenTitle']) : 0,
|
||||
'playedtime' => $char['totaltime'],
|
||||
'nomodelMask' => ($char['playerFlags'] & 0x400 ? (1 << SLOT_HEAD) : 0) | ($char['playerFlags'] & 0x800 ? (1 << SLOT_BACK) : 0),
|
||||
'talenttree1' => 0,
|
||||
'talenttree2' => 0,
|
||||
'talenttree3' => 0,
|
||||
'talentbuild1' => '',
|
||||
'talentbuild2' => '',
|
||||
'glyphs1' => '',
|
||||
'glyphs2' => '',
|
||||
'activespec' => $char['activespec'],
|
||||
'guild' => null,
|
||||
'guildRank' => null,
|
||||
'gearscore' => 0,
|
||||
'achievementpoints' => 0
|
||||
);
|
||||
|
||||
|
||||
/********************/
|
||||
/* talents + glyphs */
|
||||
/********************/
|
||||
|
||||
$t = DB::Characters($realmId)->selectCol('SELECT spec AS ARRAY_KEY, spell AS ARRAY_KEY2, spell FROM character_talent WHERE guid = ?d', $char['guid']);
|
||||
$g = DB::Characters($realmId)->select('SELECT spec AS ARRAY_KEY, glyph1 AS g1, glyph2 AS g4, glyph3 AS g5, glyph4 AS g2, glyph5 AS g3, glyph6 AS g6 FROM character_glyphs WHERE guid = ?d', $char['guid']);
|
||||
for ($i = 0; $i < 2; $i++)
|
||||
{
|
||||
// talents
|
||||
for ($j = 0; $j < 3; $j++)
|
||||
{
|
||||
$_ = DB::Aowow()->selectCol('SELECT spell AS ARRAY_KEY, MAX(IF(spell in (?a), rank, 0)) FROM ?_talents WHERE class = ?d AND tab = ?d GROUP BY id ORDER BY row, col ASC', !empty($t[$i]) ? $t[$i] : [0], $char['class'], $j);
|
||||
$data['talentbuild'.($i + 1)] .= implode('', $_);
|
||||
if ($char['activespec'] == $i)
|
||||
$data['talenttree'.($j + 1)] = array_sum($_);
|
||||
}
|
||||
|
||||
// glyphs
|
||||
if (isset($g[$i]))
|
||||
{
|
||||
$gProps = [];
|
||||
for ($j = 1; $j <= 6; $j++)
|
||||
if ($g[$i]['g'.$j])
|
||||
$gProps[$j] = $g[$i]['g'.$j];
|
||||
|
||||
if ($gProps)
|
||||
if ($gItems = DB::Aowow()->selectCol('SELECT i.id FROM ?_glyphproperties gp JOIN ?_spell s ON s.effect1MiscValue = gp.id AND s.effect1Id = 74 JOIN ?_items i ON i.class = 16 AND i.spellId1 = s.id WHERE gp.id IN (?a)', $gProps))
|
||||
$data['glyphs'.($i + 1)] = implode(':', $gItems);
|
||||
}
|
||||
}
|
||||
|
||||
$t = array(
|
||||
'spent' => [$data['talenttree1'], $data['talenttree2'], $data['talenttree3']],
|
||||
'spec' => 0
|
||||
);
|
||||
if ($t['spent'][0] > $t['spent'][1] && $t['spent'][0] > $t['spent'][2])
|
||||
$t['spec'] = 1;
|
||||
else if ($t['spent'][1] > $t['spent'][0] && $t['spent'][1] > $t['spent'][2])
|
||||
$t['spec'] = 2;
|
||||
else if ($t['spent'][2] > $t['spent'][1] && $t['spent'][2] > $t['spent'][0])
|
||||
$t['spec'] = 3;
|
||||
|
||||
// calc gearscore
|
||||
if ($items)
|
||||
$data['gearscore'] += (new ItemList(array(['id', array_column($items, 'itemEntry')])))->getScoreTotal($data['class'], $t, $mhItem, $ohItem);
|
||||
|
||||
if ($gemItems)
|
||||
{
|
||||
$gemScores = new ItemList(array(['id', array_column($gemItems, 0)]));
|
||||
foreach ($gemItems as list($itemId, $mult))
|
||||
if (isset($gemScores->json[$itemId]['gearscore']))
|
||||
$data['gearscore'] += $gemScores->json[$itemId]['gearscore'] * $mult;
|
||||
}
|
||||
|
||||
if ($permEnch) // fuck this shit .. we are guestimating this!
|
||||
{
|
||||
// enchantId => multiple spells => multiple items with varying itemlevels, quality, whatevs
|
||||
// cant reasonably get to the castItem from enchantId and slot
|
||||
|
||||
$profSpec = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, skillLevel AS "1", skillLine AS "0" FROM ?_itemenchantment WHERE id IN (?a)', $permEnch);
|
||||
foreach ($permEnch as $eId)
|
||||
{
|
||||
if ($x = Util::getEnchantmentScore(0, 0, !!$profSpec[$eId][1], $eId))
|
||||
$data['gearscore'] += $x;
|
||||
else if ($profSpec[$eId][0] != 776) // not runeforging
|
||||
$data['gearscore'] += 17; // assume high quality enchantment for unknown cases
|
||||
}
|
||||
}
|
||||
|
||||
$data['lastupdated'] = time();
|
||||
|
||||
CLI::write(' ..basic info');
|
||||
|
||||
|
||||
/***************/
|
||||
/* hunter pets */
|
||||
/***************/
|
||||
|
||||
if ((1 << ($char['class'] - 1)) == CLASS_HUNTER)
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_pets WHERE owner = ?d', $profileId);
|
||||
$pets = DB::Characters($realmId)->select('SELECT id AS ARRAY_KEY, id, entry, modelId, name FROM character_pet WHERE owner = ?d', $charGuid);
|
||||
foreach ($pets as $petGuid => $petData)
|
||||
{
|
||||
$morePet = DB::Aowow()->selectRow('SELECT p.`type`, c.family FROM ?_pet p JOIN ?_creature c ON c.family = p.id WHERE c.id = ?d', $petData['entry']);
|
||||
$petSpells = DB::Characters($realmId)->selectCol('SELECT spell FROM pet_spell WHERE guid = ?d', $petGuid);
|
||||
|
||||
$_ = DB::Aowow()->selectCol('SELECT spell AS ARRAY_KEY, MAX(IF(spell in (?a), rank, 0)) FROM ?_talents WHERE class = 0 AND petTypeMask = ?d GROUP BY id ORDER BY row, col ASC', $petSpells ?: [0], 1 << $morePet['type']);
|
||||
$pet = array(
|
||||
'id' => $petGuid,
|
||||
'owner' => $profileId,
|
||||
'name' => $petData['name'],
|
||||
'family' => $morePet['family'],
|
||||
'npc' => $petData['entry'],
|
||||
'displayId' => $petData['modelId'],
|
||||
'talents' => implode('', $_)
|
||||
);
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_pets (?#) VALUES (?a)', array_keys($pet), array_values($pet));
|
||||
}
|
||||
|
||||
CLI::write(' ..hunter pets');
|
||||
}
|
||||
|
||||
|
||||
/*******************/
|
||||
/* completion data */
|
||||
/*******************/
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_completion WHERE id = ?d', $profileId);
|
||||
|
||||
// done quests
|
||||
if ($quests = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, quest AS typeId FROM character_queststatus_rewarded WHERE guid = ?d', $profileId, TYPE_QUEST, $char['guid']))
|
||||
foreach (Util::createSqlBatchInsert($quests) as $q)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$q, array_keys($quests[0]));
|
||||
|
||||
CLI::write(' ..quests');
|
||||
|
||||
|
||||
// known skills (professions only)
|
||||
$skAllowed = DB::Aowow()->selectCol('SELECT id FROM ?_skillline WHERE typeCat IN (9, 11) AND (cuFlags & ?d) = 0', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
$skills = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, skill AS typeId, `value` AS cur, max FROM character_skills WHERE guid = ?d AND skill IN (?a)', $profileId, TYPE_SKILL, $char['guid'], $skAllowed);
|
||||
|
||||
// manually apply racial profession bonuses
|
||||
foreach ($skills as &$sk)
|
||||
{
|
||||
// Blood Elves - Arcane Affinity
|
||||
if ($sk['typeId'] == 333 && $char['race'] == 10)
|
||||
{
|
||||
$sk['cur'] += 10;
|
||||
$sk['max'] += 10;
|
||||
}
|
||||
// Draenei - Gemcutting
|
||||
if ($sk['typeId'] == 755 && $char['race'] == 11)
|
||||
{
|
||||
$sk['cur'] += 5;
|
||||
$sk['max'] += 5;
|
||||
}
|
||||
// Tauren - Cultivation
|
||||
// Gnomes - Engineering Specialization
|
||||
if (($sk['typeId'] == 182 && $char['race'] == 6) ||
|
||||
($sk['typeId'] == 202 && $char['race'] == 7))
|
||||
{
|
||||
$sk['cur'] += 15;
|
||||
$sk['max'] += 15;
|
||||
}
|
||||
}
|
||||
unset($sk);
|
||||
|
||||
if ($skills)
|
||||
foreach (Util::createSqlBatchInsert($skills) as $sk)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$sk, array_keys($skills[0]));
|
||||
|
||||
CLI::write(' ..professions');
|
||||
|
||||
|
||||
// reputation
|
||||
if ($reputation = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, faction AS typeId, standing AS cur FROM character_reputation WHERE guid = ?d AND (flags & 0xC) = 0', $profileId, TYPE_FACTION, $char['guid']))
|
||||
foreach (Util::createSqlBatchInsert($reputation) as $rep)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$rep, array_keys($reputation[0]));
|
||||
|
||||
CLI::write(' ..reputation');
|
||||
|
||||
|
||||
// known titles
|
||||
$tBlocks = explode(' ', $char['knownTitles']);
|
||||
$indizes = [];
|
||||
for ($i = 0; $i < 6; $i++)
|
||||
for ($j = 0; $j < 32; $j++)
|
||||
if ($tBlocks[$i] & (1 << $j))
|
||||
$indizes[] = $j + ($i * 32);
|
||||
|
||||
if ($indizes)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion SELECT ?d, ?d, id, NULL, NULL FROM ?_titles WHERE bitIdx IN (?a)', $profileId, TYPE_TITLE, $indizes);
|
||||
|
||||
CLI::write(' ..titles');
|
||||
|
||||
|
||||
// achievements
|
||||
if ($achievements = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, achievement AS typeId, date AS cur FROM character_achievement WHERE guid = ?d', $profileId, TYPE_ACHIEVEMENT, $char['guid']))
|
||||
{
|
||||
foreach (Util::createSqlBatchInsert($achievements) as $a)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$a, array_keys($achievements[0]));
|
||||
|
||||
$data['achievementpoints'] = DB::Aowow()->selectCell('SELECT SUM(points) FROM ?_achievement WHERE id IN (?a)', array_column($achievements, 'typeId'));
|
||||
}
|
||||
|
||||
CLI::write(' ..achievements');
|
||||
|
||||
|
||||
// raid progression
|
||||
if ($progress = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, criteria AS typeId, date AS cur, counter AS `max` FROM character_achievement_progress WHERE guid = ?d AND criteria IN (?a)', $profileId, TYPE_ACHIEVEMENT, $char['guid'], self::$raidProgression))
|
||||
{
|
||||
array_walk($progress, function (&$val) { $val['typeId'] = array_search($val['typeId'], self::$raidProgression); });
|
||||
foreach (Util::createSqlBatchInsert($progress) as $p)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$p, array_keys($progress[0]));
|
||||
}
|
||||
|
||||
CLI::write(' ..raid progression');
|
||||
|
||||
|
||||
// known spells
|
||||
if ($spells = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, spell AS typeId FROM character_spell WHERE guid = ?d AND disabled = 0', $profileId, TYPE_SPELL, $char['guid']))
|
||||
foreach (Util::createSqlBatchInsert($spells) as $s)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$s, array_keys($spells[0]));
|
||||
|
||||
CLI::write(' ..known spells (vanity pets & mounts)');
|
||||
|
||||
|
||||
/****************/
|
||||
/* related data */
|
||||
/****************/
|
||||
|
||||
// guilds
|
||||
if ($guild = DB::Characters($realmId)->selectRow('SELECT g.name AS name, g.guildid AS id, gm.rank FROM guild_member gm JOIN guild g ON g.guildid = gm.guildid WHERE gm.guid = ?d', $char['guid']))
|
||||
{
|
||||
$guildId = 0;
|
||||
if (!($guildId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_guild WHERE realm = ?d AND realmGUID = ?d', $realmId, $guild['id'])))
|
||||
{
|
||||
$gData = array( // only most basic data
|
||||
'realm' => $realmId,
|
||||
'realmGUID' => $guild['id'],
|
||||
'name' => $guild['name'],
|
||||
'nameUrl' => self::urlize($guild['name']),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
|
||||
$guildId = DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES (?a)', array_keys($gData), array_values($gData));
|
||||
}
|
||||
|
||||
$data['guild'] = $guildId;
|
||||
$data['guildRank'] = $guild['rank'];
|
||||
}
|
||||
|
||||
|
||||
// arena teams
|
||||
$teams = DB::Characters($realmId)->select('SELECT at.arenaTeamId AS ARRAY_KEY, at.name, at.type, IF(at.captainGuid = atm.guid, 1, 0) AS captain, atm.* FROM arena_team at JOIN arena_team_member atm ON atm.arenaTeamId = at.arenaTeamId WHERE atm.guid = ?d', $char['guid']);
|
||||
foreach ($teams as $rGuid => $t)
|
||||
{
|
||||
$teamId = 0;
|
||||
if (!($teamId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_arena_team WHERE realm = ?d AND realmGUID = ?d', $realmId, $rGuid)))
|
||||
{
|
||||
$team = array( // only most basic data
|
||||
'realm' => $realmId,
|
||||
'realmGUID' => $rGuid,
|
||||
'name' => $t['name'],
|
||||
'nameUrl' => self::urlize($t['name']),
|
||||
'type' => $t['type'],
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
|
||||
$teamId = DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES (?a)', array_keys($team), array_values($team));
|
||||
}
|
||||
|
||||
$member = array(
|
||||
'arenaTeamId' => $teamId,
|
||||
'profileId' => $profileId,
|
||||
'captain' => $t['captain'],
|
||||
'weekGames' => $t['weekGames'],
|
||||
'weekWins' => $t['weekWins'],
|
||||
'seasonGames' => $t['seasonGames'],
|
||||
'seasonWins' => $t['seasonWins'],
|
||||
'personalRating' => $t['personalRating']
|
||||
);
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_arena_team_member (?#) VALUES (?a) ON DUPLICATE KEY UPDATE ?a', array_keys($member), array_values($member), array_slice($member, 2));
|
||||
}
|
||||
|
||||
CLI::write(' ..associated arena teams');
|
||||
|
||||
/*********************/
|
||||
/* mark char as done */
|
||||
/*********************/
|
||||
|
||||
if (DB::Aowow()->query('UPDATE ?_profiler_profiles SET ?a WHERE realm = ?d AND realmGUID = ?d', $data, $realmId, $charGuid) !== null)
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET cuFlags = cuFlags & ?d WHERE id = ?d', ~PROFILER_CU_NEEDS_RESYNC, $profileId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getGuildFromRealm($realmId, $guildGuid)
|
||||
{
|
||||
$guild = DB::Characters($realmId)->selectRow('SELECT guildId, name, createDate, info, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor FROM guild WHERE guildId = ?d', $guildGuid);
|
||||
if (!$guild)
|
||||
return false;
|
||||
|
||||
// reminder: this query should not fail: a placeholder entry is created as soon as a team listview is created or team detail page is called
|
||||
$guildId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_guild WHERE realm = ?d AND realmGUID = ?d', $realmId, $guild['guildId']);
|
||||
|
||||
CLI::write('fetching guild #'.$guildGuid.' from realm #'.$realmId);
|
||||
CLI::write('writing...');
|
||||
|
||||
|
||||
/**************/
|
||||
/* Guild Data */
|
||||
/**************/
|
||||
|
||||
unset($guild['guildId']);
|
||||
$guild['nameUrl'] = self::urlize($guild['name']);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_guild SET ?a WHERE realm = ?d AND realmGUID = ?d', $guild, $realmId, $guildGuid);
|
||||
|
||||
// ranks
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_guild_rank WHERE guildId = ?d', $guildId);
|
||||
if ($ranks = DB::Characters($realmId)->select('SELECT ?d AS guildId, rid AS rank, rname AS name FROM guild_rank WHERE guildid = ?d', $guildId, $guildGuid))
|
||||
foreach (Util::createSqlBatchInsert($ranks) as $r)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_guild_rank (?#) VALUES '.$r, array_keys(reset($ranks)));
|
||||
|
||||
CLI::write(' ..guild data');
|
||||
|
||||
|
||||
/***************/
|
||||
/* Member Data */
|
||||
/***************/
|
||||
|
||||
$conditions = array(
|
||||
['g.guildid', $guildGuid],
|
||||
['deleteInfos_Account', null],
|
||||
['level', MAX_LEVEL, '<='], // prevents JS errors
|
||||
[['extra_flags', self::CHAR_GMFLAGS, '&'], 0] // not a staff char
|
||||
);
|
||||
|
||||
// this here should all happen within ProfileList
|
||||
$members = new RemoteProfileList($conditions, ['sv' => $realmId]);
|
||||
if (!$members->error)
|
||||
$members->initializeLocalEntries();
|
||||
else
|
||||
return false;
|
||||
|
||||
CLI::write(' ..guild members');
|
||||
|
||||
|
||||
/*********************/
|
||||
/* mark guild as done */
|
||||
/*********************/
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_guild SET cuFlags = cuFlags & ?d WHERE id = ?d', ~PROFILER_CU_NEEDS_RESYNC, $guildId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getArenaTeamFromRealm($realmId, $teamGuid)
|
||||
{
|
||||
$team = DB::Characters($realmId)->selectRow('SELECT arenaTeamId, name, type, captainGuid, rating, seasonGames, seasonWins, weekGames, weekWins, rank, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor FROM arena_team WHERE arenaTeamId = ?d', $teamGuid);
|
||||
if (!$team)
|
||||
return false;
|
||||
|
||||
// reminder: this query should not fail: a placeholder entry is created as soon as a team listview is created or team detail page is called
|
||||
$teamId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_arena_team WHERE realm = ?d AND realmGUID = ?d', $realmId, $team['arenaTeamId']);
|
||||
|
||||
CLI::write('fetching arena team #'.$teamGuid.' from realm #'.$realmId);
|
||||
CLI::write('writing...');
|
||||
|
||||
|
||||
/*************/
|
||||
/* Team Data */
|
||||
/*************/
|
||||
|
||||
$captain = $team['captainGuid'];
|
||||
unset($team['captainGuid']);
|
||||
unset($team['arenaTeamId']);
|
||||
$team['nameUrl'] = self::urlize($team['name']);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_arena_team SET ?a WHERE realm = ?d AND realmGUID = ?d', $team, $realmId, $teamGuid);
|
||||
|
||||
CLI::write(' ..team data');
|
||||
|
||||
|
||||
/***************/
|
||||
/* Member Data */
|
||||
/***************/
|
||||
|
||||
$members = DB::Characters($realmId)->select('
|
||||
SELECT
|
||||
atm.guid AS ARRAY_KEY, atm.arenaTeamId, atm.weekGames, atm.weekWins, atm.seasonGames, atm.seasonWins, atm.personalrating
|
||||
FROM
|
||||
arena_team_member atm
|
||||
JOIN
|
||||
characters c ON c.guid = atm.guid AND
|
||||
c.deleteInfos_Account IS NULL AND
|
||||
c.level <= ?d AND
|
||||
(c.extra_flags & ?d) = 0
|
||||
WHERE
|
||||
arenaTeamId = ?d',
|
||||
MAX_LEVEL,
|
||||
self::CHAR_GMFLAGS,
|
||||
$teamGuid
|
||||
);
|
||||
|
||||
$conditions = array(
|
||||
['c.guid', array_keys($members)],
|
||||
['deleteInfos_Account', null],
|
||||
['level', MAX_LEVEL, '<='], // prevents JS errors
|
||||
[['extra_flags', self::CHAR_GMFLAGS, '&'], 0] // not a staff char
|
||||
);
|
||||
|
||||
$mProfiles = new RemoteProfileList($conditions, ['sv' => $realmId]);
|
||||
if (!$mProfiles->error)
|
||||
{
|
||||
$mProfiles->initializeLocalEntries();
|
||||
foreach ($mProfiles->iterate() as $__)
|
||||
{
|
||||
|
||||
$mGuid = $mProfiles->getField('guid');
|
||||
|
||||
$members[$mGuid]['arenaTeamId'] = $teamId;
|
||||
$members[$mGuid]['captain'] = (int)($mGuid == $captain);
|
||||
$members[$mGuid]['profileId'] = $mProfiles->getField('id');
|
||||
}
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_arena_team_member WHERE arenaTeamId = ?d', $teamId);
|
||||
|
||||
foreach (Util::createSqlBatchInsert($members) as $m)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_arena_team_member (?#) VALUES '.$m, array_keys(reset($members)));
|
||||
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
CLI::write(' ..team members');
|
||||
|
||||
/*********************/
|
||||
/* mark team as done */
|
||||
/*********************/
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_arena_team SET cuFlags = cuFlags & ?d WHERE id = ?d', ~PROFILER_CU_NEEDS_RESYNC, $teamId);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
346
includes/types/arenateam.class.php
Normal file
346
includes/types/arenateam.class.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ArenaTeamList extends BaseType
|
||||
{
|
||||
use profilerHelper, listviewHelper;
|
||||
|
||||
private $rankOrder = [];
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'name' => $this->curTpl['name'],
|
||||
'realm' => Profiler::urlize($this->curTpl['realmName']),
|
||||
'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']),
|
||||
'faction' => $this->curTpl['faction'],
|
||||
'size' => $this->curTpl['type'],
|
||||
'rank' => $this->curTpl['rank'],
|
||||
'wins' => $this->curTpl['seasonWins'],
|
||||
'games' => $this->curTpl['seasonGames'],
|
||||
'rating' => $this->curTpl['rating'],
|
||||
'members' => $this->curTpl['members']
|
||||
);
|
||||
}
|
||||
|
||||
return array_values($data);
|
||||
}
|
||||
|
||||
public function renderTooltip() {}
|
||||
public function getJSGlobals($addMask = 0) {}
|
||||
}
|
||||
|
||||
|
||||
class ArenaTeamListFilter extends Filter
|
||||
{
|
||||
public $extraOpts = [];
|
||||
protected $genericFilter = [];
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [FILTER_V_LIST, [1, 2], false], // side
|
||||
'sz' => [FILTER_V_LIST, [2, 3, 5], false], // tema size
|
||||
'rg' => [FILTER_V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
'sv' => [FILTER_V_CALLBACK, 'cbServerCheck', false], // server
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr) { }
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = $this->fiData['v'];
|
||||
|
||||
// region (rg), battlegroup (bg) and server (sv) are passed to ArenaTeamList as miscData and handled there
|
||||
|
||||
// name [str]
|
||||
if (!empty($_v['na']))
|
||||
if ($_ = $this->modularizeString(['at.name'], $_v['na'], !empty($_v['ex']) && $_v['ex'] == 'on'))
|
||||
$parts[] = $_;
|
||||
|
||||
// side [list]
|
||||
if (!empty($_v['si']))
|
||||
{
|
||||
if ($_v['si'] == 1)
|
||||
$parts[] = ['c.race', [1, 3, 4, 7, 11]];
|
||||
else if ($_v['si'] == 2)
|
||||
$parts[] = ['c.race', [2, 5, 6, 8, 10]];
|
||||
}
|
||||
|
||||
// size [int]
|
||||
if (!empty($_v['sz']))
|
||||
$parts[] = ['at.type', $_v['sz']];
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbRegionCheck(&$v)
|
||||
{
|
||||
if ($v == 'eu' || $v == 'us')
|
||||
{
|
||||
$this->parentCats[0] = $v; // directly redirect onto this region
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbServerCheck(&$v)
|
||||
{
|
||||
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 RemoteArenaTeamList extends ArenaTeamList
|
||||
{
|
||||
protected $queryBase = 'SELECT `at`.*, `at`.`arenaTeamId` AS ARRAY_KEY FROM arena_team at';
|
||||
protected $queryOpts = array(
|
||||
'at' => [['atm', 'c'], 'g' => 'ARRAY_KEY', 'o' => 'rating DESC'],
|
||||
'atm' => ['j' => 'arena_team_member atm ON atm.arenaTeamId = at.arenaTeamId'],
|
||||
'c' => ['j' => 'characters c ON c.guid = atm.guid AND c.deleteInfos_Account IS NULL AND c.level <= 80 AND (c.extra_flags & '.Profiler::CHAR_GMFLAGS.') = 0', 's' => ', BIT_OR(IF(c.race IN (1, 3, 4, 7, 11), 1, 2)) - 1 AS faction']
|
||||
);
|
||||
|
||||
private $members = [];
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
// 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;
|
||||
|
||||
// ranks in DB are inaccurate. recalculate from rating (fetched as DESC from DB)
|
||||
foreach ($this->dbNames as $rId => $__)
|
||||
foreach ([2, 3, 5] as $type)
|
||||
$this->rankOrder[$rId][$type] = DB::Characters($rId)->selectCol('SELECT arenaTeamId FROM arena_team WHERE `type` = ?d ORDER BY rating DESC', $type);
|
||||
|
||||
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_BATTLEGROUP;
|
||||
|
||||
// realm, rank
|
||||
$r = explode(':', $guid);
|
||||
if (!empty($realms[$r[0]]))
|
||||
{
|
||||
$curTpl['realm'] = $r[0];
|
||||
$curTpl['realmName'] = $realms[$r[0]]['name'];
|
||||
$curTpl['region'] = $realms[$r[0]]['region'];
|
||||
$curTpl['rank'] = array_search($curTpl['arenaTeamId'], $this->rankOrder[$r[0]][$curTpl['type']]) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('arena team "'.$curTpl['name'].'" belongs to nonexistant realm #'.$r, E_USER_WARNING);
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// team members
|
||||
$this->members[$r[0]][$r[1]] = $r[1];
|
||||
|
||||
// equalize distribution
|
||||
if (empty($distrib[$curTpl['realm']]))
|
||||
$distrib[$curTpl['realm']] = 1;
|
||||
else
|
||||
$distrib[$curTpl['realm']]++;
|
||||
}
|
||||
|
||||
// get team members
|
||||
foreach ($this->members as $realmId => &$teams)
|
||||
$teams = DB::Characters($realmId)->select('
|
||||
SELECT
|
||||
at.arenaTeamId AS ARRAY_KEY, c.guid AS ARRAY_KEY2, c.name AS "0", c.class AS "1", IF(at.captainguid = c.guid, 1, 0) AS "2"
|
||||
FROM
|
||||
arena_team at
|
||||
JOIN
|
||||
arena_team_member atm ON atm.arenaTeamId = at.arenaTeamId JOIN characters c ON c.guid = atm.guid
|
||||
WHERE
|
||||
at.arenaTeamId IN (?a) AND
|
||||
c.deleteInfos_Account IS NULL AND
|
||||
c.level <= ?d AND
|
||||
(c.extra_flags & ?d) = 0',
|
||||
$teams,
|
||||
MAX_LEVEL,
|
||||
Profiler::CHAR_GMFLAGS
|
||||
);
|
||||
|
||||
// equalize subject distribution across realms
|
||||
$limit = CFG_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;
|
||||
}
|
||||
|
||||
$r = explode(':', $guid);
|
||||
if (isset($this->members[$r[0]][$r[1]]))
|
||||
$curTpl['members'] = array_values($this->members[$r[0]][$r[1]]); // [name, classId, isCaptain]
|
||||
|
||||
$distrib[$curTpl['realm']]--;
|
||||
$limit--;
|
||||
}
|
||||
}
|
||||
|
||||
public function initializeLocalEntries()
|
||||
{
|
||||
$profiles = [];
|
||||
// init members for tooltips
|
||||
foreach ($this->members as $realmId => $teams)
|
||||
{
|
||||
$gladiators = [];
|
||||
foreach ($teams as $team)
|
||||
$gladiators = array_merge($gladiators, array_keys($team));
|
||||
|
||||
$profiles[$realmId] = new RemoteProfileList(array(['c.guid', $gladiators], CFG_SQL_LIMIT_NONE), ['sv' => $realmId]);
|
||||
|
||||
if (!$profiles[$realmId]->error)
|
||||
$profiles[$realmId]->initializeLocalEntries();
|
||||
}
|
||||
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $guid => $__)
|
||||
{
|
||||
$data[$guid] = array(
|
||||
'realm' => $this->getField('realm'),
|
||||
'realmGUID' => $this->getField('arenaTeamId'),
|
||||
'name' => $this->getField('name'),
|
||||
'nameUrl' => Profiler::urlize($this->getField('name')),
|
||||
'type' => $this->getField('type'),
|
||||
'rating' => $this->getField('rating'),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
}
|
||||
|
||||
// basic arena team data
|
||||
foreach (Util::createSqlBatchInsert($data) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES '.$ins, array_keys(reset($data)));
|
||||
|
||||
// merge back local ids
|
||||
$localIds = DB::Aowow()->selectCol(
|
||||
'SELECT CONCAT(realm, ":", realmGUID) AS ARRAY_KEY, id FROM ?_profiler_arena_team 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];
|
||||
|
||||
|
||||
// profiler_arena_team_member requires profiles and arena teams to be filled
|
||||
foreach ($this->members as $realmId => $teams)
|
||||
{
|
||||
if (empty($profiles[$realmId]))
|
||||
continue;
|
||||
|
||||
$memberData = [];
|
||||
foreach ($teams as $teamId => $team)
|
||||
foreach ($team as $memberId => $member)
|
||||
$memberData[] = array(
|
||||
'arenaTeamId' => $localIds[$realmId.':'.$teamId],
|
||||
'profileId' => $profiles[$realmId]->getEntry($realmId.':'.$memberId)['id'],
|
||||
'captain' => $member[2]
|
||||
);
|
||||
|
||||
foreach (Util::createSqlBatchInsert($memberData) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team_member (?#) VALUES '.$ins, array_keys(reset($memberData)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LocalArenaTeamList extends ArenaTeamList
|
||||
{
|
||||
protected $queryBase = 'SELECT at.*, at.id AS ARRAY_KEY FROM ?_profiler_arena_team at';
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
parent::__construct($conditions, $miscData);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
$realms = Profiler::getRealms();
|
||||
|
||||
// post processing
|
||||
$members = DB::Aowow()->selectCol('SELECT *, arenaTeamId AS ARRAY_KEY, profileId AS ARRAY_KEY2 FROM ?_profiler_arena_team_member WHERE arenaTeamId IN (?a)', $this->getFoundIDs());
|
||||
|
||||
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_BATTLEGROUP;
|
||||
|
||||
$curTpl['members'] = $members[$id];
|
||||
}
|
||||
}
|
||||
|
||||
public function getProfileUrl()
|
||||
{
|
||||
$url = '?arena-team=';
|
||||
|
||||
return $url.implode('.', array(
|
||||
Profiler::urlize($this->getField('region')),
|
||||
Profiler::urlize($this->getField('realmName')),
|
||||
Profiler::urlize($this->getField('name'))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
307
includes/types/guild.class.php
Normal file
307
includes/types/guild.class.php
Normal file
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuildList extends BaseType
|
||||
{
|
||||
use profilerHelper, listviewHelper;
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$this->getGuildScores();
|
||||
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'name' => "$'".$this->curTpl['name']."'", // MUST be a string
|
||||
'members' => $this->curTpl['members'],
|
||||
'faction' => $this->curTpl['faction'],
|
||||
'achievementpoints' => $this->getField('achievementpoints'),
|
||||
'gearscore' => $this->getField('gearscore'),
|
||||
'realm' => Profiler::urlize($this->curTpl['realmName']),
|
||||
'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 = [];
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [FILTER_V_LIST, [1, 2], false], // side
|
||||
'rg' => [FILTER_V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
'sv' => [FILTER_V_CALLBACK, 'cbServerCheck', false], // server
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr) { }
|
||||
|
||||
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'] == 1)
|
||||
$parts[] = ['c.race', [1, 3, 4, 7, 11]];
|
||||
else if ($_v['si'] == 2)
|
||||
$parts[] = ['c.race', [2, 5, 6, 8, 10]];
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbRegionCheck(&$v)
|
||||
{
|
||||
if ($v == 'eu' || $v == 'us')
|
||||
{
|
||||
$this->parentCats[0] = $v; // directly redirect onto this region
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbServerCheck(&$v)
|
||||
{
|
||||
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($conditions = [], $miscData = null)
|
||||
{
|
||||
// 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_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('character "'.$curTpl['name'].'" belongs to nonexistant realm #'.$r, 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_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 IGNORE INTO ?_profiler_guild (?#) VALUES '.$ins, 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($conditions = [], $miscData = null)
|
||||
{
|
||||
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_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'))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -2311,7 +2311,7 @@ class ItemListFilter extends Filter
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
foreach (Util::getRealms() as $rId => $__)
|
||||
foreach (Profiler::getRealms() as $rId => $__)
|
||||
{
|
||||
// todo: do something sensible..
|
||||
// // todo (med): get the avgbuyout into the listview
|
||||
|
||||
@@ -4,145 +4,81 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// class CharacterList extends BaseType // new profiler-related parent: ProfilerType?; maybe a trait is enough => use ProfileHelper;
|
||||
// class GuildList extends BaseType
|
||||
// class ArenaTeamList extends BaseType
|
||||
class ProfileList extends BaseType
|
||||
{
|
||||
public static $type = 0; // profiles dont actually have one
|
||||
public static $brickFile = 'profile';
|
||||
public static $dataTable = ''; // doesn't have community content
|
||||
use profilerHelper, listviewHelper;
|
||||
|
||||
protected $queryBase = ''; // SELECT p.*, p.id AS ARRAY_KEY FROM ?_profiles p';
|
||||
protected $queryOpts = array(
|
||||
'p' => [['pa', 'pg']],
|
||||
'pam' => [['?_profiles_arenateam_member pam ON pam.memberId = p.id', true], 's' => ', pam.status'],
|
||||
'pa' => ['?_profiles_arenateam pa ON pa.id = pam.teamId', 's' => ', pa.mode, pa.name'],
|
||||
'pgm' => [['?_profiles_guid_member pgm ON pgm.memberId = p.Id', true], 's' => ', pgm.rankId'],
|
||||
'pg' => ['?_profiles_guild pg ON pg.if = pgm.guildId', 's' => ', pg.name']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
$character = array(
|
||||
'id' => 2,
|
||||
'name' => 'CharName',
|
||||
'region' => ['eu', 'Europe'],
|
||||
'battlegroup' => ['pure-pwnage', 'Pure Pwnage'],
|
||||
'realm' => ['dafuque', 'da\'Fuqúe'],
|
||||
'level' => 80,
|
||||
'classs' => 11,
|
||||
'race' => 6,
|
||||
'faction' => 1, // 0:alliance; 1:horde
|
||||
'gender' => 1, // 0:male, 1:female
|
||||
'skincolor' => 0, // playerbytes % 256
|
||||
'hairstyle' => 0, // (playerbytes >> 16) % 256
|
||||
'haircolor' => 0, // (playerbytes >> 24) % 256
|
||||
'facetype' => 0, // (playerbytes >> 8) % 256 [maybe features]
|
||||
'features' => 0, // playerBytes2 % 256 [maybe facetype]
|
||||
'source' => 2, // source: used if you create a profile from a genuine character. It inherites region, realm and bGroup
|
||||
'sourcename' => 'SourceCharName', // > if these three are false we get a 'genuine' profile [0 for genuine characters..?]
|
||||
'user' => 1, // > 'genuine' is the parameter for _isArmoryProfile(allowCustoms) ['' for genuine characters..?]
|
||||
'username' => 'TestUser', // > also, if 'source' <> 0, the char-icon is requestet via profile.php?avatar
|
||||
'published' => 1, // public / private
|
||||
'pinned' => 1, // usable for some utility funcs on site
|
||||
'nomodel' => 0x0, // unchecks DisplayOnCharacter by (1 << slotId - 1)
|
||||
'title' => 0, // titleId currently in use or null
|
||||
'guild' => 'GuildName', // only on chars; id or null
|
||||
'description' => 'this is a profile', // only on custom profiles
|
||||
'arenateams' => [], // [size(2|3|5) => DisplayName]; DisplayName gets urlized to use as link
|
||||
'playedtime' => 0, // exact to the day
|
||||
'lastupdated' => 0, // timestamp in ms
|
||||
'achievementpoints' => 0, // max you have
|
||||
'talents' => array(
|
||||
'builds' => array(
|
||||
['talents' => '', 'glyphs' => ''], // talents:string of 0-5 points; glyphs: itemIds.join(':')
|
||||
),
|
||||
'active' => 1 // 1|2
|
||||
),
|
||||
'customs' => [], // custom profiles created from this char; profileId => [name, ownerId, iconString(optional)]
|
||||
'skills' => [], // skillId => [curVal, maxVal]; can contain anything, should be limited to prim/sec professions
|
||||
'inventory' => [], // slotId => [itemId, subItemId, permEnchantId, tempEnchantId, gemItemId1, gemItemId2, gemItemId3, gemItemId4]
|
||||
'auras' => [], // custom list of buffs, debuffs [spellId]
|
||||
|
||||
// completion lists: [subjectId => amount/timestamp/1]
|
||||
'reputation' => [], // factionId => amount
|
||||
'titles' => [], // titleId => 1
|
||||
'spells' => [], // spellId => 1; recipes, pets, mounts
|
||||
'achievements' => [], // achievementId => timestamp
|
||||
'quests' => [], // questId => 1
|
||||
|
||||
// UNKNOWN
|
||||
'bookmarks' => [2], // UNK pinned or claimed userId => profileIds..?
|
||||
'statistics' => [], // UNK all statistics? [achievementId => killCount]
|
||||
'activity' => [], // UNK recent achievements? [achievementId => killCount]
|
||||
'glyphs' => [], // not really used .. i guess..?
|
||||
'pets' => array( // UNK
|
||||
[], // one array per pet, structure UNK
|
||||
),
|
||||
);
|
||||
|
||||
// parent::__construct($conditions, $miscData);
|
||||
@include('datasets/ProfilerExampleChar'); // tmp char data
|
||||
|
||||
$this->templates[2] = $character;
|
||||
$this->curTpl = $character;
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
// post processing
|
||||
// foreach ($this->iterate() as $_id => &$curTpl)
|
||||
// {
|
||||
// }
|
||||
}
|
||||
|
||||
public function getListviewData()
|
||||
public function getListviewData($addInfo = 0, array $reqCols = [])
|
||||
{
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$tDistrib = $this->getTalentDistribution();
|
||||
if ($this->getField('user') && User::$id != $this->getField('user') && !($this->getField('cuFlags') & PROFILER_CU_PUBLISHED))
|
||||
continue;
|
||||
|
||||
if (($addInfo & PROFILEINFO_PROFILE) && !$this->isCustom())
|
||||
continue;
|
||||
|
||||
if (($addInfo & PROFILEINFO_CHARACTER) && $this->isCustom())
|
||||
continue;
|
||||
|
||||
$data[$this->id] = array(
|
||||
'id' => 0,
|
||||
'name' => $this->curTpl['name'],
|
||||
'achievementpoints' => $this->curTpl['achievementpoints'],
|
||||
'guild' => $this->curTpl['guild'], // 0 if none
|
||||
'guildRank' => -1,
|
||||
'realm' => $this->curTpl['realm'][0],
|
||||
'realmname' => $this->curTpl['realm'][1],
|
||||
'battlegroup' => $this->curTpl['battlegroup'][0],
|
||||
'battlegroupname' => $this->curTpl['battlegroup'][0],
|
||||
'region' => $this->curTpl['region'][0],
|
||||
'level' => $this->curTpl['level'],
|
||||
'race' => $this->curTpl['race'],
|
||||
'gender' => $this->curTpl['gender'],
|
||||
'classs' => $this->curTpl['classs'],
|
||||
'faction' => $this->curTpl['faction'],
|
||||
'talenttree1' => $tDistrib[0],
|
||||
'talenttree2' => $tDistrib[1],
|
||||
'talenttree3' => $tDistrib[2],
|
||||
'talentspec' => $this->curTpl['talents']['active']
|
||||
'id' => $this->getField('id'),
|
||||
'name' => $this->getField('name'),
|
||||
'race' => $this->getField('race'),
|
||||
'classs' => $this->getField('class'),
|
||||
'gender' => $this->getField('gender'),
|
||||
'level' => $this->getField('level'),
|
||||
'faction' => (1 << ($this->getField('race') - 1)) & RACE_MASK_ALLIANCE ? 0 : 1,
|
||||
'talenttree1' => $this->getField('talenttree1'),
|
||||
'talenttree2' => $this->getField('talenttree2'),
|
||||
'talenttree3' => $this->getField('talenttree3'),
|
||||
'talentspec' => $this->getField('activespec') + 1, // 0 => 1; 1 => 2
|
||||
'achievementpoints' => $this->getField('achievementpoints'),
|
||||
'guild' => '$"'.$this->getField('guildname').'"', // force this to be a string
|
||||
'guildrank' => $this->getField('guildrank'),
|
||||
'realm' => Profiler::urlize($this->getField('realmName')),
|
||||
'realmname' => $this->getField('realmName'),
|
||||
// 'battlegroup' => Profiler::urlize($this->getField('battlegroup')), // was renamed to subregion somewhere around cata release
|
||||
// 'battlegroupname' => $this->getField('battlegroup'),
|
||||
'gearscore' => $this->getField('gearscore')
|
||||
);
|
||||
|
||||
if (!empty($this->curTpl['description']))
|
||||
$data[$this->id]['description'] = $this->curTpl['description'];
|
||||
|
||||
if (!empty($this->curTpl['icon']))
|
||||
$data[$this->id]['icon'] = $this->curTpl['icon'];
|
||||
// for the lv this determins if the link is profile=<id> or profile=<region>.<realm>.<name>
|
||||
if ($this->isCustom())
|
||||
$data[$this->id]['published'] = (int)!!($this->getField('cuFlags') & PROFILER_CU_PUBLISHED);
|
||||
else
|
||||
$data[$this->id]['region'] = Profiler::urlize($this->getField('region'));
|
||||
|
||||
if ($this->curTpl['cuFlags'] & PROFILE_CU_PUBLISHED)
|
||||
$data[$this->id]['published'] = 1;
|
||||
if ($addInfo & PROFILEINFO_ARENA)
|
||||
{
|
||||
$data[$this->id]['rating'] = $this->getField('rating');
|
||||
$data[$this->id]['captain'] = $this->getField('captain');
|
||||
$data[$this->id]['games'] = $this->getField('seasonGames');
|
||||
$data[$this->id]['wins'] = $this->getField('seasonWins');
|
||||
}
|
||||
|
||||
if ($this->curTpl['cuFlags'] & PROFILE_CU_PINNED)
|
||||
// Filter asked for skills - add them
|
||||
foreach ($reqCols as $col)
|
||||
$data[$this->id][$col] = $this->getField($col);
|
||||
|
||||
if ($addInfo & PROFILEINFO_PROFILE)
|
||||
if ($_ = $this->getField('description'))
|
||||
$data[$this->id]['description'] = $_;
|
||||
|
||||
if ($addInfo & PROFILEINFO_PROFILE)
|
||||
if ($_ = $this->getField('icon'))
|
||||
$data[$this->id]['icon'] = $_;
|
||||
|
||||
if ($this->getField('cuFlags') & PROFILER_CU_PINNED)
|
||||
$data[$this->id]['pinned'] = 1;
|
||||
|
||||
if ($this->curTpl['cuFlags'] & PROFILE_CU_DELETED)
|
||||
if ($this->getField('cuFlags') & PROFILER_CU_DELETED)
|
||||
$data[$this->id]['deleted'] = 1;
|
||||
}
|
||||
|
||||
return $data;
|
||||
return array_values($data);
|
||||
}
|
||||
|
||||
public function renderTooltip($interactive = false)
|
||||
@@ -150,49 +86,173 @@ class ProfileList extends BaseType
|
||||
if (!$this->curTpl)
|
||||
return [];
|
||||
|
||||
$title = '';
|
||||
$name = $this->getField('name');
|
||||
if ($_ = $this->getField('chosenTitle'))
|
||||
$title = (new TitleList(array(['bitIdx', $_])))->getField($this->getField('gender') ? 'female' : 'male', true);
|
||||
|
||||
if ($this->isCustom())
|
||||
$name .= ' (Custom Profile)';
|
||||
else if ($title)
|
||||
$name = sprintf($title, $name);
|
||||
|
||||
$x = '<table>';
|
||||
$x .= '<tr><td><b class="q">'.$this->getField('name').'</b></td></tr>';
|
||||
if ($g = $this->getField('name'))
|
||||
$x .= '<tr><td><'.$g.'> ('.$this->getField('guildrank').')</td></tr>';
|
||||
$x .= '<tr><td><b class="q">'.$name.'</b></td></tr>';
|
||||
if ($g = $this->getField('guildname'))
|
||||
$x .= '<tr><td><'.$g.'></td></tr>';
|
||||
else if ($d = $this->getField('description'))
|
||||
$x .= '<tr><td>'.$d.'</td></tr>';
|
||||
$x .= '<tr><td>'.Lang::game('level').' '.$this->getField('level').' '.Lang::game('ra', $this->curTpl['race']).' '.Lang::game('cl', $this->curTpl['classs']).'</td></tr>';
|
||||
$x .= '<tr><td>'.Lang::game('level').' '.$this->getField('level').' '.Lang::game('ra', $this->getField('race')).' '.Lang::game('cl', $this->getField('class')).'</td></tr>';
|
||||
$x .= '</table>';
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = 0) {}
|
||||
|
||||
private function getTalentDistribution()
|
||||
public function getJSGlobals($addMask = 0)
|
||||
{
|
||||
if (!empty($this->tDistribution))
|
||||
$this->tDistribution[$this->curTpl['classId']] = DB::Aowow()->selectCol('SELECT COUNT(t.id) FROM dbc_talent t JOIN dbc_talenttab tt ON t.tabId = tt.id WHERE tt.classMask & ?d GROUP BY tt.id ORDER BY tt.tabNumber ASC', 1 << ($this->curTpl['classId'] - 1));
|
||||
$data = [];
|
||||
$realms = Profiler::getRealms();
|
||||
|
||||
$result = [];
|
||||
$start = 0;
|
||||
foreach ($this->tDistribution[$this->curTpl['classId']] as $len)
|
||||
foreach ($this->iterate() as $id => $__)
|
||||
{
|
||||
$result[] = array_sum(str_split(substr($this->curTpl['talentString'], $start, $len)));
|
||||
$start += $len;
|
||||
if (($addMask & PROFILEINFO_PROFILE) && ($this->getField('cuFlags') & PROFILER_CU_PROFILE))
|
||||
{
|
||||
$profile = array(
|
||||
'id' => $this->getField('id'),
|
||||
'name' => $this->getField('name'),
|
||||
'race' => $this->getField('race'),
|
||||
'classs' => $this->getField('class'),
|
||||
'level' => $this->getField('level'),
|
||||
'gender' => $this->getField('gender')
|
||||
);
|
||||
|
||||
if ($_ = $this->getField('icon'))
|
||||
$profile['icon'] = $_;
|
||||
|
||||
$data[] = $profile;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return $result;
|
||||
if ($addMask & PROFILEINFO_CHARACTER && !($this->getField('cuFlags') & PROFILER_CU_PROFILE))
|
||||
{
|
||||
if (!isset($realms[$this->getField('realm')]))
|
||||
continue;
|
||||
|
||||
$data[] = array(
|
||||
'id' => $this->getField('id'),
|
||||
'name' => $this->getField('name'),
|
||||
'realmname' => $realms[$this->getField('realm')]['name'],
|
||||
'region' => $realms[$this->getField('realm')]['region'],
|
||||
'realm' => Profiler::urlize($realms[$this->getField('realm')]['name']),
|
||||
'race' => $this->getField('race'),
|
||||
'classs' => $this->getField('class'),
|
||||
'level' => $this->getField('level'),
|
||||
'gender' => $this->getField('gender'),
|
||||
'pinned' => $this->getField('cuFlags') & PROFILER_CU_PINNED ? 1 : 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function isCustom()
|
||||
{
|
||||
return $this->getField('cuFlags') & PROFILER_CU_PROFILE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ProfileListFilter extends Filter
|
||||
{
|
||||
public $useLocalList = false;
|
||||
public $extraOpts = [];
|
||||
|
||||
protected $genericFilter = array(
|
||||
private $realms = [];
|
||||
|
||||
protected $enums = array(
|
||||
-1 => array( // arena team sizes
|
||||
// by name by rating by contrib
|
||||
12 => 2, 13 => 2, 14 => 2,
|
||||
15 => 3, 16 => 3, 17 => 3,
|
||||
18 => 5, 19 => 5, 20 => 5
|
||||
)
|
||||
);
|
||||
|
||||
protected $genericFilter = array( // misc (bool): _NUMERIC => useFloat; _STRING => localized; _FLAG => match Value; _BOOLEAN => stringSet
|
||||
2 => [FILTER_CR_NUMERIC, 'gearscore', NUM_CAST_INT ], // gearscore [num]
|
||||
3 => [FILTER_CR_NUMERIC, 'achievementpoints', NUM_CAST_INT ], // achievementpoints [num]
|
||||
5 => [FILTER_CR_NUMERIC, 'talenttree1', NUM_CAST_INT ], // talenttree1 [num]
|
||||
6 => [FILTER_CR_NUMERIC, 'talenttree2', NUM_CAST_INT ], // talenttree2 [num]
|
||||
7 => [FILTER_CR_NUMERIC, 'talenttree3', NUM_CAST_INT ], // talenttree3 [num]
|
||||
9 => [FILTER_CR_STRING, 'g.name', ], // guildname
|
||||
10 => [FILTER_CR_CALLBACK, 'cbHasGuildRank', null, null], // guildrank
|
||||
12 => [FILTER_CR_CALLBACK, 'cbTeamName', null, null], // teamname2v2
|
||||
15 => [FILTER_CR_CALLBACK, 'cbTeamName', null, null], // teamname3v3
|
||||
18 => [FILTER_CR_CALLBACK, 'cbTeamName', null, null], // teamname5v5
|
||||
13 => [FILTER_CR_CALLBACK, 'cbTeamRating', null, null], // teamrtng2v2
|
||||
16 => [FILTER_CR_CALLBACK, 'cbTeamRating', null, null], // teamrtng3v3
|
||||
19 => [FILTER_CR_CALLBACK, 'cbTeamRating', null, null], // teamrtng5v5
|
||||
14 => [FILTER_CR_NYI_PH, 0 ], // teamcontrib2v2 [num]
|
||||
17 => [FILTER_CR_NYI_PH, 0 ], // teamcontrib3v3 [num]
|
||||
20 => [FILTER_CR_NYI_PH, 0 ], // teamcontrib5v5 [num]
|
||||
21 => [FILTER_CR_CALLBACK, 'cbWearsItems', null, null], // wearingitem [str]
|
||||
23 => [FILTER_CR_CALLBACK, 'cbCompletedAcv', null, null], // completedachievement
|
||||
25 => [FILTER_CR_CALLBACK, 'cbProfession', 171, null], // alchemy [num]
|
||||
26 => [FILTER_CR_CALLBACK, 'cbProfession', 164, null], // blacksmithing [num]
|
||||
27 => [FILTER_CR_CALLBACK, 'cbProfession', 333, null], // enchanting [num]
|
||||
28 => [FILTER_CR_CALLBACK, 'cbProfession', 202, null], // engineering [num]
|
||||
29 => [FILTER_CR_CALLBACK, 'cbProfession', 182, null], // herbalism [num]
|
||||
30 => [FILTER_CR_CALLBACK, 'cbProfession', 773, null], // inscription [num]
|
||||
31 => [FILTER_CR_CALLBACK, 'cbProfession', 755, null], // jewelcrafting [num]
|
||||
32 => [FILTER_CR_CALLBACK, 'cbProfession', 165, null], // leatherworking [num]
|
||||
33 => [FILTER_CR_CALLBACK, 'cbProfession', 186, null], // mining [num]
|
||||
34 => [FILTER_CR_CALLBACK, 'cbProfession', 393, null], // skinning [num]
|
||||
35 => [FILTER_CR_CALLBACK, 'cbProfession', 197, null], // tailoring [num]
|
||||
36 => [FILTER_CR_CALLBACK, 'cbHasGuild', null, null] // hasguild [yn]
|
||||
);
|
||||
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_RANGE, [1, 36], true ], // criteria ids
|
||||
'crs' => [FILTER_V_LIST, [FILTER_ENUM_NONE, FILTER_ENUM_ANY, [0, 5000]], true ], // criteria operators
|
||||
'crv' => [FILTER_V_REGEX, '/[\p{C};]/ui', true ], // criteria values
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [FILTER_V_LIST, [1, 2], false], // side
|
||||
'ra' => [FILTER_V_LIST, [[1, 8], 10, 11], true ], // race
|
||||
'cl' => [FILTER_V_LIST, [[1, 9], 11], true ], // class
|
||||
'minle' => [FILTER_V_RANGE, [1, MAX_LEVEL], false], // min level
|
||||
'maxle' => [FILTER_V_RANGE, [1, MAX_LEVEL], false], // max level
|
||||
'rg' => [FILTER_V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
'sv' => [FILTER_V_CALLBACK, 'cbServerCheck', false], // server
|
||||
);
|
||||
|
||||
/* heads up!
|
||||
a couple of filters are too complex to be run against the characters database
|
||||
if they are selected, force useage of LocalProfileList
|
||||
*/
|
||||
|
||||
public function __construct($fromPOST = false, $opts = [])
|
||||
{
|
||||
if (!empty($opts['realms']))
|
||||
$this->realms = $opts['realms'];
|
||||
else
|
||||
$this->realms = array_keys(Profiler::getRealms());
|
||||
|
||||
parent::__construct($fromPOST, $opts);
|
||||
|
||||
if (!empty($this->fiData['c']['cr']))
|
||||
if (array_intersect($this->fiData['c']['cr'], [2, 3, 5, 6, 7, 21]))
|
||||
$this->useLocalList = true;
|
||||
}
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
{
|
||||
if ($genCR = $this->genericCriterion($cr))
|
||||
return $genCR;
|
||||
|
||||
@@ -201,29 +261,451 @@ class ProfileListFilter extends Filter
|
||||
return [1];
|
||||
}
|
||||
|
||||
switch ($cr[0])
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unset($cr);
|
||||
$this->error = 1;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = $this->fiData['v'];
|
||||
|
||||
// name
|
||||
if (isset($_v['na']))
|
||||
if ($_ = $this->modularizeString(['name_loc'.User::$localeId]))
|
||||
$parts[] = $_;
|
||||
// region (rg), battlegroup (bg) and server (sv) are passed to ProflieList as miscData and handled there
|
||||
|
||||
// table key differs between remote and local :<
|
||||
$k = $this->useLocalList ? 'p' : 'c';
|
||||
|
||||
// name [str] - the table is case sensitive. Since i down't want to destroy indizes, lets alter the search terms
|
||||
if (!empty($_v['na']))
|
||||
{
|
||||
$lower = $this->modularizeString([$k.'.name'], Util::lower($_v['na']), !empty($_v['ex']) && $_v['ex'] == 'on');
|
||||
$proper = $this->modularizeString([$k.'.name'], Util::ucWords($_v['na']), !empty($_v['ex']) && $_v['ex'] == 'on');
|
||||
|
||||
$parts[] = ['OR', $lower, $proper];
|
||||
}
|
||||
|
||||
// side [list]
|
||||
if (!empty($_v['si']))
|
||||
{
|
||||
if ($_v['si'] == 1)
|
||||
$parts[] = [$k.'.race', [1, 3, 4, 7, 11]];
|
||||
else if ($_v['si'] == 2)
|
||||
$parts[] = [$k.'.race', [2, 5, 6, 8, 10]];
|
||||
}
|
||||
|
||||
// race [list]
|
||||
if (!empty($_v['ra']))
|
||||
$parts[] = [$k.'.race', $_v['ra']];
|
||||
|
||||
// class [list]
|
||||
if (!empty($_v['cl']))
|
||||
$parts[] = [$k.'.class', $_v['cl']];
|
||||
|
||||
// min level [int]
|
||||
if (isset($_v['minle']))
|
||||
$parts[] = [$k.'.level', $_v['minle'], '>='];
|
||||
|
||||
// max level [int]
|
||||
if (isset($_v['maxle']))
|
||||
$parts[] = [$k.'.level', $_v['maxle'], '<='];
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbRegionCheck(&$v)
|
||||
{
|
||||
if ($v == 'eu' || $v == 'us')
|
||||
{
|
||||
$this->parentCats[0] = $v; // directly redirect onto this region
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbServerCheck(&$v)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
protected function cbProfession($cr, $skillId)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return;
|
||||
|
||||
$k = 'sk_'.Util::createHash(12);
|
||||
$col = 'skill'.$skillId;
|
||||
|
||||
$this->formData['extraCols'][$skillId] = $col;
|
||||
|
||||
if ($this->useLocalList)
|
||||
{
|
||||
$this->extraOpts[$k] = array(
|
||||
'j' => ['?_profiler_completion '.$k.' ON '.$k.'.id = p.id AND '.$k.'.`type` = '.TYPE_SKILL.' AND '.$k.'.typeId = '.$skillId.' AND '.$k.'.cur '.$cr[1].' '.$cr[2], true],
|
||||
's' => [', '.$k.'.cur AS '.$col]
|
||||
);
|
||||
return [$k.'.typeId', null, '!'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->extraOpts[$k] = array(
|
||||
'j' => ['character_skills '.$k.' ON '.$k.'.guid = c.guid AND '.$k.'.skill = '.$skillId.' AND '.$k.'.value '.$cr[1].' '.$cr[2], true],
|
||||
's' => [', '.$k.'.value AS '.$col]
|
||||
);
|
||||
return [$k.'.skill', null, '!'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function cbCompletedAcv($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT))
|
||||
return false;
|
||||
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_achievement WHERE id = ?d', $cr[2]))
|
||||
return false;
|
||||
|
||||
$k = 'acv_'.Util::createHash(12);
|
||||
|
||||
if ($this->useLocalList)
|
||||
{
|
||||
$this->extraOpts[$k] = ['j' => ['?_profiler_completion '.$k.' ON '.$k.'.id = p.id AND '.$k.'.`type` = '.TYPE_ACHIEVEMENT.' AND '.$k.'.typeId = '.$cr[2], true]];
|
||||
return [$k.'.typeId', null, '!'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->extraOpts[$k] = ['j' => ['character_achievement '.$k.' ON '.$k.'.guid = c.guid AND '.$k.'.achievement = '.$cr[2], true]];
|
||||
return [$k.'.achievement', null, '!'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function cbWearsItems($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT))
|
||||
return false;
|
||||
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_items WHERE id = ?d', $cr[2]))
|
||||
return false;
|
||||
|
||||
$k = 'i_'.Util::createHash(12);
|
||||
|
||||
$this->extraOpts[$k] = ['j' => ['?_profiler_items '.$k.' ON '.$k.'.id = p.id AND '.$k.'.item = '.$cr[2], true]];
|
||||
return [$k.'.item', null, '!'];
|
||||
}
|
||||
|
||||
protected function cbHasGuild($cr)
|
||||
{
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($this->useLocalList)
|
||||
return ['p.guild', null, $cr[1] ? '!' : null];
|
||||
else
|
||||
return ['gm.guildId', null, $cr[1] ? '!' : null];
|
||||
}
|
||||
|
||||
protected function cbHasGuildRank($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($this->useLocalList)
|
||||
return ['p.guildrank', $cr[2], $cr[1]];
|
||||
else
|
||||
return ['gm.rank', $cr[2], $cr[1]];
|
||||
}
|
||||
|
||||
protected function cbTeamName($cr)
|
||||
{
|
||||
if ($_ = $this->modularizeString(['at.name'], $cr[2]))
|
||||
return ['AND', ['at.type', $this->enums[-1][$cr[0]]], $_];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbTeamRating($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
return ['AND', ['at.type', $this->enums[-1][$cr[0]]], ['at.rating', $cr[2], $cr[1]]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RemoteProfileList extends ProfileList
|
||||
{
|
||||
protected $queryBase = 'SELECT `c`.*, `c`.`guid` AS ARRAY_KEY FROM characters c';
|
||||
protected $queryOpts = array(
|
||||
'c' => [['gm', 'g', 'ca', 'ct'], 'g' => 'ARRAY_KEY', 'o' => 'level DESC, name ASC'],
|
||||
'ca' => ['j' => ['character_achievement ca ON ca.guid = c.guid', true], 's' => ', GROUP_CONCAT(DISTINCT ca.achievement SEPARATOR " ") AS _acvs'],
|
||||
'ct' => ['j' => ['character_talent ct ON ct.guid = c.guid AND ct.spec = c.activespec', true], 's' => ', GROUP_CONCAT(DISTINCT ct.spell SEPARATOR " ") AS _talents'],
|
||||
'gm' => ['j' => ['guild_member gm ON gm.guid = c.guid', true], 's' => ', gm.rank AS guildrank'],
|
||||
'g' => ['j' => ['guild g ON g.guildid = gm.guildid', true], 's' => ', g.guildid AS guild, g.name AS guildname'],
|
||||
'atm' => ['j' => ['arena_team_member atm ON atm.guid = c.guid', true], 's' => ', atm.personalRating AS rating'],
|
||||
'at' => [['atm'], 'j' => 'arena_team at ON atm.arenaTeamId = at.arenaTeamId', 's' => ', at.name AS arenateam, IF(at.captainGuid = c.guid, 1, 0) AS captain']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
// 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();
|
||||
$acvCache = [];
|
||||
$talentCache = [];
|
||||
$atCache = [];
|
||||
$distrib = null;
|
||||
$talentData = [];
|
||||
$limit = CFG_SQL_LIMIT_DEFAULT;
|
||||
|
||||
foreach ($conditions as $c)
|
||||
if (is_int($c))
|
||||
$limit = $c;
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as $guid => &$curTpl)
|
||||
{
|
||||
// battlegroup
|
||||
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
|
||||
|
||||
// realm
|
||||
$r = explode(':', $guid)[0];
|
||||
if (!empty($realms[$r]))
|
||||
{
|
||||
$curTpl['realm'] = $r;
|
||||
$curTpl['realmName'] = $realms[$r]['name'];
|
||||
$curTpl['region'] = $realms[$r]['region'];
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('character "'.$curTpl['name'].'" belongs to nonexistant realm #'.$r, E_USER_WARNING);
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// temp id
|
||||
$curTpl['id'] = 0;
|
||||
|
||||
// achievement points pre
|
||||
if ($acvs = explode(' ', $curTpl['_acvs']))
|
||||
foreach ($acvs as $a)
|
||||
if ($a && !isset($acvCache[$a]))
|
||||
$acvCache[$a] = $a;
|
||||
|
||||
// talent points pre
|
||||
if ($talents = explode(' ', $curTpl['_talents']))
|
||||
foreach ($talents as $t)
|
||||
if ($t && !isset($talentCache[$t]))
|
||||
$talentCache[$t] = $t;
|
||||
|
||||
// equalize distribution
|
||||
if ($limit != CFG_SQL_LIMIT_NONE)
|
||||
{
|
||||
if (empty($distrib[$curTpl['realm']]))
|
||||
$distrib[$curTpl['realm']] = 1;
|
||||
else
|
||||
$distrib[$curTpl['realm']]++;
|
||||
}
|
||||
|
||||
$curTpl['cuFlags'] = 0;
|
||||
}
|
||||
|
||||
if ($talentCache)
|
||||
$talentData = DB::Aowow()->select('SELECT spell AS ARRAY_KEY, tab, rank FROM ?_talents WHERE spell IN (?a)', $talentCache);
|
||||
|
||||
if ($distrib !== null)
|
||||
{
|
||||
$total = array_sum($distrib);
|
||||
foreach ($distrib as &$d)
|
||||
$d = ceil($limit * $d / $total);
|
||||
}
|
||||
|
||||
if ($acvCache)
|
||||
$acvCache = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, points FROM ?_achievement WHERE id IN (?a)', $acvCache);
|
||||
|
||||
foreach ($this->iterate() as $guid => &$curTpl)
|
||||
{
|
||||
if ($distrib !== null)
|
||||
{
|
||||
if ($limit <= 0 || $distrib[$curTpl['realm']] <= 0)
|
||||
{
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$distrib[$curTpl['realm']]--;
|
||||
$limit--;
|
||||
}
|
||||
|
||||
|
||||
$a = explode(' ', $curTpl['_acvs']);
|
||||
$t = explode(' ', $curTpl['_talents']);
|
||||
unset($curTpl['_acvs']);
|
||||
unset($curTpl['_talents']);
|
||||
|
||||
// achievement points post
|
||||
$curTpl['achievementpoints'] = array_sum(array_intersect_key($acvCache, array_combine($a, $a)));
|
||||
|
||||
// talent points post
|
||||
$curTpl['talenttree1'] = 0;
|
||||
$curTpl['talenttree2'] = 0;
|
||||
$curTpl['talenttree3'] = 0;
|
||||
foreach ($talentData as $spell => $data)
|
||||
if (in_array($spell, $t))
|
||||
$curTpl['talenttree'.($data['tab'] + 1)] += $data['rank'];
|
||||
}
|
||||
}
|
||||
|
||||
public function getListviewData($addInfoMask = 0, array $reqCols = [])
|
||||
{
|
||||
$data = parent::getListviewData($addInfoMask, $reqCols);
|
||||
|
||||
// not wanted on server list
|
||||
foreach ($data as &$d)
|
||||
unset($d['published']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function initializeLocalEntries()
|
||||
{
|
||||
$baseData = $guildData = [];
|
||||
foreach ($this->iterate() as $guid => $__)
|
||||
{
|
||||
$baseData[$guid] = array(
|
||||
'realm' => $this->getField('realm'),
|
||||
'realmGUID' => $this->getField('guid'),
|
||||
'name' => $this->getField('name'),
|
||||
'race' => $this->getField('race'),
|
||||
'class' => $this->getField('class'),
|
||||
'level' => $this->getField('level'),
|
||||
'gender' => $this->getField('gender'),
|
||||
'guild' => $this->getField('guild') ?: null,
|
||||
'guildrank' => $this->getField('guild') ? $this->getField('guildrank') : null,
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
|
||||
if ($this->getField('guild'))
|
||||
$guildData[] = array(
|
||||
'realm' => $this->getField('realm'),
|
||||
'realmGUID' => $this->getField('guild'),
|
||||
'name' => $this->getField('guildname'),
|
||||
'nameUrl' => Profiler::urlize($this->getField('guildname')),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
}
|
||||
|
||||
// basic guild data (satisfying table constraints)
|
||||
if ($guildData)
|
||||
{
|
||||
foreach (Util::createSqlBatchInsert($guildData) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES '.$ins, array_keys(reset($guildData)));
|
||||
|
||||
// merge back local ids
|
||||
$localGuilds = DB::Aowow()->selectCol('SELECT realm AS ARRAY_KEY, realmGUID AS ARRAY_KEY2, id FROM ?_profiler_guild WHERE realm IN (?a) AND realmGUID IN (?a)',
|
||||
array_column($guildData, 'realm'), array_column($guildData, 'realmGUID')
|
||||
);
|
||||
|
||||
foreach ($baseData as &$bd)
|
||||
if ($bd['guild'])
|
||||
$bd['guild'] = $localGuilds[$bd['realm']][$bd['guild']];
|
||||
}
|
||||
|
||||
// basic char data (enough for tooltips)
|
||||
if ($baseData)
|
||||
{
|
||||
foreach (Util::createSqlBatchInsert($baseData) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_profiles (?#) VALUES '.$ins, array_keys(reset($baseData)));
|
||||
|
||||
// merge back local ids
|
||||
$localIds = DB::Aowow()->select(
|
||||
'SELECT CONCAT(realm, ":", realmGUID) AS ARRAY_KEY, id, gearscore FROM ?_profiler_profiles WHERE (cuFlags & ?d) = 0 AND realm IN (?a) AND realmGUID IN (?a)',
|
||||
PROFILER_CU_PROFILE,
|
||||
array_column($baseData, 'realm'),
|
||||
array_column($baseData, 'realmGUID')
|
||||
);
|
||||
|
||||
foreach ($this->iterate() as $guid => &$_curTpl)
|
||||
if (isset($localIds[$guid]))
|
||||
$_curTpl = array_merge($_curTpl, $localIds[$guid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LocalProfileList extends ProfileList
|
||||
{
|
||||
protected $queryBase = 'SELECT p.*, p.id AS ARRAY_KEY FROM ?_profiler_profiles p';
|
||||
protected $queryOpts = array(
|
||||
'p' => [['g'], 'g' => 'p.id'],
|
||||
'ap' => ['j' => ['?_account_profiles ap ON ap.profileId = p.id', true], 's' => ', (IFNULL(ap.ExtraFlags, 0) | p.cuFlags) AS cuFlags'],
|
||||
'atm' => ['j' => ['?_profiler_arena_team_member atm ON atm.profileId = p.id', true], 's' => ', atm.captain, atm.personalRating AS rating, atm.seasonGames, atm.seasonWins'],
|
||||
'at' => [['atm'], 'j' => ['?_profiler_arena_team at ON at.id = atm.arenaTeamId', true], 's' => ', at.type'],
|
||||
'g' => ['j' => ['?_profiler_guild g ON g.id = p.guild', true], 's' => ', g.name AS guildname']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
parent::__construct($conditions, $miscData);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
$realms = Profiler::getRealms();
|
||||
|
||||
// post processing
|
||||
$acvPoints = DB::Aowow()->selectCol('SELECT pc.id AS ARRAY_KEY, SUM(a.points) FROM ?_profiler_completion pc LEFT JOIN ?_achievement a ON a.id = pc.typeId WHERE pc.`type` = ?d AND pc.id IN (?a) GROUP BY pc.id', TYPE_ACHIEVEMENT, $this->getFoundIDs());
|
||||
|
||||
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_BATTLEGROUP;
|
||||
|
||||
$curTpl['achievementpoints'] = isset($acvPoints[$id]) ? $acvPoints[$id] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public function getProfileUrl()
|
||||
{
|
||||
$url = '?profile=';
|
||||
|
||||
if ($this->isCustom())
|
||||
return $url.$this->getField('id');
|
||||
|
||||
return $url.implode('.', array(
|
||||
Profiler::urlize($this->getField('region')),
|
||||
Profiler::urlize($this->getField('realmName')),
|
||||
urlencode($this->getField('name'))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -340,33 +340,226 @@ class SpellList extends BaseType
|
||||
|
||||
public function getProfilerMods()
|
||||
{
|
||||
// weapon hand check: param: slot, class, subclass, value
|
||||
$whCheck = '$function() { var j, w = _inventory.getInventory()[%d]; if (!w[0] || !g_items[w[0]]) { return 0; } j = g_items[w[0]].jsonequip; return (j.classs == %d && (%d & (1 << (j.subclass)))) ? %d : 0; }';
|
||||
|
||||
$data = $this->getStatGain(); // flat gains
|
||||
foreach ($data as $id => &$spellData)
|
||||
{
|
||||
foreach ($spellData as $modId => $val)
|
||||
{
|
||||
if (!isset(Game::$itemMods[$modId]))
|
||||
continue;
|
||||
|
||||
if ($modId == ITEM_MOD_EXPERTISE_RATING) // not a rating .. pure expertise
|
||||
$spellData['exp'] = $val;
|
||||
else
|
||||
$spellData[Game::$itemMods[$modId]] = $val;
|
||||
|
||||
unset($spellData[$modId]);
|
||||
}
|
||||
|
||||
// apply weapon restrictions
|
||||
$this->getEntry($id);
|
||||
$class = $this->getField('equippedItemClass');
|
||||
$subClass = $this->getField('equippedItemSubClassMask');
|
||||
$slot = $subClass & 0x5000C ? 18 : 16;
|
||||
if ($class != ITEM_CLASS_WEAPON || !$subClass)
|
||||
continue;
|
||||
|
||||
foreach ($spellData as $json => $pts)
|
||||
$spellData[$json] = [1, 'functionOf', sprintf($whCheck, $slot, $class, $subClass, $pts)];
|
||||
}
|
||||
|
||||
// 4 possible modifiers found
|
||||
// <statistic> => [0.15, 'functionOf', <funcName:int>]
|
||||
// <statistic> => [0.33, 'percentOf', <statistic>]
|
||||
// <statistic> => [123, 'add']
|
||||
// <statistic> => <value> ... as from getStatGain()
|
||||
|
||||
$modXByStat = function (&$arr, $stat, $pts) use (&$mv)
|
||||
{
|
||||
if ($mv == STAT_STRENGTH)
|
||||
$arr[$stat ?: 'str'] = [$pts / 100, 'percentOf', 'str'];
|
||||
else if ($mv == STAT_AGILITY)
|
||||
$arr[$stat ?: 'agi'] = [$pts / 100, 'percentOf', 'agi'];
|
||||
else if ($mv == STAT_STAMINA)
|
||||
$arr[$stat ?: 'sta'] = [$pts / 100, 'percentOf', 'sta'];
|
||||
else if ($mv == STAT_INTELLECT)
|
||||
$arr[$stat ?: 'int'] = [$pts / 100, 'percentOf', 'int'];
|
||||
else if ($mv == STAT_SPIRIT)
|
||||
$arr[$stat ?: 'spi'] = [$pts / 100, 'percentOf', 'spi'];
|
||||
};
|
||||
|
||||
$modXBySchool = function (&$arr, $stat, $val, $mask = null) use (&$mv)
|
||||
{
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_HOLY))
|
||||
$arr['hol'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'hol'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_FIRE))
|
||||
$arr['fir'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'fir'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_NATURE))
|
||||
$arr['nat'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'nat'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_FROST))
|
||||
$arr['fro'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'fro'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_SHADOW))
|
||||
$arr['sha'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'sha'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_ARCANE))
|
||||
$arr['arc'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'arc'.$stat];
|
||||
};
|
||||
|
||||
$jsonStat = function ($stat)
|
||||
{
|
||||
if ($stat == STAT_STRENGTH)
|
||||
return 'str';
|
||||
if ($stat == STAT_AGILITY)
|
||||
return 'agi';
|
||||
if ($stat == STAT_STAMINA)
|
||||
return 'sta';
|
||||
if ($stat == STAT_INTELLECT)
|
||||
return 'int';
|
||||
if ($stat == STAT_SPIRIT)
|
||||
return 'spi';
|
||||
};
|
||||
|
||||
foreach ($this->iterate() as $id => $__)
|
||||
{
|
||||
// Priest: Spirit of Redemption is a spell but also a passive. *yaaayyyy*
|
||||
if (($this->getField('cuFlags') & SPELL_CU_TALENTSPELL) && $id != 20711)
|
||||
continue;
|
||||
|
||||
// curious cases of OH MY FUCKING GOD WHY?!
|
||||
if ($id == 16268) // Shaman - Spirit Weapons (parry is normaly stored in g_statistics)
|
||||
{
|
||||
$data[$id]['parrypct'] = [5, 'add'];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($id == 20550) // Tauren - Endurance (dependant on base health) ... if you are looking for something elegant, look away!
|
||||
{
|
||||
$data[$id]['health'] = [0.05, 'functionOf', '$function(p) { return g_statistics.combo[p.classs][p.level][5]; }'];
|
||||
continue;
|
||||
}
|
||||
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
{
|
||||
$pts = $this->calculateAmountForCurrent($i)[1];
|
||||
$mv = $this->curTpl['effect'.$i.'MiscValue'];
|
||||
$au = $this->curTpl['effect'.$i.'AuraId'];
|
||||
$mv = $this->getField('effect'.$i.'MiscValue');
|
||||
$mvB = $this->getField('effect'.$i.'MiscValueB');
|
||||
$au = $this->getField('effect'.$i.'AuraId');
|
||||
$class = $this->getField('equippedItemClass');
|
||||
$subClass = $this->getField('equippedItemSubClassMask');
|
||||
|
||||
|
||||
/* ISSUE!
|
||||
mods formated like ['<statName>' => [<points>, 'percentOf', '<statName>']] are applied as multiplier and not
|
||||
as a flat value (that is equal to the percentage, like they should be). So the stats-table won't show the actual deficit
|
||||
*/
|
||||
|
||||
switch ($this->curTpl['effect'.$i.'AuraId'])
|
||||
switch ($au)
|
||||
{
|
||||
case 101:
|
||||
$data[$id][] = ['armor' => [$pts / 100, 'percentOf', 'armor']];
|
||||
case 101: // Mod Resistance Percent
|
||||
case 142: // Mod Base Resistance Percent
|
||||
if ($mv == 1) // Armor only if explicitly specified only affects armor from equippment
|
||||
$data[$id]['armor'] = [$pts / 100, 'percentOf', ['armor', 0]];
|
||||
else if ($mv)
|
||||
$modXBySchool($data[$id], 'res', $pts);
|
||||
break;
|
||||
case 13: // damage done flat
|
||||
// per magic school, omit physical
|
||||
case 182: // Mod Resistance Of Stat Percent
|
||||
if ($mv == 1) // Armor only if explicitly specified
|
||||
$data[$id]['armor'] = [$pts / 100, 'percentOf', $jsonStat($mvB)];
|
||||
else if ($mv)
|
||||
$modXBySchool($data[$id], 'res', [$pts / 100, 'percentOf', $jsonStat($mvB)]);
|
||||
break;
|
||||
case 30: // mod skill
|
||||
// diff between character skills and trade skills
|
||||
case 137: // mod stat percent
|
||||
if ($mv > -1) // one stat
|
||||
$modXByStat($data[$id], null, $pts);
|
||||
else if ($mv < 0) // all stats
|
||||
for ($iMod = ITEM_MOD_AGILITY; $iMod <= ITEM_MOD_STAMINA; $iMod++)
|
||||
$data[$id][Game::$itemMods[$iMod]] = [$pts / 100, 'percentOf', Game::$itemMods[$iMod]];
|
||||
break;
|
||||
case 174: // Mod Spell Damage Of Stat Percent
|
||||
$mv = $mv ?: SPELL_MAGIC_SCHOOLS;
|
||||
$modXBySchool($data[$id], 'spldmg', [$pts / 100, 'percentOf', $jsonStat($mvB)]);
|
||||
break;
|
||||
case 212: // Mod Ranged Attack Power Of Stat Percent
|
||||
$modXByStat($data[$id], 'rgdatkpwr', $pts);
|
||||
break;
|
||||
case 268: // Mod Attack Power Of Stat Percent
|
||||
$modXByStat($data[$id], 'mleatkpwr', $pts);
|
||||
break;
|
||||
case 175: // Mod Spell Healing Of Stat Percent
|
||||
$modXByStat($data[$id], 'splheal', $pts);
|
||||
break;
|
||||
case 219: // Mod Mana Regeneration from Stat
|
||||
$modXByStat($data[$id], 'manargn', $pts);
|
||||
break;
|
||||
case 134: // Mod Mana Regeneration Interrupt
|
||||
$data[$id]['icmanargn'] = [$pts / 100, 'percentOf', 'oocmanargn'];
|
||||
break;
|
||||
case 57: // Mod Spell Crit Chance
|
||||
case 71: // Mod Spell Crit Chance School
|
||||
$mv = $mv ?: SPELL_MAGIC_SCHOOLS;
|
||||
$modXBySchool($data[$id], 'splcritstrkpct', [$pts, 'add']);
|
||||
if (($mv & SPELL_MAGIC_SCHOOLS) == SPELL_MAGIC_SCHOOLS)
|
||||
$data[$id]['splcritstrkpct'] = [$pts, 'add'];
|
||||
break;
|
||||
case 285: // Mod Attack Power Of Armor
|
||||
$data[$id]['mleatkpwr'] = [1 / $pts, 'percentOf', 'fullarmor'];
|
||||
$data[$id]['rgdatkpwr'] = [1 / $pts, 'percentOf', 'fullarmor'];
|
||||
break;
|
||||
case 52: // Mod Physical Crit Percent
|
||||
if ($class < 1 || ($class == ITEM_CLASS_WEAPON && ($subClass & 0x5000C)))
|
||||
$data[$id]['rgdcritstrkpct'] = [1, 'functionOf', sprintf($whCheck, 18, $class, $subClass, $pts)];
|
||||
// $data[$id]['rgdcritstrkpct'] = [$pts, 'add'];
|
||||
if ($class < 1 || ($class == ITEM_CLASS_WEAPON && ($subClass & 0xA5F3)))
|
||||
$data[$id]['mlecritstrkpct'] = [1, 'functionOf', sprintf($whCheck, 16, $class, $subClass, $pts)];
|
||||
// $data[$id]['mlecritstrkpct'] = [$pts, 'add'];
|
||||
break;
|
||||
case 47: // Mod Parry Percent
|
||||
$data[$id]['parrypct'] = [$pts, 'add'];
|
||||
break;
|
||||
case 49: // Mod Dodge Percent
|
||||
$data[$id]['dodgepct'] = [$pts, 'add'];
|
||||
break;
|
||||
case 51: // Mod Block Percent
|
||||
$data[$id]['blockpct'] = [$pts, 'add'];
|
||||
break;
|
||||
case 132: // Mod Increase Energy Percent
|
||||
if ($mv == POWER_HEALTH)
|
||||
$data[$id]['health'] = [$pts / 100, 'percentOf', 'health'];
|
||||
else if ($mv == POWER_ENERGY)
|
||||
$data[$id]['energy'] = [$pts / 100, 'percentOf', 'energy'];
|
||||
else if ($mv == POWER_MANA)
|
||||
$data[$id]['mana'] = [$pts / 100, 'percentOf', 'mana'];
|
||||
else if ($mv == POWER_RAGE)
|
||||
$data[$id]['rage'] = [$pts / 100, 'percentOf', 'rage'];
|
||||
else if ($mv == POWER_RUNIC_POWER)
|
||||
$data[$id]['runic'] = [$pts / 100, 'percentOf', 'runic'];
|
||||
break;
|
||||
case 133: // Mod Increase Health Percent
|
||||
$data[$id]['health'] = [$pts / 100, 'percentOf', 'health'];
|
||||
break;
|
||||
case 150: // Mod Shield Blockvalue Percent
|
||||
$data[$id]['block'] = [$pts / 100, 'percentOf', 'block'];
|
||||
break;
|
||||
case 290: // Mod Crit Percent
|
||||
$data[$id]['mlecritstrkpct'] = [$pts, 'add'];
|
||||
$data[$id]['rgdcritstrkpct'] = [$pts, 'add'];
|
||||
$data[$id]['splcritstrkpct'] = [$pts, 'add'];
|
||||
break;
|
||||
case 237: // Mod Spell Damage Of Attack Power
|
||||
$mv = $mv ?: SPELL_MAGIC_SCHOOLS;
|
||||
$modXBySchool($data[$id], 'spldmg', [$pts / 100, 'percentOf', 'mleatkpwr']);
|
||||
break;
|
||||
case 238: // Mod Spell Healing Of Attack Power
|
||||
$data[$id]['splheal'] = [$pts / 100, 'percentOf', 'mleatkpwr'];
|
||||
break;
|
||||
case 166: // Mod Attack Power Percent [ingmae only melee..?]
|
||||
$data[$id]['mleatkpwr'] = [$pts / 100, 'percentOf', 'mleatkpwr'];
|
||||
break;
|
||||
case 88: // Mod Health Regeneration Percent
|
||||
$data[$id]['healthrgn'] = [$pts / 100, 'percentOf', 'healthrgn'];
|
||||
break;
|
||||
case 36: // shapeshift
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ class User
|
||||
private static $dataKey = '';
|
||||
private static $expires = false;
|
||||
private static $passHash = '';
|
||||
private static $excludeGroups = 1;
|
||||
private static $profiles = null;
|
||||
|
||||
public static function init()
|
||||
{
|
||||
@@ -54,7 +56,7 @@ class User
|
||||
return false;
|
||||
|
||||
$query = DB::Aowow()->SelectRow('
|
||||
SELECT a.id, a.passHash, a.displayName, a.locale, a.userGroups, a.userPerms, a.allowExpire, BIT_OR(ab.typeMask) AS bans, IFNULL(SUM(r.amount), 0) as reputation, a.avatar, a.dailyVotes
|
||||
SELECT a.id, a.passHash, a.displayName, a.locale, a.userGroups, a.userPerms, a.allowExpire, BIT_OR(ab.typeMask) AS bans, IFNULL(SUM(r.amount), 0) as reputation, a.avatar, a.dailyVotes, a.excludeGroups
|
||||
FROM ?_account a
|
||||
LEFT JOIN ?_account_banned ab ON a.id = ab.userId AND ab.end > UNIX_TIMESTAMP()
|
||||
LEFT JOIN ?_account_reputation r ON a.id = r.userId
|
||||
@@ -82,6 +84,17 @@ class User
|
||||
self::$groups = $query['bans'] & (ACC_BAN_TEMP | ACC_BAN_PERM) ? 0 : intval($query['userGroups']);
|
||||
self::$perms = $query['bans'] & (ACC_BAN_TEMP | ACC_BAN_PERM) ? 0 : intval($query['userPerms']);
|
||||
self::$dailyVotes = $query['dailyVotes'];
|
||||
self::$excludeGroups = $query['excludeGroups'];
|
||||
|
||||
$conditions = array(
|
||||
[['cuFlags', PROFILER_CU_DELETED, '&'], 0],
|
||||
['OR', ['user', self::$id], ['ap.accountId', self::$id]]
|
||||
);
|
||||
|
||||
if (self::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
array_shift($conditions);
|
||||
|
||||
self::$profiles = (new LocalProfileList($conditions));
|
||||
|
||||
if ($query['avatar'])
|
||||
self::$avatar = $query['avatar'];
|
||||
@@ -140,11 +153,11 @@ class User
|
||||
$rawIp = explode(',', $rawIp)[0]; // [ip, proxy1, proxy2]
|
||||
|
||||
// check IPv4
|
||||
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_RES_RANGE))
|
||||
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
|
||||
break;
|
||||
|
||||
// check IPv6
|
||||
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE))
|
||||
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -565,6 +578,11 @@ class User
|
||||
$gUser['downvoteRep'] = CFG_REP_REQ_DOWNVOTE;
|
||||
$gUser['upvoteRep'] = CFG_REP_REQ_UPVOTE;
|
||||
$gUser['characters'] = self::getCharacters();
|
||||
$gUser['excludegroups'] = self::$excludeGroups;
|
||||
$gUser['settings'] = (new StdClass); // profiler requires this to be set; has property premiumborder (NYI)
|
||||
|
||||
if ($_ = self::getProfilerExclusions())
|
||||
$gUser = array_merge($gUser, $_);
|
||||
|
||||
if ($_ = self::getProfiles())
|
||||
$gUser['profiles'] = $_;
|
||||
@@ -593,36 +611,32 @@ class User
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getProfilerExclusions()
|
||||
{
|
||||
$result = [];
|
||||
$modes = [1 => 'excludes', 2 => 'includes'];
|
||||
foreach ($modes as $mode => $field)
|
||||
if ($ex = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, typeId AS ARRAY_KEY2, typeId FROM ?_account_excludes WHERE mode = ?d AND userId = ?d', $mode, self::$id))
|
||||
foreach ($ex as $type => $ids)
|
||||
$result[$field][$type] = array_values($ids);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getCharacters()
|
||||
{
|
||||
// existing chars on realm(s)
|
||||
$characters = array(
|
||||
// array(
|
||||
// 'id' => 22,
|
||||
// 'name' => 'Example Char',
|
||||
// 'realmname' => 'Example Realm',
|
||||
// 'region' => 'eu',
|
||||
// 'realm' => 'example-realm',
|
||||
// 'race' => 6,
|
||||
// 'classs' => 11,
|
||||
// 'level' => 80,
|
||||
// 'gender' => 1,
|
||||
// 'pinned' => 1
|
||||
// )
|
||||
);
|
||||
if (!self::$profiles)
|
||||
return [];
|
||||
|
||||
return $characters;
|
||||
return self::$profiles->getJSGlobals(PROFILEINFO_CHARACTER);
|
||||
}
|
||||
|
||||
public static function getProfiles()
|
||||
{
|
||||
// chars build in profiler
|
||||
$profiles = array(
|
||||
// array('id' => 21, 'name' => 'Example Profile 1', 'race' => 4, 'classs' => 5, 'level' => 72, 'gender' => 1, 'icon' => 'inv_axe_04'),
|
||||
// array('id' => 23, 'name' => 'Example Profile 2', 'race' => 11, 'classs' => 3, 'level' => 17, 'gender' => 0)
|
||||
);
|
||||
if (!self::$profiles)
|
||||
return [];
|
||||
|
||||
return $profiles;
|
||||
return self::$profiles->getJSGlobals(PROFILEINFO_PROFILE);
|
||||
}
|
||||
|
||||
public static function getCookies()
|
||||
|
||||
@@ -370,7 +370,7 @@ class Util
|
||||
);
|
||||
|
||||
public static $configCats = array(
|
||||
'Other', 'Site', 'Caching', 'Account', 'Session', 'Site Reputation', 'Google Analytics'
|
||||
'Other', 'Site', 'Caching', 'Account', 'Session', 'Site Reputation', 'Google Analytics', 'Profiler'
|
||||
);
|
||||
|
||||
public static $tcEncoding = '0zMcmVokRsaqbdrfwihuGINALpTjnyxtgevElBCDFHJKOPQSUWXYZ123456789';
|
||||
@@ -413,16 +413,6 @@ class Util
|
||||
return self::formatTime($tDiff * 1000, true);
|
||||
}
|
||||
|
||||
public static function getBuyoutForItem($itemId)
|
||||
{
|
||||
if (!$itemId)
|
||||
return 0;
|
||||
|
||||
// try, when having filled char-DB at hand
|
||||
// return DB::Characters()->selectCell('SELECT SUM(a.buyoutprice) / SUM(ii.count) FROM auctionhouse a JOIN item_instance ii ON ii.guid = a.itemguid WHERE ii.itemEntry = ?d', $itemId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function formatMoney($qty)
|
||||
{
|
||||
$money = '';
|
||||
@@ -809,42 +799,6 @@ class Util
|
||||
}
|
||||
}
|
||||
|
||||
public static function urlize($str)
|
||||
{
|
||||
$search = ['<', '>', ' / ', "'", '(', ')'];
|
||||
$replace = ['<', '>', '-', '', '', ''];
|
||||
$str = str_replace($search, $replace, $str);
|
||||
|
||||
$accents = array(
|
||||
"ß" => "ss",
|
||||
"á" => "a", "ä" => "a", "à" => "a", "â" => "a",
|
||||
"è" => "e", "ê" => "e", "é" => "e", "ë" => "e",
|
||||
"í" => "i", "î" => "i", "ì" => "i", "ï" => "i",
|
||||
"ñ" => "n",
|
||||
"ò" => "o", "ó" => "o", "ö" => "o", "ô" => "o",
|
||||
"ú" => "u", "ü" => "u", "û" => "u", "ù" => "u",
|
||||
"œ" => "oe",
|
||||
"Á" => "A", "Ä" => "A", "À" => "A", "Â" => "A",
|
||||
"È" => "E", "Ê" => "E", "É" => "E", "Ë" => "E",
|
||||
"Í" => "I", "Î" => "I", "Ì" => "I", "Ï" => "I",
|
||||
"Ñ" => "N",
|
||||
"Ò" => "O", "Ó" => "O", "Ö" => "O", "Ô" => "O",
|
||||
"Ú" => "U", "Ü" => "U", "Û" => "U", "Ù" => "U",
|
||||
"œ" => "Oe"
|
||||
);
|
||||
$str = strtr($str, $accents);
|
||||
$str = trim($str);
|
||||
$str = preg_replace('/[^a-z0-9]/i', '-', $str);
|
||||
|
||||
$str = str_replace('--', '-', $str);
|
||||
$str = str_replace('--', '-', $str);
|
||||
|
||||
$str = rtrim($str, '-');
|
||||
$str = strtolower($str);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
public static function isValidEmail($email)
|
||||
{
|
||||
return preg_match('/^([a-z0-9._-]+)(\+[a-z0-9._-]+)?(@[a-z0-9.-]+\.[a-z]{2,4})$/i', $email);
|
||||
@@ -1168,40 +1122,88 @@ class Util
|
||||
return $json;
|
||||
}
|
||||
|
||||
public static function checkOrCreateDirectory($path)
|
||||
public static function createSqlBatchInsert(array $data)
|
||||
{
|
||||
$nRows = 100;
|
||||
$nItems = count(reset($data));
|
||||
$result = [];
|
||||
$buff = [];
|
||||
|
||||
if (!count($data))
|
||||
return [];
|
||||
|
||||
foreach ($data as $d)
|
||||
{
|
||||
if (count($d) != $nItems)
|
||||
return [];
|
||||
|
||||
$d = array_map(function ($x) {
|
||||
if ($x === null)
|
||||
return 'NULL';
|
||||
|
||||
return DB::Aowow()->escape($x);
|
||||
}, $d);
|
||||
|
||||
$buff[] = implode(',', $d);
|
||||
|
||||
if (count($buff) >= $nRows)
|
||||
{
|
||||
$result[] = '('.implode('),(', $buff).')';
|
||||
$buff = [];
|
||||
}
|
||||
}
|
||||
|
||||
if ($buff)
|
||||
$result[] = '('.implode('),(', $buff).')';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/* file handling */
|
||||
/*****************/
|
||||
|
||||
public static function writeFile($file, $content)
|
||||
{
|
||||
$success = false;
|
||||
if ($handle = @fOpen($file, "w"))
|
||||
{
|
||||
if (fWrite($handle, $content))
|
||||
$success = true;
|
||||
else
|
||||
trigger_error('could not write to file', E_USER_ERROR);
|
||||
|
||||
fClose($handle);
|
||||
}
|
||||
else
|
||||
trigger_error('could not create file', E_USER_ERROR);
|
||||
|
||||
if ($success)
|
||||
@chmod($file, Util::FILE_ACCESS);
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
public static function writeDir($dir)
|
||||
{
|
||||
// remove multiple slashes
|
||||
$path = preg_replace('|/+|', '/', $path);
|
||||
$dir = preg_replace('|/+|', '/', $dir);
|
||||
|
||||
if (!is_dir($path) && !@mkdir($path, self::FILE_ACCESS, true))
|
||||
trigger_error('Could not create directory: '.$path, E_USER_ERROR);
|
||||
else if (!is_writable($path) && !@chmod($path, self::FILE_ACCESS))
|
||||
trigger_error('Cannot write into directory: '.$path, E_USER_ERROR);
|
||||
else
|
||||
if (is_dir($dir))
|
||||
{
|
||||
if (!is_writable($dir) && !@chmod($dir, Util::FILE_ACCESS))
|
||||
trigger_error('cannot write into directory', E_USER_ERROR);
|
||||
|
||||
return is_writable($dir);
|
||||
}
|
||||
|
||||
if (@mkdir($dir, Util::FILE_ACCESS, true))
|
||||
return true;
|
||||
|
||||
trigger_error('could not create directory', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static $realms = [];
|
||||
public static function getRealms()
|
||||
{
|
||||
if (DB::isConnectable(DB_AUTH) && !self::$realms)
|
||||
{
|
||||
self::$realms = DB::Auth()->select('SELECT id AS ARRAY_KEY, name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0 AND gamebuild = ?d', WOW_BUILD);
|
||||
foreach (self::$realms as $rId => $rData)
|
||||
{
|
||||
if (DB::isConnectable(DB_CHARACTERS . $rId))
|
||||
continue;
|
||||
|
||||
unset(self::$realms[$rId]);
|
||||
trigger_error('Realm #'.$rId.' ('.$rData['name'].') has no connection info set.', E_USER_NOTICE);
|
||||
}
|
||||
}
|
||||
|
||||
return self::$realms;
|
||||
}
|
||||
|
||||
|
||||
/**************/
|
||||
/* Good Skill */
|
||||
|
||||
@@ -9,6 +9,7 @@ class Lang
|
||||
private static $mail;
|
||||
private static $game;
|
||||
private static $maps;
|
||||
private static $profiler;
|
||||
private static $screenshot;
|
||||
private static $privileges;
|
||||
|
||||
@@ -48,6 +49,13 @@ class Lang
|
||||
// *cough* .. reuse-hacks (because copy-pastaing text for 5 locales sucks)
|
||||
self::$item['cat'][2] = [self::$item['cat'][2], self::$spell['weaponSubClass']];
|
||||
self::$item['cat'][2][1][14] .= ' ('.self::$item['cat'][2][0].')';
|
||||
|
||||
// not localized .. for whatever reason
|
||||
self::$profiler['regions'] = array(
|
||||
'eu' => "Europe",
|
||||
'us' => "US & Oceanic"
|
||||
);
|
||||
|
||||
self::$main['moreTitles']['privilege'] = self::$privileges['_privileges'];
|
||||
}
|
||||
|
||||
@@ -252,6 +260,11 @@ class Lang
|
||||
if ($mask & (1 << $k) && $str)
|
||||
$tmp[] = $str;
|
||||
|
||||
if (!$tmp && $class == ITEM_CLASS_ARMOR)
|
||||
return self::spell('cat', -11, 8);
|
||||
else if (!$tmp && $class == ITEM_CLASS_WEAPON)
|
||||
return self::spell('cat', -11, 6);
|
||||
else
|
||||
return implode(', ', $tmp);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ class AchievementPage extends GenericPage
|
||||
if ($this->subject->getField('flags') & 0x100 && DB::isConnectable(DB_AUTH))
|
||||
{
|
||||
$avlb = [];
|
||||
foreach (Util::getRealms() AS $rId => $rData)
|
||||
foreach (Profiler::getRealms() AS $rId => $rData)
|
||||
if (!DB::Characters($rId)->selectCell('SELECT 1 FROM character_achievement WHERE achievement = ?d LIMIT 1', $this->typeId))
|
||||
$avlb[] = Util::ucWords($rData['name']);
|
||||
|
||||
|
||||
@@ -104,14 +104,14 @@ class AdminPage extends GenericPage
|
||||
$this->lvTabs[] = [null, array(
|
||||
'data' => $t,
|
||||
'name' => $n,
|
||||
'id' => Util::urlize($n)
|
||||
'id' => Profiler::urlize($n)
|
||||
)];
|
||||
|
||||
foreach ($miscTab as $n => $t)
|
||||
$this->lvTabs[] = [null, array(
|
||||
'data' => $t,
|
||||
'name' => $n,
|
||||
'id' => Util::urlize($n)
|
||||
'id' => Profiler::urlize($n)
|
||||
)];
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,88 @@ trait ListPage
|
||||
}
|
||||
}
|
||||
|
||||
trait TrProfiler
|
||||
{
|
||||
protected $region = '';
|
||||
protected $realm = '';
|
||||
protected $realmId = 0;
|
||||
protected $battlegroup = ''; // not implemented, since no pserver supports it
|
||||
protected $subjectName = '';
|
||||
protected $subjectGUID = 0;
|
||||
protected $sumSubjects = 0;
|
||||
|
||||
protected $doResync = null;
|
||||
|
||||
protected function getSubjectFromUrl($str)
|
||||
{
|
||||
if (!$str)
|
||||
return;
|
||||
|
||||
// cat[0] is always region
|
||||
// cat[1] is realm or bGroup (must be realm if cat[2] is set)
|
||||
// cat[2] is arena-team, guild or player
|
||||
$cat = explode('.', $str, 3);
|
||||
|
||||
$cat = array_map('urldecode', $cat);
|
||||
|
||||
if (count($cat) > 3)
|
||||
return;
|
||||
|
||||
if ($cat[0] !== 'eu' && $cat[0] !== 'us')
|
||||
return;
|
||||
|
||||
$this->region = $cat[0];
|
||||
|
||||
// if ($cat[1] == Profiler::urlize(CFG_BATTLEGROUP))
|
||||
// $this->battlegroup = CFG_BATTLEGROUP;
|
||||
if (isset($cat[1]))
|
||||
{
|
||||
foreach (Profiler::getRealms() as $rId => $r)
|
||||
{
|
||||
if (Profiler::urlize($r['name']) == $cat[1])
|
||||
{
|
||||
$this->realm = $r['name'];
|
||||
$this->realmId = $rId;
|
||||
if (isset($cat[2]) && mb_strlen($cat[2]) >= 3)
|
||||
$this->subjectName = $cat[2]; // cannot reconstruct original name from urlized form; match against special name field
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function initialSync()
|
||||
{
|
||||
$this->prepareContent();
|
||||
|
||||
$this->notFound = array(
|
||||
'title' => sprintf(Lang::profiler('firstUseTitle'), $this->subjectName, $this->realm),
|
||||
'msg' => ''
|
||||
);
|
||||
$this->hasComContent = false;
|
||||
Util::arraySumByKey($this->mysql, DB::Aowow()->getStatistics(), DB::World()->getStatistics());
|
||||
|
||||
if (isset($this->tabId))
|
||||
$this->pageTemplate['activeTab'] = $this->tabId;
|
||||
|
||||
$this->display('text-page-generic');
|
||||
exit();
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
if ($this->region)
|
||||
{
|
||||
$this->path[] = $this->region;
|
||||
|
||||
if ($this->realm)
|
||||
$this->path[] = Profiler::urlize($this->realm);
|
||||
// else
|
||||
// $this->path[] = Profiler::urlize(CFG_BATTLEGROUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GenericPage
|
||||
{
|
||||
@@ -148,7 +230,7 @@ class GenericPage
|
||||
if ($pageParam)
|
||||
$this->fullParams .= '='.$pageParam;
|
||||
|
||||
if (CFG_CACHE_DIR && Util::checkOrCreateDirectory(CFG_CACHE_DIR))
|
||||
if (CFG_CACHE_DIR && Util::writeDir(CFG_CACHE_DIR))
|
||||
$this->cacheDir = mb_substr(CFG_CACHE_DIR, -1) != '/' ? CFG_CACHE_DIR.'/' : CFG_CACHE_DIR;
|
||||
|
||||
// force page refresh
|
||||
|
||||
@@ -261,7 +261,7 @@ class ItemPage extends genericPage
|
||||
|
||||
// avg auction buyout
|
||||
if (in_array($this->subject->getField('bonding'), [0, 2, 3]))
|
||||
if ($_ = Util::getBuyoutForItem($this->typeId))
|
||||
if ($_ = Profiler::getBuyoutForItem($this->typeId))
|
||||
$infobox[] = '[tooltip=tooltip_buyoutprice]'.Lang::item('buyout.').'[/tooltip]'.Lang::main('colon').'[money='.$_.']'.$each;
|
||||
|
||||
// avg money contained
|
||||
|
||||
116
prQueue
Executable file
116
prQueue
Executable file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
require 'includes/shared.php';
|
||||
|
||||
/* todo (med):
|
||||
* tidy this file
|
||||
* make win-safe
|
||||
*/
|
||||
|
||||
if (!CLI)
|
||||
die("this script must be run from CLI\n");
|
||||
if (CLI && getcwd().DIRECTORY_SEPARATOR.'prQueue' != __FILE__)
|
||||
die("this script must be run from root directory\n");
|
||||
|
||||
if ($_ = getopt('', ['log::']))
|
||||
if (!empty($_['log']))
|
||||
CLI::initLogFile(trim($_['log']));
|
||||
|
||||
// check if we already have a queue running
|
||||
if (!Profiler::queueLock(getmypid()))
|
||||
exit();
|
||||
|
||||
|
||||
CLI::write('profiler queue started', CLI::LOG_OK);
|
||||
set_time_limit(0);
|
||||
$tCycle = microtime(true);
|
||||
|
||||
$error = function ($type, $typeId, $realmId)
|
||||
{
|
||||
$what = '';
|
||||
if ($type == TYPE_PROFILE)
|
||||
$what = 'char';
|
||||
if ($type == TYPE_GUILD)
|
||||
$what = 'guild';
|
||||
if ($type == TYPE_ARENA_TEAM)
|
||||
$what = 'arena team';
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET status = ?d, errorCode = ?d WHERE realm = ?d AND type = ?d AND typeId = ?d', PR_QUEUE_STATUS_ERROR, PR_QUEUE_ERROR_CHAR, $realmId, $type, $typeId);
|
||||
trigger_error('prQueue - unknown '.$what.' guid #'.$typeId.' on realm #'.$realmId.' to sync into profiler.', E_USER_WARNING);
|
||||
CLI::write('unknown '.$what.' guid #'.$typeId.' on realm #'.$realmId.' to sync into profiler.', CLI::LOG_WARN);
|
||||
};
|
||||
|
||||
|
||||
// if (CFG_PROFILER_QUEUE) - wont work because it is not redefined if changed in config
|
||||
while (DB::Aowow()->selectCell('SELECT value FROM ?_config WHERE `key` = "profiler_queue"'))
|
||||
{
|
||||
if (($tDiff = (microtime(true) - $tCycle)) < (CFG_PROFILER_QUEUE_DELAY / 1000))
|
||||
{
|
||||
$wait = (CFG_PROFILER_QUEUE_DELAY / 1000) - $tDiff;
|
||||
CLI::write('sleeping '.Lang::nf($wait, 2).'s..');
|
||||
usleep($wait * 1000 * 1000);
|
||||
}
|
||||
|
||||
$tCycle = microtime(true);
|
||||
|
||||
$row = DB::Aowow()->selectRow('SELECT * FROM ?_profiler_sync WHERE status = ?d ORDER BY requestTime ASC', PR_QUEUE_STATUS_WAITING);
|
||||
if (!$row)
|
||||
{
|
||||
// nothing more to do
|
||||
CLI::write('profiler queue empty - process halted!', CLI::LOG_INFO);
|
||||
Profiler::queueFree();
|
||||
exit();
|
||||
}
|
||||
// scheduled for future date
|
||||
if ($row['requestTime'] > time())
|
||||
continue;
|
||||
|
||||
if (empty(Profiler::getRealms()[$row['realm']]))
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET status = ?d, errorCode = ?d WHERE realm = ?d AND type = ?d AND typeId = ?d', PR_QUEUE_STATUS_ERROR, PR_QUEUE_ERROR_ARMORY, $row['realm'], $row['type'], $row['typeId']);
|
||||
CLI::write('realm #'.$row['realm'].' for subject guid '.$row['realmGUID'].' is undefined', CLI::LOG_WARN);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET status = ?d WHERE requestTime = ?d AND realm = ?d AND type = ?d AND typeId = ?d', PR_QUEUE_STATUS_WORKING, time(), $row['realm'], $row['type'], $row['typeId']);
|
||||
|
||||
switch ($row['type'])
|
||||
{
|
||||
case TYPE_PROFILE:
|
||||
if (!Profiler::getCharFromRealm($row['realm'], $row['realmGUID']))
|
||||
{
|
||||
$error(TYPE_PROFILE, $row['realmGUID'], $row['realm']);
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
case TYPE_GUILD:
|
||||
if (!Profiler::getGuildFromRealm($row['realm'], $row['realmGUID']))
|
||||
{
|
||||
$error(TYPE_ARENA_GUILD, $row['realmGUID'], $row['realm']);
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
case TYPE_ARENA_TEAM:
|
||||
if (!Profiler::getArenaTeamFromRealm($row['realm'], $row['realmGUID']))
|
||||
{
|
||||
$error(TYPE_ARENA_TEAM, $row['realmGUID'], $row['realm']);
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_sync WHERE realm = ?d AND type = ?d AND typeId = ?d', $row['realm'], $row['type'], $row['typeId']);
|
||||
trigger_error('prQueue - unknown type #'.$row['type'].' to sync into profiler. Removing from queue...', E_USER_ERROR);
|
||||
CLI::write('unknown type #'.$row['type'].' to sync into profiler. Removing from queue...', CLI::LOG_ERROR);
|
||||
}
|
||||
|
||||
// mark as ready
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET status = ?d, errorCode = 0 WHERE realm = ?d AND type = ?d AND typeId = ?d', PR_QUEUE_STATUS_READY, $row['realm'], $row['type'], $row['typeId']);
|
||||
}
|
||||
|
||||
Profiler::queueFree();
|
||||
CLI::write('profiler queue halted!', CLI::LOG_INFO);
|
||||
|
||||
?>
|
||||
File diff suppressed because one or more lines are too long
@@ -233,12 +233,21 @@ class FileGen
|
||||
CLI::write('Also, expected include setup/tools/filegen/'.$name.'.func.php was not found.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fWrite($dest, $content))
|
||||
{
|
||||
CLI::write(sprintf(ERR_NONE, CLI::bold($destPath.$file)), CLI::LOG_OK);
|
||||
if ($content && $funcOK)
|
||||
if (CLISetup::writeFile($destPath.$file, $content))
|
||||
$success = true;
|
||||
}
|
||||
else
|
||||
CLI::write(sprintf(ERR_WRITE_FILE, CLI::bold($destPath.$file)), CLI::LOG_ERROR);
|
||||
|
||||
fClose($dest);
|
||||
}
|
||||
else
|
||||
CLI::write(sprintf(ERR_CREATE_FILE, CLI::bold($destPath.$file)), CLI::LOG_ERROR);
|
||||
}
|
||||
else
|
||||
CLI::write(sprintf(ERR_READ_FILE, CLI::bold(FileGen::$tplPath.$file.'.in')), CLI::LOG_ERROR);
|
||||
}
|
||||
|
||||
@@ -14,11 +14,27 @@ if (!CLI)
|
||||
{
|
||||
$success = true;
|
||||
$scripts = [];
|
||||
$exclusions = [];
|
||||
|
||||
$exAdd = function ($type, $typeId, $groups, $comment = '') use(&$exclusions)
|
||||
{
|
||||
$k = $type.'-'.$typeId;
|
||||
|
||||
if (!isset($exclusions[$k]))
|
||||
$exclusions[$k] = ['type' => $type, 'typeId' => $typeId, 'groups' => $groups, 'comment' => $comment];
|
||||
else
|
||||
{
|
||||
$exclusions[$k]['groups'] |= $groups;
|
||||
if ($comment)
|
||||
$exclusions[$k]['comment'] .= '; '.$comment;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**********/
|
||||
/* Quests */
|
||||
/**********/
|
||||
$scripts[] = function()
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = [
|
||||
@@ -30,6 +46,23 @@ if (!CLI)
|
||||
];
|
||||
$questz = new QuestList($condition);
|
||||
|
||||
// get quests for exclusion
|
||||
foreach ($questz->iterate() as $id => $__)
|
||||
{
|
||||
switch ($questz->getField('reqSkillId'))
|
||||
{
|
||||
case 356:
|
||||
$exAdd(TYPE_QUEST, $id, PR_EXCLUDE_GROUP_REQ_FISHING);
|
||||
break;
|
||||
case 202:
|
||||
$exAdd(TYPE_QUEST, $id, PR_EXCLUDE_GROUP_REQ_ENGINEERING);
|
||||
break;
|
||||
case 197:
|
||||
$exAdd(TYPE_QUEST, $id, PR_EXCLUDE_GROUP_REQ_TAILORING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$_ = [];
|
||||
$currencies = array_column($questz->rewards, TYPE_CURRENCY);
|
||||
foreach ($currencies as $curr)
|
||||
@@ -62,50 +95,10 @@ if (!CLI)
|
||||
return $success;
|
||||
};
|
||||
|
||||
/****************/
|
||||
/* Achievements */
|
||||
/****************/
|
||||
$scripts[] = function()
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
CFG_SQL_LIMIT_NONE,
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
[['flags', 1, '&'], 0], // no statistics
|
||||
);
|
||||
$achievez = new AchievementList($condition);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load(Util::$localeStrings[$l]);
|
||||
|
||||
$sumPoints = 0;
|
||||
$buff = "var _ = g_achievements;\n";
|
||||
foreach ($achievez->getListviewData(ACHIEVEMENTINFO_PROFILE) as $id => $data)
|
||||
{
|
||||
$sumPoints += $data['points'];
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
// categories to sort by
|
||||
$buff .= "\ng_achievement_catorder = [92, 14863, 97, 169, 170, 171, 172, 14802, 14804, 14803, 14801, 95, 161, 156, 165, 14806, 14921, 96, 201, 160, 14923, 14808, 14805, 14778, 14865, 14777, 14779, 155, 14862, 14861, 14864, 14866, 158, 162, 14780, 168, 14881, 187, 14901, 163, 14922, 159, 14941, 14961, 14962, 14981, 15003, 15002, 15001, 15041, 15042, 81]";
|
||||
// sum points
|
||||
$buff .= "\ng_achievement_points = [".$sumPoints."];\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-achievements', $buff))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/**********/
|
||||
/* Titles */
|
||||
/**********/
|
||||
$scripts[] = function()
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
@@ -114,6 +107,11 @@ if (!CLI)
|
||||
);
|
||||
$titlez = new TitleList($condition);
|
||||
|
||||
// get titles for exclusion
|
||||
foreach ($titlez->iterate() as $id => $__)
|
||||
if (empty($titlez->sources[$id][4]) && empty($titlez->sources[$id][12]))
|
||||
$exAdd(TYPE_TITLE, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
@@ -142,7 +140,7 @@ if (!CLI)
|
||||
/**********/
|
||||
/* Mounts */
|
||||
/**********/
|
||||
$scripts[] = function()
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
@@ -177,7 +175,7 @@ if (!CLI)
|
||||
/**************/
|
||||
/* Companions */
|
||||
/**************/
|
||||
$scripts[] = function()
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
@@ -212,7 +210,7 @@ if (!CLI)
|
||||
/************/
|
||||
/* Factions */
|
||||
/************/
|
||||
$scripts[] = function()
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array( // todo (med): exclude non-gaining reputation-header
|
||||
@@ -244,7 +242,7 @@ if (!CLI)
|
||||
/***********/
|
||||
/* Recipes */
|
||||
/***********/
|
||||
$scripts[] = function()
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
// special case: secondary skills are always requested, so put them in one single file (185, 129, 356); it also contains g_skill_order
|
||||
$skills = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, [185, 129, 356]];
|
||||
@@ -303,6 +301,81 @@ if (!CLI)
|
||||
return $success;
|
||||
};
|
||||
|
||||
/****************/
|
||||
/* Achievements */
|
||||
/****************/
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
CFG_SQL_LIMIT_NONE,
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
[['flags', 1, '&'], 0], // no statistics
|
||||
);
|
||||
$achievez = new AchievementList($condition);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load(Util::$localeStrings[$l]);
|
||||
|
||||
$sumPoints = 0;
|
||||
$buff = "var _ = g_achievements;\n";
|
||||
foreach ($achievez->getListviewData(ACHIEVEMENTINFO_PROFILE) as $id => $data)
|
||||
{
|
||||
$sumPoints += $data['points'];
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
// categories to sort by
|
||||
$buff .= "\ng_achievement_catorder = [92, 14863, 97, 169, 170, 171, 172, 14802, 14804, 14803, 14801, 95, 161, 156, 165, 14806, 14921, 96, 201, 160, 14923, 14808, 14805, 14778, 14865, 14777, 14779, 155, 14862, 14861, 14864, 14866, 158, 162, 14780, 168, 14881, 187, 14901, 163, 14922, 159, 14941, 14961, 14962, 14981, 15003, 15002, 15001, 15041, 15042, 81]";
|
||||
// sum points
|
||||
$buff .= "\ng_achievement_points = [".$sumPoints."];\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/achievements', $buff))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/******************/
|
||||
/* Quick Excludes */
|
||||
/******************/
|
||||
$scripts[] = function() use (&$exclusions)
|
||||
{
|
||||
$s = count($exclusions);
|
||||
$i = $n = 0;
|
||||
CLI::write('applying '.$s.' baseline exclusions');
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_excludes WHERE comment = ""');
|
||||
foreach ($exclusions as $ex)
|
||||
{
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_excludes (?#) VALUES (?a)', array_keys($ex), array_values($ex));
|
||||
if ($i >= 500)
|
||||
{
|
||||
$i = 0;
|
||||
CLI::write(' * '.$n.' / '.$s.' ('.Lang::nf(100 * $n / $s, 1).'%)');
|
||||
}
|
||||
$i++;
|
||||
$n++;
|
||||
}
|
||||
|
||||
// excludes; type => [excludeGroupBit => [typeIds]]
|
||||
$excludes = [];
|
||||
|
||||
$exData = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, `typeId` AS ARRAY_KEY2, groups FROM ?_profiler_excludes');
|
||||
for ($i = 0; (1 << $i) < PR_EXCLUDE_GROUP_ANY; $i++)
|
||||
foreach ($exData as $type => $data)
|
||||
if ($ids = array_keys(array_filter($data, function ($x) use ($i) { return $x & (1 << $i); } )))
|
||||
$excludes[$type][$i + 1] = $ids;
|
||||
|
||||
$buff = "g_excludes = ".Util::toJSON($excludes ?: (new Stdclass)).";\n";
|
||||
|
||||
return CLISetup::writeFile('datasets/quick-excludes', $buff);
|
||||
};
|
||||
|
||||
// check directory-structure
|
||||
foreach (Util::$localeStrings as $dir)
|
||||
if (!CLISetup::writeDir('datasets/'.$dir))
|
||||
|
||||
@@ -42,21 +42,24 @@ if (!CLI)
|
||||
$subUS = [];
|
||||
$set = 0x0;
|
||||
$menu = [
|
||||
['us', 'US & Oceanic', null,[[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subUS]]],
|
||||
['eu', 'Europe', null,[[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subEU]]]
|
||||
// skip usage of battlegroup
|
||||
// ['us', Lang::profiler('regions', 'us'), null,[[Profiler::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subUS]]],
|
||||
// ['eu', Lang::profiler('regions', 'eu'), null,[[Profiler::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subEU]]]
|
||||
['us', Lang::profiler('regions', 'us'), null, &$subUS],
|
||||
['eu', Lang::profiler('regions', 'eu'), null, &$subEU]
|
||||
];
|
||||
|
||||
foreach (Util::getRealms() as $row)
|
||||
foreach (Profiler::getRealms() as $row)
|
||||
{
|
||||
if ($row['region'] == 'eu')
|
||||
{
|
||||
$set |= 0x1;
|
||||
$subEU[] = [Util::urlize($row['name']), $row['name']];
|
||||
$subEU[] = [Profiler::urlize($row['name']), $row['name']];
|
||||
}
|
||||
else if ($row['region'] == 'us')
|
||||
{
|
||||
$set |= 0x2;
|
||||
$subUS[] = [Util::urlize($row['name']), $row['name']];
|
||||
$subUS[] = [Profiler::urlize($row['name']), $row['name']];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ if (!CLI)
|
||||
|
||||
function realms()
|
||||
{
|
||||
$realms = Util::getRealms();
|
||||
$realms = Profiler::getRealms();
|
||||
if (!$realms)
|
||||
CLI::write(' - realms: Auth-DB not set up .. static data g_realms will be empty', CLI::LOG_WARN);
|
||||
else
|
||||
foreach ($realms as &$r)
|
||||
$r['battlegroup'] = CFG_BATTLEGROUP;
|
||||
// else
|
||||
// foreach ($realms as &$r)
|
||||
// $r['battlegroup'] = CFG_BATTLEGROUP;
|
||||
|
||||
$toFile = "var g_realms = ".Util::toJSON($realms).";";
|
||||
$file = 'datasets/realms';
|
||||
|
||||
@@ -32,21 +32,21 @@ if (!CLI)
|
||||
baseParryPct
|
||||
ParryCap
|
||||
baseBlockPct
|
||||
directMod1 applies mod directly only one class having something worth mentioning: DK
|
||||
directMod2 applies mod directly so what were they originally used for..?
|
||||
classMod1 applies mod directly only one class having something worth mentioning: DK
|
||||
classMod2 applies mod directly so what were they originally used for..?
|
||||
*/
|
||||
|
||||
$dataz = array(
|
||||
1 => [[-20, 2, 0, 3], [-10, 0, 1, 1], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 5, 0, 0],
|
||||
2 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.4943, 88.129021, 5, 47.003525, 5, 0, 0],
|
||||
3 => [[-20, 1, 1, 2], [-10, 0, 2, 2], null, 0.9880, -4.0873, 145.560408, 5, 145.560408, 0, 0, 0],
|
||||
4 => [[-20, 1, 1, 2], [-10, 0, 1, 1], null, 0.9880, 2.0957, 145.560408, 5, 145.560408, 0, 0, 0],
|
||||
5 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.4178, 150.375940, 0, 0.0, 0, 0, 0],
|
||||
6 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 0, 0, ['parryrtng' => [0.25, 'percentOf', 'str']]], // Forcefull Deflection (49410)
|
||||
7 => [[-20, 1, 1, 2], [-10, 0, 1, 0], null, 0.9880, 2.1080, 145.560408, 0, 145.560408, 5, 0, 0],
|
||||
8 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.6587, 150.375940, 0, 0.0, 0, 0, 0],
|
||||
9 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 2.4211, 150.375940, 0, 0.0, 0, 0, 0],
|
||||
11 => [[-20, 2, 0, 0], [-10, 0, 1, 0], null, 0.9720, 5.6097, 116.890707, 0, 0.0, 0, 0, 0]
|
||||
1 => [[-20, 2, 0, 3], [-10, 0, 1, 1], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 5, [], []],
|
||||
2 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.4943, 88.129021, 5, 47.003525, 5, [], []],
|
||||
3 => [[-20, 1, 1, 2], [-10, 0, 1, 2], null, 0.9880, -4.0873, 145.560408, 5, 145.560408, 0, [], []],
|
||||
4 => [[-20, 1, 1, 2], [-10, 0, 1, 1], null, 0.9880, 2.0957, 145.560408, 5, 145.560408, 0, [], []],
|
||||
5 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.4178, 150.375940, 0, 0.0, 0, [], []],
|
||||
6 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 0, [], ['parryrtng' => [0.25, 'percentOf', 'str']]], // Forcefull Deflection (49410)
|
||||
7 => [[-20, 1, 1, 2], [-10, 0, 1, 0], null, 0.9880, 2.1080, 145.560408, 0, 145.560408, 5, [], []],
|
||||
8 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.6587, 150.375940, 0, 0.0, 0, [], []],
|
||||
9 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 2.4211, 150.375940, 0, 0.0, 0, [], []],
|
||||
11 => [[-20, 2, 0, 0], [-10, 0, 1, 0], null, 0.9720, 5.6097, 116.890707, 0, 0.0, 0, [], []]
|
||||
);
|
||||
|
||||
foreach ($dataz as $class => &$data)
|
||||
@@ -57,20 +57,43 @@ if (!CLI)
|
||||
|
||||
$race = function()
|
||||
{
|
||||
// { str, agi, sta, int, spi, hp, mana, directMod1, directMod2 }
|
||||
|
||||
return array(
|
||||
1 => [20, 20, 20, 20, 20, 0, ['spi' => [0.05, 'percentOf', 'spi']]], // The Human Spirit (20598)
|
||||
2 => [23, 17, 22, 17, 23, 0, 0],
|
||||
3 => [22, 16, 23, 19, 19, 0, 0],
|
||||
4 => [17, 25, 19, 20, 20, 0, 0],
|
||||
5 => [19, 18, 21, 18, 25, 0, 0],
|
||||
6 => [25, 15, 22, 15, 22, 0, ['health' => [0.05, 'functionOf', '$function(p) { return g_statistics.combo[p.classs][p.level][5]; }']]], // Endurance (20550) ... if you are looking for something elegant, look away!
|
||||
7 => [15, 23, 19, 24, 20, 0, ['int' => [0.05, 'percentOf', 'int']]], // Expansive Mind (20591)
|
||||
8 => [21, 22, 21, 16, 21, 0, ['healthrgn' => [0.1, 'percentOf', 'healthrgn']]], // Regeneration (20555)
|
||||
10 => [17, 22, 18, 24, 19, 0, 0],
|
||||
11 => [21, 17, 19, 21, 22, 0, 0] // ['mlehitpct' => [1, 'add'], 'splhitpct' => [1, 'add'], 'rgdhitpct' => [1, 'add']] // Heroic Presence (6562, 28878) (not actually shown..?)
|
||||
// where did i get this data again..?
|
||||
// { str, agi, sta, int, spi, raceMod1, raceMod2 }
|
||||
$raceData = array(
|
||||
1 => [20, 20, 20, 20, 20, [], []],
|
||||
2 => [23, 17, 22, 17, 23, [], []],
|
||||
3 => [22, 16, 23, 19, 19, [], []],
|
||||
4 => [17, 25, 19, 20, 20, [], []],
|
||||
5 => [19, 18, 21, 18, 25, [], []],
|
||||
6 => [25, 15, 22, 15, 22, [], []],
|
||||
7 => [15, 23, 19, 24, 20, [], []],
|
||||
8 => [21, 22, 21, 16, 21, [], []],
|
||||
10 => [17, 22, 18, 24, 19, [], []],
|
||||
11 => [21, 17, 19, 21, 22, [], []]
|
||||
);
|
||||
|
||||
$racials = new SpellList(array(['typeCat', -4], ['reqClassMask', 0]));
|
||||
$allMods = $racials->getProfilerMods();
|
||||
foreach ($allMods as $spellId => $mods)
|
||||
{
|
||||
if (!$mods)
|
||||
continue;
|
||||
|
||||
// if there is ever a case where a racial is shared between races i don't want to know about it!
|
||||
$raceId = log($racials->getEntry($spellId)['reqRaceMask'], 2) + 1;
|
||||
if (!isset($raceData[$raceId]))
|
||||
continue;
|
||||
|
||||
foreach ($mods as $jsonStat => $mod)
|
||||
{
|
||||
if (empty($raceData[$raceId][5][$jsonStat]))
|
||||
$raceData[$raceId][5][$jsonStat] = $mod;
|
||||
else
|
||||
$raceData[$raceId][6][$jsonStat] = $mod;
|
||||
}
|
||||
}
|
||||
|
||||
return $raceData;
|
||||
};
|
||||
|
||||
$combo = function()
|
||||
@@ -143,12 +166,27 @@ if (!CLI)
|
||||
|
||||
$skills = function()
|
||||
{
|
||||
// profession perks (skinning => +crit, mining => +stam) and maybe some others; skillId:{rankNo:someJSON, ..}?
|
||||
|
||||
return [];
|
||||
// profession perks ... too lazy to formulate a search algorithm for two occurences
|
||||
return array(
|
||||
186 => array( // mining / toughness
|
||||
75 => ['sta' => 3],
|
||||
150 => ['sta' => 5],
|
||||
225 => ['sta' => 7],
|
||||
300 => ['sta' => 10],
|
||||
375 => ['sta' => 30],
|
||||
450 => ['sta' => 60],
|
||||
),
|
||||
393 => array( // skinning / master of anatomy
|
||||
75 => ['critstrkrtng' => 3],
|
||||
150 => ['critstrkrtng' => 6],
|
||||
225 => ['critstrkrtng' => 9],
|
||||
300 => ['critstrkrtng' => 12],
|
||||
375 => ['critstrkrtng' => 20],
|
||||
450 => ['critstrkrtng' => 40],
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
// todo: x
|
||||
$sub = ['classs', 'race', 'combo', 'level', 'skills'];
|
||||
$out = [];
|
||||
$success = true;
|
||||
|
||||
@@ -31,7 +31,9 @@ if (!CLI)
|
||||
function talentCalc()
|
||||
{
|
||||
$success = true;
|
||||
$buildTree = function ($class) use (&$petFamIcons, &$tSpells)
|
||||
$spellMods = (new SpellList(array(['typeCat', -2], CFG_SQL_LIMIT_NONE)))->getProfilerMods();
|
||||
|
||||
$buildTree = function ($class) use (&$petFamIcons, &$tSpells, $spellMods)
|
||||
{
|
||||
$petCategories = [];
|
||||
|
||||
@@ -41,43 +43,44 @@ if (!CLI)
|
||||
$tabs = DB::Aowow()->select('SELECT * FROM dbc_talenttab WHERE classMask = ?d ORDER BY `tabNumber`, `creatureFamilyMask`', $mask);
|
||||
$result = [];
|
||||
|
||||
for ($l = 0; $l < count($tabs); $l++)
|
||||
for ($tabIdx = 0; $tabIdx < count($tabs); $tabIdx++)
|
||||
{
|
||||
$talents = DB::Aowow()->select('SELECT t.id AS tId, t.*, s.name_loc0, s.name_loc2, s.name_loc3, s.name_loc6, s.name_loc8, LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) AS iconString FROM dbc_talent t, dbc_spell s, dbc_spellicon si WHERE si.`id` = s.`iconId` AND t.`tabId`= ?d AND s.`id` = t.`rank1` ORDER by t.`row`, t.`column`', $tabs[$l]['id']);
|
||||
$result[$l] = array(
|
||||
'n' => Util::localizedString($tabs[$l], 'name'),
|
||||
$talents = DB::Aowow()->select('SELECT t.id AS tId, t.*, s.name_loc0, s.name_loc2, s.name_loc3, s.name_loc6, s.name_loc8, LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) AS iconString FROM dbc_talent t, dbc_spell s, dbc_spellicon si WHERE si.`id` = s.`iconId` AND t.`tabId`= ?d AND s.`id` = t.`rank1` ORDER by t.`row`, t.`column`', $tabs[$tabIdx]['id']);
|
||||
$result[$tabIdx] = array(
|
||||
'n' => Util::localizedString($tabs[$tabIdx], 'name'),
|
||||
't' => []
|
||||
);
|
||||
|
||||
if (!$class)
|
||||
{
|
||||
$petFamId = log($tabs[$l]['creatureFamilyMask'], 2);
|
||||
$result[$l]['icon'] = $petFamIcons[$petFamId];
|
||||
$petFamId = log($tabs[$tabIdx]['creatureFamilyMask'], 2);
|
||||
$result[$tabIdx]['icon'] = $petFamIcons[$petFamId];
|
||||
$petCategories = DB::Aowow()->SelectCol('SELECT id AS ARRAY_KEY, categoryEnumID FROM dbc_creaturefamily WHERE petTalentType = ?d', $petFamId);
|
||||
$result[$l]['f'] = array_keys($petCategories);
|
||||
$result[$tabIdx]['f'] = array_keys($petCategories);
|
||||
}
|
||||
|
||||
// talent dependencies go here
|
||||
$depLinks = [];
|
||||
$tNums = [];
|
||||
|
||||
for ($j = 0; $j < count($talents); $j++)
|
||||
for ($talentIdx = 0; $talentIdx < count($talents); $talentIdx++)
|
||||
{
|
||||
$tNums[$talents[$j]['tId']] = $j;
|
||||
$tNums[$talents[$talentIdx]['tId']] = $talentIdx;
|
||||
|
||||
$d = [];
|
||||
$s = [];
|
||||
$i = $talents[$j]['tId'];
|
||||
$n = Util::localizedString($talents[$j], 'name');
|
||||
$x = $talents[$j]['column'];
|
||||
$y = $talents[$j]['row'];
|
||||
$i = $talents[$talentIdx]['tId'];
|
||||
$n = Util::localizedString($talents[$talentIdx], 'name');
|
||||
$x = $talents[$talentIdx]['column'];
|
||||
$y = $talents[$talentIdx]['row'];
|
||||
$r = null;
|
||||
$t = [];
|
||||
$icon = $talents[$j]['iconString'];
|
||||
$m = $talents[$j]['rank2'] == 0 ? 1 : (
|
||||
$talents[$j]['rank3'] == 0 ? 2 : (
|
||||
$talents[$j]['rank4'] == 0 ? 3 : (
|
||||
$talents[$j]['rank5'] == 0 ? 4 : 5
|
||||
$j = [];
|
||||
$icon = $talents[$talentIdx]['iconString'];
|
||||
$m = $talents[$talentIdx]['rank2'] == 0 ? 1 : (
|
||||
$talents[$talentIdx]['rank3'] == 0 ? 2 : (
|
||||
$talents[$talentIdx]['rank4'] == 0 ? 3 : (
|
||||
$talents[$talentIdx]['rank5'] == 0 ? 4 : 5
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -87,34 +90,38 @@ if (!CLI)
|
||||
foreach ($petCategories as $k => $v)
|
||||
{
|
||||
// cant handle 64bit integer .. split
|
||||
if ($v >= 32 && ((1 << ($v - 32)) & $talents[$j]['petCategory2']))
|
||||
if ($v >= 32 && ((1 << ($v - 32)) & $talents[$talentIdx]['petCategory2']))
|
||||
$f[] = $k;
|
||||
else if ($v < 32 && ((1 << $v) & $talents[$j]['petCategory1']))
|
||||
else if ($v < 32 && ((1 << $v) & $talents[$talentIdx]['petCategory1']))
|
||||
$f[] = $k;
|
||||
}
|
||||
|
||||
for ($k = 0; $k <= ($m - 1); $k++)
|
||||
for ($itr = 0; $itr <= ($m - 1); $itr++)
|
||||
{
|
||||
if (!$tSpells->getEntry($talents[$j]['rank'.($k + 1)]))
|
||||
if (!$tSpells->getEntry($talents[$talentIdx]['rank'.($itr + 1)]))
|
||||
continue;
|
||||
|
||||
$d[] = $tSpells->parseText()[0];
|
||||
$s[] = $talents[$j]['rank'.($k + 1)];
|
||||
$s[] = $talents[$talentIdx]['rank'.($itr + 1)];
|
||||
if (isset($spellMods[$talents[$talentIdx]['rank'.($itr + 1)]]))
|
||||
$j[] = $spellMods[$talents[$talentIdx]['rank'.($itr + 1)]];
|
||||
else
|
||||
$j[] = null;
|
||||
|
||||
if ($talents[$j]['talentSpell'])
|
||||
if ($talents[$talentIdx]['talentSpell'])
|
||||
$t[] = $tSpells->getTalentHeadForCurrent();
|
||||
}
|
||||
|
||||
if ($talents[$j]['reqTalent'])
|
||||
if ($talents[$talentIdx]['reqTalent'])
|
||||
{
|
||||
// we didn't encounter the required talent yet => create reference
|
||||
if (!isset($tNums[$talents[$j]['reqTalent']]))
|
||||
$depLinks[$talents[$j]['reqTalent']] = $j;
|
||||
if (!isset($tNums[$talents[$talentIdx]['reqTalent']]))
|
||||
$depLinks[$talents[$talentIdx]['reqTalent']] = $talentIdx;
|
||||
|
||||
$r = @[$tNums[$talents[$j]['reqTalent']], $talents[$j]['reqRank'] + 1];
|
||||
$r = @[$tNums[$talents[$talentIdx]['reqTalent']], $talents[$talentIdx]['reqRank'] + 1];
|
||||
}
|
||||
|
||||
$result[$l]['t'][$j] = array(
|
||||
$result[$tabIdx]['t'][$talentIdx] = array(
|
||||
'i' => $i,
|
||||
'n' => $n,
|
||||
'm' => $m,
|
||||
@@ -122,31 +129,32 @@ if (!CLI)
|
||||
's' => $s,
|
||||
'x' => $x,
|
||||
'y' => $y,
|
||||
'j' => $j
|
||||
);
|
||||
|
||||
if (isset($r))
|
||||
$result[$l]['t'][$j]['r'] = $r;
|
||||
$result[$tabIdx]['t'][$talentIdx]['r'] = $r;
|
||||
|
||||
if (!empty($t))
|
||||
$result[$l]['t'][$j]['t'] = $t;
|
||||
$result[$tabIdx]['t'][$talentIdx]['t'] = $t;
|
||||
|
||||
if (!empty($f))
|
||||
$result[$l]['t'][$j]['f'] = $f;
|
||||
$result[$tabIdx]['t'][$talentIdx]['f'] = $f;
|
||||
|
||||
if ($class)
|
||||
$result[$l]['t'][$j]['iconname'] = $icon;
|
||||
$result[$tabIdx]['t'][$talentIdx]['iconname'] = $icon;
|
||||
|
||||
// If this talent is a reference, add it to the array of talent dependencies
|
||||
if (isset($depLinks[$talents[$j]['tId']]))
|
||||
if (isset($depLinks[$talents[$talentIdx]['tId']]))
|
||||
{
|
||||
$result[$l]['t'][$depLinks[$talents[$j]['tId']]]['r'][0] = $j;
|
||||
unset($depLinks[$talents[$j]['tId']]);
|
||||
$result[$tabIdx]['t'][$depLinks[$talents[$talentIdx]['tId']]]['r'][0] = $talentIdx;
|
||||
unset($depLinks[$talents[$talentIdx]['tId']]);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all dependencies for which the talent has not been found
|
||||
foreach ($depLinks as $dep_link)
|
||||
unset($result[$l]['t'][$dep_link]['r']);
|
||||
unset($result[$tabIdx]['t'][$dep_link]['r']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
371
setup/updates/1521735363_01.sql
Normal file
371
setup/updates/1521735363_01.sql
Normal file
@@ -0,0 +1,371 @@
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_sync`;
|
||||
CREATE TABLE `aowow_profiler_sync` (
|
||||
`realm` tinyint(3) unsigned NOT NULL,
|
||||
`realmGUID` int(10) unsigned NOT NULL,
|
||||
`type` smallint(5) unsigned NOT NULL,
|
||||
`typeId` int(10) unsigned NOT NULL,
|
||||
`requestTime` int(10) unsigned NOT NULL,
|
||||
`status` tinyint(3) unsigned NOT NULL,
|
||||
`errorCode` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
UNIQUE KEY `realm_realmGUID_type_typeId` (`realm`,`realmGUID`,`type`),
|
||||
UNIQUE KEY `type_typeId` (`type`,`typeId`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_guild`;
|
||||
CREATE TABLE `aowow_profiler_guild` (
|
||||
`id` int(10) unsigned NOT NULL,
|
||||
`realm` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`realmGUID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`cuFlags` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`name` varchar(26) NOT NULL DEFAULT '',
|
||||
`nameUrl` varchar(26) NOT NULL DEFAULT '',
|
||||
`emblemStyle` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`emblemColor` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`borderStyle` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`borderColor` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`backgroundColor` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`info` varchar(500) NOT NULL DEFAULT '',
|
||||
`createDate` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
INDEX `name` (`name`),
|
||||
INDEX `guild` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_guild_rank`;
|
||||
CREATE TABLE `aowow_profiler_guild_rank` (
|
||||
`guildId` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`rank` tinyint(3) unsigned NOT NULL,
|
||||
`name` varchar(20) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`guildId`,`rank`),
|
||||
INDEX `rank` (`rank`),
|
||||
CONSTRAINT `FK_aowow_profiler_guild_rank_aowow_profiler_guild` FOREIGN KEY (`guildId`) REFERENCES `aowow_profiler_guild` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_profiles`;
|
||||
CREATE TABLE `aowow_profiler_profiles` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`realm` tinyint(3) unsigned DEFAULT NULL,
|
||||
`realmGUID` int(11) unsigned DEFAULT NULL,
|
||||
`cuFlags` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`sourceId` int(11) unsigned DEFAULT NULL,
|
||||
`sourceName` varchar(50) DEFAULT NULL,
|
||||
`copy` int(10) unsigned DEFAULT NULL,
|
||||
`icon` varchar(50) DEFAULT NULL,
|
||||
`user` int(11) unsigned DEFAULT NULL,
|
||||
`name` varchar(50) NOT NULL,
|
||||
`race` tinyint(3) unsigned NOT NULL,
|
||||
`class` tinyint(3) unsigned NOT NULL,
|
||||
`level` tinyint(3) unsigned NOT NULL,
|
||||
`gender` tinyint(3) unsigned NOT NULL,
|
||||
`guild` int(10) unsigned NULL,
|
||||
`guildrank` tinyint(3) unsigned DEFAULT NULL COMMENT '0: guild master',
|
||||
`skincolor` tinyint(3) unsigned NOT NULL,
|
||||
`hairstyle` tinyint(3) unsigned NOT NULL,
|
||||
`haircolor` tinyint(3) unsigned NOT NULL,
|
||||
`facetype` tinyint(3) unsigned NOT NULL,
|
||||
`features` tinyint(3) unsigned NOT NULL,
|
||||
`nomodelMask` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`title` tinyint(3) unsigned NOT NULL,
|
||||
`description` text NULL,
|
||||
`playedtime` int(11) unsigned NOT NULL,
|
||||
`gearscore` smallint(5) unsigned NOT NULL,
|
||||
`achievementpoints` smallint(5) unsigned NOT NULL,
|
||||
`lastupdated` int(11) NOT NULL,
|
||||
`talenttree1` tinyint(4) unsigned NOT NULL COMMENT 'points spend in 1st tree',
|
||||
`talenttree2` tinyint(4) unsigned NOT NULL COMMENT 'points spend in 2nd tree',
|
||||
`talenttree3` tinyint(4) unsigned NOT NULL COMMENT 'points spend in 3rd tree',
|
||||
`talentbuild1` varchar(105) NOT NULL,
|
||||
`talentbuild2` varchar(105) NOT NULL,
|
||||
`glyphs1` varchar(45) NOT NULL,
|
||||
`glyphs2` varchar(45) NOT NULL,
|
||||
`activespec` tinyint(1) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `realm_realmGUID_name` (`realm`,`realmGUID`,`name`),
|
||||
INDEX `user` (`user`),
|
||||
INDEX `guild` (`guild`),
|
||||
CONSTRAINT `FK_aowow_profiler_profiles_aowow_profiler_guild` FOREIGN KEY (`guild`) REFERENCES `aowow_profiler_guild` (`id`) ON UPDATE CASCADE ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_items`;
|
||||
CREATE TABLE `aowow_profiler_items` (
|
||||
`id` int(11) unsigned DEFAULT NULL,
|
||||
`slot` tinyint(3) unsigned DEFAULT NULL,
|
||||
`item` mediumint(8) unsigned DEFAULT NULL,
|
||||
`subItem` smallint(6) DEFAULT NULL,
|
||||
`permEnchant` mediumint(8) unsigned DEFAULT NULL,
|
||||
`tempEnchant` mediumint(8) unsigned DEFAULT NULL,
|
||||
`extraSocket` tinyint(3) unsigned DEFAULT NULL COMMENT 'not used .. the appropriate gem slot is set to -1 instead',
|
||||
`gem1` mediumint(8) DEFAULT NULL,
|
||||
`gem2` mediumint(8) DEFAULT NULL,
|
||||
`gem3` mediumint(8) DEFAULT NULL,
|
||||
`gem4` mediumint(8) DEFAULT NULL,
|
||||
UNIQUE KEY `id_slot` (`id`,`slot`),
|
||||
INDEX `id` (`id`),
|
||||
INDEX `item` (`item`),
|
||||
CONSTRAINT `FK_pr_items` FOREIGN KEY (`id`) REFERENCES `aowow_profiler_profiles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_arena_team`;
|
||||
CREATE TABLE `aowow_profiler_arena_team` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`realm` tinyint(3) unsigned NOT NULL,
|
||||
`realmGUID` int(10) unsigned NOT NULL,
|
||||
`name` varchar(24) NOT NULL,
|
||||
`nameUrl` varchar(24) NOT NULL,
|
||||
`type` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`cuFlags` int(11) unsigned NOT NULL,
|
||||
`rating` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`seasonGames` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`seasonWins` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`weekGames` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`weekWins` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`rank` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`backgroundColor` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`emblemStyle` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`emblemColor` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`borderStyle` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`borderColor` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `realm_realmGUID` (`realm`,`realmGUID`),
|
||||
INDEX `name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_arena_team_member`;
|
||||
CREATE TABLE `aowow_profiler_arena_team_member` (
|
||||
`arenaTeamId` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`profileId` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`captain` tinyint(1) unsigned NOT NULL DEFAULT '0',
|
||||
`weekGames` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`weekWins` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`seasonGames` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`seasonWins` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`personalRating` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`arenaTeamId`,`profileId`),
|
||||
INDEX `guid` (`profileId`),
|
||||
CONSTRAINT `FK_aowow_profiler_arena_team_member_aowow_profiler_arena_team` FOREIGN KEY (`arenaTeamId`) REFERENCES `aowow_profiler_arena_team` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `FK_aowow_profiler_arena_team_member_aowow_profiler_profiles` FOREIGN KEY (`profileId`) REFERENCES `aowow_profiler_profiles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_completion`;
|
||||
CREATE TABLE `aowow_profiler_completion` (
|
||||
`id` int(11) unsigned NOT NULL,
|
||||
`type` smallint(6) unsigned NOT NULL,
|
||||
`typeId` mediumint(9) NOT NULL,
|
||||
`cur` int(11) DEFAULT NULL,
|
||||
`max` int(11) DEFAULT NULL,
|
||||
INDEX `id` (`id`),
|
||||
INDEX `type` (`type`),
|
||||
INDEX `typeId` (`typeId`),
|
||||
CONSTRAINT `FK_pr_completion` FOREIGN KEY (`id`) REFERENCES `aowow_profiler_profiles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_pets`;
|
||||
CREATE TABLE `aowow_profiler_pets` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`owner` int(10) unsigned DEFAULT NULL,
|
||||
`name` varchar(50) DEFAULT NULL,
|
||||
`family` tinyint(3) unsigned DEFAULT NULL,
|
||||
`npc` smallint(5) unsigned DEFAULT NULL,
|
||||
`displayId` smallint(5) unsigned DEFAULT NULL,
|
||||
`talents` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `owner` (`owner`),
|
||||
CONSTRAINT `FK_pr_pets` FOREIGN KEY (`owner`) REFERENCES `aowow_profiler_profiles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_profiler_excludes`;
|
||||
CREATE TABLE `aowow_profiler_excludes` (
|
||||
`type` smallint(5) unsigned NOT NULL,
|
||||
`typeId` mediumint(8) unsigned NOT NULL,
|
||||
`groups` smallint(5) unsigned NOT NULL COMMENT 'see exclude group defines',
|
||||
`comment` varchar(50) NOT NULL COMMENT 'rebuilding profiler files will delete everything without a comment',
|
||||
PRIMARY KEY (`type`,`typeId`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
INSERT INTO `aowow_profiler_excludes` (`type`, `typeId`, `groups`, `comment`) VALUES
|
||||
(6, 459, 1, 'Gray Wolf'),
|
||||
(6, 468, 1, 'White Stallion'),
|
||||
(6, 471, 1, 'Palamino'),
|
||||
(6, 472, 1, 'Pinto'),
|
||||
(6, 578, 1, 'Black Wolf'),
|
||||
(6, 579, 1, 'Red Wolf'),
|
||||
(6, 581, 1, 'Winter Wolf'),
|
||||
(6, 3363, 1, 'Nether Drake'),
|
||||
(6, 6896, 1, 'Black Ram'),
|
||||
(6, 6897, 1, 'Blue Ram'),
|
||||
(6, 8980, 1, 'Skeletal Horse'),
|
||||
(6, 10681, 1, 'Summon Cockatoo'),
|
||||
(6, 10686, 1, 'Summon Prairie Chicken'),
|
||||
(6, 10687, 1, 'Summon White Plymouth Rock'),
|
||||
(6, 10699, 1, 'Summon Bronze Whelpling'),
|
||||
(6, 10700, 1, 'Summon Faeling'),
|
||||
(6, 10701, 1, 'Summon Dart Frog'),
|
||||
(6, 10702, 1, 'Summon Island Frog'),
|
||||
(6, 10705, 1, 'Summon Eagle Owl'),
|
||||
(6, 10708, 1, 'Summon Snowy Owl'),
|
||||
(6, 10710, 1, 'Summon Cottontail Rabbit'),
|
||||
(6, 10712, 1, 'Summon Spotted Rabbit'),
|
||||
(6, 10715, 1, 'Summon Blue Racer'),
|
||||
(6, 10718, 1, 'Green Water Snake'),
|
||||
(6, 10719, 1, 'Ribbon Snake'),
|
||||
(6, 10720, 1, 'Scarlet Snake'),
|
||||
(6, 10721, 1, 'Summon Elven Wisp'),
|
||||
(6, 10795, 1, 'Ivory Raptor'),
|
||||
(6, 10798, 1, 'Obsidian Raptor'),
|
||||
(6, 15648, 1, 'Corrupted Kitten'),
|
||||
(6, 15779, 1, 'White Mechanostrider Mod B'),
|
||||
(6, 15780, 1, 'Green Mechanostrider'),
|
||||
(6, 15781, 1, 'Steel Mechanostrider'),
|
||||
(6, 16055, 1, 'Black Nightsaber'),
|
||||
(6, 16056, 1, 'Ancient Frostsaber'),
|
||||
(6, 16058, 1, 'Primal Leopard'),
|
||||
(6, 16059, 1, 'Tawny Sabercat'),
|
||||
(6, 16060, 1, 'Golden Sabercat'),
|
||||
(6, 16080, 1, 'Red Wolf'),
|
||||
(6, 16081, 1, 'Winter Wolf'),
|
||||
(6, 16082, 1, 'Palomino'),
|
||||
(6, 16083, 1, 'White Stallion'),
|
||||
(6, 16084, 1, 'Mottled Red Raptor'),
|
||||
(6, 17450, 1, 'Ivory Raptor'),
|
||||
(6, 17455, 1, 'Purple Mechanostrider'),
|
||||
(6, 17456, 1, 'Red and Blue Mechanostrider'),
|
||||
(6, 17458, 1, 'Fluorescent Green Mechanostrider'),
|
||||
(6, 17459, 1, 'Icy Blue Mechanostrider Mod A'),
|
||||
(6, 17460, 1, 'Frost Ram'),
|
||||
(6, 17461, 1, 'Black Ram'),
|
||||
(6, 17468, 1, 'Pet Fish'),
|
||||
(6, 17469, 1, 'Pet Stone'),
|
||||
(6, 18363, 1, 'Riding Kodo'),
|
||||
(6, 18991, 1, 'Green Kodo'),
|
||||
(6, 18992, 1, 'Teal Kodo'),
|
||||
(6, 19363, 1, 'Summon Mechanical Yeti'),
|
||||
(6, 23220, 1, 'Swift Dawnsaber'),
|
||||
(6, 23428, 1, 'Albino Snapjaw'),
|
||||
(6, 23429, 1, 'Loggerhead Snapjaw'),
|
||||
(6, 23430, 1, 'Olive Snapjaw'),
|
||||
(6, 23431, 1, 'Leatherback Snapjaw'),
|
||||
(6, 23432, 1, 'Hawksbill Snapjaw'),
|
||||
(6, 23530, 16, 'Tiny Red Dragon'),
|
||||
(6, 23531, 16, 'Tiny Green Dragon'),
|
||||
(6, 24985, 1, 'Summon Baby Murloc (Blue)'),
|
||||
(6, 24986, 1, 'Summon Baby Murloc (Green)'),
|
||||
(6, 24987, 1, 'Summon Baby Murloc (Orange)'),
|
||||
(6, 24988, 4, 'Lurky'),
|
||||
(6, 24989, 1, 'Summon Baby Murloc (Pink)'),
|
||||
(6, 24990, 1, 'Summon Baby Murloc (Purple)'),
|
||||
(6, 25849, 1, 'Baby Shark'),
|
||||
(6, 26067, 1, 'Summon Mechanical Greench'),
|
||||
(6, 26391, 1, 'Tentacle Call'),
|
||||
(6, 28828, 1, 'Nether Drake'),
|
||||
(6, 29059, 1, 'Naxxramas Deathcharger'),
|
||||
(6, 30152, 1, 'White Tiger Cub'),
|
||||
(6, 30156, 2, 'Hippogryph Hatchling'),
|
||||
(6, 30174, 2, 'Riding Turtle'),
|
||||
(6, 32298, 4, 'Netherwhelp'),
|
||||
(6, 32345, 1, 'Peep the Phoenix Mount'),
|
||||
(6, 33050, 128, 'Magical Crawdad'),
|
||||
(6, 33057, 1, 'Summon Mighty Mr. Pinchy'),
|
||||
(6, 33630, 1, 'Blue Mechanostrider'),
|
||||
(6, 34407, 1, 'Great Elite Elekk'),
|
||||
(6, 35157, 1, 'Summon Spotted Rabbit'),
|
||||
(6, 37015, 1, 'Swift Nether Drake'),
|
||||
(6, 40319, 16, 'Lucky'),
|
||||
(6, 40405, 16, 'Lucky'),
|
||||
(6, 43688, 1, 'Amani War Bear'),
|
||||
(6, 43810, 1, 'Frost Wyrm'),
|
||||
(6, 44317, 1, 'Merciless Nether Drake'),
|
||||
(6, 44744, 1, 'Merciless Nether Drake'),
|
||||
(6, 45125, 2, 'Rocket Chicken'),
|
||||
(6, 45174, 16, 'Golden Pig'),
|
||||
(6, 45175, 16, 'Silver Pig'),
|
||||
(6, 45890, 1, 'Scorchling'),
|
||||
(6, 47037, 1, 'Swift War Elekk'),
|
||||
(6, 48406, 16, 'Essence of Competition'),
|
||||
(6, 48408, 1, 'Essence of Competition'),
|
||||
(6, 48954, 8, 'Swift Zhevra'),
|
||||
(6, 49322, 8, 'Swift Zhevra'),
|
||||
(6, 49378, 1, 'Brewfest Riding Kodo'),
|
||||
(6, 50869, 1, 'Brewfest Kodo'),
|
||||
(6, 50870, 1, 'Brewfest Ram'),
|
||||
(6, 51851, 1, 'Vampiric Batling'),
|
||||
(6, 51960, 1, 'Frost Wyrm Mount'),
|
||||
(6, 52615, 4, 'Frosty'),
|
||||
(6, 53082, 8, 'Mini Tyrael'),
|
||||
(6, 53768, 1, 'Haunted'),
|
||||
(6, 54187, 1, 'Clockwork Rocket Bot'),
|
||||
(6, 55068, 1, 'Mr. Chilly'),
|
||||
(6, 58983, 8, 'Big Blizzard Bear'),
|
||||
(6, 59572, 1, 'Black Polar Bear'),
|
||||
(6, 59573, 1, 'Brown Polar Bear'),
|
||||
(6, 59802, 1, 'Grand Ice Mammoth'),
|
||||
(6, 59804, 1, 'Grand Ice Mammoth'),
|
||||
(6, 59976, 1, 'Black Proto-Drake'),
|
||||
(6, 60021, 1, 'Plagued Proto-Drake'),
|
||||
(6, 60136, 1, 'Grand Caravan Mammoth'),
|
||||
(6, 60140, 1, 'Grand Caravan Mammoth'),
|
||||
(6, 61309, 512, 'Magnificent Flying Carpet'),
|
||||
(6, 61442, 1, 'Swift Mooncloth Carpet'),
|
||||
(6, 61444, 1, 'Swift Shadoweave Carpet'),
|
||||
(6, 61446, 1, 'Swift Spellfire Carpete'),
|
||||
(6, 61451, 512, 'Flying Carpet'),
|
||||
(6, 61855, 1, 'Baby Blizzard Bear'),
|
||||
(6, 62048, 1, 'Black Dragonhawk Mount'),
|
||||
(6, 62514, 1, 'Alarming Clockbot'),
|
||||
(6, 63318, 8, 'Murkimus the Gladiator'),
|
||||
(6, 64351, 1, 'XS-001 Constructor Bot'),
|
||||
(6, 64656, 1, 'Blue Skeletal Warhorse'),
|
||||
(6, 64731, 128, 'Sea Turtle'),
|
||||
(6, 65682, 1, 'Warbot'),
|
||||
(6, 65917, 2, 'Magic Rooster'),
|
||||
(6, 66030, 8, 'Grunty'),
|
||||
(6, 66122, 1, 'Magic Rooster - dummy spell'),
|
||||
(6, 66123, 1, 'Magic Rooster - dummy spell'),
|
||||
(6, 66124, 1, 'Magic Rooster - dummy spell'),
|
||||
(6, 66520, 1, 'Jade Tiger'),
|
||||
(6, 66907, 1, 'Argent Warhorse'),
|
||||
(6, 67527, 16, 'Onyx Panther'),
|
||||
(6, 68767, 2, 'Tuskarr Kite'),
|
||||
(6, 68810, 2, 'Spectral Tiger Cub'),
|
||||
(6, 69002, 1, 'Onyxian Whelpling'),
|
||||
(6, 69452, 8, 'Core Hound Pup'),
|
||||
(6, 69535, 4, 'Gryphon Hatchling'),
|
||||
(6, 69536, 4, 'Wind Rider Cub'),
|
||||
(6, 69539, 1, 'Zipao Tiger'),
|
||||
(6, 69541, 4, 'Pandaren Monk'),
|
||||
(6, 69677, 4, 'Lil\' K.T.'),
|
||||
(6, 74856, 2, 'Blazing Hippogryph'),
|
||||
(6, 74918, 2, 'Wooly White Rhino'),
|
||||
(6, 75596, 512, 'Frosty Flying Carpet'),
|
||||
(6, 75613, 1, 'Celestial Dragon'),
|
||||
(6, 75614, 16, 'Celestial Steed'),
|
||||
(6, 75906, 4, 'Lil\' XT'),
|
||||
(6, 75936, 1, 'Murkimus the Gladiator'),
|
||||
(6, 75973, 8, 'X-53 Touring Rocket'),
|
||||
(6, 78381, 8, 'Mini Thor'),
|
||||
(8, 87, 1024, 'Bloodsail Buccaneers - max rank is honored'),
|
||||
(8, 92, 1024, 'Gelkis Clan Centaur - max rank is friendly'),
|
||||
(8, 93, 1024, 'Magram Clan Centaur - max rank is friendly');
|
||||
|
||||
CREATE TABLE `aowow_account_profiles` (
|
||||
`accountId` INT(10) UNSIGNED NOT NULL,
|
||||
`profileId` INT(10) UNSIGNED NOT NULL,
|
||||
`extraFlags` INT(10) UNSIGNED NOT NULL,
|
||||
UNIQUE INDEX `accountId_profileId` (`accountId`, `profileId`),
|
||||
INDEX `accountId` (`accountId`),
|
||||
INDEX `profileId` (`profileId`),
|
||||
CONSTRAINT `FK_account_id` FOREIGN KEY (`accountId`) REFERENCES `aowow_account` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
CONSTRAINT `FK_profile_id` FOREIGN KEY (`profileId`) REFERENCES `aowow_profiler_profiles` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
|
||||
) COLLATE='utf8_general_ci' ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE `aowow_account_excludes` (
|
||||
`userId` INT(11) UNSIGNED NOT NULL,
|
||||
`type` SMALLINT(5) UNSIGNED NOT NULL,
|
||||
`typeId` MEDIUMINT(8) UNSIGNED NOT NULL,
|
||||
`mode` TINYINT(2) UNSIGNED NOT NULL COMMENT '1: exclude; 2: include',
|
||||
UNIQUE INDEX `userId_type_typeId` (`userId`, `type`, `typeId`),
|
||||
INDEX `userId` (`userId`),
|
||||
CONSTRAINT `FK_acc_excludes` FOREIGN KEY (`userId`) REFERENCES `aowow_account` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
|
||||
) COLLATE='utf8_general_ci' ENGINE=InnoDB;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
16
setup/updates/1521735363_02.sql
Normal file
16
setup/updates/1521735363_02.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
DELETE FROM aowow_config WHERE `key` LIKE 'profiler_%';
|
||||
INSERT INTO aowow_config (`key`, `value`, `cat`, `flags`, `comment`) VALUES
|
||||
('profiler_queue', 0, 7, 0x84, 'default: 0 - enable/disable profiler queue'),
|
||||
('profiler_queue_delay', 3000, 7, 0x81, 'default: 3000 - min. delay between queue cycles (in ms)'),
|
||||
('profiler_resync_ping', 5000, 7, 0x81, 'default: 5000 - how often the javascript asks for for updates, when queued (in ms)'),
|
||||
('profiler_resync_delay', 1*60*60, 7, 0x81, 'default: 1*60*60 - how often a character can be refreshed (in sec)');
|
||||
|
||||
DROP TABLE IF EXISTS `aowow_characters`;
|
||||
|
||||
ALTER TABLE `aowow_talents`
|
||||
ADD COLUMN `petTypeMask` TINYINT(3) UNSIGNED NOT NULL AFTER `class`;
|
||||
|
||||
ALTER TABLE `aowow_account`
|
||||
ADD COLUMN `excludeGroups` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'profiler - completion exclude bitmask' AFTER `description`;
|
||||
|
||||
UPDATE aowow_dbversion SET `sql` = CONCAT(IFNULL(`sql`, ''), ' talents');
|
||||
Reference in New Issue
Block a user