完成任务系统
parent
d39a4861c4
commit
50090fcf5b
@ -0,0 +1,2 @@
|
|||||||
|
<?php
|
||||||
|
$specialPageAliases = [];
|
@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
"name": "IsekaiUserPointsQuests",
|
||||||
|
"namemsg": "isekai-userpoints-quests",
|
||||||
|
"author": "Hyperzlib",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"url": "https://git.isekai.cn/Isekai-Project/mediawiki-extension-IsekaiUserPoints",
|
||||||
|
"descriptionmsg": "isekai-userpoints-quests-desc",
|
||||||
|
"license-name": "MIT",
|
||||||
|
"type": "api",
|
||||||
|
"requires": {
|
||||||
|
"MediaWiki": ">= 1.39.0"
|
||||||
|
},
|
||||||
|
"MessagesDirs": {
|
||||||
|
"IsekaiUserPointsQuests": [
|
||||||
|
"i18n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ExtensionMessagesFiles": {
|
||||||
|
"IsekaiUserPointsQuestsAlias": "IsekaiUserPointsQuests.alias.php"
|
||||||
|
},
|
||||||
|
"AutoloadNamespaces": {
|
||||||
|
"Isekai\\UserPoints\\Quests\\": "includes"
|
||||||
|
},
|
||||||
|
"Hooks": {
|
||||||
|
"LoadExtensionSchemaUpdates": "Isekai\\UserPoints\\Quests\\Hooks::onLoadExtensionSchemaUpdates",
|
||||||
|
"PageSaveComplete": "Isekai\\UserPoints\\Quests\\Hooks::onPageSaveComplete",
|
||||||
|
"BeforePageDisplay": "Isekai\\UserPoints\\Quests\\Hooks::onBeforePageDisplay"
|
||||||
|
},
|
||||||
|
"ResourceModules": {
|
||||||
|
"ext.isekai.userpoints.quests.notification": {
|
||||||
|
"scripts": ["ext.isekai.userpoints.quests.notification.js"],
|
||||||
|
"messages": [
|
||||||
|
"comma-separator",
|
||||||
|
"isekai-userpoints-point-name-num",
|
||||||
|
"isekai-quests-complete-notification-title",
|
||||||
|
"isekai-quests-complete-notification-message",
|
||||||
|
"isekai-quests-daily-count",
|
||||||
|
"isekai-quests-weekly-count",
|
||||||
|
"isekai-quests-monthly-count",
|
||||||
|
"isekai-quests-type-edit-notification",
|
||||||
|
"isekai-quests-type-create-notification"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ResourceFileModulePaths": {
|
||||||
|
"localBasePath": "modules",
|
||||||
|
"remoteExtPath": "IsekaiUserPoints/Quests/modules"
|
||||||
|
},
|
||||||
|
"APIModules": {
|
||||||
|
"userquestsgetnotification": "Isekai\\UserPoints\\Quests\\Api\\ApiUserQuestsGetNotification"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"IsekaiQuestsConfig": {
|
||||||
|
"value": {
|
||||||
|
"new": {
|
||||||
|
"periodQuestNumber": 1,
|
||||||
|
"periodType": "daily",
|
||||||
|
"points": {
|
||||||
|
"exp": {
|
||||||
|
"points": [60]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"edit": {
|
||||||
|
"periodQuestNumber": 2,
|
||||||
|
"periodType": "daily",
|
||||||
|
"points": {
|
||||||
|
"exp": {
|
||||||
|
"points": [40, 40]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IsekaiQuestsTaskConfig": {
|
||||||
|
"value": {
|
||||||
|
"edit": {
|
||||||
|
"unitPoints": {
|
||||||
|
"exp": 10
|
||||||
|
},
|
||||||
|
"maxPoints": {
|
||||||
|
"exp": 400
|
||||||
|
},
|
||||||
|
"unitWords": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"manifest_version": 2
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
namespace Isekai\UserPoints\Quests\Api;
|
||||||
|
|
||||||
|
use ApiBase;
|
||||||
|
use Isekai\UserPoints\Quests\QuestsUtils;
|
||||||
|
use MediaWiki\Session\SessionManager;
|
||||||
|
|
||||||
|
class ApiUserQuestsGetNotification extends ApiBase {
|
||||||
|
public function __construct( $main, $method ) {
|
||||||
|
parent::__construct( $main->getMain(), $method );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute() {
|
||||||
|
$user = $this->getUser();
|
||||||
|
|
||||||
|
if (!$user->isRegistered()) {
|
||||||
|
$this->dieWithError('apierror-mustbeloggedin-generic', 'login-required');
|
||||||
|
}
|
||||||
|
|
||||||
|
$sesssionManager = SessionManager::getGlobalSession();
|
||||||
|
if ($sesssionManager->exists(QuestsUtils::SESSION_KEY_QUEST_COMPLETE_NOTIFICATION)) {
|
||||||
|
$notificationData = $sesssionManager->get(QuestsUtils::SESSION_KEY_QUEST_COMPLETE_NOTIFICATION);
|
||||||
|
$this->getResult()->addValue(['userquestsgetnotification'], 'notification', $notificationData);
|
||||||
|
} else {
|
||||||
|
$this->getResult()->addValue(['userquestsgetnotification'], 'notification', null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isInternal() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Isekai\UserPoints\Quests;
|
||||||
|
|
||||||
|
use MediaWiki\MediaWikiServices;
|
||||||
|
use MediaWiki\Session\SessionManager;
|
||||||
|
use OutputPage;
|
||||||
|
|
||||||
|
class Hooks {
|
||||||
|
/**
|
||||||
|
* Implements LoadExtensionSchemaUpdates hook.
|
||||||
|
*
|
||||||
|
* @param \DatabaseUpdater $updater
|
||||||
|
*/
|
||||||
|
public static function onLoadExtensionSchemaUpdates($updater) {
|
||||||
|
$dir = dirname(__DIR__) . '/sql/';
|
||||||
|
$type = $updater->getDB()->getType();
|
||||||
|
$updater->addExtensionTable('isekai_user_quests_record', $dir . $type . '/isekai_user_quests_record.sql');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \WikiPage $wikiPage
|
||||||
|
* @param \MediaWiki\User\UserIdentity $user
|
||||||
|
* @param string $summary
|
||||||
|
* @param int $flags
|
||||||
|
* @param \MediaWiki\Revision\RevisionRecord $revisionRecord
|
||||||
|
* @param \MediaWiki\Storage\EditResult $editResult
|
||||||
|
*/
|
||||||
|
public static function onPageSaveComplete($wikiPage, $user, $summary, $flags, $revisionRecord, $editResult) {
|
||||||
|
wfDebugLog('IsekaiQuests', 'onPageSaveComplete');
|
||||||
|
$services = MediaWikiServices::getInstance();
|
||||||
|
$config = $services->getMainConfig();
|
||||||
|
|
||||||
|
$questsConfig = $config->get('IsekaiQuestsConfig');
|
||||||
|
|
||||||
|
$allowedNamespaces = [NS_MAIN, NS_CATEGORY, NS_TEMPLATE, NS_HELP];
|
||||||
|
|
||||||
|
if (in_array($wikiPage->getNamespace(), $allowedNamespaces)) {
|
||||||
|
if ($flags & EDIT_NEW && isset($questsConfig['new'])) {
|
||||||
|
// 新建页面
|
||||||
|
$questConfig = $questsConfig['new'];
|
||||||
|
|
||||||
|
$questRes = QuestsUtils::onQuestComplete($user, 'new', $questConfig);
|
||||||
|
wfDebugLog('IsekaiQuests', 'quest finished: ', var_export($questRes, true));
|
||||||
|
if ($questRes) {
|
||||||
|
QuestsUtils::setQuestCompleteNotification('new', $questRes['deltaPoints'], $questRes['completeNum'], $questConfig);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果新建页面的任务次数已满,则作为编辑页面处理
|
||||||
|
if ($flags & EDIT_UPDATE && isset($questsConfig['edit'])) {
|
||||||
|
// 编辑页面
|
||||||
|
$questConfig = $questsConfig['edit'];
|
||||||
|
|
||||||
|
$questRes = QuestsUtils::onQuestComplete($user, 'edit', $questConfig);
|
||||||
|
wfDebugLog('IsekaiQuests', 'quest finished: ', var_export($questRes, true));
|
||||||
|
if ($questRes) {
|
||||||
|
QuestsUtils::setQuestCompleteNotification('edit', $questRes['deltaPoints'], $questRes['completeNum'], $questConfig);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function onBeforePageDisplay(OutputPage $out, $skin) {
|
||||||
|
$out->addModules(['ext.isekai.userpoints.quests.notification']);
|
||||||
|
|
||||||
|
$sessionManager = SessionManager::getGlobalSession();
|
||||||
|
if ($sessionManager->exists(QuestsUtils::SESSION_KEY_QUEST_COMPLETE_NOTIFICATION)) {
|
||||||
|
$out->addJsConfigVars([
|
||||||
|
'wgIsekaiQuestsCompleteNotification' => $sessionManager->get(QuestsUtils::SESSION_KEY_QUEST_COMPLETE_NOTIFICATION),
|
||||||
|
]);
|
||||||
|
$sessionManager->remove(QuestsUtils::SESSION_KEY_QUEST_COMPLETE_NOTIFICATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Isekai\UserPoints\Quests;
|
||||||
|
|
||||||
|
use MediaWiki\MediaWikiServices;
|
||||||
|
use User;
|
||||||
|
|
||||||
|
use Isekai\UserPoints\Service\IsekaiUserPointsFactory;
|
||||||
|
use Isekai\UserPoints\Utils;
|
||||||
|
use MediaWiki\Session\SessionManager;
|
||||||
|
|
||||||
|
class QuestsUtils {
|
||||||
|
public const SESSION_KEY_QUEST_COMPLETE_NOTIFICATION = 'IsekaiQuests::questCompleteNotification';
|
||||||
|
|
||||||
|
public static function getUserQuestCompleteNum(User $user, string $questType, string $periodTime) {
|
||||||
|
$dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection(DB_REPLICA);
|
||||||
|
|
||||||
|
$res = $dbr->newSelectQueryBuilder()
|
||||||
|
->from('isekai_user_quests_record')
|
||||||
|
->where([
|
||||||
|
'user_id' => $user->getId(),
|
||||||
|
'quest_type' => $questType,
|
||||||
|
'period_time' => $periodTime,
|
||||||
|
])->field('quest_complete_num')
|
||||||
|
->fetchField();
|
||||||
|
|
||||||
|
if ($res === false) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return intval($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setUserQuestCompleteNum(User $user, string $questType, string $periodTime, int $num) {
|
||||||
|
$dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection(DB_REPLICA);
|
||||||
|
$dbw = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection(DB_PRIMARY);
|
||||||
|
|
||||||
|
$res = $dbr->selectField('isekai_user_quests_record', 'id', [
|
||||||
|
'user_id' => $user->getId(),
|
||||||
|
'quest_type' => $questType,
|
||||||
|
'period_time' => $periodTime,
|
||||||
|
], __METHOD__);
|
||||||
|
|
||||||
|
if ($res === false) {
|
||||||
|
$dbw->insert('isekai_user_quests_record', [
|
||||||
|
'user_id' => $user->getId(),
|
||||||
|
'quest_type' => $questType,
|
||||||
|
'period_time' => $periodTime,
|
||||||
|
'quest_complete_num' => $num,
|
||||||
|
], __METHOD__);
|
||||||
|
} else {
|
||||||
|
$dbw->update('isekai_user_quests_record', [
|
||||||
|
'quest_complete_num' => $num,
|
||||||
|
], [
|
||||||
|
'id' => $res,
|
||||||
|
], __METHOD__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function onQuestComplete(User $user, string $questType, array $questConfig) {
|
||||||
|
$services = MediaWikiServices::getInstance();
|
||||||
|
|
||||||
|
$periodQuestNumber = $questConfig['periodQuestNumber'];
|
||||||
|
$periodType = $questConfig['periodType'];
|
||||||
|
$pointsConfig = $questConfig['points'];
|
||||||
|
|
||||||
|
$periodTime = QuestsUtils::getPeriodTime($periodType);
|
||||||
|
|
||||||
|
$completeNum = QuestsUtils::getUserQuestCompleteNum($user, $questType, $periodTime);
|
||||||
|
|
||||||
|
if ($completeNum > $periodQuestNumber) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$deltaPoints = [];
|
||||||
|
|
||||||
|
/** @var IsekaiUserPointsFactory */
|
||||||
|
$userPointsFactory = $services->getService('IsekaiUserPoints');
|
||||||
|
foreach ($pointsConfig as $pointType => $pointConfig) {
|
||||||
|
$userPoints = $userPointsFactory->newFromUser($user, $pointType);
|
||||||
|
|
||||||
|
if ($userPoints) {
|
||||||
|
$expireTime = $pointConfig['expireTime'] ?? -1;
|
||||||
|
$pointsAddConfig = $pointConfig['points'];
|
||||||
|
|
||||||
|
if (count($pointsAddConfig) > 0) {
|
||||||
|
// 获取当前任务完成次数对应的积分数量
|
||||||
|
$periodIndex = $completeNum % count($pointsAddConfig);
|
||||||
|
$pointsAdd = $pointsAddConfig[$periodIndex];
|
||||||
|
|
||||||
|
$userPoints->addPoints($pointsAdd, $expireTime, 'quests', $questType);
|
||||||
|
|
||||||
|
$deltaPoints[$pointType] = $pointsAdd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$completeNum ++;
|
||||||
|
QuestsUtils::setUserQuestCompleteNum($user, $questType, $periodTime, $completeNum);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'completeNum' => $completeNum,
|
||||||
|
'deltaPoints' => $deltaPoints,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get period time string from period type
|
||||||
|
* @param string $periodType
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getPeriodTime($periodType = 'daily') {
|
||||||
|
switch ($periodType) {
|
||||||
|
case 'daily':
|
||||||
|
return date('Y-m-d');
|
||||||
|
case 'weekly':
|
||||||
|
return date('Y-W') . 'week';
|
||||||
|
case 'monthly':
|
||||||
|
return date('Y-m');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setQuestCompleteNotification(string $questType, array $deltaPoints, $completeNum = null, ?array $questConfig = null) {
|
||||||
|
$sesssionManager = SessionManager::getGlobalSession();
|
||||||
|
|
||||||
|
$resultPointDelta = [];
|
||||||
|
foreach ($deltaPoints as $pointType => $delta) {
|
||||||
|
$pointName = Utils::getPointName($pointType);
|
||||||
|
$pointIcon = Utils::getPointIcon($pointType);
|
||||||
|
|
||||||
|
$resultPointDelta[] = [
|
||||||
|
'point_type' => $pointType,
|
||||||
|
'name' => $pointName,
|
||||||
|
'icon' => $pointIcon,
|
||||||
|
'points' => $delta,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$notificationData = [
|
||||||
|
'questType' => $questType,
|
||||||
|
'deltaPoints' => $resultPointDelta,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($questConfig) {
|
||||||
|
$notificationData['completeNum'] = $completeNum;
|
||||||
|
$notificationData['periodQuestNumber'] = $questConfig['periodQuestNumber'];
|
||||||
|
$notificationData['periodType'] = $questConfig['periodType'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$sesssionManager->set(self::SESSION_KEY_QUEST_COMPLETE_NOTIFICATION, $notificationData);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE /*_*/isekai_user_quests_record (
|
||||||
|
`id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
`user_id` INT UNSIGNED NOT NULL,
|
||||||
|
`quest_type` VARCHAR(60) NOT NULL,
|
||||||
|
`period_time` VARCHAR(50) NOT NULL,
|
||||||
|
`quest_complete_num` INT UNSIGNED NOT NULL DEFAULT '0'
|
||||||
|
) /*$wgDBTableOptions*/;
|
||||||
|
ALTER TABLE /*_*/isekai_user_quests_record ADD INDEX (`user_id`, `quest_type`);
|
||||||
|
ALTER TABLE /*_*/isekai_user_quests_record ADD INDEX (`user_id`);
|
@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE isekai_user_quests_record (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
user_id INT NOT NULL,
|
||||||
|
quest_type VARCHAR(60) NOT NULL,
|
||||||
|
period_time VARCHAR(50) NOT NULL,
|
||||||
|
quest_complete_num INT NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
ALTER TABLE isekai_user_points_log ADD INDEX (user_id, quest_type);
|
||||||
|
ALTER TABLE isekai_user_points_log ADD INDEX (user_id);
|
Loading…
Reference in New Issue