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