Browse Source

Add async methods for registering commands

pull/12/head
Anton Tarasenko 2 years ago
parent
commit
3d7f11688c
  1. 46
      sources/BaseAPI/API/Commands/CommandAPI.uc
  2. 54
      sources/BaseAPI/API/Commands/CommandRegistrationJob.uc

46
sources/BaseAPI/API/Commands/CommandAPI.uc

@ -21,11 +21,27 @@
*/
class CommandAPI extends AcediaObject;
// Classes registered to be registered in async way
var private array< class<Command> > pendingClasses;
// Job that is supposed to register pending commands
var private CommandRegistrationJob registeringJob;
var private Commands_Feature commandsFeature;
// DO NOT CALL MANUALLY
public final /*internal*/ function _reloadFeature()
{
public final /*internal*/ function class<Command> _popPending() {
local class<Command> result;
if (pendingClasses.length == 0) {
return none;
}
result = pendingClasses[0];
pendingClasses.Remove(0, 1);
return result;
}
// DO NOT CALL MANUALLY
public final /*internal*/ function _reloadFeature() {
if (commandsFeature != none) {
commandsFeature.FreeSelf();
commandsFeature = none;
@ -41,6 +57,8 @@ public final function bool AreCommandsEnabled() {
/// Registers given command class, making it available via `Execute()`.
///
/// Unless you need command right now, it is recommended to use `RegisterCommandAsync()` instead.
///
/// Returns `true` if command was successfully registered and `false` otherwise`.
///
/// # Errors
@ -55,6 +73,30 @@ public final function bool RegisterCommand(class<Command> commandClass) {
return false;
}
/// Registers given command class asynchronously, making it available via `Execute()`.
///
/// Doesn't register commands immediately, instead scheduling it to be done at a later moment in
/// time, allowing.
/// This can help to reduce amount of work we do every tick during server startup, therefore
/// avoiding crashed due to the faulty infinite loop detection.
///
/// # Errors
///
/// If `commandClass` provides command with a name that is already taken (comparison is
/// case-insensitive) by a different command - a warning will be logged and newly passed
/// `commandClass` discarded.
public final function RegisterCommandAsync(class<Command> commandClass) {
if (commandsFeature == none) {
return;
}
pendingClasses[pendingClasses.length] = commandClass;
if (registeringJob == none || registeringJob.IsCompleted()) {
_.memory.Free(registeringJob);
registeringJob = CommandRegistrationJob(_.memory.Allocate(class'CommandRegistrationJob'));
_.scheduler.AddJob(registeringJob);
}
}
/// Removes command of given class from the list of registered commands.
///
/// Removing once registered commands is not an action that is expected to be performed under normal

54
sources/BaseAPI/API/Commands/CommandRegistrationJob.uc

@ -0,0 +1,54 @@
/**
* Author: dkanus
* Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
* License: GPL
* Copyright 2023 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class CommandRegistrationJob extends SchedulerJob;
var private class<Command> nextCommand;
protected function Constructor() {
nextCommand = _.commands._popPending();
}
protected function Finalizer() {
nextCommand = none;
}
public function bool IsCompleted() {
return (nextCommand == none);
}
public function DoWork(int allottedWorkUnits) {
local int i, iterationsAmount;
// Expected 300 units per tick, to register 20 commands per tick use about 10
iterationsAmount = Max(allottedWorkUnits / 10, 1);
for (i = 0; i < iterationsAmount; i += 1) {
_.commands.RegisterCommand(nextCommand);
nextCommand = _.commands._popPending();
if (nextCommand == none) {
break;
}
}
}
defaultproperties
{
}
Loading…
Cancel
Save