Files
caliverse_server/GameServer/Contents/Shop/Helper/ShopHelper.cs
2025-05-01 07:20:41 +09:00

337 lines
12 KiB
C#

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;
}
}