Files
DP-S_Script/示例项目/NPC商店限购/NPC商店限购.nut
2026-04-16 16:27:53 +08:00

290 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
g_ShopLimitCache <- {};
class _Shop_Limit_Bynangua {
function get_trade_time() {
local currentDate = date()
local year = currentDate.year
local month = currentDate.month + 1
local day = currentDate.day
local hour = currentDate.hour
local minute = currentDate.min
local second = currentDate.sec
return format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
}
// 计算下个月的1号早上6点
function GetFirstOfNextMonth() {
local currentDate = date()
local year = currentDate.year
local month = currentDate.month + 2 // +2是因为month是从0开始的且要算下个月
local day = 1
local hour = 6
local minute = 0
local second = 0
return format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
}
// 计算下周一早上6点
function GetNextMonday() {
local currentDate = date()
local day = currentDate.wday // 0是周日1-6是周一到周六
local diff = (day == 0) ? 1 : (8 - day)
currentDate.day += diff
local year = currentDate.year
local month = currentDate.month + 1
local day = currentDate.day
local hour = 6
local minute = 0
local second = 0
return format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
}
// 计算第二天早上6点
function GetSixAMNextDay() {
local currentDate = date()
local year = currentDate.year
local month = currentDate.month + 1
local day = currentDate.day + 1
local hour = 6
local minute = 0
local second = 0
return format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
}
// 获取刷新时间
function GetRefreshTime(refresh_month, refresh_weeks, refresh_days) {
if (refresh_month == 1) {
return GetFirstOfNextMonth()
} else if (refresh_weeks == 1) {
return GetNextMonday()
} else if (refresh_days == 1) {
return GetSixAMNextDay()
}
return null
}
function HandlePurchase(SUser, item_id, item_shop_id, item_info, item_cnt) {
local charac_no = SUser.GetCID();
local cache_key = charac_no + "_" + item_id + "_" + item_shop_id;
if (g_ShopLimitCache.rawin(cache_key)) {
local cache_data = g_ShopLimitCache[cache_key];
local buy_count = cache_data.buy_count;
local refresh_time = cache_data.refresh_time;
local current_time = get_trade_time();
if (current_time >= refresh_time) {
if (item_cnt > item_info[1]) {
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + item_info[1] + " 个", 8);
return true;
}
local new_refresh_time = GetRefreshTime(item_info[2], item_info[3], item_info[4]);
g_ShopLimitCache[cache_key] <- {
buy_count = item_cnt,
refresh_time = new_refresh_time
};
updateDatabaseAsync(charac_no, item_id, item_shop_id, item_cnt, new_refresh_time);
} else {
local remaining = item_info[1] - buy_count;
if (item_cnt > remaining) {
if (remaining == 0) {
local refresh_msg = "";
if (item_info[2] == 1) { // 月刷新
refresh_msg = "每月一日上午六点";
} else if (item_info[3] == 1) { // 周刷新
refresh_msg = "每周一日上午六点";
} else if (item_info[4] == 1) { // 日刷新
refresh_msg = "每日一日上午六点";
}
SUser.SendNotiPacketMessage("当前商品已售罄,将在" + refresh_msg + "刷新", 8);
} else {
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + remaining + " 个", 8);
}
return true;
}
g_ShopLimitCache[cache_key] <- {
buy_count = buy_count + item_cnt,
refresh_time = refresh_time
};
updateDatabaseAsync(charac_no, item_id, item_shop_id, buy_count + item_cnt, refresh_time);
}
return false;
}
local SqlObj = MysqlPool.GetInstance().GetConnect();
local query = "SELECT id, charac_no, item_id, buy_count, item_shop, refresh_time FROM DP_S.restrict_npc_shop_buy WHERE charac_no=" + charac_no + " AND item_id=" + item_id + " AND item_shop=" + item_shop_id;
local column_type_list = ["int", "int", "int", "int", "int", "string"];
local result = SqlObj.Select(query, column_type_list);
MysqlPool.GetInstance().PutConnect(SqlObj);
if (result.len() == 0) {
if (item_cnt > item_info[1]) {
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + item_info[1] + " 个", 8);
return true;
}
local refresh_time = GetRefreshTime(item_info[2], item_info[3], item_info[4]);
g_ShopLimitCache[cache_key] <- {
buy_count = item_cnt,
refresh_time = refresh_time
};
updateDatabaseAsync(charac_no, item_id, item_shop_id, item_cnt, refresh_time);
} else {
local buy_count = result[0][3];
local refresh_time = result[0][5];
local current_time = get_trade_time();
g_ShopLimitCache[cache_key] <- {
buy_count = buy_count,
refresh_time = refresh_time
};
if (current_time >= refresh_time) {
if (item_cnt > item_info[1]) {
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + item_info[1] + " 个", 8);
return true;
}
local new_refresh_time = GetRefreshTime(item_info[2], item_info[3], item_info[4]);
g_ShopLimitCache[cache_key] <- {
buy_count = item_cnt,
refresh_time = new_refresh_time
};
updateDatabaseAsync(charac_no, item_id, item_shop_id, item_cnt, new_refresh_time);
} else {
local remaining = item_info[1] - buy_count;
if (item_cnt > remaining) {
if (remaining == 0) {
local refresh_msg = "";
if (item_info[2] == 1) { // 月刷新
refresh_msg = "每月一日上午六点";
} else if (item_info[3] == 1) { // 周刷新
refresh_msg = "每周一日上午六点";
} else if (item_info[4] == 1) { // 日刷新
refresh_msg = "每日一日上午六点";
}
SUser.SendNotiPacketMessage("当前商品已售罄,将在" + refresh_msg + "刷新", 8);
} else {
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + remaining + " 个", 8);
}
return true;
}
g_ShopLimitCache[cache_key] <- {
buy_count = buy_count + item_cnt,
refresh_time = refresh_time
};
updateDatabaseAsync(charac_no, item_id, item_shop_id, buy_count + item_cnt, refresh_time);
}
}
return false;
}
}
// 更新缓存到数据库
function updateDatabaseAsync(charac_no, item_id, item_shop_id, buy_count, refresh_time) {
local SqlObj = MysqlPool.GetInstance().GetConnect();
// 使用 ON DUPLICATE KEY UPDATE 来更新已存在的记录
local query = "INSERT INTO DP_S.restrict_npc_shop_buy (charac_no, item_id, buy_count, item_shop, refresh_time) " +
"VALUES (" + charac_no + ", " + item_id + ", " + buy_count + ", " + item_shop_id + ", '" + refresh_time + "') " +
"ON DUPLICATE KEY UPDATE buy_count = VALUES(buy_count), refresh_time = VALUES(refresh_time)";
SqlObj.Select(query, []);
MysqlPool.GetInstance().PutConnect(SqlObj);
}
// 服务器启动时加载缓存
function loadShopLimitCache() {
local SqlObj = MysqlPool.GetInstance().GetConnect();
local query = "SELECT charac_no, item_id, item_shop, buy_count, refresh_time FROM DP_S.restrict_npc_shop_buy";
local column_type_list = ["int", "int", "int", "int", "string"];
local result = SqlObj.Select(query, column_type_list);
MysqlPool.GetInstance().PutConnect(SqlObj);
foreach(row in result) {
local cache_key = row[0] + "_" + row[1] + "_" + row[2];
g_ShopLimitCache[cache_key] <- {
buy_count = row[3],
refresh_time = row[4]
};
}
}
// 服务器关闭时保存缓存
Cb_Server_Close_Enter_Func.ShopLimitSave <- function(arg) {
foreach(cache_key, data in g_ShopLimitCache) {
local parts = split(cache_key, "_");
local charac_no = parts[0].tointeger();
local item_id = parts[1].tointeger();
local item_shop = parts[2].tointeger();
updateDatabaseAsync(charac_no, item_id, item_shop, data.buy_count, data.refresh_time);
}
g_ShopLimitCache <- {};
}
function _Dps_Shop_Limit_Main_() {
CreateShopLimitTable();
loadShopLimitCache();
Cb_BuyItem_check_error_Leave_Func.Shop_Limit_ByNangua <- function(args) {
local Config = GlobalConfig.Get("NPC商店限购配置_Nangua.json");
local shop_limit_config = Config["商店限购配置"];
local is_buy = false;
local SUser = User(args[1]);
local msg_base = args[2];
local Item_id = NativePointer(msg_base).add(13).readU32();
local item_shop = NativePointer(msg_base).add(21).readU32();
local item_cnt = NativePointer(msg_base).add(17).readU32();
local item_shop_id = item_shop.tostring();
if (item_shop_id in shop_limit_config) {
local items_list = shop_limit_config[item_shop_id];
foreach(item_info in items_list) {
if (item_info[0] == Item_id) {
is_buy = _Shop_Limit_Bynangua.HandlePurchase(SUser, Item_id, item_shop, item_info, item_cnt);
break;
}
}
}
if (is_buy) {
return 19;
}
}
}
function CreateShopLimitTable() {
local Config = GlobalConfig.Get("NPC商店限购配置_Nangua.json");
local PoolObj = MysqlPool.GetInstance();
local Ip = Config["数据库IP 不是外置数据库不要更改"];
local Port = Config["数据库端口 不懂不要更改"];
local DbName = Config["数据库用户名 本地用户名不懂不要更改"];
local Password = Config["数据库密码 本地密码不懂不要更改"];
PoolObj.SetBaseConfiguration(Ip, Port, DbName, Password);
PoolObj.PoolSize = 10;
PoolObj.Init();
// 建库建表SQL
local CreateSql1 = "create database if not exists DP_S default charset utf8;";
local CreateSql2 = "CREATE TABLE IF NOT EXISTS DP_S.restrict_npc_shop_buy (" +
"id int(11) AUTO_INCREMENT, " +
"charac_no int(11) NOT NULL, " +
"item_id int(11) NOT NULL, " +
"buy_count int(11) NOT NULL, " +
"item_shop int(11) NOT NULL, " +
"refresh_time varchar(255) NOT NULL, " +
"PRIMARY KEY (id), " +
"UNIQUE KEY unique_purchase (charac_no, item_id, item_shop)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8;";
// 执行SQL
local SqlObj = MysqlPool.GetInstance().GetConnect();
SqlObj.Exec_Sql(CreateSql1);
SqlObj.Exec_Sql(CreateSql2);
MysqlPool.GetInstance().PutConnect(SqlObj);
}