跳到主要内容

迁移至 open.mp

· 阅读时间约6分钟
Y_Less

SA:MP 已停滞多年,毫无更新,且需要大量变通方案才能维持运行。open.mp 改变了这一现状——它是一个完整的重写版本,修复了长期存在的问题,改进了脚本功能,并移除了旧的限制,同时确保你现有代码的兼容性。但这对你来说究竟意味着什么?让我们来详细分解一下。

注意

以下内容已过时,且大部分与 open.mp 的当前状态无关。本文发布于此仅作归档用。

长期以来,Kalcor 不再维护 SA:MP 已是显而易见的事实;这本身无可厚非,但作为唯一拥有官方源代码访问权限的人,这使他成为了新版本更新的瓶颈。YSF 和 fixes.inc 的创建都是为了填补这一空白——即在无法访问源代码的情况下修复服务器中的错误和不一致;前者是插件,后者是包含文件。尽管这些(以及其他)项目付出了巨大的努力,力求尽可能稳定、全面且易于使用,但它们自然也开始遇到自身的极限,需要新一代的修复方案。这就是 open.mp 诞生的原因。

open.mp 秉承同样的理念,并汲取了社区十多年来开发的无数改进,是对原始 SA:MP 服务器的从头重写,包含其直接前身的所有修复,以及许多难以管理或根本不可能实现的修复。诚然,这种方法并非没有争议——一些服务器已经开发了自己私有的方法来应对 SA:MP 的特性,独立于社区的努力,但这些技术并非每个脚本编写者都应为自己重新开发的,本文将帮助迁移现有代码。

我们希望解决主要的难点,但如果我们遗漏了任何问题,请随时通过 Discord 或 GitHub 联系我们,我们将很乐意修改本指南。

另一种选择是使用一个与 fixes.inc 对应的库——breaks.inc,来撤销这些修复:

https://github.com/pawn-lang/sa-mp-fixes/blob/master/breaks.inc

因此,你可以自由安装它,通过钩子透明地恢复所有旧的行为。

标签(Tags)

open.mp 的包含文件为函数添加了许多新标签,但仍试图在急需的升级和侵入性之间取得平衡。由于这些变更可能影响广泛,我们编写了一个工具来自动化处理其中大部分工作:

HideMenuForPlayer

此函数一直带有一个菜单 ID 参数,但在 SA:MP 中,此 ID 并未被使用。因此,无论给定什么值,玩家的当前菜单都会被关闭,即使他们看的并不是你指定的那个菜单。

旧代码可能如下所示:

gShopMenu = CreateMenu("text", 2, 100.0, 30.0, 7.0);

HideMenuForPlayer(gShopMenu, playerid);

无论玩家实际在看哪个菜单,上述代码总会关闭其当前菜单。现在,你需要记住他们正在看哪个菜单,或者直接获取它:

gShopMenu = CreateMenu("text", 2, 100.0, 30.0, 7.0);

HideMenuForPlayer(GetPlayerMenu(playerid), playerid);

SetPlayerAttachedObject

在 SA:MP 中,附加的物件会在游戏模式变更后保留,但在 open.mp 中则不会。如果你希望玩家在模式重启后保留他们的物件,你需要在 OnPlayerConnect 中重新添加它们:

enum E_ATTACHMENT_DATA
{
E_ATTACHMENT_DATA_MODEL,
E_ATTACHMENT_DATA_BONE,
E_ATTACHMENT_DATA_OFFSET_X,
E_ATTACHMENT_DATA_OFFSET_Y,
E_ATTACHMENT_DATA_OFFSET_Z,
E_ATTACHMENT_DATA_ROT_X,
E_ATTACHMENT_DATA_ROT_Y,
E_ATTACHMENT_DATA_ROT_Z,
E_ATTACHMENT_DATA_SCALE_X,
E_ATTACHMENT_DATA_SCALE_Y,
E_ATTACHMENT_DATA_SCALE_Z,
E_ATTACHMENT_DATA_COLOUR_1,
E_ATTACHMENT_DATA_COLOUR_2,
}

