<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[samp | open.mp 联机社区论坛 - 库]]></title>
		<link>https://open-mp.cn/</link>
		<description><![CDATA[samp | open.mp 联机社区论坛 - https://open-mp.cn]]></description>
		<pubDate>Mon, 04 May 2026 12:37:57 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[[转发][库] tdialogs 异步处理对话框]]></title>
			<link>https://open-mp.cn/showthread.php?tid=12</link>
			<pubDate>Mon, 02 Mar 2026 12:46:03 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=12</guid>
			<description><![CDATA[<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">tdialogs</span></span><br />
<br />
tdialogs 是一个库，它通过 PawnPlus 任务系统的强大功能，提供了多种函数来在 open.mp 服务器中异步处理对话框响应。<br />
<br />
作者: TommyB123<br />
GitHub地址: <a href="https://github.com/TommyB123/tdialogs" target="_blank" rel="noopener" class="mycode_url">https://github.com/TommyB123/tdialogs</a><br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">依赖项</span></span><br />
<br />
本库需要以下依赖项。 * <a href="https://github.com/IS4Code/PawnPlus" target="_blank" rel="noopener" class="mycode_url">PawnPlus</a> * <a href="https://github.com/Y-Less/sscanf" target="_blank" rel="noopener" class="mycode_url">sscanf</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b">安装</span><br />
<br />
只需安装到您的项目中：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>sampctl install TommyB123/tdialogs</code></div></div><br />
在您的代码中包含并开始使用该库：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;tdialogs&gt;</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">介绍</span></span><br />
<br />
如上所述，tdialogs 是一个基于 PawnPlus 的库，可用于在单个 PAWN 函数中异步处理对话框响应。这里有一个简单的示例。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyCoolFunction()<br />
{<br />
    yield 1;<br />
    new response[DIALOG_RESPONSE];<br />
    await_arr(response) ShowAsyncDialog(playerid, DIALOG_STYLE_LIST, "酷炫对话框", "条目 1&#92;n条目 2&#92;n条目 3", "不错！", "返回");<br />
    if(response[DIALOG_RESPONSE_RESPONSE])<br />
    {<br />
        SendClientMessage(playerid, -1, "您点击了第 %i 行，并收到了消息：%s",<br />
            response[DIALOG_RESPONSE_LISTITEM], response[DIALOG_RESPONSE_INPUTTEXT]); // 值可能分别为 1 和 "条目 2"<br />
    }<br />
    else<br />
    {<br />
        SendClientMessage(playerid, -1, "您关闭了对话框");<br />
    }<br />
}</code></div></div><br />
如果您熟悉所有可用的对话框处理库，您可能会想知道这个库与它们有何不同。简单的答案是，我包含了大量函数来快速从对话框响应中获取特定/单个值。您只需要显示一个快速的是/否确认对话框吗？没问题。使用 ShowAsyncConfirmationDialog。需要从游戏内商店购买用户输入的数量吗？ShowAsyncNumberInputDialog 可以满足您的要求。示例用法可以在<a href="https://github.com/TommyB123/tdialogs?tab=readme-ov-file#examples" target="_blank" rel="noopener" class="mycode_url">这里</a>找到。<br />
<br />
从 1.1.0 版本开始，自动分页对话框也被包含在内，可以通过 AddPaginatedDialogRow 和 ShowAsyncPaginatedDialog 创建。完整的函数参数和示例如下。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">对话框数据</span><br />
<br />
tdialogs 还有一个虽小但实用的功能，用于在整个对话框流程中跟踪 ID 或其他数据。每个玩家在登录时都会获得一个动态的 <a href="https://github.com/IS4Code/PawnPlus/wiki/Lists" target="_blank" rel="noopener" class="mycode_url">PawnPlus 列表</a> 分配给他们。这个列表可用于存储诸如房屋索引、车辆 ID 或其他与对话框内文本行匹配的数据。这样做是为了保留标识符，并避免进行不必要的循环查找或其他成本较高的方法来获取您已经找到的数据。<br />
<br />
除了这个列表之外，还有一个专门结合其使用而设计的对话框函数。当您格式化了一个对话框并将相应的实体 ID（例如房屋 ID）推送到 DialogData 列表后，可以使用 ShowAsyncEntityIndexDialog 通过一行代码获取玩家点击的房屋 ID。您可以在下面的示例部分看到它的实际应用。<br />
<br />
需要注意的是，在显示新对话框之前，<span style="font-weight: bold;" class="mycode_b">必须</span>使用 list_clear 清理该列表。否则，先前显示的对话框中的数据会混入后续的对话框显示中。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">常量</span></span><br />
<br />
<br />
 常量                                              默认值                               描述 <ul class="mycode_list"><li>TDIALOG_DIALOG_ID_BEGIN           1234                                  该库为每种对话框类型（不要与对话框样式混淆）预留了 9 个对话框 ID TDIALOG_DIALOG_ID_BEGIN 是第一个将被使用的 ID，随后依次是接下来的 8 个数字。请注意您已有的任何对话框 ID 并相应地进行调整<br />
</li>
<li>PAGINATED_NEXT_TEXT                 "--&gt; 下一页"                        当分页对话框提示您查看下一页时将显示的字符串。[/td][/tr]<br />
</li>
<li>PAGINATED_PREVIOUS_TEXT          "&lt;-- 上一页"                        当您在分页对话框中可以返回上一页时将显示的字符串。[/td][/tr]<br />
</li>
</ul>
<br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">前提条件</span></span><br />
<br />
建议您在包含 PawnPlus <span style="font-weight: bold;" class="mycode_b">之前</span>添加 #define PP_SYNTAX_AWAIT。这允许您使用本库编写时所考虑的正确的 await 方法。<br />
<br />
同时建议也添加 #define PP_SYNTAX_YIELD。这是 task_yield 的一个快速别名，用于在函数等待任务时将临时值让出给函数。例如，如果您在命令中没有 yield 1;，您很可能会在聊天中收到错误的未知命令错误。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">函数</span></span><br />
<br />
以下所有函数都有 PawnPlus 字符串变体。ShowAsyncDialog 对应 ShowAsyncDialog_s，以此类推。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowPlayerDialog_s(playerid, dialogid, DIALOG_STYLE:style, ConstAmxString:title, ConstAmxString:body, const button1[], const button2[])</code></div></div><br />
ShowPlayerDialog 的简单 PawnPlus 字符串封装。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncDialog(playerid, DIALOG_STYLE:style, const title[], const body[], const button1[], const button2[] = "")</code></div></div><br />
显示一个异步对话框，返回完整的对话框响应数组。<br />
<br />
与 await_arr(response) ShowAsyncDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncNumberInputDialog(playerid, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个专门用于解析数字输入的异步对话框。<br />
<br />
如果未接收到整数，对话框将简单地再次显示。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回 cellmin。<br />
<br />
与 new number = await ShowAsyncNumberInputDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncFloatInputDialog(playerid, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个专门用于解析数字输入的异步对话框。<br />
<br />
如果未接收到浮点数，对话框将简单地再次显示。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回 FLOAT_NAN。<br />
<br />
与 new Float:number = Float:await ShowAsyncFloatInputDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncStringInputDialog(playerid, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个专门用于解析字符串输入的异步对话框。<br />
<br />
如果接收到空字符串，对话框将简单地再次显示。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回空字符串。使用 isnull 进行检查。<br />
<br />
与 await_str(string) ShowAsyncStringInputDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncPasswordDialog(playerid, const title[], const body[], const button1[], const button2[])</code></div></div><br />
与 ShowAsyncStringInputDialog 相同，但使用密码对话框样式。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncListitemTextDialog(playerid, DIALOG_STYLE:style, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个异步对话框，仅返回通过列表项传递的文本。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回空字符串。使用 isnull 进行检查。<br />
<br />
与 await_str(string) ShowAsyncListitemTextDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncListitemIndexDialog(playerid, DIALOG_STYLE:style, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个异步对话框，仅返回被点击的列表项的索引。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回 -1。<br />
<br />
与 new index = await ShowAsyncListitemIndexDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncConfirmationDialog(playerid, const title[], const body[], const button1[], const button2[] = "")</code></div></div><br />
显示一个异步对话框，仅将响应状态作为布尔值返回。<br />
<br />
与 new bool:confirm = bool:await ShowAsyncConfirmationDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncEntityIndexDialog(playerid, DIALOG_STYLE:style, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个异步对话框，返回在玩家 DialogData <a href="https://github.com/IS4Code/PawnPlus/wiki/Lists" target="_blank" rel="noopener" class="mycode_url">列表</a>中位于 listitem 位置的值。在<a href="https://github.com/TommyB123/tdialogs/edit/main/README.md#dialog-data" target="_blank" rel="noopener" class="mycode_url">此处</a>或下面的示例中阅读更多信息。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回 -1。<br />
<br />
与 new id = await ShowAsyncEntityIndexDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncPaginatedDialog(playerid, DIALOG_STYLE:style, rows_per_page, const title[], const button1[], const button2[], const tablist_header_text[] = "")</code></div></div><br />
显示一个异步对话框，根据提供的每页行数对提供的文本进行分页。返回完整的对话框响应。<br />
<br />
此函数仅兼容 DIALOG_STYLE_TABLIST_HEADERS、DIALOG_STYLE_TABLIST 和 DIALOG_STYLE_LIST。<br />
<br />
tablist_header_text 参数仅用于 DIALOG_STYLE_TABLIST_HEADERS，顾名思义，是对话框的标题头文本。<br />
<br />
与 await_arr(response) ShowAsyncPaginatedDialog 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>AddPaginatedDialogRow(playerid, const text[], extraid = 0)</code></div></div><br />
向分页对话框添加一行。extraid 参数可用于传递与您追加的文本行相关的额外 ID。<br />
<br />
构建分页对话框时必需。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">示例</span></span><br />
<br />
这里有一些稍微深入一点的示例。<br />
<br />
快速确认用户是否想出售他们的房子。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>CMD:sellmyhouse(playerid)<br />
{<br />
    if(PlayerOwnsHouse(playerid))<br />
    {<br />
        task_yield(1);<br />
        new bool:confirm = bool:await ShowAsyncConfirmationDialog(playerid, "出售您的房子？", "您确定要出售您的房子吗？", "是", "否");<br />
        if(confirm)<br />
        {<br />
            SellPlayerHouse(playerid);<br />
        }<br />
    }<br />
}</code></div></div><br />
输入您想从商店购买多少鱼饵。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new baitamount = await ShowAsyncNumberInputDialog(playerid, "鱼饵数量", "在下面输入您想购买的鱼饵数量", "购买", "取消");<br />
if(baitamount == cellmin) return false; // 当玩家取消对话框时返回 cellmin<br />
if(baitamount &lt;= 0 || baitamount &gt; 10000)<br />
{<br />
    SendClientMessage(playerid, -1, "无效的鱼饵数量。");<br />
    return false;<br />
}<br />
GivePlayerFishBait(playerid, baitamount);<br />
return true;</code></div></div><br />
通过使用 DialogData 列表从对话框中解析出房屋 ID。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowHouseTeleportDialog(playerid)<br />
{<br />
    new string[256], substring[64];<br />
    list_clear(DialogData[playerid]); // 清空持久的 DialogData 列表，使其与我们即将显示的对话框中的行数匹配<br />
    for(new i = 0; i &lt; MAX_HOUSES; ++i)<br />
    {<br />
        if(HouseData[i][HouseOwner] == playerid)<br />
        {<br />
            // 将房屋名称追加到字符串，并将房屋索引添加到 DialogData 列表。<br />
            // 这样做是为了使房屋名称行与任意的房屋 ID 保持一致。<br />
            // 可能有 500 栋房子，但玩家只拥有其中少数（甚至一栋）。以这种方式存储<br />
            // 房屋索引让我们能够快速获取正确的 ID，而无需进行额外的、不必要的查找。<br />
            format(substring, sizeof(substring), "%s&#92;n", HouseData[i][HouseAddress]);<br />
            strcat(string, substring);<br />
            list_add(DialogData[playerid], i);<br />
        }<br />
    }<br />
    new houseid = await ShowAsyncEntityIndexDialog(playerid, DIALOG_STYLE_LIST, "传送到您的家", string, "传送！", "算了");<br />
    if(houseid != -1) // 如果玩家取消对话框，返回 -1<br />
    {<br />
        SetPlayerPos(playerid, HouseData[houseid][HouseX], HouseData[houseid][HouseY], HouseData[houseid][HouseZ]);<br />
    }<br />
}</code></div></div><br />
显示一个每页 10 行的分页对话框。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowOwnedVehiclesDialog(playerid)<br />
{<br />
    new string[128];<br />
    list_clear(DialogData[playerid]);<br />
    for(new i = 1; i &lt;= MAX_VEHICLES; ++i)<br />
    {<br />
        if(PlayerOwnsVehicle(playerid, i))<br />
        {<br />
            format(string, sizeof(string), "%s&#92;t%s&#92;n", ReturnVehicleName(i), ReturnVehicleLocation(i));<br />
            AddPaginatedDialogRow(playerid, string, i);<br />
        }<br />
    }<br />
    new response[DIALOG_RESPONSE];<br />
    await_arr(response) ShowAsyncPaginatedDialog(playerid, DIALOG_STYLE_TABLIST_HEADERS, 10, "您的车辆", "传送", "取消", "车辆&#92;t位置");<br />
    if(!response[DIALOG_RESPONSE_RESPONSE]) return false;<br />
    new vehicleid = response[DIALOG_RESPONSE_EXTRAID], Float:x, Float:y, Float:z;<br />
    GetVehiclePos(vehicleid, x, y, z);<br />
    SetPlayerPos(playerid, x, y, z);<br />
    SendClientMessage(playerid, -1, "您已传送到您的 %s", ReturnVehicleName(vehicleid));<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">致谢</span></span><br />
<br />
TommyB123<br />
<br />
特别感谢 <a href="https://github.com/AGraber" target="_blank" rel="noopener" class="mycode_url">Graber</a>。在使用他的原创 <a href="https://github.com/AGraber/samp-async-dialogs" target="_blank" rel="noopener" class="mycode_url">async dialogs</a> 库多年后，我才受到启发制作了自己的库。如果您不需要我的库提供的额外功能，可以考虑使用他的库。]]></description>
			<content:encoded><![CDATA[<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">tdialogs</span></span><br />
<br />
tdialogs 是一个库，它通过 PawnPlus 任务系统的强大功能，提供了多种函数来在 open.mp 服务器中异步处理对话框响应。<br />
<br />
作者: TommyB123<br />
GitHub地址: <a href="https://github.com/TommyB123/tdialogs" target="_blank" rel="noopener" class="mycode_url">https://github.com/TommyB123/tdialogs</a><br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">依赖项</span></span><br />
<br />
本库需要以下依赖项。 * <a href="https://github.com/IS4Code/PawnPlus" target="_blank" rel="noopener" class="mycode_url">PawnPlus</a> * <a href="https://github.com/Y-Less/sscanf" target="_blank" rel="noopener" class="mycode_url">sscanf</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b">安装</span><br />
<br />
只需安装到您的项目中：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>sampctl install TommyB123/tdialogs</code></div></div><br />
在您的代码中包含并开始使用该库：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;tdialogs&gt;</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">介绍</span></span><br />
<br />
如上所述，tdialogs 是一个基于 PawnPlus 的库，可用于在单个 PAWN 函数中异步处理对话框响应。这里有一个简单的示例。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyCoolFunction()<br />
{<br />
    yield 1;<br />
    new response[DIALOG_RESPONSE];<br />
    await_arr(response) ShowAsyncDialog(playerid, DIALOG_STYLE_LIST, "酷炫对话框", "条目 1&#92;n条目 2&#92;n条目 3", "不错！", "返回");<br />
    if(response[DIALOG_RESPONSE_RESPONSE])<br />
    {<br />
        SendClientMessage(playerid, -1, "您点击了第 %i 行，并收到了消息：%s",<br />
            response[DIALOG_RESPONSE_LISTITEM], response[DIALOG_RESPONSE_INPUTTEXT]); // 值可能分别为 1 和 "条目 2"<br />
    }<br />
    else<br />
    {<br />
        SendClientMessage(playerid, -1, "您关闭了对话框");<br />
    }<br />
}</code></div></div><br />
如果您熟悉所有可用的对话框处理库，您可能会想知道这个库与它们有何不同。简单的答案是，我包含了大量函数来快速从对话框响应中获取特定/单个值。您只需要显示一个快速的是/否确认对话框吗？没问题。使用 ShowAsyncConfirmationDialog。需要从游戏内商店购买用户输入的数量吗？ShowAsyncNumberInputDialog 可以满足您的要求。示例用法可以在<a href="https://github.com/TommyB123/tdialogs?tab=readme-ov-file#examples" target="_blank" rel="noopener" class="mycode_url">这里</a>找到。<br />
<br />
从 1.1.0 版本开始，自动分页对话框也被包含在内，可以通过 AddPaginatedDialogRow 和 ShowAsyncPaginatedDialog 创建。完整的函数参数和示例如下。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">对话框数据</span><br />
<br />
tdialogs 还有一个虽小但实用的功能，用于在整个对话框流程中跟踪 ID 或其他数据。每个玩家在登录时都会获得一个动态的 <a href="https://github.com/IS4Code/PawnPlus/wiki/Lists" target="_blank" rel="noopener" class="mycode_url">PawnPlus 列表</a> 分配给他们。这个列表可用于存储诸如房屋索引、车辆 ID 或其他与对话框内文本行匹配的数据。这样做是为了保留标识符，并避免进行不必要的循环查找或其他成本较高的方法来获取您已经找到的数据。<br />
<br />
除了这个列表之外，还有一个专门结合其使用而设计的对话框函数。当您格式化了一个对话框并将相应的实体 ID（例如房屋 ID）推送到 DialogData 列表后，可以使用 ShowAsyncEntityIndexDialog 通过一行代码获取玩家点击的房屋 ID。您可以在下面的示例部分看到它的实际应用。<br />
<br />
需要注意的是，在显示新对话框之前，<span style="font-weight: bold;" class="mycode_b">必须</span>使用 list_clear 清理该列表。否则，先前显示的对话框中的数据会混入后续的对话框显示中。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">常量</span></span><br />
<br />
<br />
 常量                                              默认值                               描述 <ul class="mycode_list"><li>TDIALOG_DIALOG_ID_BEGIN           1234                                  该库为每种对话框类型（不要与对话框样式混淆）预留了 9 个对话框 ID TDIALOG_DIALOG_ID_BEGIN 是第一个将被使用的 ID，随后依次是接下来的 8 个数字。请注意您已有的任何对话框 ID 并相应地进行调整<br />
</li>
<li>PAGINATED_NEXT_TEXT                 "--&gt; 下一页"                        当分页对话框提示您查看下一页时将显示的字符串。[/td][/tr]<br />
</li>
<li>PAGINATED_PREVIOUS_TEXT          "&lt;-- 上一页"                        当您在分页对话框中可以返回上一页时将显示的字符串。[/td][/tr]<br />
</li>
</ul>
<br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">前提条件</span></span><br />
<br />
建议您在包含 PawnPlus <span style="font-weight: bold;" class="mycode_b">之前</span>添加 #define PP_SYNTAX_AWAIT。这允许您使用本库编写时所考虑的正确的 await 方法。<br />
<br />
同时建议也添加 #define PP_SYNTAX_YIELD。这是 task_yield 的一个快速别名，用于在函数等待任务时将临时值让出给函数。例如，如果您在命令中没有 yield 1;，您很可能会在聊天中收到错误的未知命令错误。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">函数</span></span><br />
<br />
以下所有函数都有 PawnPlus 字符串变体。ShowAsyncDialog 对应 ShowAsyncDialog_s，以此类推。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowPlayerDialog_s(playerid, dialogid, DIALOG_STYLE:style, ConstAmxString:title, ConstAmxString:body, const button1[], const button2[])</code></div></div><br />
ShowPlayerDialog 的简单 PawnPlus 字符串封装。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncDialog(playerid, DIALOG_STYLE:style, const title[], const body[], const button1[], const button2[] = "")</code></div></div><br />
显示一个异步对话框，返回完整的对话框响应数组。<br />
<br />
与 await_arr(response) ShowAsyncDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncNumberInputDialog(playerid, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个专门用于解析数字输入的异步对话框。<br />
<br />
如果未接收到整数，对话框将简单地再次显示。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回 cellmin。<br />
<br />
与 new number = await ShowAsyncNumberInputDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncFloatInputDialog(playerid, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个专门用于解析数字输入的异步对话框。<br />
<br />
如果未接收到浮点数，对话框将简单地再次显示。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回 FLOAT_NAN。<br />
<br />
与 new Float:number = Float:await ShowAsyncFloatInputDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncStringInputDialog(playerid, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个专门用于解析字符串输入的异步对话框。<br />
<br />
如果接收到空字符串，对话框将简单地再次显示。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回空字符串。使用 isnull 进行检查。<br />
<br />
与 await_str(string) ShowAsyncStringInputDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncPasswordDialog(playerid, const title[], const body[], const button1[], const button2[])</code></div></div><br />
与 ShowAsyncStringInputDialog 相同，但使用密码对话框样式。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncListitemTextDialog(playerid, DIALOG_STYLE:style, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个异步对话框，仅返回通过列表项传递的文本。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回空字符串。使用 isnull 进行检查。<br />
<br />
与 await_str(string) ShowAsyncListitemTextDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncListitemIndexDialog(playerid, DIALOG_STYLE:style, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个异步对话框，仅返回被点击的列表项的索引。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回 -1。<br />
<br />
与 new index = await ShowAsyncListitemIndexDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncConfirmationDialog(playerid, const title[], const body[], const button1[], const button2[] = "")</code></div></div><br />
显示一个异步对话框，仅将响应状态作为布尔值返回。<br />
<br />
与 new bool:confirm = bool:await ShowAsyncConfirmationDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncEntityIndexDialog(playerid, DIALOG_STYLE:style, const title[], const body[], const button1[], const button2[])</code></div></div><br />
显示一个异步对话框，返回在玩家 DialogData <a href="https://github.com/IS4Code/PawnPlus/wiki/Lists" target="_blank" rel="noopener" class="mycode_url">列表</a>中位于 listitem 位置的值。在<a href="https://github.com/TommyB123/tdialogs/edit/main/README.md#dialog-data" target="_blank" rel="noopener" class="mycode_url">此处</a>或下面的示例中阅读更多信息。<br />
<br />
如果玩家关闭对话框/按下 ESC，则返回 -1。<br />
<br />
与 new id = await ShowAsyncEntityIndexDialog(...) 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowAsyncPaginatedDialog(playerid, DIALOG_STYLE:style, rows_per_page, const title[], const button1[], const button2[], const tablist_header_text[] = "")</code></div></div><br />
显示一个异步对话框，根据提供的每页行数对提供的文本进行分页。返回完整的对话框响应。<br />
<br />
此函数仅兼容 DIALOG_STYLE_TABLIST_HEADERS、DIALOG_STYLE_TABLIST 和 DIALOG_STYLE_LIST。<br />
<br />
tablist_header_text 参数仅用于 DIALOG_STYLE_TABLIST_HEADERS，顾名思义，是对话框的标题头文本。<br />
<br />
与 await_arr(response) ShowAsyncPaginatedDialog 一起使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>AddPaginatedDialogRow(playerid, const text[], extraid = 0)</code></div></div><br />
向分页对话框添加一行。extraid 参数可用于传递与您追加的文本行相关的额外 ID。<br />
<br />
构建分页对话框时必需。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">示例</span></span><br />
<br />
这里有一些稍微深入一点的示例。<br />
<br />
快速确认用户是否想出售他们的房子。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>CMD:sellmyhouse(playerid)<br />
{<br />
    if(PlayerOwnsHouse(playerid))<br />
    {<br />
        task_yield(1);<br />
        new bool:confirm = bool:await ShowAsyncConfirmationDialog(playerid, "出售您的房子？", "您确定要出售您的房子吗？", "是", "否");<br />
        if(confirm)<br />
        {<br />
            SellPlayerHouse(playerid);<br />
        }<br />
    }<br />
}</code></div></div><br />
输入您想从商店购买多少鱼饵。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new baitamount = await ShowAsyncNumberInputDialog(playerid, "鱼饵数量", "在下面输入您想购买的鱼饵数量", "购买", "取消");<br />
if(baitamount == cellmin) return false; // 当玩家取消对话框时返回 cellmin<br />
if(baitamount &lt;= 0 || baitamount &gt; 10000)<br />
{<br />
    SendClientMessage(playerid, -1, "无效的鱼饵数量。");<br />
    return false;<br />
}<br />
GivePlayerFishBait(playerid, baitamount);<br />
return true;</code></div></div><br />
通过使用 DialogData 列表从对话框中解析出房屋 ID。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowHouseTeleportDialog(playerid)<br />
{<br />
    new string[256], substring[64];<br />
    list_clear(DialogData[playerid]); // 清空持久的 DialogData 列表，使其与我们即将显示的对话框中的行数匹配<br />
    for(new i = 0; i &lt; MAX_HOUSES; ++i)<br />
    {<br />
        if(HouseData[i][HouseOwner] == playerid)<br />
        {<br />
            // 将房屋名称追加到字符串，并将房屋索引添加到 DialogData 列表。<br />
            // 这样做是为了使房屋名称行与任意的房屋 ID 保持一致。<br />
            // 可能有 500 栋房子，但玩家只拥有其中少数（甚至一栋）。以这种方式存储<br />
            // 房屋索引让我们能够快速获取正确的 ID，而无需进行额外的、不必要的查找。<br />
            format(substring, sizeof(substring), "%s&#92;n", HouseData[i][HouseAddress]);<br />
            strcat(string, substring);<br />
            list_add(DialogData[playerid], i);<br />
        }<br />
    }<br />
    new houseid = await ShowAsyncEntityIndexDialog(playerid, DIALOG_STYLE_LIST, "传送到您的家", string, "传送！", "算了");<br />
    if(houseid != -1) // 如果玩家取消对话框，返回 -1<br />
    {<br />
        SetPlayerPos(playerid, HouseData[houseid][HouseX], HouseData[houseid][HouseY], HouseData[houseid][HouseZ]);<br />
    }<br />
}</code></div></div><br />
显示一个每页 10 行的分页对话框。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowOwnedVehiclesDialog(playerid)<br />
{<br />
    new string[128];<br />
    list_clear(DialogData[playerid]);<br />
    for(new i = 1; i &lt;= MAX_VEHICLES; ++i)<br />
    {<br />
        if(PlayerOwnsVehicle(playerid, i))<br />
        {<br />
            format(string, sizeof(string), "%s&#92;t%s&#92;n", ReturnVehicleName(i), ReturnVehicleLocation(i));<br />
            AddPaginatedDialogRow(playerid, string, i);<br />
        }<br />
    }<br />
    new response[DIALOG_RESPONSE];<br />
    await_arr(response) ShowAsyncPaginatedDialog(playerid, DIALOG_STYLE_TABLIST_HEADERS, 10, "您的车辆", "传送", "取消", "车辆&#92;t位置");<br />
    if(!response[DIALOG_RESPONSE_RESPONSE]) return false;<br />
    new vehicleid = response[DIALOG_RESPONSE_EXTRAID], Float:x, Float:y, Float:z;<br />
    GetVehiclePos(vehicleid, x, y, z);<br />
    SetPlayerPos(playerid, x, y, z);<br />
    SendClientMessage(playerid, -1, "您已传送到您的 %s", ReturnVehicleName(vehicleid));<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">致谢</span></span><br />
<br />
TommyB123<br />
<br />
特别感谢 <a href="https://github.com/AGraber" target="_blank" rel="noopener" class="mycode_url">Graber</a>。在使用他的原创 <a href="https://github.com/AGraber/samp-async-dialogs" target="_blank" rel="noopener" class="mycode_url">async dialogs</a> 库多年后，我才受到启发制作了自己的库。如果您不需要我的库提供的额外功能，可以考虑使用他的库。]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[库][分享转发] sa-mp/pawn 标准库包]]></title>
			<link>https://open-mp.cn/showthread.php?tid=8</link>
			<pubDate>Sat, 28 Feb 2026 14:39:44 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=8</guid>
			<description><![CDATA[<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">samp-stdlib | pawn-stdlib</span></span><br />
<br />
默认 sa-mp 服务器包含文件的更新版本。支持const校验、文档齐全且完整<br />
<br />
<span style="font-weight: bold;" class="mycode_b">下载地址: </span><br />
<br />
 - <a href="https://github.com/pawn-lang/pawn-stdlib" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/pawn-stdlib</a><br />
<br />
 - <a href="https://github.com/pawn-lang/samp-stdlib" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/samp-stdlib</a><br />
<br />
San Andreas Multiplayer Pawn 标准库包 - 专为 <a href="http://sampctl.com" target="_blank" rel="noopener" class="mycode_url">sampctl 包管理系统</a> 设计。<br />
<br />
当前最新版本为 <span style="font-weight: bold;" class="mycode_b">0.3.7-R2-2-1 | 0.3.DL-R1</span><br />
<br />
master 分支头部目前不包含任何 RC 库。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">为什么？</span><br />
<br />
sampctl 工具内置的包管理系统基于 GitHub（类似于 Go 语言），因此将标准库也存储在 GitHub 上可以简化流程。这意味着不需要为标准库编写任何特殊代码，它可以像其他所有包一样只是一个普通包。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">版本如何运作？</span><br />
<br />
<span style="text-decoration: underline;" class="mycode_u">版本通过 <a href="https://help.github.com/articles/working-with-tags/" target="_blank" rel="noopener" class="mycode_url">Git 标签</a> 表示</span><br />
<br />
使用 sampctl 时始终指定一个版本。要依赖最新版本，只需在依赖项中使用 sampctl/samp-stdlib:0.3.7-R2-2-1。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">发布候选版本（RC）期间会发生什么？</span><br />
<br />
master 分支将包含 RC 库（如果存在活跃的 RC）。最近的 RC 是 0.3.8，但由于该版本已取消，此代码库不包含任何 0.3.8 RC 库。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">版本标签与 <a href="https://github.com/Southclaws/sampctl/wiki/Dependencies#versioning" target="_blank" rel="noopener" class="mycode_url">sampctl</a> 完全兼容</span><br />
<br />
<a href="http://bit.ly/sampctl" target="_blank" rel="noopener" class="mycode_url">sampctl</a> 简化了版本控制，此代码库的存在是为了帮助使用多个 SA:MP 服务器版本的 sampctl 用户。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">版本起始于 0.3z（具体为 0.3z-R1）</span><br />
<br />
0.3z 是 <a href="http://bit.ly/sampctl" target="_blank" rel="noopener" class="mycode_url">sampctl</a> 支持的最早版本。大多数服务器使用最新版本，因此似乎没有必要归档每个 SA:MP 库版本。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">某些标签指向同一提交</span><br />
<br />
有些版本仅更改了服务器的内部机制，从未涉及库文件。在这些情况下，版本标签仍存在于该代码库中，但它们仅指向同一提交。]]></description>
			<content:encoded><![CDATA[<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">samp-stdlib | pawn-stdlib</span></span><br />
<br />
默认 sa-mp 服务器包含文件的更新版本。支持const校验、文档齐全且完整<br />
<br />
<span style="font-weight: bold;" class="mycode_b">下载地址: </span><br />
<br />
 - <a href="https://github.com/pawn-lang/pawn-stdlib" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/pawn-stdlib</a><br />
<br />
 - <a href="https://github.com/pawn-lang/samp-stdlib" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/samp-stdlib</a><br />
<br />
San Andreas Multiplayer Pawn 标准库包 - 专为 <a href="http://sampctl.com" target="_blank" rel="noopener" class="mycode_url">sampctl 包管理系统</a> 设计。<br />
<br />
当前最新版本为 <span style="font-weight: bold;" class="mycode_b">0.3.7-R2-2-1 | 0.3.DL-R1</span><br />
<br />
master 分支头部目前不包含任何 RC 库。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">为什么？</span><br />
<br />
sampctl 工具内置的包管理系统基于 GitHub（类似于 Go 语言），因此将标准库也存储在 GitHub 上可以简化流程。这意味着不需要为标准库编写任何特殊代码，它可以像其他所有包一样只是一个普通包。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">版本如何运作？</span><br />
<br />
<span style="text-decoration: underline;" class="mycode_u">版本通过 <a href="https://help.github.com/articles/working-with-tags/" target="_blank" rel="noopener" class="mycode_url">Git 标签</a> 表示</span><br />
<br />
使用 sampctl 时始终指定一个版本。要依赖最新版本，只需在依赖项中使用 sampctl/samp-stdlib:0.3.7-R2-2-1。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">发布候选版本（RC）期间会发生什么？</span><br />
<br />
master 分支将包含 RC 库（如果存在活跃的 RC）。最近的 RC 是 0.3.8，但由于该版本已取消，此代码库不包含任何 0.3.8 RC 库。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">版本标签与 <a href="https://github.com/Southclaws/sampctl/wiki/Dependencies#versioning" target="_blank" rel="noopener" class="mycode_url">sampctl</a> 完全兼容</span><br />
<br />
<a href="http://bit.ly/sampctl" target="_blank" rel="noopener" class="mycode_url">sampctl</a> 简化了版本控制，此代码库的存在是为了帮助使用多个 SA:MP 服务器版本的 sampctl 用户。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">版本起始于 0.3z（具体为 0.3z-R1）</span><br />
<br />
0.3z 是 <a href="http://bit.ly/sampctl" target="_blank" rel="noopener" class="mycode_url">sampctl</a> 支持的最早版本。大多数服务器使用最新版本，因此似乎没有必要归档每个 SA:MP 库版本。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">某些标签指向同一提交</span><br />
<br />
有些版本仅更改了服务器的内部机制，从未涉及库文件。在这些情况下，版本标签仍存在于该代码库中，但它们仅指向同一提交。]]></content:encoded>
		</item>
	</channel>
</rss>