跳至正文
版本:bleeding-edge 🩸

事件指南

关于事件你需要了解的一切。

类事件​

在 nanos world 中,玩家或实体执行的所有操作都可以通过事件来获取。

最基本的事件例子是 Spawn(生成)。每当实体生成时,都会触发 Spawn 事件。

订阅类事件​

使用 :Subscribe() 方法注册事件非常简单直接。例如,我们想在有玩家加入服务器时获得通知:

Server/Index.lua
Player.Subscribe("Spawn", function(player)
Console.Log(player:GetName() .. " has joined!")
end)
信息

大多数事件都会在客户端和服务器端同时触发,只有少数例外情况,这些例外会在每个事件中的可用性图标中标出。

阻止操作​

某些事件会在某事发生之前触发,并允许你通过返回 false 来取消该操作。它们通常以 Attempt 开头,例如 AttemptEnterVehicle:

Server/Index.lua
-- 仅允许队伍 1 的 Character 驾驶载具
Character.Subscribe("AttemptEnterVehicle", function(character, vehicle, seat_index)
if (seat_index == 0 and character:GetTeam() ~= 1) then
return false
end
end)

退订类事件​

目前有两种退订事件的方法:

信息

注意: 退订事件将始终只会注销在你当前 Package 中注册的事件。

退订所有事件​

-- 这将注销在此 Package 中注册的所有 Player 的 "Spawn" 事件
Player.Unsubscribe("Spawn")

退订特定的事件回调​

-- 提前声明回调函数
function OnSpawnPlayer(player)
Console.Log(player:GetName() .. " has joined!")
end

-- 订阅事件并传入回调
Player.Subscribe("Spawn", OnSpawnPlayer)

-- 再次订阅同一个事件
Player.Subscribe("Spawn", function(player)
Console.Log(player:GetName() .. " has joined again!")
end)

-- 仅退订第一个回调
Player.Unsubscribe("Spawn", OnSpawnPlayer)

-- 这将继续触发 "player has joined again",但不再触发
-- "player has joined"
提示

Subscribe 会返回你传递的回调,因此你稍后也可以退订匿名函数:

local my_callback = Player.Subscribe("Spawn", function(player) end)
Player.Unsubscribe("Spawn", my_callback)

实体事件​

在 nanos world 中,你也可以为特定实体注册事件。这样一来,只有当该特定实体成为事件触发原因时,才会触发回调。

订阅实体事件​

Server/Index.lua
-- 生成一个 Character
local my_character = Character(Vector(0, 0, 100), Rotator(), "nanos-world::SK_Male")

my_character:Subscribe("EnterVehicle", function(self, vehicle)
-- my_character 进入了载具
end)
提示

请注意,一旦实体被销毁,为该实体注册的所有事件都会自动注销!

退订实体事件​

目前有两种退订事件的方法:

信息

注意: 退订事件将始终只会注销在你当前 Package 中注册的事件。

退订所有实体事件​

-- 这将注销在此 Package 中注册的该特定 Character 的所有 "EnterVehicle" 事件
my_character:Unsubscribe("EnterVehicle")

退订特定实体事件回调​

-- 提前声明回调函数
function OnCharacterEnteredVehicle(character, vehicle)
-- 进入了载具!
end

-- 订阅事件并传入回调
my_character:Subscribe("EnterVehicle", OnCharacterEnteredVehicle)

-- 再次订阅同一个事件
my_character:Subscribe("EnterVehicle", function(character, vehicle)
-- 再次进入了载具!
end)

-- 仅退订第一个回调
my_character:Unsubscribe("EnterVehicle", OnCharacterEnteredVehicle)

自定义事件​

在 nanos world 中,可以定义和调用自定义事件。技术文档请参考 Events 静态类。

自定义事件是由用户创建的事件,你可以向所有其他 Package 订阅或调用这些事件。它们有两种类型:

本地事件​

本地事件保持在同一端(服务器或客户端),并传达到该端上的每一个包。使用 Events.Call() 来触发它们,使用 Events.Subscribe() 来监听:

Server/Index.lua
-- 在任何包中
Events.Subscribe("RoundStarted", function(round_number)
Console.Log("Round %d started!", round_number)
end)

-- 在任何其他包中(或同一个包中)
Events.Call("RoundStarted", 1)

远程事件​

远程事件通过网络传输,从客户端发送到服务器,或从服务器发送到客户端。使用 Events.SubscribeRemote() 监听它们:

Server/Index.lua
-- 在服务器,第一个参数始终是发送它的 Player
Events.SubscribeRemote("BuyItem", function(player, item_name)
Console.Log("%s wants to buy %s", player:GetName(), item_name)

-- 仅回复该 Player
Events.CallRemote("ItemBought", player, Reliability.Reliable, item_name)
end)
Client/Index.lua
Events.SubscribeRemote("ItemBought", function(item_name)
Console.Log("I bought %s!", item_name)
end)

-- 发送到服务器
Events.CallRemote("BuyItem", Reliability.Reliable, "medkit")

服务器还可以使用 CallRemotePlayers 向 Player 列表发送事件,使用 BroadcastRemote 向所有人发送事件,或使用 BroadcastRemoteInRadius 和 BroadcastRemoteDimension 仅向指定半径或维度内的 Player 发送事件。

需要牢记的几个重要事项:

  • 可靠性:Reliability.Reliable 保证事件按顺序送达。 Reliability.Unreliable 开销更小但可能会丢失,适用于发送非常频繁(例如每个 Tick)且只有最新事件重要的场景。
  • Entity 可以作为参数传递,它们在另一端会作为相同的实体到达(只要它在另一端存在)。
  • 本地和远程是分开的:Events.Subscribe 不会接收远程事件,Events.SubscribeRemote 也不会接收本地事件。
  • 永远不要信任客户端:玩家可以发送带有任何参数的任何远程事件,请务必在服务器对其进行校验。参阅永远不要信任客户端指南。
提示

Entity 也拥有自己的远程事件,这些事件会在特定实体上触发。参见 :CallRemoteEvent() 和 :BroadcastRemoteEvent()。