wip: GetFrontInfo
This commit is contained in:
@@ -0,0 +1,467 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\General;
|
||||||
|
|
||||||
|
use DateTimeInterface;
|
||||||
|
use MeekroDB;
|
||||||
|
use sammo\CityConst;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\VoteInfo;
|
||||||
|
use sammo\Enums\APIRecoveryType;
|
||||||
|
use sammo\Enums\CityColumn;
|
||||||
|
use sammo\Enums\GeneralColumn;
|
||||||
|
use sammo\Enums\RankColumn;
|
||||||
|
use sammo\GameConst;
|
||||||
|
use sammo\General;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
use sammo\LastTurn;
|
||||||
|
use sammo\Validator;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use sammo\TimeUtil;
|
||||||
|
use sammo\Util;
|
||||||
|
|
||||||
|
use function sammo\buildNationCommandClass;
|
||||||
|
use function sammo\checkLimit;
|
||||||
|
use function sammo\getTournamentTermText;
|
||||||
|
use function sammo\buildNationTypeClass;
|
||||||
|
use function sammo\getNationStaticInfo;
|
||||||
|
use function sammo\getOfficerLevelText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 통째로 메인페이지의 주요 정보를 반환하는 날로먹는 API
|
||||||
|
*/
|
||||||
|
class GetFrontInfo extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('lengthMin', 'lastNationNoticeDate', 19);
|
||||||
|
if (!$v->validate()) {
|
||||||
|
return $v->errorStr();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateGlobalInfo(MeekroDB $db): array
|
||||||
|
{
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
|
||||||
|
[
|
||||||
|
$scenarioText, $extendedGeneral, $isFiction, $npcMode,
|
||||||
|
$joinMode, $autorunUser, $turnterm, $lastExecuted,
|
||||||
|
$lastVoteID, $develCost, $noticeMsg,
|
||||||
|
$onlineNations, $onlineUserCnt,
|
||||||
|
$year, $month, $startYear,
|
||||||
|
$generalCntLimit,
|
||||||
|
$apiLimit,
|
||||||
|
] = $gameStor->getValuesAsArray([
|
||||||
|
'scenario_text', 'extended_general', 'fiction', 'npcmode',
|
||||||
|
'join_mode', 'autorun_user', 'turnterm', 'turntime',
|
||||||
|
'lastVote', 'develcost', 'msg',
|
||||||
|
'online_nation', 'online_user_cnt',
|
||||||
|
'year', 'month', 'startyear',
|
||||||
|
'maxgeneral',
|
||||||
|
'conlimit',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($lastVoteID) {
|
||||||
|
$voteStor = KVStorage::getStorage($db, 'vote');
|
||||||
|
$lastVote = VoteInfo::fromArray($voteStor->getValue("vote_{$lastVoteID}"));
|
||||||
|
if ($lastVote->endDate && $lastVote->endDate < TimeUtil::now()) {
|
||||||
|
$lastVote = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$auctionCount = $db->queryFirstField('SELECT count(*) FROM ng_auction WHERE finished = 0');
|
||||||
|
$isTournamentActive = $gameStor->tournament > 0;
|
||||||
|
$isTournamentApplicationOpen = $gameStor->tournament == 1;
|
||||||
|
$isBettingActive = $gameStor->tournament == 6;
|
||||||
|
$tournamentType = $gameStor->tnmt_type;
|
||||||
|
$tournamentState = getTournamentTermText($gameStor->turnterm);
|
||||||
|
$isLocked = boolval($db->queryFirstField('SELECT plock FROM plock WHERE `type`="GAME" LIMIT 1'));
|
||||||
|
|
||||||
|
$globalGenCount = $db->queryAllLists('SELECT npc, count(no) FROM general GROUP BY npc');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'scenarioText' => $scenarioText,
|
||||||
|
'extendedGeneral' => $extendedGeneral,
|
||||||
|
'isFiction' => $isFiction,
|
||||||
|
'npcMode' => $npcMode,
|
||||||
|
'joinMode' => $joinMode,
|
||||||
|
'startyear' => $startYear,
|
||||||
|
'year' => $year,
|
||||||
|
'month' => $month,
|
||||||
|
'autorunUser' => $autorunUser,
|
||||||
|
'turnterm' => $turnterm,
|
||||||
|
'lastExecuted' => $lastExecuted,
|
||||||
|
'lastVoteID' => $lastVoteID,
|
||||||
|
'develCost' => $develCost,
|
||||||
|
'noticeMsg' => $noticeMsg,
|
||||||
|
'onlineNations' => $onlineNations,
|
||||||
|
'onlineUserCnt' => $onlineUserCnt,
|
||||||
|
'apiLimit' => $apiLimit,
|
||||||
|
'auctionCount' => $auctionCount,
|
||||||
|
'isTournamentActive' => $isTournamentActive,
|
||||||
|
'isTournamentApplicationOpen' => $isTournamentApplicationOpen,
|
||||||
|
'isBettingActive' => $isBettingActive,
|
||||||
|
'isLocked' => $isLocked,
|
||||||
|
'tournamentType' => $tournamentType,
|
||||||
|
'tournamentState' => $tournamentState,
|
||||||
|
'genCount' => $globalGenCount,
|
||||||
|
'generalCntLimit' => $generalCntLimit,
|
||||||
|
'lastVote' => $lastVote === null ? null : $lastVote->toArray(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateNationInfo(MeekroDB $db, General $general, array $rawNation): array
|
||||||
|
{
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$admin = $gameStor->getAll(true);
|
||||||
|
|
||||||
|
$lastNationNoticeDate = $this->args['lastNationNoticeDate'] ?? '2022-08-19 00:00:00';
|
||||||
|
|
||||||
|
$nationID = $general->getNationID();
|
||||||
|
|
||||||
|
//XXX: 매번 더하는가?
|
||||||
|
$nationPopulation = $db->queryFirstRow(
|
||||||
|
'SELECT COUNT(*) as cityCnt, SUM(pop) as `now`, SUM(pop_max) as `max` from city where nation=%i',
|
||||||
|
$nationID
|
||||||
|
);
|
||||||
|
|
||||||
|
//XXX: 매번 더하는가?
|
||||||
|
$nationCrew = $db->queryFirstRow(
|
||||||
|
'SELECT COUNT(*) as generalCnt, SUM(crew) as `now`,SUM(leadership)*100 as `max` from general where nation=%i AND npc != 5',
|
||||||
|
$nationID
|
||||||
|
);
|
||||||
|
|
||||||
|
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
|
||||||
|
[$nationNotice, $onlineGen] = $nationStor->getValuesAsArray(['nationNotice', 'online_genenerals']);
|
||||||
|
if (!$nationNotice || ($nationNotice['date'] ?? '') <= $lastNationNoticeDate) {
|
||||||
|
$nationNotice = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$topChiefs = Util::convertArrayToDict($db->query(
|
||||||
|
'SELECT officer_level, no, name, npc FROM general WHERE nation = %i AND officer_level >= 11',
|
||||||
|
$nationID
|
||||||
|
), 'officer_level');
|
||||||
|
|
||||||
|
$impossibleStrategicCommandLists = [];
|
||||||
|
$strategicCommandLists = GameConst::$availableChiefCommand['전략'];
|
||||||
|
$yearMonth = Util::joinYearMonth($admin['year'], $admin['month']);
|
||||||
|
foreach ($strategicCommandLists as $command) {
|
||||||
|
$cmd = buildNationCommandClass($command, $general, $admin, new LastTurn());
|
||||||
|
$nextAvailableTurn = $cmd->getNextAvailableTurn();
|
||||||
|
if ($nextAvailableTurn > $yearMonth) {
|
||||||
|
$impossibleStrategicCommandLists[] = [$cmd->getName(), $nextAvailableTurn - $yearMonth];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nationClass = buildNationTypeClass($rawNation['type']);
|
||||||
|
|
||||||
|
//TODO: 이부분은 const로 빼야하지 않는가?
|
||||||
|
$officerLevelTexts = [];
|
||||||
|
foreach (range(0, 4) as $officerLevel) {
|
||||||
|
$officerLevelTexts[$officerLevel] = getOfficerLevelText($officerLevel);
|
||||||
|
}
|
||||||
|
foreach (range(5, 12) as $officerLevel) {
|
||||||
|
$officerLevelTexts[$officerLevel] = getOfficerLevelText($rawNation['level'] * 100 + $officerLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $nationID,
|
||||||
|
'name' => $rawNation['name'],
|
||||||
|
'population' => $nationPopulation,
|
||||||
|
'crew' => $nationCrew,
|
||||||
|
'type' => [
|
||||||
|
'raw' => $rawNation['type'],
|
||||||
|
'name' => $nationClass->getName(),
|
||||||
|
'pros' => $nationClass::$pros,
|
||||||
|
'cons' => $nationClass::$cons,
|
||||||
|
],
|
||||||
|
'color' => $rawNation['color'],
|
||||||
|
'level' => $rawNation['level'],
|
||||||
|
'capital' => $rawNation['capital'],
|
||||||
|
'gold' => $rawNation['gold'],
|
||||||
|
'rice' => $rawNation['rice'],
|
||||||
|
'tech' => $rawNation['tech'],
|
||||||
|
'gennum' => $rawNation['gennum'],
|
||||||
|
'power' => $rawNation['power'],
|
||||||
|
|
||||||
|
'bill' => $rawNation['bill'],
|
||||||
|
'taxRate' => $rawNation['rate'],
|
||||||
|
'onlineGen' => $onlineGen,
|
||||||
|
'notice' => $nationNotice,
|
||||||
|
'topChiefs' => $topChiefs,
|
||||||
|
'officerLevelTexts' => $officerLevelTexts,
|
||||||
|
|
||||||
|
'diplomaticLimit' => $rawNation['surlimit'],
|
||||||
|
'strategicCmdLimit' => $rawNation['strategic_cmd_limit'],
|
||||||
|
'impossibleStrategicCommand' => $impossibleStrategicCommandLists,
|
||||||
|
|
||||||
|
|
||||||
|
'prohibitScout' => $rawNation['scout'],
|
||||||
|
'prohibitWar' => $rawNation['war'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateDummyNationInfo(MeekroDB $db, General $general, array $rawNation): array
|
||||||
|
{
|
||||||
|
$staticInfo = getNationStaticInfo(0);
|
||||||
|
return [
|
||||||
|
'id' => 0,
|
||||||
|
'name' => $staticInfo['name'],
|
||||||
|
'population' => [
|
||||||
|
'cityCnt' => 0,
|
||||||
|
'now' => 0,
|
||||||
|
'max' => 0,
|
||||||
|
],
|
||||||
|
'crew' => [
|
||||||
|
'generalCnt' => 0,
|
||||||
|
'now' => 0,
|
||||||
|
'max' => 0,
|
||||||
|
],
|
||||||
|
'type' => [
|
||||||
|
'raw' => 'None',
|
||||||
|
'name' => '-',
|
||||||
|
'pros' => '',
|
||||||
|
'cons' => '',
|
||||||
|
],
|
||||||
|
'color' => $staticInfo['color'],
|
||||||
|
'level' => $staticInfo['level'],
|
||||||
|
'capital' => $staticInfo['capital'],
|
||||||
|
'gold' => $staticInfo['gold'],
|
||||||
|
'rice' => $staticInfo['rice'],
|
||||||
|
'tech' => $staticInfo['tech'],
|
||||||
|
'gennum' => $staticInfo['gennum'],
|
||||||
|
'power' => $staticInfo['power'],
|
||||||
|
'onlineGen' => '', //TODO 접속자
|
||||||
|
'notice' => '',
|
||||||
|
'topChiefs' => [],
|
||||||
|
'impossibleStrategicCommand' => [],
|
||||||
|
'officerLevelTexts' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateGeneralInfo(MeekroDB $db, General $general, array $rawNation): array
|
||||||
|
{
|
||||||
|
$result = [
|
||||||
|
'no' => $general->getID(), // number;
|
||||||
|
'name' => $general->getName(), // string;
|
||||||
|
'nation' => $general->getNationID(), // number;
|
||||||
|
'npc' => $general->getNPCType(), // number;
|
||||||
|
'injury' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'leadership' => $general->getVar(GeneralColumn::leadership), // number;
|
||||||
|
'strength' => $general->getVar('strength'), // number;
|
||||||
|
'intel' => $general->getVar('intel'), // number;
|
||||||
|
'explevel' => $general->getVar('explevel'), // number;
|
||||||
|
'dedlevel' => $general->getVar('dedlevel'), // number;
|
||||||
|
'gold' => $general->getVar('gold'), // number;
|
||||||
|
'rice' => $general->getVar('rice'), // number;
|
||||||
|
'killturn' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'picture' => $general->getVar(GeneralColumn::injury), // string;
|
||||||
|
'imgsvr' => $general->getVar(GeneralColumn::injury), // 0 | 1;
|
||||||
|
'age' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'specialDomestic' => $general->getVar(GeneralColumn::injury), // GameObjClassKey;
|
||||||
|
'specialWar' => $general->getVar(GeneralColumn::injury), // GameObjClassKey;
|
||||||
|
'personal' => $general->getVar(GeneralColumn::injury), // GameObjClassKey;
|
||||||
|
'belong' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'connect' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
|
||||||
|
'officerLevel' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'officerLevelText' => $general->getVar(GeneralColumn::injury), // string;
|
||||||
|
'lbonus' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'ownerName' => $general->getVar(GeneralColumn::injury), // string | null;
|
||||||
|
'honorText' => $general->getVar(GeneralColumn::injury), // string;
|
||||||
|
'dedLevelText' => $general->getVar(GeneralColumn::injury), // string;
|
||||||
|
'bill' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'reservedCommand' => $general->getVar(GeneralColumn::injury), // TurnObj[] | null;
|
||||||
|
|
||||||
|
'autorun_limit' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
|
||||||
|
'city' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'troop' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
//P0 End
|
||||||
|
|
||||||
|
'con' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'specage' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'specage2' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'leadership_exp' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'strength_exp' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
'intel_exp' => $general->getVar(GeneralColumn::injury), // number;
|
||||||
|
|
||||||
|
'dex1' => $general->getVar(GeneralColumn::dex1), // number;
|
||||||
|
'dex2' => $general->getVar(GeneralColumn::dex2), // number;
|
||||||
|
'dex3' => $general->getVar(GeneralColumn::dex3), // number;
|
||||||
|
'dex4' => $general->getVar(GeneralColumn::dex4), // number;
|
||||||
|
'dex5' => $general->getVar(GeneralColumn::dex5), // number;
|
||||||
|
|
||||||
|
'experience' => $general->getVar(GeneralColumn::experience), // number;
|
||||||
|
'dedication' => $general->getVar(GeneralColumn::dedication), // number;
|
||||||
|
'officer_level' => $general->getVar(GeneralColumn::officer_level), // number;
|
||||||
|
'officer_city' => $general->getVar(GeneralColumn::officer_city), // number;
|
||||||
|
'defence_train' => $general->getVar(GeneralColumn::defence_train), // number;
|
||||||
|
'crewtype' => $general->getVar(GeneralColumn::crewtype), // GameObjClassKey;
|
||||||
|
'crew' => $general->getVar(GeneralColumn::crew), // number;
|
||||||
|
'train' => $general->getVar(GeneralColumn::train), // number;
|
||||||
|
'atmos' => $general->getVar(GeneralColumn::atmos), // number;
|
||||||
|
'turntime' => $general->getVar(GeneralColumn::turntime), // string;
|
||||||
|
'recent_war' => $general->getVar(GeneralColumn::recent_war), // string;
|
||||||
|
'horse' => $general->getVar(GeneralColumn::horse), // GameObjClassKey;
|
||||||
|
'weapon' => $general->getVar(GeneralColumn::weapon), // GameObjClassKey;
|
||||||
|
'book' => $general->getVar(GeneralColumn::book), // GameObjClassKey;
|
||||||
|
'item' => $general->getVar(GeneralColumn::item), // GameObjClassKey;
|
||||||
|
|
||||||
|
'warnum' => $general->getRankVar(RankColumn::warnum), // number;
|
||||||
|
'killnum' => $general->getRankVar(RankColumn::killnum), // number;
|
||||||
|
'deathnum' => $general->getRankVar(RankColumn::deathnum), // number;
|
||||||
|
'killcrew' => $general->getRankVar(RankColumn::killcrew), // number;
|
||||||
|
'deathcrew' => $general->getRankVar(RankColumn::deathcrew), // number;
|
||||||
|
'firenum' => $general->getRankVar(RankColumn::firenum), // number;
|
||||||
|
//P1 End
|
||||||
|
];
|
||||||
|
|
||||||
|
$nationID = $general->getNationID();
|
||||||
|
$troopID = $general->getVar(GeneralColumn::troop);
|
||||||
|
if (!$troopID) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$troopName = $db->queryFirstField(
|
||||||
|
'SELECT `name` FROM troop WHERE nation = %i AND troop_leader = %i',
|
||||||
|
$nationID,
|
||||||
|
$troopID
|
||||||
|
);
|
||||||
|
if (!$troopName) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$troopCityID = $db->queryFirstField(
|
||||||
|
'SELECT city FROM general WHERE nation = %i AND `no` = %i',
|
||||||
|
$nationID,
|
||||||
|
$troopID
|
||||||
|
);
|
||||||
|
if (!$troopCityID) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$troopReservedCommand = $db->query(
|
||||||
|
'SELECT action, arg, brief FROM general_turn WHERE general_id = %i AND turn_idx < 5 ORDER BY turn_idx asc',
|
||||||
|
$troopID
|
||||||
|
);
|
||||||
|
if ($troopReservedCommand) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['troopInfo'] = [
|
||||||
|
'leader' => [
|
||||||
|
'city' => $troopCityID,
|
||||||
|
'reservedCommand' => $troopReservedCommand,
|
||||||
|
],
|
||||||
|
'name' => $troopName,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateCityInfo(MeekroDB $db, General $general, array $rawNation): array
|
||||||
|
{
|
||||||
|
$rawCity = $general->getRawCity() ?? [];
|
||||||
|
$cityID = $rawCity[CityColumn::city->value];
|
||||||
|
|
||||||
|
$nationID = $rawCity[CityColumn::nation->value];
|
||||||
|
if ($nationID == $general->getNationID()) {
|
||||||
|
$nationName = $rawNation['name'];
|
||||||
|
$nationColor = $rawNation['color'];
|
||||||
|
} else {
|
||||||
|
$staticNation = getNationStaticInfo($nationID);
|
||||||
|
$nationName = $staticNation['name'];
|
||||||
|
$nationColor = $staticNation['color'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$rawOfficerList = $db->query('SELECT officer_level, name, npc FROM general WHERE city = %i AND officer_level IN (4,3,2)', $cityID);
|
||||||
|
$officerList = [4=>null, 3=>null, 2=>null];
|
||||||
|
foreach($rawOfficerList as $officer){
|
||||||
|
$officerLevel = $officer['officer_level'];
|
||||||
|
$officerList[$officerLevel] = $officer;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'id' => $rawCity[CityColumn::city->value],
|
||||||
|
'name' => $rawCity[CityColumn::name->value],
|
||||||
|
'nationInfo' => [
|
||||||
|
'id' => $nationID,
|
||||||
|
'name' => $nationName,
|
||||||
|
'color' => $nationColor,
|
||||||
|
],
|
||||||
|
'level' => $rawCity[CityColumn::level->value],
|
||||||
|
'trust' => $rawCity[CityColumn::trust->value],
|
||||||
|
'pop' => [$rawCity[CityColumn::pop->value], $rawCity[CityColumn::pop_max->value]],
|
||||||
|
'agri' => [$rawCity[CityColumn::agri->value], $rawCity[CityColumn::agri_max->value]],
|
||||||
|
'comm' => [$rawCity[CityColumn::comm->value], $rawCity[CityColumn::comm_max->value]],
|
||||||
|
'secu' => [$rawCity[CityColumn::secu->value], $rawCity[CityColumn::secu_max->value]],
|
||||||
|
'def' => [$rawCity[CityColumn::def->value], $rawCity[CityColumn::def_max->value]],
|
||||||
|
'wall' => [$rawCity[CityColumn::wall->value], $rawCity[CityColumn::wall_max->value]],
|
||||||
|
'trade' => $rawCity[CityColumn::trade->value],
|
||||||
|
'officerList' => $officerList,
|
||||||
|
];
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
//NOTE: 이 경우 staticNation 정보를 조회한다.
|
||||||
|
$general = General::createGeneralObjFromDB($generalID);
|
||||||
|
$nationID = $general->getNationID();
|
||||||
|
$cityID = $general->getCityID();
|
||||||
|
|
||||||
|
$con = checkLimit($general->getVar('con'));
|
||||||
|
if ($con >= 2) {
|
||||||
|
return [
|
||||||
|
'result' => false,
|
||||||
|
'reason' => '접속 제한중입니다.',
|
||||||
|
'recovery' => APIRecoveryType::GameQuota,
|
||||||
|
'recovery_arg' => $general->getVar('turntime'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$gameStor->cacheAll(true);
|
||||||
|
|
||||||
|
$rawCity = $db->queryFirstRow('SELECT * FROM city WHERE city = %i', $cityID);
|
||||||
|
$general->setRawCity($rawCity);
|
||||||
|
|
||||||
|
if ($nationID == 0) {
|
||||||
|
$rawNation = getNationStaticInfo(0);
|
||||||
|
} else {
|
||||||
|
$rawNation = $db->queryFirstRow('SELECT * FROM nation WHERE nation = %i', $nationID);
|
||||||
|
}
|
||||||
|
|
||||||
|
$globalInfo = $this->generateGlobalInfo($db);
|
||||||
|
$nationInfo = $nationID != 0 ?
|
||||||
|
$this->generateNationInfo($db, $general, $rawNation) :
|
||||||
|
$this->generateDummyNationInfo($db, $general, $rawNation);
|
||||||
|
$generalInfo = $this->generateGeneralInfo($db, $general, $rawNation);
|
||||||
|
$cityInfo = $this->generateCityInfo($db, $general, $rawNation);
|
||||||
|
|
||||||
|
//TODO: 마지막 투표, 토너먼트, 베팅을 했는지 정보를 별도로 가져와야 함. aux?
|
||||||
|
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'global' => $globalInfo,
|
||||||
|
'nation' => $nationInfo,
|
||||||
|
'general' => $generalInfo,
|
||||||
|
'city' => $cityInfo,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
+69
-16
@@ -27,7 +27,15 @@
|
|||||||
<div class="reservedCommandZone">예턴</div>
|
<div class="reservedCommandZone">예턴</div>
|
||||||
<div class="cityInfo">도시 정보</div>
|
<div class="cityInfo">도시 정보</div>
|
||||||
<div class="nationInfo">국가 정보</div>
|
<div class="nationInfo">국가 정보</div>
|
||||||
<div class="generalInfo">장수 정보</div>
|
<div v-if="frontInfo && generalInfo && nationStaticInfo" class="generalInfo">
|
||||||
|
<GeneralBasicCard
|
||||||
|
:general="generalInfo"
|
||||||
|
:nation="nationStaticInfo"
|
||||||
|
:troopInfo="frontInfo.general.troopInfo"
|
||||||
|
:turnTerm="frontInfo.global.turnterm"
|
||||||
|
:lastExecuted="lastExecuted"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="generalCommandToolbar">국가 툴바</div>
|
<div class="generalCommandToolbar">국가 툴바</div>
|
||||||
<div class="actionMiniPlate">갱신/로비 버튼</div>
|
<div class="actionMiniPlate">갱신/로비 버튼</div>
|
||||||
<div class="PublicRecord">
|
<div class="PublicRecord">
|
||||||
@@ -87,8 +95,11 @@ import { parseTime } from "./util/parseTime";
|
|||||||
import { unwrap } from "./util/unwrap";
|
import { unwrap } from "./util/unwrap";
|
||||||
import Denque from "denque";
|
import Denque from "denque";
|
||||||
import { formatLog } from "@/utilGame/formatLog";
|
import { formatLog } from "@/utilGame/formatLog";
|
||||||
import type { ExecuteResponse } from "./defs/API/Global";
|
import type { ExecuteResponse, GetFrontInfoResponse } from "./defs/API/Global";
|
||||||
import { delay } from "./util/delay";
|
import { delay } from "./util/delay";
|
||||||
|
import GeneralBasicCard from "./components/GeneralBasicCard.vue";
|
||||||
|
import type { GeneralListItemP1 } from "./defs/API/Nation";
|
||||||
|
import type { NationStaticItem } from "./defs";
|
||||||
|
|
||||||
const { serverName, serverNick, serverID } = staticValues;
|
const { serverName, serverNick, serverID } = staticValues;
|
||||||
|
|
||||||
@@ -115,21 +126,19 @@ async function tryRefresh() {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
responseLock = true;
|
responseLock = true;
|
||||||
const responseP = SammoAPI.Global.ExecuteEngine({ serverID }, true).then(
|
const responseP = SammoAPI.Global.ExecuteEngine({ serverID }, true).then((response) => {
|
||||||
(response) => {
|
if (response.result) {
|
||||||
if (response.result) {
|
lastExecuted.value = parseTime(response.lastExecuted);
|
||||||
lastExecuted.value = parseTime(response.lastExecuted);
|
serverLocked.value = response.locked;
|
||||||
serverLocked.value = response.locked;
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
);
|
return response;
|
||||||
|
});
|
||||||
|
|
||||||
//TODO: 갱신 알림 띄우기
|
//TODO: 갱신 알림 띄우기
|
||||||
const response = await Promise.race([delay(3000), responseP]);
|
const response = await Promise.race([delay(3000), responseP]);
|
||||||
responseLock = false;
|
responseLock = false;
|
||||||
|
|
||||||
if(response === undefined){
|
if (response === undefined) {
|
||||||
//timeout이지만 일단 갱신한다.
|
//timeout이지만 일단 갱신한다.
|
||||||
refreshCounter.value += 1;
|
refreshCounter.value += 1;
|
||||||
return;
|
return;
|
||||||
@@ -179,7 +188,7 @@ const worldHistory = ref(new Denque<[number, string]>());
|
|||||||
let recordLock = false;
|
let recordLock = false;
|
||||||
|
|
||||||
watch(refreshCounter, async () => {
|
watch(refreshCounter, async () => {
|
||||||
if(recordLock){
|
if (recordLock) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -215,11 +224,10 @@ watch(refreshCounter, async () => {
|
|||||||
if (!generalRecords.value.isEmpty() && id <= unwrap(generalRecords.value.get(0))[0]) {
|
if (!generalRecords.value.isEmpty() && id <= unwrap(generalRecords.value.get(0))[0]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(generalRecords.value.length >= 15) {
|
if (generalRecords.value.length >= 15) {
|
||||||
generalRecords.value.pop();
|
generalRecords.value.pop();
|
||||||
}
|
}
|
||||||
generalRecords.value.unshift([id, record]);
|
generalRecords.value.unshift([id, record]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (response.global.length) {
|
while (response.global.length) {
|
||||||
@@ -227,7 +235,7 @@ watch(refreshCounter, async () => {
|
|||||||
if (!globalRecords.value.isEmpty() && id <= unwrap(globalRecords.value.get(0))[0]) {
|
if (!globalRecords.value.isEmpty() && id <= unwrap(globalRecords.value.get(0))[0]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(globalRecords.value.length >= 15) {
|
if (globalRecords.value.length >= 15) {
|
||||||
globalRecords.value.pop();
|
globalRecords.value.pop();
|
||||||
}
|
}
|
||||||
globalRecords.value.unshift([id, record]);
|
globalRecords.value.unshift([id, record]);
|
||||||
@@ -238,7 +246,7 @@ watch(refreshCounter, async () => {
|
|||||||
if (!worldHistory.value.isEmpty() && id <= unwrap(worldHistory.value.get(0))[0]) {
|
if (!worldHistory.value.isEmpty() && id <= unwrap(worldHistory.value.get(0))[0]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(worldHistory.value.length >= 15) {
|
if (worldHistory.value.length >= 15) {
|
||||||
worldHistory.value.pop();
|
worldHistory.value.pop();
|
||||||
}
|
}
|
||||||
worldHistory.value.unshift([id, record]);
|
worldHistory.value.unshift([id, record]);
|
||||||
@@ -252,6 +260,51 @@ watch(refreshCounter, async () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const frontInfo = ref<GetFrontInfoResponse>();
|
||||||
|
|
||||||
|
const generalInfo = ref<GeneralListItemP1>();
|
||||||
|
const nationStaticInfo = ref<NationStaticItem>();
|
||||||
|
|
||||||
|
let generalInfoLock = false;
|
||||||
|
|
||||||
|
watch(refreshCounter, async () => {
|
||||||
|
if (generalInfoLock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
generalInfoLock = true;
|
||||||
|
const response = await SammoAPI.General.GetFrontInfo();
|
||||||
|
generalInfoLock = false;
|
||||||
|
|
||||||
|
frontInfo.value = response;
|
||||||
|
generalInfo.value = response.general;
|
||||||
|
|
||||||
|
const newLastExecuted = parseTime(response.global.lastExecuted);
|
||||||
|
if(newLastExecuted.getTime() > lastExecuted.value.getTime()){
|
||||||
|
lastExecuted.value = newLastExecuted;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawNation = response.nation;
|
||||||
|
nationStaticInfo.value = {
|
||||||
|
nation: rawNation.id,
|
||||||
|
name: rawNation.name,
|
||||||
|
color: rawNation.color,
|
||||||
|
type: rawNation.type.raw,
|
||||||
|
level: rawNation.level,
|
||||||
|
capital: rawNation.capital,
|
||||||
|
gennum: rawNation.gennum,
|
||||||
|
power: rawNation.power,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
recordLock = false;
|
||||||
|
console.error(e);
|
||||||
|
toasts.danger({
|
||||||
|
title: "최근 정보 갱신 실패",
|
||||||
|
body: `${e}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "@scss/common/break_500px.scss";
|
@import "@scss/common/break_500px.scss";
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import type {
|
|||||||
GetConstResponse,
|
GetConstResponse,
|
||||||
GetCurrentHistoryResponse,
|
GetCurrentHistoryResponse,
|
||||||
GetDiplomacyResponse,
|
GetDiplomacyResponse,
|
||||||
|
GetFrontInfoResponse,
|
||||||
GetHistoryResponse,
|
GetHistoryResponse,
|
||||||
GetRecentRecordResponse,
|
GetRecentRecordResponse,
|
||||||
} from "./defs/API/Global";
|
} from "./defs/API/Global";
|
||||||
@@ -131,6 +132,7 @@ const apiRealPath = {
|
|||||||
DieOnPrestart: POST as APICallT<undefined>,
|
DieOnPrestart: POST as APICallT<undefined>,
|
||||||
BuildNationCandidate: POST as APICallT<undefined>,
|
BuildNationCandidate: POST as APICallT<undefined>,
|
||||||
GetCommandTable: GET as APICallT<undefined, CommandTableResponse>,
|
GetCommandTable: GET as APICallT<undefined, CommandTableResponse>,
|
||||||
|
GetFrontInfo: GET as APICallT<undefined, GetFrontInfoResponse>,
|
||||||
},
|
},
|
||||||
Global: {
|
Global: {
|
||||||
GeneralList: GET as APICallT<undefined, GeneralListResponse>,
|
GeneralList: GET as APICallT<undefined, GeneralListResponse>,
|
||||||
|
|||||||
+201
-80
@@ -1,96 +1,217 @@
|
|||||||
import type { CityID, CrewTypeID, GameCityDefault, GameConstType, GameUnitType, GameIActionKey, GameIActionCategory, GameIActionInfo } from "@/defs/GameObj";
|
import type {
|
||||||
import type { diplomacyState, MapResult, SimpleNationObj } from "@/defs";
|
CityID,
|
||||||
|
CrewTypeID,
|
||||||
|
GameCityDefault,
|
||||||
|
GameConstType,
|
||||||
|
GameUnitType,
|
||||||
|
GameIActionKey,
|
||||||
|
GameIActionCategory,
|
||||||
|
GameIActionInfo,
|
||||||
|
} from "@/defs/GameObj";
|
||||||
|
import type { diplomacyState, MapResult, NationLevel, SimpleNationObj } from "@/defs";
|
||||||
|
import type { GeneralListItemP0, GeneralListItemP1 } from "./Nation";
|
||||||
|
import type { VoteInfo } from "./Vote";
|
||||||
|
|
||||||
export interface GetConstResponse {
|
export interface GetConstResponse {
|
||||||
result: true;
|
result: true;
|
||||||
cacheKey: string;
|
cacheKey: string;
|
||||||
data: {
|
data: {
|
||||||
gameConst: GameConstType;
|
gameConst: GameConstType;
|
||||||
gameUnitConst: Record<CrewTypeID, GameUnitType>;
|
gameUnitConst: Record<CrewTypeID, GameUnitType>;
|
||||||
cityConst: Record<CityID, GameCityDefault>;
|
cityConst: Record<CityID, GameCityDefault>;
|
||||||
cityConstMap: {
|
cityConstMap: {
|
||||||
region: Record<number | string, string | number>;
|
region: Record<number | string, string | number>;
|
||||||
level: Record<number | string, string | number>; //defs.CityLevelText
|
level: Record<number | string, string | number>; //defs.CityLevelText
|
||||||
};
|
|
||||||
iActionInfo: Record<
|
|
||||||
GameIActionCategory,
|
|
||||||
Record<
|
|
||||||
GameIActionKey,
|
|
||||||
GameIActionInfo
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
iActionKeyMap: {
|
|
||||||
availableNationType: "nationType";
|
|
||||||
neutralNationType: "nationType";
|
|
||||||
defaultSpecialDomestic: "specialDomestic";
|
|
||||||
availableSpecialDomestic: "specialDomestic";
|
|
||||||
optionalSpecialDomestic: "specialDomestic";
|
|
||||||
defaultSpecialWar: "specialWar";
|
|
||||||
availableSpecialWar: "specialWar";
|
|
||||||
optionalSpecialWar: "specialWar";
|
|
||||||
neutralPersonality: "personality";
|
|
||||||
availablePersonality: "personality";
|
|
||||||
optionalPersonality: "personality";
|
|
||||||
allItems: "item";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
iActionInfo: Record<GameIActionCategory, Record<GameIActionKey, GameIActionInfo>>;
|
||||||
|
iActionKeyMap: {
|
||||||
|
availableNationType: "nationType";
|
||||||
|
neutralNationType: "nationType";
|
||||||
|
defaultSpecialDomestic: "specialDomestic";
|
||||||
|
availableSpecialDomestic: "specialDomestic";
|
||||||
|
optionalSpecialDomestic: "specialDomestic";
|
||||||
|
defaultSpecialWar: "specialWar";
|
||||||
|
availableSpecialWar: "specialWar";
|
||||||
|
optionalSpecialWar: "specialWar";
|
||||||
|
neutralPersonality: "personality";
|
||||||
|
availablePersonality: "personality";
|
||||||
|
optionalPersonality: "personality";
|
||||||
|
allItems: "item";
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HistoryObj = {
|
export type HistoryObj = {
|
||||||
server_id: string,
|
server_id: string;
|
||||||
year: number;
|
year: number;
|
||||||
month: number;
|
month: number;
|
||||||
map: MapResult,
|
map: MapResult;
|
||||||
global_history: string[],
|
global_history: string[];
|
||||||
global_action: string[],
|
global_action: string[];
|
||||||
nations: {
|
nations: {
|
||||||
capital: number,
|
capital: number;
|
||||||
cities: string[],
|
cities: string[];
|
||||||
color: string,
|
color: string;
|
||||||
gennum: number,
|
gennum: number;
|
||||||
level: number,
|
level: number;
|
||||||
name: string,
|
name: string;
|
||||||
nation: number,
|
nation: number;
|
||||||
power: number,
|
power: number;
|
||||||
type: GameIActionKey
|
type: GameIActionKey;
|
||||||
}[],
|
}[];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type GetHistoryResponse = {
|
export type GetHistoryResponse = {
|
||||||
result: true;
|
result: true;
|
||||||
data: HistoryObj & {
|
data: HistoryObj & {
|
||||||
hash: string;
|
hash: string;
|
||||||
//no: number,
|
//no: number,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export type GetCurrentHistoryResponse = {
|
export type GetCurrentHistoryResponse = {
|
||||||
result: true;
|
result: true;
|
||||||
data: HistoryObj;
|
data: HistoryObj;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
export type GetDiplomacyResponse = {
|
export type GetDiplomacyResponse = {
|
||||||
result: true;
|
result: true;
|
||||||
nations: SimpleNationObj[];
|
nations: SimpleNationObj[];
|
||||||
conflict: [number, Record<number, number>][];
|
conflict: [number, Record<number, number>][];
|
||||||
diplomacyList: Record<number, Record<number, diplomacyState>>;
|
diplomacyList: Record<number, Record<number, diplomacyState>>;
|
||||||
myNationID: number;
|
myNationID: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ExecuteResponse = {
|
export type ExecuteResponse = {
|
||||||
result: true;
|
result: true;
|
||||||
updated: boolean;
|
updated: boolean;
|
||||||
locked: boolean;
|
locked: boolean;
|
||||||
lastExecuted: string;
|
lastExecuted: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type GetRecentRecordResponse = {
|
export type GetRecentRecordResponse = {
|
||||||
result: true;
|
result: true;
|
||||||
history: [number, string][];
|
history: [number, string][];
|
||||||
global: [number, string][];
|
global: [number, string][];
|
||||||
general: [number, string][];
|
general: [number, string][];
|
||||||
flushHistory: 1 | 0;
|
flushHistory: 1 | 0;
|
||||||
flushGlobal: 1 | 0;
|
flushGlobal: 1 | 0;
|
||||||
flushGeneral: 1 | 0;
|
flushGeneral: 1 | 0;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export type AutorunUserMode = "develop" | "warp" | "recruit" | "recruit_high" | "train" | "battle" | "chief";
|
||||||
|
|
||||||
|
export type GetFrontInfoResponse = {
|
||||||
|
result: true;
|
||||||
|
global: {
|
||||||
|
scenarioText: string;
|
||||||
|
extendedGeneral: 1 | 0;
|
||||||
|
isFiction: 1 | 0;
|
||||||
|
npcMode: 2 | 1 | 0;
|
||||||
|
joinMode: "onlyRandom" | "full";
|
||||||
|
startyear: number;
|
||||||
|
year: number;
|
||||||
|
month: number;
|
||||||
|
autorunUser: AutorunUserMode[];
|
||||||
|
turnterm: number;
|
||||||
|
lastExecuted: string;
|
||||||
|
lastVoteID: number;
|
||||||
|
develCost: number;
|
||||||
|
noticeMsg: number;
|
||||||
|
onlineNations: string; //TODO: string[]으로 변경
|
||||||
|
onlineUserCnt: number;
|
||||||
|
apiLimit: number;
|
||||||
|
auctionCount: number;
|
||||||
|
isTournamentActive: boolean;
|
||||||
|
isTournamentApplicationOpen: boolean;
|
||||||
|
isBettingActive: boolean;
|
||||||
|
isLocked: boolean;
|
||||||
|
tournamentType: null | 0 | 1 | 2 | 3;
|
||||||
|
tournamentState: string;
|
||||||
|
genCount: number;
|
||||||
|
generalCntLimit: number;
|
||||||
|
lastVote: VoteInfo | null;
|
||||||
|
};
|
||||||
|
general: GeneralListItemP1 & {
|
||||||
|
troopInfo?: {
|
||||||
|
leader: {
|
||||||
|
city: number;
|
||||||
|
reservedCommand: GeneralListItemP1["reservedCommand"];
|
||||||
|
};
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nation: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
population: {
|
||||||
|
cityCnt: number;
|
||||||
|
now: number;
|
||||||
|
max: number;
|
||||||
|
};
|
||||||
|
crew: {
|
||||||
|
generalCnt: number;
|
||||||
|
now: number;
|
||||||
|
max: number;
|
||||||
|
};
|
||||||
|
type: {
|
||||||
|
raw: GameIActionKey;
|
||||||
|
name: string;
|
||||||
|
pros: string;
|
||||||
|
cons: string;
|
||||||
|
};
|
||||||
|
color: string;
|
||||||
|
level: NationLevel;
|
||||||
|
capital: number;
|
||||||
|
gold: number;
|
||||||
|
rice: number;
|
||||||
|
tech: number;
|
||||||
|
gennum: number;
|
||||||
|
power: number;
|
||||||
|
bill: number;
|
||||||
|
taxRate: number;
|
||||||
|
onlineGen: string;
|
||||||
|
notice: string;
|
||||||
|
topChiefs: Record<
|
||||||
|
11 | 12,
|
||||||
|
{
|
||||||
|
officer_level: number;
|
||||||
|
no: number;
|
||||||
|
name: string;
|
||||||
|
npc: GeneralListItemP0["npc"];
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
officerLevelTexts: Record<number, string>;
|
||||||
|
diplomaticLimit: number;
|
||||||
|
strategicCmdLimit: number;
|
||||||
|
impossibleStrategicCommand: [string, number][];
|
||||||
|
prohibitScout: 1 | 0;
|
||||||
|
prohibitWar: 1 | 0;
|
||||||
|
};
|
||||||
|
city: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
nationInfo: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
level: number;
|
||||||
|
trust: number;
|
||||||
|
pop: [number, number];
|
||||||
|
agri: [number, number];
|
||||||
|
comm: [number, number];
|
||||||
|
secu: [number, number];
|
||||||
|
def: [number, number];
|
||||||
|
wall: [number, number];
|
||||||
|
trade: null | number;
|
||||||
|
officerList: Record<
|
||||||
|
2 | 3 | 4,
|
||||||
|
{
|
||||||
|
officer_level: 2 | 3 | 4;
|
||||||
|
name: string;
|
||||||
|
npc: GeneralListItemP0["npc"];
|
||||||
|
} | null
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user