초기커밋
This commit is contained in:
337
GameServer/Contents/Shop/Helper/ShopHelper.cs
Normal file
337
GameServer/Contents/Shop/Helper/ShopHelper.cs
Normal file
@@ -0,0 +1,337 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class ShopPurchaseInfo
|
||||
{
|
||||
public int m_shop_id { get; set; }
|
||||
public int m_shop_product_id { get; set; }
|
||||
public int m_shop_product_count { get; set; }
|
||||
public SpentInfo? m_spent { get; set; }
|
||||
public PurchaseInfo? m_purchase { get; set; }
|
||||
}
|
||||
|
||||
public class SpentInfo
|
||||
{
|
||||
public ShopBuyType m_buy_type { get; set; }
|
||||
public CurrencyType m_currency_type { get; set; }
|
||||
public int m_item_id { get; set; }
|
||||
public double m_spent { get; set; }
|
||||
}
|
||||
|
||||
public class PurchaseInfo
|
||||
{
|
||||
public ShopBuyType m_purchase_type { get; set; }
|
||||
|
||||
public List<GameServer.Item>? m_purchase_items { get; set; }
|
||||
|
||||
public List<GameServer.Item>? m_spend_items { get; set; }
|
||||
public CurrencyType m_purchase_currency_type { get; set; } = CurrencyType.None;
|
||||
public double m_purchase_currency { get; set; }
|
||||
}
|
||||
|
||||
public static class ShopHelper
|
||||
{
|
||||
public static (Result result, MetaAssets.ShopMetaData? shop_data) checkShopIdFromTableData(int shop_id)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (MetaData.Instance._ShopMetaTable.TryGetValue(shop_id, out var shop_products) == false)
|
||||
{
|
||||
result.setFail(ServerErrorCode.NotFoundShopId, $"Not Found ShopDataTable Shop Id : {shop_id}");
|
||||
}
|
||||
|
||||
return (result, shop_products);
|
||||
}
|
||||
|
||||
public static IEnumerable<ShopMetaData> getShopMetaData() => MetaData.Instance._ShopMetaTable.Select(data => data.Value).ToList();
|
||||
|
||||
public static (Result result, MetaAssets.ShopProductMetaData? product_data) checkProductIdFromTableData(int product_id)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (MetaData.Instance._ShopProductMetaTable.TryGetValue(product_id, out var product_data) == false)
|
||||
{
|
||||
result.setFail(ServerErrorCode.NotFoundProductId, $"Not Found ProductDataTable Product Id : {product_id}");
|
||||
}
|
||||
|
||||
return (result, product_data);
|
||||
}
|
||||
|
||||
public static (Result result, MetaAssets.ItemMetaData? item_data) checkItemIdFromTableData(int item_id)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (MetaData.Instance._ItemTable.TryGetValue(item_id, out var item_data) == false)
|
||||
{
|
||||
result.setFail(ServerErrorCode.NotFoundItemTableId, $"Not Found ItemDataTable Item Id : {item_id}");
|
||||
}
|
||||
|
||||
return (result, item_data);
|
||||
}
|
||||
|
||||
public static (Result result, MetaAssets.CurrencyMetaData? currency_data) checkCurrencyDataFromProductIdInTableData(int product_id)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (MetaData.Instance.Meta.CurrencyMetaTable.CurrencyMetaDataListbyId.TryGetValue(product_id, out var currency_data) == false)
|
||||
{
|
||||
result.setFail(ServerErrorCode.NotFoundItemTableId, $"Not Found CurrencyData Product Id : {product_id}");
|
||||
}
|
||||
|
||||
return (result, currency_data);
|
||||
}
|
||||
|
||||
public static (Result result, CurrencyType currencyType) checkCurrencyTypeFromCurrencyId(int currencyId)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
(result, var currency_type) = checkCurrencyDataFromProductIdInTableData(currencyId);
|
||||
if (result.isFail()) return (result, CurrencyType.None);
|
||||
|
||||
NullReferenceCheckHelper.throwIfNull(currency_type, () => $"currency_type is null !!!");
|
||||
|
||||
return (result, currency_type.CurrencyType);
|
||||
}
|
||||
|
||||
public static (Result result, MetaAssets.BasicStyleMetaData? basic_style_data) checkBasicStyleDataFromTableData(UInt32 basic_style_id)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (MetaData.Instance._BasicStyleMetaTable.TryGetValue((int)basic_style_id, out var basic_style_data) == false)
|
||||
{
|
||||
result.setFail(ServerErrorCode.NotFoundTable, $"Not Found BasicStyleDataTable basic style id : {basic_style_id}");
|
||||
}
|
||||
|
||||
return (result, basic_style_data);
|
||||
}
|
||||
|
||||
public static bool createNewShopProductTradingMetersAttribute(ShopProductTradingMeterAttribute attribute, int shop_id, USER_GUID owner_guid)
|
||||
{
|
||||
var check = checkShopIdFromTableData(shop_id);
|
||||
if (check.result.isFail()) return false;
|
||||
|
||||
attribute.ShopId = shop_id;
|
||||
|
||||
// 1. 신규 생성 여부 체크
|
||||
var is_create = attribute.ShopProductTradingMeterSubs.Count <= 0;
|
||||
|
||||
// 2. sub data 초기화
|
||||
attribute.ShopProductTradingMeterSubs.Clear();
|
||||
|
||||
// 3. 판매 종료시간 갱신
|
||||
attribute.EndTime = calculateSaleEndTime(check.shop_data!.ResetTime);
|
||||
|
||||
var product_max_count = check.shop_data.ShopProduct_List;
|
||||
|
||||
// 4. 판매 물품 갱신
|
||||
product_max_count = addNecessaryProductByGroupIdTable(check.shop_data.ShopProduct_Group_Id, product_max_count, attribute);
|
||||
addRandomProductByGroupIdTable(check.shop_data.ShopProduct_Group_Id, product_max_count, attribute);
|
||||
|
||||
// 5. renewalCount 초기화
|
||||
attribute.initRenewalCount();
|
||||
|
||||
if (is_create)
|
||||
{
|
||||
attribute.newEntityAttribute();
|
||||
}
|
||||
else
|
||||
{
|
||||
attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int addNecessaryProductByGroupIdTable(int group_id, int max_count, ShopProductTradingMeterAttribute attribute)
|
||||
{
|
||||
if (MetaData.Instance._ShopNecessaryProductByGroupIdTable.TryGetValue(group_id, out var shopNecessaryProductList) != true) return max_count;
|
||||
|
||||
foreach (var productInfo in shopNecessaryProductList)
|
||||
{
|
||||
if (max_count <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var sub_attribute = new ShopProductTradingMeterSubAttribute
|
||||
{
|
||||
ProductId = productInfo.ID,
|
||||
LeftCount = productInfo.ProductType_BuyCount
|
||||
};
|
||||
|
||||
|
||||
attribute.ShopProductTradingMeterSubs.Add(sub_attribute);
|
||||
|
||||
max_count -= 1;
|
||||
}
|
||||
|
||||
return max_count;
|
||||
}
|
||||
|
||||
private static void addRandomProductByGroupIdTable(int group_id, int max_count, ShopProductTradingMeterAttribute attribute)
|
||||
{
|
||||
if (MetaData.Instance._ShopRandomProductByGroupIdTable.TryGetValue(group_id, out var shop_random_group) != true) return;
|
||||
|
||||
var total_weight = shop_random_group.TotalWeight;
|
||||
List<ShopProductTradingMeterSubAttribute> added_products = new();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (max_count <= 0 || total_weight <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// randomProduct 에서 선택되지 않을 수 있음 ( 선택이 되지 않아도 상점 리스트는 차감됨 )
|
||||
var spent_weight = selectRandomProduct(added_products, shop_random_group, total_weight);
|
||||
|
||||
total_weight -= spent_weight;
|
||||
max_count -= 1;
|
||||
}
|
||||
|
||||
attribute.ShopProductTradingMeterSubs.AddRange(added_products);
|
||||
}
|
||||
|
||||
private static int selectRandomProduct(List<ShopProductTradingMeterSubAttribute> added_list, ShopProductRandomGroupInfo shop_random_group, int total_weight)
|
||||
{
|
||||
var weight = 0;
|
||||
var random_weight = RandomHelper.next(0, total_weight);
|
||||
var spend_weight = 0;
|
||||
|
||||
foreach (var productInfo in shop_random_group.RandomGroupList)
|
||||
{
|
||||
// 이미 추가되어 있으면 패스
|
||||
var breakCheck = added_list.Any(randomProduct => randomProduct.ProductId == productInfo.ID);
|
||||
if (breakCheck) continue;
|
||||
|
||||
weight += productInfo.Weight;
|
||||
|
||||
// productInfo.Weight 가 0 인 경우 선택 자체가 되지 않음 ( random_weight >= 0 )
|
||||
if (weight <= random_weight) continue;
|
||||
|
||||
var sub_attribute = new ShopProductTradingMeterSubAttribute
|
||||
{
|
||||
ProductId = productInfo.ID,
|
||||
LeftCount = productInfo.ProductType_BuyCount
|
||||
};
|
||||
added_list.Add(sub_attribute);
|
||||
|
||||
spend_weight = productInfo.Weight;
|
||||
break;
|
||||
}
|
||||
|
||||
return spend_weight;
|
||||
}
|
||||
|
||||
public static Timestamp calculateSaleEndTime(int resetTime)
|
||||
{
|
||||
var interval_count = (DateTime.UtcNow.Ticks - ServerCommon.Constant.SHOP_DEFINE_TIME.Ticks) / (resetTime * TimeSpan.TicksPerMinute);
|
||||
return ServerCommon.Constant.SHOP_DEFINE_TIME.AddMinutes((interval_count + 1) * resetTime).ToTimestamp();
|
||||
}
|
||||
|
||||
public static async Task<(Result result, SpentInfo? spent_info)> checkRequiredPurchaseFromProductMeta(ShopProductMetaData productData, int purchaseCount, int discountRate)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var spent_info = new SpentInfo();
|
||||
spent_info.m_buy_type = productData.Buy_Price_Type;
|
||||
|
||||
switch (productData.Buy_Price_Type)
|
||||
{
|
||||
case ShopBuyType.Currency:
|
||||
var currency_data = ShopHelper.checkCurrencyDataFromProductIdInTableData(productData.Buy_Id);
|
||||
if (currency_data.result.isFail()) return (currency_data.result, null);
|
||||
|
||||
NullReferenceCheckHelper.throwIfNull(currency_data.currency_data, () => $"currency_data.currency_data is null !!!");
|
||||
|
||||
spent_info.m_currency_type = currency_data.currency_data.CurrencyType;
|
||||
|
||||
var price = await checkCaliumCurrency(spent_info.m_currency_type, productData.Buy_Price, discountRate);
|
||||
spent_info.m_spent = purchaseCount * price;
|
||||
break;
|
||||
case ShopBuyType.Item:
|
||||
spent_info.m_item_id = productData.Buy_Id;
|
||||
spent_info.m_spent = purchaseCount * productData.Buy_Price;
|
||||
break;
|
||||
case ShopBuyType.None:
|
||||
default:
|
||||
var err_msg = $"fail to get shop product meta data !!! : invalid shop buy type {productData.Buy_Price_Type}";
|
||||
result.setFail(ServerErrorCode.InvalidShopBuyType, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, spent_info);
|
||||
}
|
||||
|
||||
public static bool checkRenewallableTime(ShopProductTradingMeterAttribute attribute)
|
||||
{
|
||||
bool is_renewallable_time = false;
|
||||
var now = DateTimeHelper.Current;
|
||||
var end_time = attribute.EndTime.ToDateTime();
|
||||
|
||||
var timeDifference = Math.Abs((now - end_time).TotalSeconds);
|
||||
|
||||
// 차이가 ShopRenewalBlockTime초 이상이면 true, 그렇지 않으면 false
|
||||
if (timeDifference >= MetaHelper.GameConfigMeta.ShopRenewalBlockTime)
|
||||
{
|
||||
is_renewallable_time = true;
|
||||
}
|
||||
|
||||
return is_renewallable_time;
|
||||
}
|
||||
|
||||
public static bool renewalNewShopProductTradingMetersAttribute(USER_GUID owner_guid, ShopProductTradingMeterAttribute attribute, ShopMetaData shopData)
|
||||
{
|
||||
attribute.ShopId = shopData.Id;
|
||||
|
||||
// 1. 신규 생성 여부 체크
|
||||
//var is_create = attribute.ShopProductTradingMeterSubs.Count <= 0;
|
||||
|
||||
// 2. sub data 초기화
|
||||
attribute.ShopProductTradingMeterSubs.Clear();
|
||||
|
||||
var product_max_count = shopData.ShopProduct_List;
|
||||
|
||||
// 3. 판매 물품 갱신
|
||||
product_max_count = addNecessaryProductByGroupIdTable(shopData.ShopProduct_Group_Id, product_max_count, attribute);
|
||||
addRandomProductByGroupIdTable(shopData.ShopProduct_Group_Id, product_max_count, attribute);
|
||||
|
||||
// 4. renewal count 중가
|
||||
attribute.increaseRenewalCount();
|
||||
|
||||
// 리뉴얼은 무조건 상점이 존재해야 하므로 modified만 체크
|
||||
attribute.modifiedEntityAttribute();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<double> checkCaliumCurrency(CurrencyType currencyType, double price, int discountRate)
|
||||
{
|
||||
var calculate_price = price;
|
||||
|
||||
if (currencyType == CurrencyType.Calium)
|
||||
{
|
||||
calculate_price = await CaliumStorageHelper.calculateCaliumFromSapphire(price, true);
|
||||
}
|
||||
|
||||
return (calculate_price * 100 - calculate_price * discountRate) / 100;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user