feat(wip): 경매 세부 기능 구현
This commit is contained in:
+105
-40
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use DateTimeInterface;
|
||||||
use Ds\Map;
|
use Ds\Map;
|
||||||
use sammo\DTO\AuctionBidItem;
|
use sammo\DTO\AuctionBidItem;
|
||||||
use sammo\DTO\AuctionBidItemData;
|
use sammo\DTO\AuctionBidItemData;
|
||||||
@@ -45,11 +48,41 @@ class Auction
|
|||||||
if (!$prevAuction->info->finished) {
|
if (!$prevAuction->info->finished) {
|
||||||
return '아직 경매가 끝나지 않았습니다.';
|
return '아직 경매가 끝나지 않았습니다.';
|
||||||
}
|
}
|
||||||
|
unset($openedAuction[$info->reqResource->value]);
|
||||||
|
$general->setAuxVar('openedAuction', $openedAuction);
|
||||||
}
|
}
|
||||||
|
|
||||||
$auctionStor->setValue("id_{$auctionID}", $info->toArray());
|
$auctionStor->setValue("id_{$auctionID}", $info->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getHighestBid(): AuctionBidItem
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
$rawHighestBid = $db->queryFirstRow(
|
||||||
|
'SELECT * FROM ng_auction WHERE auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
||||||
|
$this->info->id
|
||||||
|
);
|
||||||
|
if(!$rawHighestBid){
|
||||||
|
throw new \Exception('입찰이 없습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuctionBidItem::fromArray($rawHighestBid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMyPrevBid(): ?AuctionBidItem
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
$rawMyPrevBid = $db->queryFirstRow(
|
||||||
|
'SELECT * FROM ng_auction WHERE general_id = %i AND auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
||||||
|
$this->general->getID(),
|
||||||
|
$this->info->id
|
||||||
|
);
|
||||||
|
if (!$rawMyPrevBid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return AuctionBidItem::fromArray($rawMyPrevBid);
|
||||||
|
}
|
||||||
|
|
||||||
public function __construct(private readonly int $auctionID, private General $general)
|
public function __construct(private readonly int $auctionID, private General $general)
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
@@ -61,7 +94,66 @@ class Auction
|
|||||||
$this->info = AuctionInfo::fromArray($rawAuctionInfo);
|
$this->info = AuctionInfo::fromArray($rawAuctionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function closeAuction(): void
|
public function getInfo(): AuctionInfo
|
||||||
|
{
|
||||||
|
return $this->info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extendCloseDate(DateTimeInterface $date): void
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
$auctionStor = KVStorage::getStorage($db, 'auction');
|
||||||
|
$this->info->closeDate = DateTimeImmutable::createFromInterface($date);
|
||||||
|
$auctionStor->setValue("id_{$this->info->id}", $this->info->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refundBid(AuctionBidItem $bidItem, string $reason): void
|
||||||
|
{
|
||||||
|
if($bidItem->auctionID !== $this->info->id){
|
||||||
|
throw new \RuntimeException('잘못된 경매입니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
if($bidItem->generalID === $this->general->generalID) {
|
||||||
|
$oldBidder = $this->general;
|
||||||
|
} else {
|
||||||
|
$oldBidder = General::createGeneralObjFromDB($bidItem->general_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->info->reqResource === ResourceType::inheritancePoint){
|
||||||
|
$oldBidder->increaseInheritancePoint(InheritanceKey::previous, $bidItem->amount);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$oldBidder->increaseVar($this->info->reqResource->value, $bidItem->amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
$staticNation = $oldBidder->getStaticNation();
|
||||||
|
$src = new MessageTarget(0, '', 0, 'System', '#000000');
|
||||||
|
$dest = new MessageTarget(
|
||||||
|
$oldBidder->getID(),
|
||||||
|
$oldBidder->getName(),
|
||||||
|
$oldBidder->getNationID(),
|
||||||
|
$staticNation['name'],
|
||||||
|
$staticNation['color'],
|
||||||
|
GetImageURL($oldBidder->getVar('imgsvr'), $oldBidder->getVar('picture'))
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||||
|
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||||
|
$msg = new Message(
|
||||||
|
Message::MSGTYPE_PRIVATE,
|
||||||
|
$src,
|
||||||
|
$dest,
|
||||||
|
$reason,
|
||||||
|
new DateTime(),
|
||||||
|
new DateTime('9999-12-31'),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
$oldBidder->applyDB($db);
|
||||||
|
$msg->send(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function closeAuction(bool $isRollback = false): void
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$auctionStor = KVStorage::getStorage($db, 'auction');
|
$auctionStor = KVStorage::getStorage($db, 'auction');
|
||||||
@@ -73,25 +165,21 @@ class Auction
|
|||||||
unset($openedAuction[$this->info->reqResource->value]);
|
unset($openedAuction[$this->info->reqResource->value]);
|
||||||
$this->general->setAuxVar('openedAuction', $openedAuction);
|
$this->general->setAuxVar('openedAuction', $openedAuction);
|
||||||
}
|
}
|
||||||
|
if ($isRollback) {
|
||||||
|
$this->refundBid($this->getHighestBid(), "{$this->info->title} 경매가 취소되었습니다.");
|
||||||
|
}
|
||||||
$auctionID = $this->info->id;
|
$auctionID = $this->info->id;
|
||||||
$auctionStor->setValue("id_{$auctionID}", $this->info->toArray());
|
$auctionStor->setValue("id_{$auctionID}", $this->info->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function bidInheritPoint(int $amount, ?int $priority, string $now): void
|
private function bidInheritPoint(int $amount, \DateTimeImmutable $now): void
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
|
|
||||||
$auctionInfo = $this->info;
|
$auctionInfo = $this->info;
|
||||||
$general = $this->general;
|
$general = $this->general;
|
||||||
|
|
||||||
$rawHighestBid = $db->queryFirstRow(
|
$highestBid = $this->getHighestBid();
|
||||||
'SELECT * FROM ng_auction WHERE auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
|
||||||
$auctionInfo->id
|
|
||||||
);
|
|
||||||
if (!$rawHighestBid) {
|
|
||||||
throw new \RuntimeException('최고 입찰가가 없습니다.');
|
|
||||||
}
|
|
||||||
$highestBid = AuctionBidItem::fromArray($rawHighestBid);
|
|
||||||
if ($amount <= $highestBid->amount) {
|
if ($amount <= $highestBid->amount) {
|
||||||
throw new \RuntimeException('현재입찰가보다 높게 입찰해야 합니다.');
|
throw new \RuntimeException('현재입찰가보다 높게 입찰해야 합니다.');
|
||||||
}
|
}
|
||||||
@@ -109,7 +197,7 @@ class Auction
|
|||||||
|
|
||||||
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
||||||
$currPoint = $general->getInheritancePoint(InheritanceKey::previous);
|
$currPoint = $general->getInheritancePoint(InheritanceKey::previous);
|
||||||
if($currPoint === null || $currPoint < $morePoint){
|
if ($currPoint === null || $currPoint < $morePoint) {
|
||||||
throw new \RuntimeException('유산포인트가 부족합니다.');
|
throw new \RuntimeException('유산포인트가 부족합니다.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +213,6 @@ class Auction
|
|||||||
new AuctionBidItemData(
|
new AuctionBidItemData(
|
||||||
$general->getVar('owner_name'),
|
$general->getVar('owner_name'),
|
||||||
$general->getName(),
|
$general->getName(),
|
||||||
$priority
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$db->insert('ng_auction', $newBid->toArray());
|
$db->insert('ng_auction', $newBid->toArray());
|
||||||
@@ -134,18 +221,12 @@ class Auction
|
|||||||
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $morePoint);
|
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $morePoint);
|
||||||
|
|
||||||
if ($myPrevBid === null || $myPrevBid->id !== $highestBid->id) {
|
if ($myPrevBid === null || $myPrevBid->id !== $highestBid->id) {
|
||||||
$oldBidder = General::createGeneralObjFromDB($highestBid->general_id);
|
$this->refundBid($highestBid, "{$auctionInfo->title} 경매에 상회입찰자가 나타났습니다.");
|
||||||
$oldBidder->increaseInheritancePoint(InheritanceKey::previous, $highestBid->amount);
|
|
||||||
//TODO: 전역 알림이 나타나야한다.
|
|
||||||
$oldBidder->getLogger()->pushGeneralActionLog(
|
|
||||||
"유산포인트 {$auctionInfo->id}번 경매에 상회입찰이 되었습니다.",
|
|
||||||
);
|
|
||||||
$oldBidder->applyDB($db);
|
|
||||||
}
|
}
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bid(int $amount, ?int $priority): void
|
public function bid(int $amount): void
|
||||||
{
|
{
|
||||||
$auctionInfo = $this->info;
|
$auctionInfo = $this->info;
|
||||||
$general = $this->general;
|
$general = $this->general;
|
||||||
@@ -154,7 +235,7 @@ class Auction
|
|||||||
throw new \RuntimeException('경매가 이미 끝났습니다.');
|
throw new \RuntimeException('경매가 이미 끝났습니다.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$now = TimeUtil::now();
|
$now = new \DateTimeImmutable();
|
||||||
|
|
||||||
if ($auctionInfo->closeDate < $now) {
|
if ($auctionInfo->closeDate < $now) {
|
||||||
throw new \RuntimeException('경매가 이미 끝났습니다.');
|
throw new \RuntimeException('경매가 이미 끝났습니다.');
|
||||||
@@ -168,7 +249,7 @@ class Auction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($auctionInfo->reqResource === ResourceType::inheritancePoint) {
|
if ($auctionInfo->reqResource === ResourceType::inheritancePoint) {
|
||||||
$this->bidInheritPoint($amount, $priority, $now);
|
$this->bidInheritPoint($amount, $now);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,16 +269,7 @@ class Auction
|
|||||||
throw new \RuntimeException('현재입찰가보다 높게 입찰해야 합니다.');
|
throw new \RuntimeException('현재입찰가보다 높게 입찰해야 합니다.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$rawMyPrevBid = $db->queryFirstRow(
|
$myPrevBid = $this->getMyPrevBid();
|
||||||
'SELECT * FROM ng_auction WHERE general_id = %i AND auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
|
||||||
$general->getID(),
|
|
||||||
$auctionInfo->id
|
|
||||||
);
|
|
||||||
if ($rawMyPrevBid === null) {
|
|
||||||
$myPrevBid = null;
|
|
||||||
} else {
|
|
||||||
$myPrevBid = AuctionBidItem::fromArray($rawMyPrevBid);
|
|
||||||
}
|
|
||||||
|
|
||||||
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
||||||
$resType = $auctionInfo->reqResource;
|
$resType = $auctionInfo->reqResource;
|
||||||
@@ -222,7 +294,6 @@ class Auction
|
|||||||
new AuctionBidItemData(
|
new AuctionBidItemData(
|
||||||
$general->getVar('owner_name'),
|
$general->getVar('owner_name'),
|
||||||
$general->getName(),
|
$general->getName(),
|
||||||
$priority
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$db->insert('ng_auction', $newBid->toArray());
|
$db->insert('ng_auction', $newBid->toArray());
|
||||||
@@ -230,13 +301,7 @@ class Auction
|
|||||||
$general->setVar($resType->value, $general->getVar($resType->value) - $morePoint);
|
$general->setVar($resType->value, $general->getVar($resType->value) - $morePoint);
|
||||||
|
|
||||||
if ($myPrevBid === null || $myPrevBid->id !== $highestBid->id) {
|
if ($myPrevBid === null || $myPrevBid->id !== $highestBid->id) {
|
||||||
$oldBidder = General::createGeneralObjFromDB($highestBid->general_id);
|
$this->refundBid($highestBid, "{$auctionInfo->title} 경매에 상회입찰자가 나타났습니다.");
|
||||||
$oldBidder->increaseVar($resType->value, $highestBid->amount);
|
|
||||||
//TODO: 전역 알림이 나타나야한다.
|
|
||||||
$oldBidder->getLogger()->pushGeneralActionLog(
|
|
||||||
"{$resType->getName()} {$auctionInfo->id}번 경매에 상회입찰이 되었습니다.",
|
|
||||||
);
|
|
||||||
$oldBidder->applyDB($db);
|
|
||||||
}
|
}
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
namespace sammo\DTO;
|
namespace sammo\DTO;
|
||||||
|
|
||||||
|
use sammo\DTO\Attr\Convert;
|
||||||
use sammo\DTO\Attr\JsonString;
|
use sammo\DTO\Attr\JsonString;
|
||||||
use sammo\DTO\Attr\NullIsUndefined;
|
use sammo\DTO\Attr\NullIsUndefined;
|
||||||
use sammo\DTO\Attr\RawName;
|
use sammo\DTO\Attr\RawName;
|
||||||
|
use sammo\DTO\Converter\DateTimeConverter;
|
||||||
|
|
||||||
class AuctionBidItem extends DTO
|
class AuctionBidItem extends DTO
|
||||||
{
|
{
|
||||||
@@ -20,7 +22,8 @@ class AuctionBidItem extends DTO
|
|||||||
|
|
||||||
public int $amount,
|
public int $amount,
|
||||||
|
|
||||||
public string $date,
|
#[Convert(DateTimeConverter::class)]
|
||||||
|
public \DateTimeImmutable $date,
|
||||||
#[JsonString]
|
#[JsonString]
|
||||||
public AuctionBidItemData $data,
|
public AuctionBidItemData $data,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ class AuctionBidItemData extends DTO
|
|||||||
#[NullIsUndefined]
|
#[NullIsUndefined]
|
||||||
public ?string $ownerName,
|
public ?string $ownerName,
|
||||||
public string $generalName,
|
public string $generalName,
|
||||||
#[NullIsUndefined]
|
|
||||||
public ?int $priority,
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace sammo\DTO;
|
namespace sammo\DTO;
|
||||||
|
|
||||||
|
use sammo\DTO\Attr\Convert;
|
||||||
|
use sammo\DTO\Converter\DateTimeConverter;
|
||||||
use sammo\Enums\ResourceType;
|
use sammo\Enums\ResourceType;
|
||||||
|
|
||||||
class AuctionInfo extends DTO
|
class AuctionInfo extends DTO
|
||||||
@@ -11,12 +13,16 @@ class AuctionInfo extends DTO
|
|||||||
public int $openerName,
|
public int $openerName,
|
||||||
public int $openerGeneralID,
|
public int $openerGeneralID,
|
||||||
public string $type,
|
public string $type,
|
||||||
|
public string $title,
|
||||||
public bool $finished,
|
public bool $finished,
|
||||||
public ResourceType $reqResource,
|
public ResourceType $reqResource,
|
||||||
public int $minAmount,
|
public int $minAmount,
|
||||||
public ?int $buyImmediatelyAmount,
|
public ?int $buyImmediatelyAmount,
|
||||||
public string $openDate,
|
|
||||||
public string $closeDate,
|
#[Convert(DateTimeConverter::class)]
|
||||||
|
public \DateTimeImmutable $openDate,
|
||||||
|
#[Convert(DateTimeConverter::class)]
|
||||||
|
public \DateTimeImmutable $closeDate,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user