跳到主要内容
版本:Next

Server events

Systems tick every frame, and RPC handlers run when a client asks for something. Server events are the third way a mod gets control: the relay tells you when something happened.

New in 0.2.0.

Subscribing

Derive from ServerEventHandlersBase and implement Subscribe and Unsubscribe. The base class hooks both into the mod lifecycle, so you never unsubscribe by hand:

EventHandlers.cs
public class EventHandlers(ServerEventsApi events, EcsApi ecs, ILogger logger)
: ServerEventHandlersBase(events)
{
protected override void Subscribe(ServerEventsApi e)
{
e.OnPlayerActivatedCell += OnPlayerActivatedCell;
e.OnCellDeleted += OnCellDeleted;
}

protected override void Unsubscribe(ServerEventsApi e)
{
e.OnPlayerActivatedCell -= OnPlayerActivatedCell;
e.OnCellDeleted -= OnCellDeleted;
}

private void OnPlayerActivatedCell(PlayerId player, FullCellId cell)
=> logger.LogInformation("{Player} loaded {Cell}", player, cell);

private void OnCellDeleted(FullCellId cell, Entity entity)
{
// nobody has this cell loaded any more, tear down whatever we hung off it
}
}

Register it as a singleton in your mod's Init, the same as a system:

Services.RegisterSingleton<EventHandlers>();

The events

EventArgumentsFires when
OnWorldEntityCreatedentitythe world entity exists, once at startup
OnPlayerConnectedplayer, entitya player finishes connecting
OnPlayerDisconnectedplayer, entity, reasona player drops or leaves
OnAreaCreatedarea, entitythe first player enters an area
OnAreaDeletedarea, entitythe last player leaves an area
OnPlayerJoinedAreaplayer, areaa player enters an area that already exists
OnPlayerLeftAreaplayer, areaa player leaves an area others are still in
OnCellCreatedcell, entitythe first player activates a cell
OnCellDeletedcell, entitythe last player deactivates a cell
OnPlayerActivatedCellplayer, cella player loads a cell that is already active
OnPlayerDeactivatedCellplayer, cella player unloads a cell others still have loaded

Where an event hands you an Entity, that is the entity for the thing the event is about, so you can write to its components without going looking for it first.

The cell events are the Oblivion-specific half of this list. They follow the same create/delete plus join/leave shape as the area events, one level further in: an area is the world space, a cell is the chunk a player currently has loaded. See Entities.

OnWorldEntityCreated

Your mod's Init runs before the world entity exists, so this is the earliest point at which you can write world components:

protected override void Subscribe(ServerEventsApi e)
=> e.OnWorldEntityCreated += OnWorld;

private void OnWorld(Entity world)
{
ref var state = ref ecs.GetComponentRef<WorldStateComponent>(world.Id);
// seed whatever your mod needs before the first player connects
}

If you find yourself wanting to seed state at startup and not finding anywhere to put it, this is the hook you want. See Archetypes and components for what the world entity carries.

Threading

Event handlers run on the server's update thread, the same one your systems tick on. That means you can query and modify entities directly, with no marshalling, and it also means a slow handler delays the tick. Keep them short.