feat,wip: 경매장을 db table로 분리
This commit is contained in:
+19
-46
@@ -5,21 +5,17 @@ namespace sammo;
|
|||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use Ds\Map;
|
|
||||||
use sammo\DTO\AuctionBidItem;
|
use sammo\DTO\AuctionBidItem;
|
||||||
use sammo\DTO\AuctionBidItemData;
|
use sammo\DTO\AuctionBidItemData;
|
||||||
use sammo\DTO\AuctionInfo;
|
use sammo\DTO\AuctionInfo;
|
||||||
use sammo\Enums\InheritanceKey;
|
use sammo\Enums\InheritanceKey;
|
||||||
use sammo\Enums\RankColumn;
|
use sammo\Enums\RankColumn;
|
||||||
use sammo\Enums\ResourceType;
|
use sammo\Enums\ResourceType;
|
||||||
use sammo\VO\InheritancePointType;
|
|
||||||
|
|
||||||
class Auction
|
class Auction
|
||||||
{
|
{
|
||||||
|
|
||||||
protected AuctionInfo $info;
|
protected AuctionInfo $info;
|
||||||
public const LAST_AUCTION_ID_KEY = 'last_auction_id';
|
|
||||||
|
|
||||||
|
|
||||||
public const COEFF_AUCTION_CLOSE_MINUTES = 24;
|
public const COEFF_AUCTION_CLOSE_MINUTES = 24;
|
||||||
public const COEFF_EXTENSION_MINUTES_PER_BID = 1 / 6;
|
public const COEFF_EXTENSION_MINUTES_PER_BID = 1 / 6;
|
||||||
@@ -30,39 +26,24 @@ class Auction
|
|||||||
public const MIN_EXTENSION_MINUTES_LIMIT_BY_BID = 5;
|
public const MIN_EXTENSION_MINUTES_LIMIT_BY_BID = 5;
|
||||||
public const MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 5;
|
public const MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 5;
|
||||||
|
|
||||||
static public function genNextAuctionID(): int
|
static public function openAuction(AuctionInfo $info, General $general): int|string
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
|
if ($info->id !== null) {
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
return 'id가 지정되어 있습니다.';
|
||||||
$gameStor->invalidateCacheValue(self::LAST_AUCTION_ID_KEY);
|
|
||||||
$auctionID = ($gameStor->getValue(self::LAST_AUCTION_ID_KEY) ?? 0) + 1;
|
|
||||||
|
|
||||||
$gameStor->setValue(self::LAST_AUCTION_ID_KEY, $auctionID);
|
|
||||||
|
|
||||||
return $auctionID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static public function openAuction(AuctionInfo $info, General $general): ?string
|
|
||||||
{
|
|
||||||
$db = DB::db();
|
|
||||||
$auctionID = $info->id;
|
|
||||||
$auctionStor = KVStorage::getStorage($db, 'auction');
|
|
||||||
|
|
||||||
$openedAuction = $general->getAuxVar('openedAuction') ?? [];
|
|
||||||
$prevAuctionID = $openedAuction[$info->type->value] ?? null;
|
|
||||||
if ($prevAuctionID !== null) {
|
|
||||||
//XXX: 이 구조보다는 차라리 DB에 insert로 넣는 게 나을 수도.
|
|
||||||
$prevAuction = new Auction($prevAuctionID, $general);
|
|
||||||
if (!$prevAuction->info->finished) {
|
|
||||||
return '아직 경매가 끝나지 않았습니다.';
|
|
||||||
}
|
|
||||||
unset($openedAuction[$info->type->value]);
|
|
||||||
$general->setAuxVar('openedAuction', $openedAuction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$auctionStor->setValue("id_{$auctionID}", $info->toArray());
|
$prevAuctionID = $db->queryFirstField(
|
||||||
|
'SELECT id FROM ng_auction WHERE opener_general_id = %i AND finished = 0 AND `type` = %s',
|
||||||
|
$general->getID(),
|
||||||
|
$info->type
|
||||||
|
);
|
||||||
|
if ($prevAuctionID !== null) {
|
||||||
|
return '아직 경매가 끝나지 않았습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->insert('ng_auction', $info->toArray());
|
||||||
|
return $db->insertId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHighestBid(): ?AuctionBidItem
|
public function getHighestBid(): ?AuctionBidItem
|
||||||
@@ -96,8 +77,7 @@ class Auction
|
|||||||
public function __construct(protected readonly int $auctionID, protected General $general)
|
public function __construct(protected readonly int $auctionID, protected General $general)
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$auctionStor = KVStorage::getStorage($db, 'auction');
|
$rawAuctionInfo = $db->query('SELECT * FROM ng_auction WHERE id = %i', $auctionID);
|
||||||
$rawAuctionInfo = $auctionStor->getValue("id_{$auctionID}");
|
|
||||||
if ($rawAuctionInfo === null) {
|
if ($rawAuctionInfo === null) {
|
||||||
throw new \RuntimeException("해당 경매가 없습니다: {$auctionID}");
|
throw new \RuntimeException("해당 경매가 없습니다: {$auctionID}");
|
||||||
}
|
}
|
||||||
@@ -111,7 +91,7 @@ class Auction
|
|||||||
|
|
||||||
public function extendCloseDate(DateTimeInterface $date, bool $force = false): ?string
|
public function extendCloseDate(DateTimeInterface $date, bool $force = false): ?string
|
||||||
{
|
{
|
||||||
if(!$force){
|
if (!$force) {
|
||||||
if ($this->info->remainCloseExtensionCnt === null) {
|
if ($this->info->remainCloseExtensionCnt === null) {
|
||||||
return '연장할 수 없는 경매입니다.';
|
return '연장할 수 없는 경매입니다.';
|
||||||
}
|
}
|
||||||
@@ -124,7 +104,6 @@ class Auction
|
|||||||
}
|
}
|
||||||
|
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$auctionStor = KVStorage::getStorage($db, 'auction');
|
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
$turnTerm = $gameStor->getValue('turnterm');
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
$closeDate = DateTimeImmutable::createFromInterface($date);
|
$closeDate = DateTimeImmutable::createFromInterface($date);
|
||||||
@@ -132,7 +111,7 @@ class Auction
|
|||||||
$this->info->availableLatestBidCloseDate = $closeDate->add(TimeUtil::secondsToDateInterval(
|
$this->info->availableLatestBidCloseDate = $closeDate->add(TimeUtil::secondsToDateInterval(
|
||||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||||
));
|
));
|
||||||
$auctionStor->setValue("id_{$this->info->id}", $this->info->toArray());
|
$db->update('ng_auction', $this->info->toArrayExcept('id'), 'id = %i', $this->info->id);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,23 +163,17 @@ class Auction
|
|||||||
public function closeAuction(bool $isRollback = false): void
|
public function closeAuction(bool $isRollback = false): void
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$auctionStor = KVStorage::getStorage($db, 'auction');
|
|
||||||
|
|
||||||
$this->info->finished = true;
|
$this->info->finished = true;
|
||||||
|
|
||||||
$openedAuction = $this->general->getAuxVar('openedAuction') ?? [];
|
|
||||||
if (key_exists($this->info->type->value, $openedAuction)) {
|
|
||||||
unset($openedAuction[$this->info->type->value]);
|
|
||||||
$this->general->setAuxVar('openedAuction', $openedAuction);
|
|
||||||
}
|
|
||||||
if ($isRollback) {
|
if ($isRollback) {
|
||||||
$highestBid = $this->getHighestBid();
|
$highestBid = $this->getHighestBid();
|
||||||
if ($highestBid !== null) {
|
if ($highestBid !== null) {
|
||||||
$this->refundBid($highestBid, "{$this->info->title} 경매가 취소되었습니다.");
|
$this->refundBid($highestBid, "{$this->info->title} 경매가 취소되었습니다.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$auctionID = $this->info->id;
|
|
||||||
$auctionStor->setValue("id_{$auctionID}", $this->info->toArray());
|
$db->update('ng_auction', $this->info->toArrayExcept('id'), 'id = %i', $this->info->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function bidInheritPoint(int $amount, \DateTimeImmutable $now, bool $tryExtendCloseDate): ?string
|
private function bidInheritPoint(int $amount, \DateTimeImmutable $now, bool $tryExtendCloseDate): ?string
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace sammo;
|
|||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use sammo\DTO\AuctionBidItem;
|
use sammo\DTO\AuctionBidItem;
|
||||||
use sammo\DTO\AuctionInfo;
|
use sammo\DTO\AuctionInfo;
|
||||||
|
use sammo\DTO\AuctionInfoDetail;
|
||||||
use sammo\Enums\AuctionType;
|
use sammo\Enums\AuctionType;
|
||||||
use sammo\Enums\InheritanceKey;
|
use sammo\Enums\InheritanceKey;
|
||||||
use sammo\Enums\ResourceType;
|
use sammo\Enums\ResourceType;
|
||||||
@@ -44,7 +45,7 @@ class AuctionUniqueItem extends Auction
|
|||||||
return "{$namePool[$subIdx]}{$dupIdx}";
|
return "{$namePool[$subIdx]}{$dupIdx}";
|
||||||
}
|
}
|
||||||
|
|
||||||
static public function openItemAuction(BaseItem $item, General $general, int $startAmount): ?string
|
static public function openItemAuction(BaseItem $item, General $general, int $startAmount): self|string
|
||||||
{
|
{
|
||||||
if ($startAmount < GameConst::$inheritItemUniqueMinPoint) {
|
if ($startAmount < GameConst::$inheritItemUniqueMinPoint) {
|
||||||
return '최소 경매 금액은 ' . GameConst::$inheritItemUniqueMinPoint . '입니다.';
|
return '최소 경매 금액은 ' . GameConst::$inheritItemUniqueMinPoint . '입니다.';
|
||||||
@@ -58,9 +59,6 @@ class AuctionUniqueItem extends Auction
|
|||||||
return '구매할 수 있는 아이템입니다.';
|
return '구매할 수 있는 아이템입니다.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameConst::$allItems)
|
|
||||||
|
|
||||||
$auctionID = static::genNextAuctionID();
|
|
||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable();
|
||||||
|
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
@@ -75,25 +73,28 @@ class AuctionUniqueItem extends Auction
|
|||||||
));
|
));
|
||||||
|
|
||||||
$info = new AuctionInfo(
|
$info = new AuctionInfo(
|
||||||
$auctionID,
|
|
||||||
static::genObfuscatedName($general->getID()),
|
|
||||||
$general->getID(),
|
|
||||||
AuctionType::UniqueItem,
|
|
||||||
$item->getRawClassName(),
|
|
||||||
"{$item->getName()} 경매",
|
|
||||||
false,
|
|
||||||
ResourceType::inheritancePoint,
|
|
||||||
$startAmount,
|
|
||||||
null,
|
null,
|
||||||
1,
|
AuctionType::UniqueItem,
|
||||||
|
false,
|
||||||
|
$item->getRawClassName(),
|
||||||
|
$general->getID(),
|
||||||
|
ResourceType::inheritancePoint,
|
||||||
$now,
|
$now,
|
||||||
$closeDate,
|
$closeDate,
|
||||||
$availableLatestBidCloseDate,
|
new AuctionInfoDetail(
|
||||||
|
"{$item->getName()} 경매",
|
||||||
|
static::genObfuscatedName($general->getID()),
|
||||||
|
|
||||||
|
$startAmount,
|
||||||
|
null,
|
||||||
|
1,
|
||||||
|
$availableLatestBidCloseDate,
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$result = static::openAuction($info, $general);
|
$auctionID = static::openAuction($info, $general);
|
||||||
if ($result !== null) {
|
if (!is_int($auctionID)) {
|
||||||
return $result;
|
return $auctionID;
|
||||||
}
|
}
|
||||||
$auction = new static($auctionID, $general);
|
$auction = new static($auctionID, $general);
|
||||||
try {
|
try {
|
||||||
@@ -105,7 +106,7 @@ class AuctionUniqueItem extends Auction
|
|||||||
return "경매를 시작했지만, 첫 입찰에 실패했습니다: {$msg}";
|
return "경매를 시작했지만, 첫 입찰에 실패했습니다: {$msg}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return $auction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function giveUniqueItem(AuctionBidItem $highestBid, General $bidder): ?string
|
private function giveUniqueItem(AuctionBidItem $highestBid, General $bidder): ?string
|
||||||
@@ -137,7 +138,7 @@ class AuctionUniqueItem extends Auction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($availableEquipUniqueCnt <= 0){
|
if ($availableEquipUniqueCnt <= 0) {
|
||||||
return '유니크 아이템 소유 제한 상태입니다. 종료 시간이 연장됩니다.';
|
return '유니크 아이템 소유 제한 상태입니다. 종료 시간이 연장됩니다.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
namespace sammo\DTO;
|
namespace sammo\DTO;
|
||||||
|
|
||||||
use sammo\DTO\Attr\Convert;
|
use sammo\DTO\Attr\Convert;
|
||||||
|
use sammo\DTO\Attr\JsonString;
|
||||||
|
use sammo\DTO\Attr\NullIsUndefined;
|
||||||
use sammo\DTO\Converter\DateTimeConverter;
|
use sammo\DTO\Converter\DateTimeConverter;
|
||||||
use sammo\Enums\AuctionType;
|
use sammo\Enums\AuctionType;
|
||||||
use sammo\Enums\ResourceType;
|
use sammo\Enums\ResourceType;
|
||||||
@@ -10,24 +12,21 @@ use sammo\Enums\ResourceType;
|
|||||||
class AuctionInfo extends DTO
|
class AuctionInfo extends DTO
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public int $id,
|
#[NullIsUndefined]
|
||||||
public string $openerName,
|
public ?int $id,
|
||||||
public int $openerGeneralID,
|
|
||||||
public AuctionType $type,
|
public AuctionType $type,
|
||||||
public ?string $target,
|
|
||||||
public string $title,
|
|
||||||
public bool $finished,
|
public bool $finished,
|
||||||
|
public ?string $target,
|
||||||
|
public int $openerGeneralID,
|
||||||
public ResourceType $reqResource,
|
public ResourceType $reqResource,
|
||||||
public int $minAmount,
|
|
||||||
public ?int $buyImmediatelyAmount,
|
|
||||||
public ?int $remainCloseDateExtensionCnt,
|
|
||||||
|
|
||||||
#[Convert(DateTimeConverter::class)]
|
#[Convert(DateTimeConverter::class)]
|
||||||
public \DateTimeImmutable $openDate,
|
public \DateTimeImmutable $openDate,
|
||||||
#[Convert(DateTimeConverter::class)]
|
#[Convert(DateTimeConverter::class)]
|
||||||
public \DateTimeImmutable $closeDate,
|
public \DateTimeImmutable $closeDate,
|
||||||
#[Convert(DateTimeConverter::class)]
|
|
||||||
public ?\DateTimeImmutable $availableLatestBidCloseDate,
|
#[JsonString]
|
||||||
|
public AuctionInfoDetail $detail,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\DTO;
|
||||||
|
|
||||||
|
use sammo\DTO\Attr\Convert;
|
||||||
|
use sammo\DTO\Attr\NullIsUndefined;
|
||||||
|
use sammo\DTO\Converter\DateTimeConverter;
|
||||||
|
|
||||||
|
class AuctionInfoDetail extends DTO
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $title,
|
||||||
|
public string $openerName,
|
||||||
|
|
||||||
|
public int $minAmount,
|
||||||
|
|
||||||
|
#[NullIsUndefined]
|
||||||
|
public ?int $buyImmediatelyAmount,
|
||||||
|
#[NullIsUndefined]
|
||||||
|
public ?int $remainCloseDateExtensionCnt,
|
||||||
|
#[NullIsUndefined]
|
||||||
|
#[Convert(DateTimeConverter::class)]
|
||||||
|
public ?\DateTimeImmutable $availableLatestBidCloseDate,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-13
@@ -692,21 +692,23 @@ CREATE TABLE `vote_comment` (
|
|||||||
##############################
|
##############################
|
||||||
# 경매 객체는 KVStorage에 저장
|
# 경매 객체는 KVStorage에 저장
|
||||||
CREATE TABLE `ng_auction` (
|
CREATE TABLE `ng_auction` (
|
||||||
`no` INT(11) NOT NULL AUTO_INCREMENT,
|
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
`auction_id` INT(11) NOT NULL,
|
`type` ENUM('gold','rice','uniqueItem') NOT NULL COLLATE 'utf8mb4_bin',
|
||||||
`owner` INT(11) NULL DEFAULT NULL,
|
`finished` BIT(1) NOT NULL,
|
||||||
`general_id` INT(11) NOT NULL,
|
`target` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
|
||||||
`amount` INT(11) NOT NULL,
|
`opener_general_id` INT(11) NOT NULL,
|
||||||
`date` DATETIME NOT NULL,
|
`req_resource` ENUM('gold','rice','inheritPoint') NOT NULL COLLATE 'utf8mb4_bin',
|
||||||
`aux` LONGTEXT NOT NULL COLLATE 'utf8mb4_bin',
|
`open_date` DATETIME NOT NULL,
|
||||||
PRIMARY KEY (`no`),
|
`close_date` DATETIME NOT NULL,
|
||||||
UNIQUE INDEX `by_general` (`general_id`, `auction_id`, `amount`),
|
`detail` LONGTEXT NOT NULL COLLATE 'utf8mb4_bin',
|
||||||
UNIQUE INDEX `by_owner` (`owner`, `auction_id`, `amount`),
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
INDEX `by_amount` (`auction_id`, `amount`, `date`),
|
INDEX `by_close` (`finished`, `type`, `close_date`) USING BTREE,
|
||||||
CONSTRAINT `aux` CHECK (json_valid(`aux`))
|
INDEX `by_general_id` (`opener_general_id`, `type`, `finished`) USING BTREE,
|
||||||
|
CONSTRAINT `detail` CHECK (json_valid(`detail`))
|
||||||
)
|
)
|
||||||
COLLATE='utf8mb4_general_ci'
|
COLLATE='utf8mb4_general_ci'
|
||||||
ENGINE = Aria;
|
ENGINE=Aria
|
||||||
|
;
|
||||||
|
|
||||||
CREATE TABLE `ng_auction_bid` (
|
CREATE TABLE `ng_auction_bid` (
|
||||||
`no` INT(11) NOT NULL AUTO_INCREMENT,
|
`no` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
|||||||
Reference in New Issue
Block a user