feat(wip): 유니크 경매 세부 진행
This commit is contained in:
+80
-28
@@ -20,6 +20,16 @@ class Auction
|
||||
protected AuctionInfo $info;
|
||||
public const LAST_AUCTION_ID_KEY = 'last_auction_id';
|
||||
|
||||
|
||||
public const COEFF_AUCTION_CLOSE_MINUTES = 24;
|
||||
public const COEFF_EXTENSION_MINUTES_PER_BID = 1 / 6;
|
||||
public const COEFF_EXTENSION_MINUTES_LIMIT_BY_BID = 1;
|
||||
public const COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 1;
|
||||
public const MIN_AUCTION_CLOSE_MINUTES = 30;
|
||||
public const MIN_EXTENSION_MINUTES_PER_BID = 1;
|
||||
public const MIN_EXTENSION_MINUTES_LIMIT_BY_BID = 5;
|
||||
public const MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 5;
|
||||
|
||||
static public function genNextAuctionID(): int
|
||||
{
|
||||
$db = DB::db();
|
||||
@@ -41,14 +51,14 @@ class Auction
|
||||
$auctionStor = KVStorage::getStorage($db, 'auction');
|
||||
|
||||
$openedAuction = $general->getAuxVar('openedAuction') ?? [];
|
||||
$prevAuctionID = $openedAuction[$info->reqResource->value] ?? null;
|
||||
$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->reqResource->value]);
|
||||
unset($openedAuction[$info->type->value]);
|
||||
$general->setAuxVar('openedAuction', $openedAuction);
|
||||
}
|
||||
|
||||
@@ -62,7 +72,7 @@ class Auction
|
||||
'SELECT * FROM ng_auction WHERE auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
||||
$this->info->id
|
||||
);
|
||||
if(!$rawHighestBid){
|
||||
if (!$rawHighestBid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -99,31 +109,49 @@ class Auction
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
public function extendCloseDate(DateTimeInterface $date): void
|
||||
public function extendCloseDate(DateTimeInterface $date, bool $force = false): ?string
|
||||
{
|
||||
if(!$force){
|
||||
if ($this->info->remainCloseExtensionCnt === null) {
|
||||
return '연장할 수 없는 경매입니다.';
|
||||
}
|
||||
if ($this->info->remainCloseExtensionCnt === 0) {
|
||||
return '더 이상 연장할 수 없습니다';
|
||||
}
|
||||
if ($this->info->remainCloseExtensionCnt > 0) {
|
||||
$this->info->remainCloseExtensionCnt--;
|
||||
}
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$auctionStor = KVStorage::getStorage($db, 'auction');
|
||||
$this->info->closeDate = DateTimeImmutable::createFromInterface($date);
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
$closeDate = DateTimeImmutable::createFromInterface($date);
|
||||
$this->info->closeDate = $closeDate;
|
||||
$this->info->availableLatestBidCloseDate = $closeDate->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||
));
|
||||
$auctionStor->setValue("id_{$this->info->id}", $this->info->toArray());
|
||||
return null;
|
||||
}
|
||||
|
||||
public function refundBid(AuctionBidItem $bidItem, string $reason): void
|
||||
{
|
||||
if($bidItem->auctionID !== $this->info->id){
|
||||
if ($bidItem->auctionID !== $this->info->id) {
|
||||
throw new \RuntimeException('잘못된 경매입니다.');
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
if($bidItem->generalID === $this->general->generalID) {
|
||||
if ($bidItem->generalID === $this->general->generalID) {
|
||||
$oldBidder = $this->general;
|
||||
} else {
|
||||
$oldBidder = General::createGeneralObjFromDB($bidItem->general_id);
|
||||
$oldBidder = General::createGeneralObjFromDB($bidItem->generalID);
|
||||
}
|
||||
|
||||
if($this->info->reqResource === ResourceType::inheritancePoint){
|
||||
if ($this->info->reqResource === ResourceType::inheritancePoint) {
|
||||
$oldBidder->increaseInheritancePoint(InheritanceKey::previous, $bidItem->amount);
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
$oldBidder->increaseVar($this->info->reqResource->value, $bidItem->amount);
|
||||
}
|
||||
|
||||
@@ -161,22 +189,21 @@ class Auction
|
||||
$this->info->finished = true;
|
||||
|
||||
$openedAuction = $this->general->getAuxVar('openedAuction') ?? [];
|
||||
if (key_exists($this->info->reqResource->value, $openedAuction)) {
|
||||
unset($openedAuction[$this->info->reqResource->value]);
|
||||
if (key_exists($this->info->type->value, $openedAuction)) {
|
||||
unset($openedAuction[$this->info->type->value]);
|
||||
$this->general->setAuxVar('openedAuction', $openedAuction);
|
||||
}
|
||||
if ($isRollback) {
|
||||
$highestBid = $this->getHighestBid();
|
||||
if($highestBid !== null){
|
||||
if ($highestBid !== null) {
|
||||
$this->refundBid($highestBid, "{$this->info->title} 경매가 취소되었습니다.");
|
||||
}
|
||||
|
||||
}
|
||||
$auctionID = $this->info->id;
|
||||
$auctionStor->setValue("id_{$auctionID}", $this->info->toArray());
|
||||
}
|
||||
|
||||
private function bidInheritPoint(int $amount, \DateTimeImmutable $now): void
|
||||
private function bidInheritPoint(int $amount, \DateTimeImmutable $now, bool $tryExtendCloseDate): ?string
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
@@ -185,7 +212,7 @@ class Auction
|
||||
|
||||
$highestBid = $this->getHighestBid();
|
||||
if ($highestBid !== null && $amount <= $highestBid->amount) {
|
||||
throw new \RuntimeException('현재입찰가보다 높게 입찰해야 합니다.');
|
||||
return '현재입찰가보다 높게 입찰해야 합니다.';
|
||||
}
|
||||
|
||||
$rawMyPrevBid = $db->queryFirstRow(
|
||||
@@ -202,7 +229,7 @@ class Auction
|
||||
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
||||
$currPoint = $general->getInheritancePoint(InheritanceKey::previous);
|
||||
if ($currPoint === null || $currPoint < $morePoint) {
|
||||
throw new \RuntimeException('유산포인트가 부족합니다.');
|
||||
return '유산포인트가 부족합니다.';
|
||||
}
|
||||
|
||||
//여기서부터 입찰 성공
|
||||
@@ -217,9 +244,26 @@ class Auction
|
||||
new AuctionBidItemData(
|
||||
$general->getVar('owner_name'),
|
||||
$general->getName(),
|
||||
$tryExtendCloseDate,
|
||||
)
|
||||
);
|
||||
$db->insert('ng_auction', $newBid->toArray());
|
||||
if ($db->affectedRows() == 0) {
|
||||
return '입찰에 실패했습니다: DB 오류';
|
||||
}
|
||||
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$turnTerm = $gameStor->getValue('turnterm');
|
||||
|
||||
if ($this->info->availableLatestBidCloseDate !== null) {
|
||||
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||
));
|
||||
|
||||
if ($extendedCloseDate > $this->info->closeDate && $this->info->closeDate < $this->info->availableLatestBidCloseDate) {
|
||||
$this->extendCloseDate(min($extendedCloseDate, $this->info->availableLatestBidCloseDate));
|
||||
}
|
||||
}
|
||||
|
||||
$general->increaseInheritancePoint(InheritanceKey::previous, -$morePoint);
|
||||
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $morePoint);
|
||||
@@ -228,33 +272,33 @@ class Auction
|
||||
$this->refundBid($highestBid, "{$auctionInfo->title} 경매에 상회입찰자가 나타났습니다.");
|
||||
}
|
||||
$general->applyDB($db);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function bid(int $amount): void
|
||||
public function bid(int $amount, bool $tryExtendCloseDate = false): ?string
|
||||
{
|
||||
$auctionInfo = $this->info;
|
||||
$general = $this->general;
|
||||
|
||||
if ($auctionInfo->finished) {
|
||||
throw new \RuntimeException('경매가 이미 끝났습니다.');
|
||||
return '경매가 이미 끝났습니다.';
|
||||
}
|
||||
|
||||
$now = new \DateTimeImmutable();
|
||||
|
||||
if ($auctionInfo->closeDate < $now) {
|
||||
throw new \RuntimeException('경매가 이미 끝났습니다.');
|
||||
return '경매가 이미 끝났습니다.';
|
||||
}
|
||||
if ($auctionInfo->closeDate > $now) {
|
||||
throw new \RuntimeException('경매가 아직 시작되지 않았습니다.');
|
||||
if ($auctionInfo->openDate > $now) {
|
||||
return '경매가 아직 시작되지 않았습니다.';
|
||||
}
|
||||
|
||||
if ($auctionInfo->buyImmediatelyAmount !== null && $auctionInfo->buyImmediatelyAmount < $amount) {
|
||||
throw new \RuntimeException('즉시판매가보다 높을 수 없습니다.');
|
||||
return '즉시판매가보다 높을 수 없습니다.';
|
||||
}
|
||||
|
||||
if ($auctionInfo->reqResource === ResourceType::inheritancePoint) {
|
||||
$this->bidInheritPoint($amount, $now);
|
||||
return;
|
||||
return $this->bidInheritPoint($amount, $now, $tryExtendCloseDate);
|
||||
}
|
||||
|
||||
//reqResource는 말 그대로 '구매자가 내야하는 자원'이다.
|
||||
@@ -263,7 +307,7 @@ class Auction
|
||||
|
||||
$highestBid = $this->getHighestBid();
|
||||
if ($highestBid !== null && $amount <= $highestBid->amount) {
|
||||
throw new \RuntimeException('현재입찰가보다 높게 입찰해야 합니다.');
|
||||
return '현재입찰가보다 높게 입찰해야 합니다.';
|
||||
}
|
||||
|
||||
$myPrevBid = $this->getMyPrevBid();
|
||||
@@ -276,7 +320,7 @@ class Auction
|
||||
};
|
||||
|
||||
if ($general->getVar($resType->value) < $morePoint + $minReqRes) {
|
||||
throw new \RuntimeException($resType->getName() . '이 부족합니다.');
|
||||
return $resType->getName() . '이 부족합니다.';
|
||||
}
|
||||
|
||||
//여기서부터 입찰 성공
|
||||
@@ -291,9 +335,16 @@ class Auction
|
||||
new AuctionBidItemData(
|
||||
$general->getVar('owner_name'),
|
||||
$general->getName(),
|
||||
$tryExtendCloseDate,
|
||||
)
|
||||
);
|
||||
|
||||
$db->insert('ng_auction', $newBid->toArray());
|
||||
if ($db->affectedRows() == 0) {
|
||||
return '입찰에 실패했습니다: DB 오류';
|
||||
}
|
||||
|
||||
|
||||
|
||||
$general->setVar($resType->value, $general->getVar($resType->value) - $morePoint);
|
||||
|
||||
@@ -301,5 +352,6 @@ class Auction
|
||||
$this->refundBid($highestBid, "{$auctionInfo->title} 경매에 상회입찰자가 나타났습니다.");
|
||||
}
|
||||
$general->applyDB($db);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user