接下来告诉大家怎么实现一种卡密实现兑换游戏内多种项目的方法:
1.首先你服务器必须支持mysql模组extdb3,比如生活服,我们先在你的库下建立一个兑换码表,它储存着所有用来兑换各种游戏内项目的卡密。
CREATE TABLE `destiny_sell_key` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`card_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`card_type` int(0) NOT NULL DEFAULT 0 COMMENT '0=vip卡,1=钱',
`card_active` int(0) NOT NULL DEFAULT 0,
`vip_level` int(0) NULL DEFAULT 0,
`vip_day_num` int(0) NULL DEFAULT 0,
`game_money` int(0) NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 49 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
有必要解释下这些字段是干嘛的:
card_key 是储存卡密 长度是255字符,这里可以根据你的卡密长度自己设置
card_type 是卡密类型
card_active 是是否已经使用
vip_level 是VIP卡密时,兑换的vip等级
vip_day_num 是VIP卡密时,兑换的vip的天数
game_money 是金币卡密时兑换的游戏币
2.然后在你的玩家表中添加一个字段:
一般带有数据库的服务器,玩家进来需要读取玩家的数据,在储存这个玩家数据的表上添加一个字段:vip_end_date 类型:int 长度:0
这个字段用来储存玩家VIP的到期时间,它是10位时间戳。
3.接下来需要写一个储存过程,它用来实现具体的兑换卡密功能:
CREATE DEFINER=`root`@`localhost` PROCEDURE `setVip`(IN `pid` varchar(255),IN `card` varchar(255))
BEGIN
/*
设置服务器VIP
描述: 添加VIP/变更vip到期时间/根据等级折算vip时间/根据金币卡密添加游戏币 by destiny studio
-1 无效的卡密
0 卡密已经被使用
1 成功
*/
DECLARE CURRENT_VIP_TIME BIGINT DEFAULT 0;
DECLARE VIP_END_TIME BIGINT DEFAULT 0;
DECLARE donator_level BIGINT DEFAULT 0;
DECLARE var_card_key varchar(255) DEFAULT "";
DECLARE var_card_type BIGINT DEFAULT 0;
DECLARE var_card_active BIGINT DEFAULT 0;
DECLARE var_vip_level BIGINT DEFAULT 0;
DECLARE var_vip_day_num BIGINT DEFAULT 0;
DECLARE var_game_money BIGINT DEFAULT 0;
SELECT card_key,card_type,card_active,vip_level,vip_day_num,game_money INTO var_card_key,var_card_type,var_card_active,var_vip_level,var_vip_day_num,var_game_money FROM destiny_sell_key WHERE card_key = card;
IF var_card_key != ""
THEN
IF var_card_active = 0
THEN
IF var_card_type = 0
THEN
SELECT vip_end_date,donatorLevel INTO CURRENT_VIP_TIME,donator_level FROM phxclients where playerid = pid;
IF unix_timestamp() > CURRENT_VIP_TIME
THEN SET VIP_END_TIME = unix_timestamp(TIMESTAMPADD(day,var_vip_day_num,from_unixtime(unix_timestamp())));
ELSE
IF donator_level != var_vip_level
THEN
SET VIP_END_TIME = unix_timestamp(TIMESTAMPADD(day,var_vip_day_num,from_unixtime(unix_timestamp(TIMESTAMPADD(day,-(ROUND(((CURRENT_VIP_TIME-unix_timestamp()) / (24*3600))/2)),from_unixtime(CURRENT_VIP_TIME))))));
ELSE
SET VIP_END_TIME = unix_timestamp(TIMESTAMPADD(day,var_vip_day_num,from_unixtime(CURRENT_VIP_TIME)));
END IF;
END IF;
UPDATE phxclients SET vip_end_date = VIP_END_TIME,donatorLevel = var_vip_level WHERE playerid = pid;
ELSE
UPDATE phxclients SET bankacc = bankacc + var_game_money WHERE playerid = pid;
END IF;
UPDATE destiny_sell_key SET card_active = 1 WHERE card_key = card;
SELECT 1;
ELSE
SELECT 0;
END IF;
ELSE
SELECT -1;
END IF;
END
相信你们都看明白了,这里有个折算操作,当你买了3个月VIP1,再次买1个月VIP2,也就是比VIP1更高的等级时,会出现把之前的VIP1时间折一半+当前卡密等级的时间。如果不需要可以自行修改,比如你买了60天VIP1,再买30天VIP2,那么就会 (60/2) + 30 = 最终的时间
再写一个获取VIP时间过程:
CREATE DEFINER=`root`@`localhost` PROCEDURE `getVipTime`(IN `pid` varchar(255))
BEGIN
DECLARE CURRENT_VIP_TIME BIGINT DEFAULT 0;
SELECT vip_end_date INTO CURRENT_VIP_TIME FROM phxclients where playerid = pid;
IF unix_timestamp() > CURRENT_VIP_TIME
THEN SELECT 0,FROM_UNIXTIME(CURRENT_VIP_TIME) AS vip_time;
ELSE
SELECT 1,FROM_UNIXTIME(CURRENT_VIP_TIME) AS vip_time,ROUND(((CURRENT_VIP_TIME-unix_timestamp()) / (24*3600))) AS vip_date;
END IF;
END
注意里面的查询的表,我这里是phxclients 换成你的,其次查询的字段我这里是donatorLevel 是vip赞助等级,换成你的。还有playerid,换成你表中对应的玩家UID字段
4.SQF实现这些功能:
4.1:当玩家加入服务器读取玩家数据之前,我们要检查他的VIP是否过期:
[format ["UPDATE phxclients SET donatorLevel = (if ( unix_timestamp() > vip_end_date,0,donatorLevel)) WHERE playerid='%1'",_steamid], 1] call DB_fnc_asyncCall;
phxclients = 换成你的玩家表
donatorLevel = 换成你的VIP等级字段
_steamid = 换成初始化玩家的UID
DB_fnc_asyncCall = 换成你的调用函数
4.2:然后我们要实现真正的兑换代码:
destiny_fnc_setVip = {
params ["_player", "_key"];
_pid = getPlayerUID _player;
if (_pid isEqualTo "") exitWith {};
if (_key != "") then {
_result = [format ["call setVip('%1','%2')",_pid,_key], 2,true] call DB_fnc_asyncCall;//DB_fnc_asyncCall执行你自己的数据库函数
try{
_result_type = _result # 0 # 0;
if (_result_type != 1) exitWith {
_msg = switch (_result_type) do {
case -1: {"无效的卡密!"};
case 0: {"卡密已经被使用!"};
default {"未知的卡密状态!"};
};
//执行你自己的通知
//[_msg,"red"] remoteExec ["PHX_fnc_notify",_player];
};
_var_card_key = _result # 0 # 1;
_var_card_type = _result # 0 # 2;
_var_card_active = _result # 0 # 3;
_var_vip_level = _result # 0 # 4;
_var_vip_day_num = _result # 0 # 5;
_var_game_money = _result # 0 # 6;
_var_vip_end_time = _result # 0 # 7;
if (_var_card_type == 0) then {
//实现你自己的逻辑,兑换的项目
//这里模拟兑换VIP
[_var_vip_level] remoteExec ["destiny_fnc_vipLevel",_player];
_time = format["%1-%2-%3 %4:%5:%6",_var_vip_end_time # 0,_var_vip_end_time # 1,_var_vip_end_time # 2,_var_vip_end_time # 3,_var_vip_end_time # 4,_var_vip_end_time # 5];
//执行你自己的通知
[format ["充值成功:现在您的VIP等级为 %1 到期日为:%2 ,尽情享受吧!",_var_vip_level,_time],"green"] remoteExec ["PHX_fnc_notify",_player];
};
if (_var_card_type == 1) then {
//实现你自己的逻辑,兑换的项目
//这里模拟兑换游戏币
[_var_game_money,0,1] remoteExec ["destiny_fnc_handleMoney",_player];
//执行你自己的通知
[format ["充值成功:您的 %1 已汇入银行!",([_var_game_money] call BIS_fnc_numberText)],"green"] remoteExec ["PHX_fnc_notify",_player];
};
} catch {
diag_log _exception;
//执行你自己的通知
["充值:执行存储过程等一系列操作时发生异常!请重试或联系管理员!","red"] remoteExec ["PHX_fnc_notify",_player];
};
};
};
4.3它是个服务器函数,所以我们玩家需要远程调用它给服务器执行,传入玩家对象和卡密就可以了!
然后再写一个获取VIP时间:
_pid = getPlayerUID _this;
_key = format ["destiny_var_vipQueryTime_%1",_pid];
_vtime = missionNamespace getVariable [_key,0];
if (serverTime > _vtime) then {
missionNamespace setVariable [_key,(serverTime + 60)];
_result = [format ["call getVipTime('%1')",_pid], 2,true] call DB_fnc_asyncCall;
_newResult = _result # 0;
_status = _newResult # 0;
_vipDate = _newResult # 1;
_data = [];
if (_status == 1) then {
_data = [format ["%1-%2-%3 %4:%5:%6",_vipDate#0,_vipDate#1,_vipDate#2,_vipDate#3,_vipDate#4,_vipDate#5],_newResult # 2];
} else {
_data = ["已到期",0];
};
_data remoteExecCall ["destiny_fnc_receiveVip",_this];
};
传入玩家对象就可以了,为了防止重复点击或其他因素,我们记录下时间+60秒,每60秒才可以同步时间,这也是服务器函数,需要玩家远程调用它给服务器执行, call DB_fnc_asyncCall 也要换成你的,其次 _data remoteExecCall [“destiny_fnc_receiveVip”,_this]; 中的destiny_fnc_receiveVip是个本地函数,它会接受到获取到的时间,自行处理。
5.实现游戏中的兑换卡密UI和功能:
我们需要来到你的任务文件夹,找到description.ext打开并写入一下代码:
class destiny_dialog_buy_vip
{
idd = -1;
movingEnable = true;
class ControlsBackground
{
class Control_bg
{
type = 0;
idc = 0;
x = 0;
y = 0;
w = 1;
h = 1;
style = 0;
text = "";
colorBackground[] = {0,0,0,0.5};
colorText[] = {0.851,0.9137,0.2353,1};
font = "PuristaMedium";
sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1);
};
class Control_title
{
type = 0;
idc = 0;
x = safeZoneX + safeZoneW * 0.29375;
y = safeZoneY + safeZoneH * 0.225;
w = safeZoneW * 0.4125;
h = safeZoneH * 0.06851852;
style = 2;
text = "自由都市-在线赞助";
colorBackground[] = {0.502,0.6,1,0.8};
colorText[] = {1,1,1,1};
font = "PuristaMedium";
sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1.5);
};
class Control_tip
{
type = 0;
idc = 0;
x = safeZoneX + safeZoneW * 0.29375;
y = safeZoneY + safeZoneH * 0.28981482;
w = safeZoneW * 0.4125;
h = safeZoneH * 0.03148149;
style = 2;
text = "注意:将你的卡密输入,然后点击确定,卡密有VIP卡,金币卡2种。";
colorBackground[] = {0.502,0.6,1,0.8};
colorText[] = {1,1,1,1};
font = "PuristaMedium";
sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1);
};
class Control_tip2
{
type = 0;
idc = 0;
x = safeZoneX + safeZoneW * 0.29375;
y = safeZoneY + safeZoneH * 0.73425926;
w = safeZoneW * 0.4125;
h = safeZoneH * 0.04074075;
style = 2;
text = "注意:如果您是续费VIP,并且当前的VIP等级和卡密等级不匹配,到期日期将设置为:(当前VIP剩余时间 / 2) + 卡密VIP时间";
colorBackground[] = {0.502,0.6,1,0.8};
colorText[] = {0.902,0.302,0.302,1};
font = "PuristaMedium";
sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 0.8);
};
class Control_text
{
type = 0;
idc = 0;
x = safeZoneX + safeZoneW * 0.37291667;
y = safeZoneY + safeZoneH * 0.37314815;
w = safeZoneW * 0.2640625;
h = safeZoneH * 0.0962963;
style = 2;
text = "您的卡密:";
colorBackground[] = {1,1,1,0};
colorText[] = {1,1,1,1};
font = "PuristaMedium";
sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 2);
};
};
class Controls
{
class Control_input
{
type = 2;
idc = 5670;
x = safeZoneX + safeZoneW * 0.3234375;
y = safeZoneY + safeZoneH * 0.475;
w = safeZoneW * 0.353125;
h = safeZoneH * 0.04074075;
style = 0;
text = "";
autocomplete = "";
colorBackground[] = {0.502,0.6,1,0.8};
colorDisabled[] = {0.2,0.2,0.2,1};
colorSelection[] = {1,0,0,1};
colorText[] = {1,1,1,1};
font = "PuristaMedium";
sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1);
onChar = "";
};
class Control1_sub
{
type = 1;
idc = -1;
x = safeZoneX + safeZoneW * 0.4125;
y = safeZoneY + safeZoneH * 0.61388889;
w = safeZoneW * 0.16510417;
h = safeZoneH * 0.04074075;
style = 0+2;
text = "确定";
borderSize = 0;
colorBackground[] = {0,0,0,1};
colorBackgroundActive[] = {0,0,0,1};
colorBackgroundDisabled[] = {0,0,0,1};
colorBorder[] = {0,0,0,0};
colorDisabled[] = {0.2,0.2,0.2,1};
colorFocused[] = {0.2,0.2,0.2,1};
colorShadow[] = {0,0,0,1};
colorText[] = {1,1,1,1};
font = "PuristaMedium";
offsetPressedX = 0.01;
offsetPressedY = 0.01;
offsetX = 0.01;
offsetY = 0.01;
sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1.5);
soundClick[] = {"\A3\ui_f\data\sound\RscButton\soundClick",0.09,1.0};
soundEnter[] = {"\A3\ui_f\data\sound\RscButton\soundEnter",0.09,1.0};
soundEscape[] = {"\A3\ui_f\data\sound\RscButton\soundEscape",0.09,1.0};
soundPush[] = {"\A3\ui_f\data\sound\RscButton\soundPush",0.09,1.0};
onButtonClick = "_key = ctrlText 5670;[_key] call destiny_fnc_subBuy;";
};
};
};
我们需要来到你的任务文件夹,找到initPlayerLocal.sqf打开并写入一下代码:
destiny_var_subBuyTime = 0;
destiny_fnc_subBuy = {
params ["_key"];
closeDialog 0;
if (time > destiny_var_subBuyTime) then {
destiny_var_subBuyTime = time + 10;
if (isNil "_key" || _key isEqualTo "") exitWith {
["请输入卡密!","red"] spawn PHX_fnc_notify;
};
[player,_key] remoteExec ["destiny_fnc_setVip",2];
} else {
["服务器繁忙,请等待一会儿再试试...","red"] spawn PHX_fnc_notify;
};
};
//这些代码可以储存在服务器然后通过publicVariable发送给所有客户端,达到不需要修改任务的目的
创建一个下面类型的对话框进行测试:
destiny_dialog_buy_vip
6.完成,去测试和实现你的功能吧~