Porting to open.mp
Từ lâu, rõ ràng là Kalcor không còn hứng thú với việc duy trì SA:MP nữa; bản thân điều này là tốt, nhưng với tư cách là người duy nhất có quyền truy cập mã nguồn chính thức, điều này khiến anh trở thành nút thắt cổ chai đối với các bản cập nhật mới. Cả YSF và fixs.inc đều được tạo ra để lấp đầy khoảng trống này - sửa lỗi và sự không nhất quán trong máy chủ mà không cần quyền truy cập mã nguồn; cái trước là plugin và cái sau là include. Mặc dù đã có một số nỗ lực to lớn để làm cho các dự án này (và các dự án khác) trở nên ổn định, toàn diện và dễ sử dụng nhất có thể, nhưng chúng tự nhiên bắt đầu chạm đến giới hạn của mình và cần một thế hệ bản sửa lỗi mới. Đây chính là lúc open.mp xuất hiện.
Được thành lập trên cùng một nguyên tắc và áp dụng tất cả vô số cải tiến được cộng đồng phát triển trong hơn một thập kỷ, open.mp là bản viết lại từ đầu của máy chủ SA:MP ban đầu với tất cả các bản sửa lỗi từ các phiên bản tiền nhiệm trực tiếp của nó và nhiều bản sửa lỗi khác không thể quản lý hoặc hoàn toàn không thể thực hiện được. Phải thừa nhận rằng cách tiếp cận này không phải là không có tranh cãi - một số máy chủ đã phát triển các phương pháp riêng để xử lý các điểm kỳ quặc của SA:MP mà không phụ thuộc vào nỗ lực của cộng đồng, nhưng đây không phải là các kỹ thuật mà mọi người viết kịch bản đều phải tự phát triển và bài viết này sẽ giúp ích cho việc chuyển mã hiện có.
Chúng tôi hy vọng sẽ giải quyết được các điểm mấu chốt chính, nhưng nếu có bất kỳ điểm nào chúng tôi bỏ sót, hãy thoải mái liên hệ qua discord hoặc github và chúng tôi sẽ rất vui lòng sửa đổi hướng dẫn.
Tùy chọn thay thế là hoàn tác các bản sửa lỗi bằng cách sử dụng thư viện song sinh với fixing.inc - breaks.inc:
https://github.com/pawn-lang/sa-mp-fixes/blob/master/breaks.inc
Vì vậy, hãy thoải mái cài đặt nó để quay lại tất cả các hành vi cũ một cách minh bạch thông qua các móc.
Tags
open.mp bao gồm thêm nhiều thẻ mới vào các chức năng, mặc dù vẫn cố gắng cân bằng giữa các nâng cấp rất cần thiết và tính xâm lấn. Do những thay đổi này có thể lan rộng nên chúng tôi đã viết một công cụ để tự động hóa nhiều thay đổi:
HideMenuForPlayer
Hàm này luôn lấy tham số ID menu, nhưng trong SA:MP, ID này không được sử dụng. Vì vậy, bất kỳ giá trị nào được đưa ra, menu hiện tại của người chơi sẽ bị đóng, ngay cả khi họ không nhìn vào menu mà bạn yêu cầu đóng.
Mã cũ có thể trông như sau:
gShopMenu = CreateMenu("text", 2, 100.0, 30.0, 7.0);
HideMenuForPlayer(gShopMenu, playerid);
Điều đó sẽ luôn đóng menu hiện tại của người chơi, bất kể họ thực sự đang nhìn vào menu nào. Bây giờ bạn sẽ cần phải nhớ họ đang nhìn vào menu nào hoặc chỉ cần lấy nó:
gShopMenu = CreateMenu("text", 2, 100.0, 30.0, 7.0);
HideMenuForPlayer(GetPlayerMenu(playerid), playerid);
SetPlayerAttachedObject
Các đối tượng đính kèm trong SA:MP sẽ tồn tại sau khi thay đổi chế độ chơi, nhưng trong open.mp thì không. Nếu bạn muốn người chơi giữ lại các đối tượng của họ khi khởi động lại chế độ, bạn sẽ phải thêm lại chúng trong 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]
);
}
}
ClearAnimations
ClearAnimations
là hàm kép của ApplyAnimation
để ngăn người chơi thực hiện hành động đã yêu cầu trước đó. Tuy nhiên, khi sử dụng trên người chơi trong xe, hàm này cũng sẽ khiến người chơi bị loại khỏi xe. Đây là một hàm hữu ích, vì nó xảy ra ngay lập tức, nhưng không nằm trong phạm vi của hàm ClearAnimations
. Để buộc người chơi rời khỏi xe ngay lập tức, hãy sử dụng:
RemovePlayerFromVehicle(playerid, true);
Death money
Khi một người chơi chết trong San Andreas, họ sẽ bị trừ 100 đô la để tự động chi trả hóa đơn viện phí. Tính năng này vẫn còn trong SA:MP, nhưng đã bị xóa khỏi open.mp để cho phép các tập lệnh tự quản lý toàn bộ số tiền của mình. Một số tập lệnh đã cố gắng khắc phục lỗi này bằng cách thêm 100 đô la cho người chơi sau khi chết hoặc khi xuất hiện. Nếu đây là tập lệnh của bạn, chỉ cần xóa bản sửa lỗi bổ sung, mặc dù mã trong open.mp có cố gắng tính đến các tập lệnh thực hiện việc này. Nếu tập lệnh của bạn dựa vào tính năng này, chỉ cần thêm mã sau vào OnPlayerDeath
:
GivePlayerMoney(playerid, -100);
OnPlayerConnect
Khi một chế độ chơi bắt đầu hoặc khởi động lại trong SA:MP, OnPlayerConnect
được gọi ngay lập tức cho tất cả người chơi đã kết nối với máy chủ, nhưng không phải khi một tập lệnh lọc bắt đầu hoặc khởi động lại. Trong khi hành vi sau này phù hợp hơn với tên, hành vi trước đây được khai thác cực kỳ rộng rãi trong các tập lệnh và do đó đã được mở rộng cho tất cả các loại tập lệnh trong open.mp để duy trì tính nhất quán.
Các tập lệnh khởi tạo dữ liệu cho người chơi không còn cần phải thực hiện mã này ở hai vị trí khác nhau nữa:
public OnFilterScriptInit()
{
for (new playerid = 0; playerid != MAX_PLAYERS; ++playerid)
{
if (IsPlayerConnected(playerid))
{
InitialisePlayer(playerid);
}
}
}
public OnPlayerConnect(playerid)
{
InitialisePlayer(playerid);
}
Vòng lặp trong OnFilterScriptInit
hiện có thể bị xóa:
public OnPlayerConnect(playerid)
{
InitialisePlayer(playerid);
}
Nếu một tập lệnh khai thác thực tế này để chỉ chạy mã cho những người chơi mới tham gia máy chủ sau khi tập lệnh bắt đầu, chứ không phải cho những người đã tham gia trước đó, thì điều này sẽ không còn hiệu quả nữa, nhưng cũng có thể dễ dàng sửa lỗi này:
static bool:gAlreadyHere[MAX_PLAYERS];
public OnFilterScriptInit()
{
for (new playerid = 0; playerid != MAX_PLAYERS; ++playerid)
{
gAlreadyHere[playerid] = IsPlayerConnected(playerid);
}
}
public OnPlayerConnect(playerid)
{
if (gAlreadyHere[playerid])
{
gAlreadyHere[playerid] = false;
}
else
{
SendClientMessage(playerid, COLOUR_WARN, "You're late!");
}
}
Điều này có thể chỉ đơn giản là đổi một vòng lặp trong OnFilterScriptInit
thành một vòng lặp khác, nhưng việc muốn loại trừ những người chơi hiện tại khỏi một số mã là trường hợp sử dụng ít phổ biến hơn so với việc muốn làm điều gì đó cho tất cả mọi người, do đó, nhìn chung đây là một cải tiến ròng; và như đã nêu trước đây, ít xâm lấn hơn nhiều so với việc không gọi OnPlayerConnect
trong chế độ trò chơi.
Game texts
SA:MP có sáu kiểu văn bản trò chơi khác nhau, nhưng một số trong số chúng về cơ bản là không sử dụng được. Một kiểu liên tục mờ dần, một kiểu biến mất sau một khoảng thời gian nhất định bất kể thời gian bạn đặt và một kiểu không bao giờ biến mất bất kể thời gian đã chọn. Tuy nhiên, hóa ra tất cả các kiểu văn bản trò chơi này đều có thể được tái tạo chính xác bằng cách sử dụng các bản vẽ văn bản. Do đó, fixing.inc và sau đó là open.mp đã làm như vậy. Giao diện của các văn bản trò chơi vẫn giống như trước, ưu điểm là tất cả các kiểu đều có thể sử dụng được, nhược điểm là chúng không còn mờ dần nữa.
Hiện tại không có cách nào để bỏ qua tính năng này để có lại hiệu ứng mờ dần, ngoại trừ việc sử dụng Pawn.RakNet và gửi trực tiếp tin nhắn văn bản trò chơi:
FadingGameTextForPlayer(playerid, const format[], time, style)
{
if (style > 6)
{
// There's no fading version of these styles.
GameTextForPlayer(playerid, format, time, style)
}
else
{
// Send a raw message via Pawn.RakNet
}
}
* Ngoại trừ một ngoại lệ đáng chú ý - phong cách văn bản trò chơi đồng hồ mới. Vì một lý do nào đó không rõ, màu sắc của đồng hồ khác nhau đối với những người khác nhau, dẫn đến nhiều cuộc thảo luận qua lại về cách tốt nhất để sao chép phong cách này cho đến khi tìm ra sự khác biệt. Chúng tôi phải chọn một trong hai để thống nhất.
Pool sizes
GetPlayerPoolSize
, GetActorPoolSize
và GetVehiclePoolSize
có phần vô nghĩa khi chúng mới được giới thiệu; trả về ID được kết nối cao nhất, không liên quan đến số lượng người chơi được kết nối và rất lâu sau khi các phương pháp lặp tốt hơn nhiều đã tồn tại. Việc hơi ngớ ngẩn không phải là lý do để xóa các hàm, nhưng thật không may, chúng cũng bị hỏng và trả về dữ liệu không chính xác khi không có người chơi nào được kết nối. Không có cách nào để sửa các giá trị trả về này theo cách vừa tương thích ngược vừa chính xác khi tiến về phía trước (tin tôi đi, chúng tôi đã thử). Với những sự thật này, chúng tôi đã chọn cách xóa các hàm. Chỉ cần sử dụng vòng lặp thông thường hoặc foreach
:
foreach (new i : Player)
{
}
Một số tập lệnh đã bị sập khi thay đổi này được đưa vào, nhưng chỉ khi sử dụng dạng vòng lặp sau:
for (new i = 0; i != GetPlayerPoolSize(); ++i)
{
}
Mặc dù giá trị cao nhất là một người chơi thực sự khi có người trực tuyến nhưng mã này vẫn sai - nó bỏ sót một người.
Spellings
SA:MP rất không nhất quán trong cách viết mã - một số thứ sử dụng tiếng Anh, một số thứ sử dụng tiếng Mỹ:
Bumper
- Tiếng AnhHood
- Tiếng MỹArmour
- Tiếng AnhStereo
- Tiếng Mỹ
Chúng tôi đã thống nhất những điều này và quyết định sử dụng cách viết tiếng Anh. Ví dụ:
TextDrawBoxColor(Text:textid, boxColor);
Bây giờ là:
TextDrawBoxColour(Text:textid, boxColour);
Công cụ nâng cấp sẽ tự động xử lý hầu hết những việc này.