354 lines
17 KiB
C#
354 lines
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Collections.Concurrent;
|
|
|
|
|
|
|
|
using Amazon.S3.Model;
|
|
using Amazon.DynamoDBv2.Model;
|
|
using Amazon.DynamoDBv2;
|
|
using Renci.SshNet.Security;
|
|
|
|
|
|
|
|
using ServerCore; using ServerBase;
|
|
using ServerCommon;
|
|
|
|
|
|
|
|
using META_ID = System.UInt32;
|
|
using USER_GUID = System.String;
|
|
using LAND_AUCTION_NUMBER = System.Int32;
|
|
|
|
|
|
|
|
|
|
namespace GameServer
|
|
{
|
|
|
|
|
|
public class UserLandAuctionAction : EntityActionBase
|
|
{
|
|
private readonly ConcurrentDictionary<string, LandAuctionRefundBidPrice> m_refund_bid_prices = new();
|
|
|
|
public UserLandAuctionAction(Player owner)
|
|
: base(owner)
|
|
{
|
|
}
|
|
|
|
public override void onClear()
|
|
{
|
|
return;
|
|
}
|
|
|
|
public override async Task<Result> onInit()
|
|
{
|
|
await Task.CompletedTask;
|
|
|
|
var result = new Result();
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<Result> tryLoadLandAuctionBidPriceAllFromDb()
|
|
{
|
|
var owner = getOwner() as Player;
|
|
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null");
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var db_connector = server_logic.getDynamoDbClient();
|
|
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
(result, var read_docs) = await LandAuctionDbHelper.readLandAuctionRefundBidPriceDocsFromDb(owner);
|
|
if(result.isFail())
|
|
{
|
|
err_msg = $"Failed to readLandAuctionRefundBidPriceDocsFromDb() !!! : {result.toBasicString()} - {owner.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
|
|
return result;
|
|
}
|
|
NullReferenceCheckHelper.throwIfNull(read_docs, () => $"read_docs is null !!! - {owner.toBasicString()}");
|
|
|
|
foreach (var read_doc in read_docs)
|
|
{
|
|
var refund_bid_price = new LandAuctionRefundBidPrice(owner);
|
|
var init_result = await refund_bid_price.onInit();
|
|
if (init_result.isFail())
|
|
{
|
|
Log.getLogger().error(init_result.toBasicString());
|
|
continue;
|
|
}
|
|
|
|
var primary_key = read_doc.getPrimaryKey();
|
|
if (false == m_refund_bid_prices.TryAdd(primary_key.SK, refund_bid_price))
|
|
{
|
|
err_msg = $"Failed to TryAdd() !!!, duplicated SK !!! : {primary_key.toBasicString()} - {owner.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
continue;
|
|
}
|
|
|
|
var refund_bid_price_action = refund_bid_price.getEntityAction<LandAuctionRefundBidPriceAction>();
|
|
NullReferenceCheckHelper.throwIfNull(refund_bid_price_action, () => $"refund_bid_price_action is null !!!");
|
|
|
|
var load_result = refund_bid_price_action.tryLoadRefundBidPriceFromDoc(read_doc);
|
|
if (load_result.isFail())
|
|
{
|
|
Log.getLogger().error(load_result.toBasicString());
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task updateRefundBidPriceAll()
|
|
{
|
|
var player = getOwner() as Player;
|
|
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null");
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var db_connector = server_logic.getDynamoDbClient();
|
|
var redis_connector = server_logic.getRedisDb();
|
|
|
|
var fn_land_auction_bid_price_refund = async delegate ()
|
|
{
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var to_delete_refund_bid_prices = new List<LandAuctionRefundBidPrice>();
|
|
var to_send_new_mail_docs = new List<DynamoDbDocBase>();
|
|
|
|
var refund_bid_prices = m_refund_bid_prices.Values.ToList();
|
|
|
|
foreach (var refund_bid_price in refund_bid_prices)
|
|
{
|
|
var refund_bid_price_action = refund_bid_price.getEntityAction<LandAuctionRefundBidPriceAction>();
|
|
NullReferenceCheckHelper.throwIfNull(refund_bid_price_action, () => $"refund_bid_price_action is null !!! - {player.toBasicString()}");
|
|
|
|
var update_result = await refund_bid_price_action.tryUpdateRefundBidPrice();
|
|
if (update_result.isFail())
|
|
{
|
|
err_msg = $"Failed to tryUpdateRefundBidPrice() !!! : {update_result.toBasicString()} - {player.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
continue;
|
|
}
|
|
|
|
if(true == refund_bid_price_action.isDeletable())
|
|
{
|
|
var key = LandAuctionRefundBidPriceDoc.makeCombinationKeyForSK(refund_bid_price_action.getLandMetaId(), refund_bid_price_action.getAuctionNumber());
|
|
m_refund_bid_prices.Remove(key, out _);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
var result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "RefundBidPrice", fn_land_auction_bid_price_refund);
|
|
if (result.isFail())
|
|
{
|
|
var err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
}
|
|
}
|
|
|
|
public async Task<(Result, LandAuctionBidResult?)> tryBidLandAuction( LandAuctionBidType reqBidType
|
|
, CurrencyType currencyType, double bidPrice
|
|
, LandAuctionCheckResult checkResult )
|
|
{
|
|
var owner = getOwner() as Player;
|
|
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null");
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var db_connector = server_logic.getDynamoDbClient();
|
|
var redis_connector = server_logic.getRedisDb();
|
|
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var land_meta_id = (META_ID)checkResult.LandAuctionInfo.LandMetaId;
|
|
var auction_number = checkResult.LandAuctionInfo.AuctionNumber;
|
|
|
|
var found_land_auction = LandAuctionManager.It.findActivitingLandAuction(land_meta_id);
|
|
if( null == found_land_auction )
|
|
{
|
|
err_msg = $"Not found activiting LandAuction !!! : landMetaId:{land_meta_id} - {owner.toBasicString()}";
|
|
result.setFail(ServerErrorCode.LandAuctionNotFound, err_msg);
|
|
Log.getLogger().error(err_msg);
|
|
return (result, null);
|
|
}
|
|
var land_auction_action = found_land_auction.getEntityAction<LandAuctionAction>();
|
|
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {owner.toBasicString()}");
|
|
|
|
// 1. 입찰 가능 여부를 체크 한다.
|
|
result = land_auction_action.isBidableLandAuction(checkResult, currencyType, bidPrice);
|
|
if (result.isFail()) { return (result, null); }
|
|
|
|
// 2. 금전 소모 가능 여부를 체크 한다.
|
|
var money_action = owner.getEntityAction<MoneyAction>();
|
|
NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!! - {owner.toBasicString()}");
|
|
result = await money_action.spendMoney(currencyType, bidPrice, useCaliumEvent:false);
|
|
if(result.isFail()) { return (result, null); }
|
|
|
|
// 3. LandAuctionBidPriceDoc를 존재하는 지 체크하고, 없으면 생성 한다 !!!
|
|
var bid_price_doc = new LandAuctionRefundBidPriceDoc(owner.getUserGuid(), land_meta_id, auction_number);
|
|
result = await bid_price_doc.newDoc4Query();
|
|
if (result.isFail()) { return (result, null); }
|
|
result = await db_connector.createIfNotExist<LandAuctionRefundBidPriceDoc>(bid_price_doc
|
|
, (bid_price_doc) =>
|
|
{
|
|
var bid_price_attrib = bid_price_doc.getAttrib<LandAuctionRefundBidPriceAttrib>();
|
|
NullReferenceCheckHelper.throwIfNull(bid_price_attrib, () => $"bid_price_attrib is null !!! - {owner.toBasicString()}");
|
|
bid_price_attrib.LandMetaId = land_meta_id;
|
|
bid_price_attrib.AuctionNumber = auction_number;
|
|
bid_price_attrib.BidUserGuid = owner.getUserGuid();
|
|
bid_price_attrib.BidCurrencyType = currencyType;
|
|
}
|
|
);
|
|
if (result.isFail()) { return (result, null); }
|
|
|
|
// 4. 입찰을 시도 한다.
|
|
( result, var bid_result ) = await land_auction_action.tryBidLandAuction( checkResult
|
|
, owner
|
|
, reqBidType
|
|
, currencyType, bidPrice );
|
|
if(result.isFail()) { return (result, null); }
|
|
NullReferenceCheckHelper.throwIfNull(bid_result, () => $"bid_result is null !!! - {owner.toBasicString()}");
|
|
|
|
return (result, bid_result);
|
|
}
|
|
|
|
public async Task completedRefundBidPrice(LandAuctionBidResult bidResult, QueryExecutorBase queryExecutorBase)
|
|
{
|
|
await Task.CompletedTask;
|
|
|
|
var owner = getOwner() as Player;
|
|
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null");
|
|
|
|
var land_auction = bidResult.TargetLandAuction;
|
|
NullReferenceCheckHelper.throwIfNull(land_auction, () => $"land_auction is null - {owner.toBasicString()}");
|
|
var curr_top_bidder = bidResult.CurrTopBidder;
|
|
NullReferenceCheckHelper.throwIfNull(curr_top_bidder, () => $"curr_top_bidder is null - {owner.toBasicString()}");
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var db_connector = server_logic.getDynamoDbClient();
|
|
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var registry_attribute = land_auction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"registry_attribute is null - {owner.toBasicString()}");
|
|
|
|
var land_meta_id = registry_attribute.LandMetaId;
|
|
var auction_number = registry_attribute.AuctionNumber;
|
|
|
|
// 입찰자의 입찰 환급 처리 LandAuctionRefundBidPrice 객체를 생성 및 등록 한다.
|
|
{
|
|
(result, var refund_bid_price_doc) = await LandAuctionDbHelper.readLandAuctionRefundBidPriceDocFromDb(owner, land_meta_id, auction_number);
|
|
if (result.isFail())
|
|
{
|
|
err_msg = $"Failed to readLandAuctionRefundBidPriceDocFromDb() !!! : {result.toBasicString()}, {land_auction.toBasicString()} - {owner.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
}
|
|
else
|
|
{
|
|
NullReferenceCheckHelper.throwIfNull(refund_bid_price_doc, () => $"refund_bid_price_doc is null - {owner.toBasicString()}");
|
|
var refund_bid_price_attrib = refund_bid_price_doc.getAttrib<LandAuctionRefundBidPriceAttrib>();
|
|
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attrib, () => $"refund_bid_price_attrib is null - {owner.toBasicString()}");
|
|
|
|
var key = LandAuctionRefundBidPriceDoc.makeCombinationKeyForSK(land_meta_id, auction_number);
|
|
if (false == m_refund_bid_prices.TryGetValue(key, out var found_bid_price))
|
|
{
|
|
found_bid_price = new LandAuctionRefundBidPrice(owner);
|
|
result = await found_bid_price.onInit();
|
|
if (result.isFail())
|
|
{
|
|
err_msg = $"Failed to onInit() !!! : {result.toBasicString()}, {land_auction.toBasicString()} - {owner.toBasicString()}";
|
|
Log.getLogger().fatal(err_msg);
|
|
}
|
|
else
|
|
{
|
|
m_refund_bid_prices[key] = found_bid_price;
|
|
}
|
|
}
|
|
|
|
var refund_bid_price_attribute = found_bid_price.getEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attribute, () => $"refund_bid_price_attribute is null - {owner.toBasicString()}");
|
|
|
|
result = found_bid_price.copyDocToEntityAttributeForRefundBidPrice(refund_bid_price_attribute, refund_bid_price_doc);
|
|
if (result.isFail())
|
|
{
|
|
err_msg = $"Failed to copyDocToEntityAttributeForRefundBidPrice() !!! : {result.toBasicString()}, docType:{refund_bid_price_doc.getTypeName()}, {result.toBasicString()}, {land_auction.toBasicString()} - {owner.toBasicString()}";
|
|
Log.getLogger().fatal(err_msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 최고 입찰자와 차순위 입찰자의 비즈니스 로그를 작성 한다. !!!
|
|
var bidder_caches = new List<LandAuctionTopBidderCache>();
|
|
bidder_caches.Add(curr_top_bidder);
|
|
if (null != bidResult.OldTopBidder) { bidder_caches.Add(bidResult.OldTopBidder); }
|
|
|
|
foreach (var bidder_cache in bidder_caches)
|
|
{
|
|
var target_user_guid = bidder_cache.HighestBidUserGuid;
|
|
|
|
(result, var refund_bid_price_doc) = await LandAuctionDbHelper.readLandAuctionRefundBidPriceDocFromDb(target_user_guid, land_meta_id, auction_number);
|
|
if (result.isFail())
|
|
{
|
|
err_msg = $"Failed to readLandAuctionRefundBidPriceDocFromDb() !!! : {result.toBasicString()}, landMetaId:{land_meta_id}, auctionNumber:{auction_number}, bidUserGuid:{target_user_guid} - {owner.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
continue;
|
|
}
|
|
if (null == refund_bid_price_doc)
|
|
{
|
|
err_msg = $"Not found LandAuctionRefundBidPriceDoc !!! : landMetaId:{land_meta_id}, auctionNumber:{auction_number} - {owner.toBasicString()}";
|
|
Log.getLogger().warn(err_msg);
|
|
continue;
|
|
}
|
|
|
|
LandAuctionBusinessLogHelper.writeBusinessLogByLandAuctionBidPriceRefund(refund_bid_price_doc, registry_attribute.LandAuctionResult, queryExecutorBase);
|
|
}
|
|
}
|
|
|
|
public async Task<(Result, LandAuctionRefundBidPriceDoc?)> findRefundBidPriceDoc(META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber)
|
|
{
|
|
var owner = getOwner() as Player;
|
|
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var db_client = server_logic.getDynamoDbClient();
|
|
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionRefundBidPriceDoc>( owner.getUserGuid()
|
|
, LandAuctionRefundBidPriceDoc.makeCombinationKeyForSK(landMetaId, auctionNumber) );
|
|
if (result.isFail())
|
|
{
|
|
err_msg = $"Failed to makePrimaryKey<LandAuctionRefundBidPriceDoc>() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
|
Log.getLogger().error(err_msg);
|
|
|
|
return (result, null);
|
|
}
|
|
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
|
|
|
var query_config = db_client.makeQueryConfigForReadByPKSK(make_primary_key.PK, make_primary_key.SK);
|
|
(result, var found_refund_bid_price_doc) = await db_client.simpleQueryDocTypeWithQueryOperationConfig<LandAuctionRefundBidPriceDoc>(query_config, false);
|
|
if (result.isFail())
|
|
{
|
|
err_msg = $"Failed to parse simpleQueryDocTypeWithQueryOperationConfig<LandAuctionRefundBidPriceDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()} - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}";
|
|
Log.getLogger().error(err_msg);
|
|
|
|
return (result, null);
|
|
}
|
|
|
|
return (result, found_refund_bid_price_doc);
|
|
}
|
|
}
|
|
}
|