public OnPlayerConnect(playerid)
{
for (new i = 0; i != MAX_OBJECT_ATTACHMENT_SLOTS; ++i)
{
SetPlayerAttachedObject(
playerid,
i,
gAttachementData[playerid][E_ATTACHMENT_DATA_MODEL],
gAttachementData[playerid][E_ATTACHMENT_DATA_BONE],
gAttachementData[playerid][E_ATTACHMENT_DATA_OFFSET_X],
gAttachementData[playerid][E_ATTACHMENT_DATA_OFFSET_Y],
gAttachementData[playerid][E_ATTACHMENT_DATA_OFFSET_Z],
gAttachementData[playerid][E_ATTACHMENT_DATA_ROT_X],
gAttachementData[playerid][E_ATTACHMENT_DATA_ROT_Y],
gAttachementData[playerid][E_ATTACHMENT_DATA_ROT_Z],
gAttachementData[playerid][E_ATTACHMENT_DATA_SCALE_X],
gAttachementData[playerid][E_ATTACHMENT_DATA_SCALE_Y],
gAttachementData[playerid][E_ATTACHMENT_DATA_SCALE_Z],
gAttachementData[playerid][E_ATTACHMENT_DATA_COLOUR_1],
gAttachementData[playerid][E_ATTACHMENT_DATA_COLOUR_2]
);
}
}

死亡金钱

在圣安地列斯中,当玩家死亡时,会自动扣除其 $100 作为医疗费。此特性在 SA:MP 中保留,但在 open.mp 中被移除,以便脚本可以完全管理自己的金钱。已有一些脚本试图通过在玩家死亡后或重生时增加 $100 来修复此问题。如果你的脚本属于这种情况,直接删除这个额外的修复即可,尽管 open.mp 中的代码确实尝试考虑到了执行此操作的脚本。如果你的脚本依赖于此特性,只需在 OnPlayerDeath 中添加以下代码:

GivePlayerMoney(playerid, -100);

游戏文本

SA:MP 有六种不同的游戏文本样式,但其中几种基本无法使用。一种会不断淡入淡出,一种无论你设置多长时间都会在固定时间后消失,还有一种无论选择多长时间都永远不会消失。然而,事实证明,所有这些游戏文本样式都可以通过文本绘图准确地1再现。因此 fixes.inc 以及随后的 open.mp 这样做了。游戏文本的外观与以前相同,优点是所有样式都可用,缺点是不再具有淡入淡出效果。

FadingGameTextForPlayer(playerid, const format[], time, style)
{
if (style > 6)
{
// 这些样式没有淡入淡出版本。
GameTextForPlayer(playerid, format, time, style)
}
else
{
// 通过 Pawn.RakNet 发送原始消息
}
}

池大小

GetPlayerPoolSizeGetActorPoolSizeGetVehiclePoolSize 在首次引入时有些多余;它们返回已连接的最高 ID,这与已连接玩家的数量无关,而且远在已有更好的循环方法出现之后。有点愚蠢本身并不是移除函数的理由,但不幸的是,当没有玩家连接时,它们也存在问题并返回错误数据。没有办法在既保持向后兼容性又确保未来正确性的情况下修复这些返回值(相信我,我们试过)。鉴于这些事实,我们选择直接移除这些函数。只需使用普通循环或 foreach

foreach (new i : Player)
{
}

引入此变更时,一些脚本确实会崩溃,但仅当使用以下循环形式时:

for (new i = 0; i != GetPlayerPoolSize(); ++i)
{
}

尽管当有玩家在线时,最高值是一个真实的玩家 ID,但这段代码本身就有问题——它漏掉了一个人。

拼写

SA:MP 在其代码拼写方面非常不一致——有些使用英式英语,有些使用美式英语:

  • Bumper - 英式
  • Hood - 美式
  • Armour - 英式
  • Stereo - 美式

我们已统一了这些拼写,并确定使用英式拼写。例如:

TextDrawBoxColor(Text:textid, boxColor);

现在是:

TextDrawBoxColour(Text:textid, boxColour);

升级工具将自动处理其中大部分更改。

Footnotes

  1. 有一个显著的例外——新的时钟游戏文本样式。出于未知的原因,时钟的颜色对不同的人显示不同,这导致在发现此差异之前,关于如何最好地复制此样式有很多来回的讨论。我们必须选择两者之一以保证一致性。