注册 | 登录

游侠NETSHOW论坛





查看: 23431|回复: 27
打印 上一主题 下一主题

[分享] 工作做完了,来写一下sourcemod的插件制作教程. [复制链接]

帖子
1160
精华
0
积分
663
金钱
3834
荣誉
8
人气
34
评议
0
跳转到指定楼层
楼主
发表于 2009-7-13 06:48:56 |只看该作者 |倒序浏览
需要的工具:

      Ultraedit或EditPlus或同类文本编辑软件,不推荐用记事本,因为很不完善.可到http://www.97sky.cn去下载这些软件.
      或者直接用Pawn Studio,不过因为Pawn Studio对中文支持不好,所以有时候显得麻烦 http://nchc.dl.sourceforge.net/s ... o/pstudio-0.8.3.zip

需要的网站:
       http://wiki.alliedmods.net/index ... urceMod_Development                    (SourceMod Development-----SourceMod 开发文档)
       http://docs.sourcemod.net/api/            (SourceMod API)
       http://docs.sourcemod.net/dox/functions_func.html




开始了,为了方便,我就用Pawn Studio(以下简称PW)来讲解了

打开PW


按下File->New->SorceMod->SourcePawn Script

然后会在编辑窗口出现以下代码

  1. /* Plugin Template generated by Pawn Studio */

  2. #include <sourcemod>

  3. public Plugin:myinfo =
  4. {
  5.         name = "New Plugin",
  6.         author = "Unknown",
  7.         description = "<- Description ->",
  8.         version = "1.0",
  9.         url = "<- URL ->"
  10. }

  11. public OnPluginStart()
  12. {
  13.         // Add your own code here...
  14. }
复制代码


这里我们以创建一个玩家登陆服务器,欢迎为例子.


public Plugin:myinfo= 这代子程序中的意思仅仅是做一个简介,让SourceMod知道这是个什么,具体的意思不做解释了,都是简单的英文


public OnPluginStart()  为插件被加载的子程序,也就是当你写的这个插件,被SourceMod加载的时候会被首先运行到的段落,只会被运行一次,通常这里都会写一些初始东西,例如我的lxd中这里写的是创建配置文件lxd-wind.cfg的东东.因为要写登陆欢迎的事件,所以这里就不会用到了,而此刻调用Sourcemod的API,于是我们打开 http://docs.sourcemod.net/api/

选择Clients,我们会发现许多

  1. OnClientConnect
  2. OnClientConnected
  3. OnClientPutInServer
  4. OnClientDisconnect
  5. OnClientDisconnect_Post
  6. OnClientCommand
  7. OnClientSettingsChanged
  8. OnClientAuthorized
  9. OnClientPreAdminCheck
  10. OnClientPostAdminFilter
  11. OnClientPostAdminCheck
  12. .................
复制代码


而我们只需要OnClientConnected,意思为当客户端连接成功后

单击OnClientConnected,得知 Syntax:
forward OnClientConnected(client);

那么我们在代码中建立一个

  1. public OnClientConnected(client)
  2. {
  3.         // 代码部分
  4. }
复制代码



当玩家连接成功后会做什么

我们是写欢迎消息,因为这部分是Half Life通用的东东,所以我们到 halflife 里面去找.单击网页halflife

会看到
  1. PrintToChat
  2. PrintToChatAll
  3. PrintCenterText
  4. PrintCenterTextAll
  5. PrintHintText
  6. PrintHintTextToAll
复制代码


我们可以选择各种不同的显示方式

PrintToChat 是现实在聊天窗口的信息,触发对象指定,这些你可以具体选择查看

因为我们是通告所有玩家,所以我们选择 PrintToChatAll,PrintCenterTextAll,PrintHintTextToAll中的任意一种

这里先说下颜色
  1. PrintToChatAll ("\x01 1 .. \x02 2 .. \x03 3 .. \x04 4 .. \x05 5 .. \x06 6 .. \x07 7 .. \x08 8");
复制代码
的结果为



代码则为
  1. PrintToChatAll("\欢迎x01 %N 来到 \x02 Left 4 Dead 玩家服务器,client)
复制代码


虽然我没有写过此类的插件,但是我们应该考虑一个问题,因为在Srdcs.exe中我们看见infected一方被创建后,依然占用了一个位置,不难想象他们是否也会触发相同的事件?不过按道理说,他们应该不是被Connect进来的,相反的如果我们用Putinserver(见Onclientconnected的那个网页)可能他们就会被触发.

为了安全起见,我们加上判断,依然看Client的那个网页

  1. Syntax:
  2. native bool:IsFakeClient(client);

  3. Usage:
  4. client                Player index.
  5. Notes:
  6. Returns if a certain player is a fake client.

  7. Return:
  8. True if player is a fake client, false otherwise.

  9. Version Added:
  10. 1.0.0.1946
复制代码


return的值为真,那么我们这里就需要判断假,也就是判断,如果该玩家不是fake client
if(!IsFakeClient(client))
{
PrintToChatAll("\欢迎x01 %N 来到 \x02 Left 4 Dead 玩家服务器,client)
}


因为SourceMod的语法和标准的C语言一样,所以很多东西都是通用的例如 &&=and || = or     !=not


现在我们来看看,我们完成的所有代码

  1. /* Plugin Template generated by Pawn Studio */

  2. #include <sourcemod>

  3. public Plugin:myinfo =
  4. {
  5.         name = "New Plugin",
  6.         author = "Unknown",
  7.         description = "<- Description ->",
  8.         version = "1.0",
  9.         url = "<- URL ->"
  10. }

  11. public OnPluginStart()
  12. {
  13.         // Add your own code here...
  14. }
  15. public OnClientConnected(client)
  16. {
  17.         if(!IsFakeClient(client))
  18.         {
  19.                 PrintToChatAll("\欢迎x01 %N 来到 \x02 Left 4 Dead 玩家服务器,client)
  20.         }
  21. }
复制代码



很简单吧,当然我们也可以通过其他方式来实现.

例如事件

http://wiki.alliedmods.net/Generic_Source_Events

核心事件

首先需要在Onplugins里面Hook事件

  1. public OnPluginStart()
  2. {
  3.         HookEvent("player_spawn", welcome);
  4. }
复制代码


hookevent说明:

  1. native HookEvent(const String:name[], EventHook:callback, EventHookMode:mode=EventHookMode_Post);
复制代码




我们则创建

  1. public Action:welcome(Handle:event, const String:name[], bool:dontBroadcast)
  2. {
  3. }
复制代码



这样每当有玩家被创建的时候,就会执行这里的代码,不过此法很不好,不适合用来做欢迎信息.这里只是为了抛砖引玉.


好了就这么多了,其实很简单的,因为都是C语言的框架.当你了解了这个以后,对C语言可能也有更深一步的了解了.以后看到此类的东东也会很容易上手了,我发现我自己实在不适合写教程,都不知道大家能看明白否,不过写了也就放上来吧.

[ 本帖最后由 lovemf 于 2009-7-13 09:07 编辑 ]
附件: 你需要登录才可以下载或查看附件。没有帐号?注册

使用道具 举报

帖子
1160
精华
0
积分
663
金钱
3834
荣誉
8
人气
34
评议
0
沙发
发表于 2009-7-13 06:57:39 |只看该作者
而想制作更为强大的plug需要自己多去看别人的sp源代码,从中受益.

使用道具 举报

帖子
1160
精华
0
积分
663
金钱
3834
荣誉
8
人气
34
评议
0
板凳
发表于 2009-7-13 07:16:56 |只看该作者
反正还有时间,我就拿我写的换地图的脚本讲解下


  1. #pragma semicolon 1

  2. #include <sourcemod>
  3. #define PLUGIN_VERSION "1.0.0"
  4. #define CVAR_FLAGS FCVAR_PLUGIN

  5. new Handle:voteTimeout; // 申明一个句柄

  6. new bool:inVoteTimeout[MAXPLAYERS+1];   //申明一个数据类型 关于bool 可以到这里了解下 [[url]http://baike.baidu.com/view/1557195.htm[/url]]

  7. public Plugin:myinfo =
  8. {
  9.         name = "NewMap Change",
  10.         author = "AlliedModders LLC",
  11.         description = "BY WIND",
  12.         version = PLUGIN_VERSION,
  13.         url = "http://www.sourcemod.net/"
  14. };

  15. public OnPluginStart( )
  16. {
  17.         RegConsoleCmd("sm_newmap",check, "changethemap");  // 注册控制台指令 sm_newmap ,因为在sourcemod中的core.cfg中 sm会被定义为!所以,基本上大家都是习惯性的挂上sm,这样游戏里面就可以输入!newmap了,当然也可以是!sm_newmap
  18.         voteTimeout         = CreateConVar("newmap_vote_timeout",                "120", "玩家发起新地图切换投票需要间隔",CVAR_FLAGS,true,0.0); // 这里是刚才申明的句柄,这里要赋予它一个值.
  19. }

  20. public OnMapStart() //插件加载
  21. {
  22.         for(new i=0;i<sizeof(inVoteTimeout);i++) // 一段循环, 因为前面已经MAXPLAYERS+1过了,所以这里 按照理解应该是 new i=0;i<maxclient();i++) 分别返回false值,
  23.                 inVoteTimeout[i]=false;
  24. }

  25. public OnClientConnected(client)  //当玩家连接成功后
  26. {
  27.         inVoteTimeout[client]=false;  //赋予玩家false
  28. }

  29. public isInVoteTimeout(client)
  30. {
  31.         if (GetConVarBool(voteTimeout))  // 如果为真
  32.         {
  33.                 return inVoteTimeout[client];        //返回inVoteTimeout
  34.         }
  35.         return false; //返回
  36. }

  37. public Action:TimeOutOver(Handle:timer, any:client)  //时钟
  38. {
  39.         inVoteTimeout[client] = false; //设置为初始值
  40. }

  41. public Action:check(client, args)
  42. {
  43.         if(GetConVarInt(FindConVar("sv_hosting_lobby")) == 1) // 这里是检测是否为大厅服务器
  44.         {
  45.                 ReplyToCommand(client, "\x01[SM] Server was started from lobby.  can change map because mp_gamemode is locked\x03");
  46.                 return Plugin_Handled;
  47.         }
  48.        
  49.         if(GetClientTeam(client) != 2) //判断是否为幸存者团队   1=怪物 3=空闲玩家
  50.         {
  51.         PrintToChat(client, "\x04[SM] \x01 你没有权限使用该功能.");
  52.         return Plugin_Handled;
  53.         }
  54.        
  55.         if (isInVoteTimeout(client)) //如果为真isInVoteTimeout(client)) =true
  56.         {
  57.                 PrintToChat(client, "\x04[SM] \x01你必须要等待 %.1f 秒才可以再次发起切换地图投票.",GetConVarFloat(voteTimeout)); //则提示你需要等待多少秒后才可以继续投票.
  58.                 return Plugin_Handled;               
  59.         }
  60.        
  61.         inVoteTimeout[client]=true;  // 不满足以上的判断则说明该玩家没有发表过投票,则现在给予他true的值,当下次再循环到的时候则会提示判断true,不再进行下面的操作
  62.         new Float:timeout = GetConVarFloat(voteTimeout); //定义一个浮点型数据类timeout,他的值从voteTimeout中获得,参见 Onplugins
  63.         if (timeout > 0.0) //如果时间>0,这里仅作为一个开关使用,如果我们在上面的onplugins中设置为0,这里的判断就会失效,那么一个人投票一次后就无法再输入!newmap来进行投票了.因为他们的值被给予了true而不会还原
  64.         {
  65.         CreateTimer(timeout, TimeOutOver, client); //创建一个时钟,附带参数client
  66.         }
  67.        
  68.         newmap(client, args);  // 执行子程序
  69.         return Plugin_Handled;
  70. }

  71. public Action:newmap(client, args)
  72. {

  73.         new Handle:menu = CreateMenu(ModeMenuHandler); //申请menu,创建菜单ModeMenuHandler
  74.        
  75.         SetMenuTitle(menu, "地图切换");  // 标题
  76.         AddMenuItem(menu, "option1", "地图切换"); //创建菜单
  77.         AddMenuItem(menu, "option2", "帮助说明");
  78.         SetMenuExitButton(menu, true);  // 能够看见关闭按钮
  79.        
  80.         DisplayMenu(menu, client, MENU_TIME_FOREVER); //永久显示菜单,直到用户操作
  81. }

  82. public ModeMenuHandler(Handle:menu, MenuAction:action, client, itemNum) //因为上面的操作都是针对menu(CreateMenu(ModeMenuHandler); ) 所以就跳到这里了
  83. {
  84.    if ( action == MenuAction_Select )   // 判断操作选择
  85.         {
  86.         switch (itemNum)
  87.         {
  88.             case 0: // changemap
  89.             {
  90.                                 MapMenuVote(client, 0);   // 调用子程序
  91.             }
  92.             case 1: // help
  93.             {
  94.                                 PrintToChat(client,"\x01[SM] 如果发现无法按下5,6,7,8,9,0键,请在控制台输入 bind 5 slot5; bind 6 slot6; bind 7 slot7; bind 8 slot8; bind 9 slot9; bind 0 slot10\x03");
  95.             }
  96.         }
  97.     }
  98. }


  99. public Action:MapMenuVote(client, args)
  100. {
  101.         new Handle:menu = CreateMenu(MapMenuVoteHandler); // 又创建了一个新的menu
  102.        
  103.         SetMenuTitle(menu, "请投票选择地图");
  104.         AddMenuItem(menu, "option1", "保持当前地图");
  105.         AddMenuItem(menu, "option2", "停尸间惊魂");
  106.         AddMenuItem(menu, "option3", "死亡电站");
  107.         AddMenuItem(menu, "option4", "血腥之城");
  108.         AddMenuItem(menu, "option5", "监狱惊魂");
  109.         SetMenuExitButton(menu, false);
  110.        
  111.         VoteMenuToAll(menu, 20);  //调出投票,20秒后自动消失,这些都是API,所以很简单的就能完成了,而真正的C语言就不会那么容易了.
  112.        
  113.         return Plugin_Handled;
  114. }

  115. public MapMenuHandler(Handle:menu, MenuAction:action, client, itemNum)
  116. {
  117.     if ( action == MenuAction_Select )
  118.         {
  119.         switch (itemNum)
  120.         {
  121.             case 0:
  122.             {
  123.                                 PrintToChatAll("[SM:] 投票失败,当前地图不会变更."); //选择1为保持当前投票,所以自然要给别人一点提示
  124.                                 return; // 跳出
  125.             }
  126.             case 1:
  127.             {
  128.                                 ServerCommand("changelevel l4d_mortuary01");  //执行服务器指令
  129.             }
  130.             case 2:
  131.             {
  132.                                 ServerCommand("changelevel l4d_powerstation_utg_01");
  133.             }
  134.             case 3:
  135.             {
  136.                                 ServerCommand("changelevel l4d_deadcity01_riverside");
  137.             }       
  138.             case 4:
  139.             {
  140.                                 ServerCommand("changelevel l4d_deathaboard01_prison");
  141.             }
  142.         }
  143.     }
  144. }

  145. public MapMenuVoteHandler(Handle:menu, MenuAction:action, param1, param2)
  146. {
  147.         if (action == MenuAction_End)  //如果20秒不进行操作则
  148.         {
  149.                 CloseHandle(menu); //关闭菜单
  150.         }
  151.         else if (action == MenuAction_VoteEnd)   //如果投票结束后
  152.         {
  153.                 MapMenuHandler(menu, MenuAction_Select, 0, param1); //调用子程序
  154.         }
  155. }
复制代码



很多不明白的,可以到顶帖中的网址去查阅了,好了去睡觉了..

使用道具 举报

帖子
2442
精华
0
积分
1231
金钱
2453
荣誉
1
人气
3
评议
0

地板
发表于 2009-7-13 09:24:18 |只看该作者
哈哈,学术讨论帖..

虽然没研究过,但是还是要帮顶一下啊~

使用道具 举报

帖子
748
精华
0
积分
385
金钱
890
荣誉
1
人气
0
评议
0
5#
发表于 2009-7-13 10:38:18 |只看该作者
支持lovemf。。
最近想学习学习改sp档

使用道具 举报

帖子
15
精华
0
积分
8
金钱
71
荣誉
0
人气
0
评议
0
6#
发表于 2009-7-27 05:42:35 |只看该作者
.......好好研究一下

目前想寫一個判斷當前地圖關卡名稱的片段用來載入不同cfg...

使用道具 举报

帖子
31
精华
0
积分
16
金钱
159
荣誉
0
人气
0
评议
0
7#
发表于 2009-9-25 13:55:59 |只看该作者
写SP还是建议用editplus

使用道具 举报

帖子
2050
精华
0
积分
1055
金钱
2172
荣誉
3
人气
0
评议
0
8#
发表于 2009-9-25 14:40:39 |只看该作者
楼主经常玩消失,要bs,[冲啊]
不过技术文章一定要支持。

使用道具 举报

帖子
289
精华
0
积分
145
金钱
565
荣誉
0
人气
0
评议
0
9#
发表于 2009-9-25 17:03:03 |只看该作者
LZ,可以用VC++来编辑吗?

使用道具 举报

帖子
289
精华
0
积分
145
金钱
565
荣誉
0
人气
0
评议
0
10#
发表于 2009-9-25 17:04:09 |只看该作者
语句后还有注释,LZ可以去教编程了,嘻嘻

使用道具 举报

帖子
54
精华
0
积分
37
金钱
223
荣誉
1
人气
0
评议
0
11#
发表于 2010-1-3 01:13:06 |只看该作者
感觉这就是传说中的C啊~~
#include  经典~~~

使用道具 举报

帖子
6380
精华
0
积分
3361
金钱
33371
荣誉
17
人气
13
评议
0
12#
发表于 2010-1-3 13:18:40 |只看该作者
sp没几个人会分享的!

只能找老外的SP学习或自己琢磨了!
Q6600[3.0]+Tt                         I7 3770
微星P45 NEO3-FR                      华硕P8Z77-V LM
威刚(万紫千红)DDR2800 2GX2     威刚(万紫千红)DDR31600 4GX2+8GX2(ddr31866)
影驰GTX670四星大将4G              影驰GTX970名人堂4G
希捷1T+1.5T                            希捷2T+2T+3T
三星2494HS
win10Pro 64bit                          win7旗舰版64bit

使用道具 举报

帖子
358
精华
0
积分
180
金钱
3055
荣誉
0
人气
0
评议
0
13#
发表于 2010-1-3 15:18:39 |只看该作者
该来的终于来了。。。。。。。。。。。。。

使用道具 举报

帖子
358
精华
0
积分
180
金钱
3055
荣誉
0
人气
0
评议
0
14#
发表于 2010-1-3 15:20:31 |只看该作者
原帖由 超级玩家 于 2010-1-3 13:18 发表
sp没几个人会分享的!

只能找老外的SP学习或自己琢磨了!

是啊,这就是为啥咱们的mod水平远远不如老外,乐于分享水涨船高啊

使用道具 举报

帖子
12
精华
0
积分
6
金钱
102
荣誉
0
人气
0
评议
0
15#
发表于 2010-1-5 01:15:35 |只看该作者
ddddddddddddddddddddd

使用道具 举报

帖子
1882
精华
0
积分
942
金钱
20985
荣誉
0
人气
10
评议
0
16#
发表于 2010-1-5 12:54:40 |只看该作者
技术帖,要好好的支持一下。

另,你签名里面的网址下载不到L4D最新的补丁哈,12月中旬好像更新了一次
STEAM ID: SilenCe370           L4D ID: SilenCe.L
----------------------------------------------------------------------------
Intel Core2 Quad 8200
Gigabyte GA-EP45T-UD3LR
Kingstone DDRIII 1333 2G*2
Sapphire HD 4870 1G GDDR5 PCI-E QP
Seagate 1T  7200.12
ViewSonic VX2233wm
Razer Mamba & Razer Imperator  & Razer Naga  &  Logitech G500 G400 嗯,鼠标……

Intel® Core™ i7-975 Processor Extreme Edition
Gigabyte GA-X58A-UD3R ver2.0
Kingstone DDRIII HYPERX 1866 8G*6
ASUS STRIX-GTX970-DC2OC-4GD5
Logitech G502

使用道具 举报

帖子
546
精华
0
积分
274
金钱
600
荣誉
0
人气
0
评议
0
17#
发表于 2010-1-5 13:18:48 |只看该作者
noob已经离尘而去了,追思。。。。。。。。。。。。。

使用道具 举报

帖子
284
精华
0
积分
143
金钱
294
荣誉
0
人气
0
评议
0
18#
发表于 2010-1-5 13:27:09 |只看该作者
不喜歡編程(太繁複了),純支持一下

使用道具 举报

帖子
71
精华
0
积分
36
金钱
112
荣誉
0
人气
0
评议
0
19#
发表于 2010-1-5 22:11:44 |只看该作者
留名研究下.....2020202020202020202020

使用道具 举报

帖子
24
精华
0
积分
12
金钱
231
荣誉
0
人气
0
评议
0
20#
发表于 2011-8-20 10:53:49 |只看该作者
好东西,必须要顶...
我来学习的...

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

手机版|Archiver|游侠NETSHOW论坛 ( 苏ICP备2023007791号 )

GMT+8, 2025-11-8 20:11 , Processed in 0.373356 second(s), 12 queries , Gzip On, Memcache On.

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

分享到