UnrealScript library and basis for all Acedia Framework mods
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

652 lines
21 KiB

4 years ago
/**
* Object that provides simple access to console output.
* Can either write to a certain player's console or to all consoles at once.
* Supports "fancy" and "raw" output (for more details @see `ConsoleAPI`).
* Copyright 2020 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 ConsoleWriter extends AcediaObject
dependson(ConsoleAPI)
dependson(ConnectionService);
// Prefixes we output before every line to signify whether they were broken
// or not
var private string NEWLINE_PREFIX;
var private string BROKENLINE_PREFIX;
var private string INDENTATION;
4 years ago
/**
* Describes current output target of the `ConsoleWriter`.
*/
enum ConsoleWriterTarget
{
// No one. Can happed if our target disconnects.
CWTARGET_None,
// A certain set of players.
CWTARGET_Players,
4 years ago
// All players.
CWTARGET_All
};
var private ConsoleWriterTarget targetType;
// Players that will receive output passed to this `ConsoleWriter`.
// Only used when `targetType == CWTARGET_Players`
var private array<APlayer> outputTargets;
4 years ago
var private ConsoleBuffer outputBuffer;
var private bool needToResetColor;
4 years ago
var private ConsoleAPI.ConsoleDisplaySettings displaySettings;
// Sometimes we want to output a certain part of text with a color
// different from the default one. However this requires to remember current
// default in additional variable, set new color and then return the old one.
// To slightly simplify this process we use pair of `UseColor()`/`ResetColor()`
// methods that use this variable to remember "real" default color and allowing
// us to quickly reset back to it.
// This also means that `displaySettings` can sometimes store "default"
// color information instead.
var private Color defaultColor;
4 years ago
public final function ConsoleWriter Initialize(
ConsoleAPI.ConsoleDisplaySettings newDisplaySettings)
{
defaultColor = newDisplaySettings.defaultColor;
4 years ago
displaySettings = newDisplaySettings;
if (outputBuffer == none) {
outputBuffer = ConsoleBuffer(_.memory.Allocate(class'ConsoleBuffer'));
4 years ago
}
else {
outputBuffer.Clear();
}
outputBuffer.SetSettings(displaySettings);
return self;
}
/**
* Return default color setting for caller `ConsoleWriter`. It can be
* temporarily overwritten by `UseColor()` method.
4 years ago
*
* This method returns default color setting, i.e. color that will be used
* if no other is specified by text you're outputting and if it was not
* overwritten with `UseColor()` method.
* To get color currently used for outputting text, see `GetColor()`
* method.
*
* Do note that `ConsoleWriter` can have two "default" colors: a "real"
* default and a "temporary" default: "temporary" one can be set with
* `UseColor()` or `UseColorOnce()` method calls to temporarily color certain
* part of the output and then revert to the "real" default color.
* This method always returns "real" default color.
4 years ago
*
* This value is not synchronized with the global value from `ConsoleAPI`
* (or such value from any other `ConsoleWriter`) and affects only
* output produced by this `ConsoleWriter`.
*
* @return Current default color (the one that will be used to color output
* text after `ResetColor()` method call).
*/
public final function Color GetDefaultColor()
{
return defaultColor;
}
/**
* Return currently used default color for caller `ConsoleWriter`.
*
* This method returns default color, i.e. color that will be used if
* no other is specified by text you're outputting. If color is specified,
* this value is ignored.
* See also `GetDefaultColor()`.
*
* Do note that `ConsoleWriter` can have two "default" colors: a "real"
* default and a "temporary" default: "temporary" one can be set with
* `UseColor()` or `UseColorOnce()` method calls to temporarily color certain
* part of the output and then revert to the "real" default color.
* This method always return the color that will be actually used to
* output text, so "temporary" default if it's set and "real" default
* otherwise.
*
* @return Current default color (currently used to output text information).
4 years ago
*/
public final function Color GetColor()
{
return displaySettings.defaultColor;
}
/**
* Sets default color for caller 'ConsoleWriter`'s output.
*
* This only changes default color, i.e. color that will be used if no other is
* specified by "temporary" color. If color is specified, this value will
* be ignored.
*
* If you only want to quickly color certain part of output, it is better to
* use `UseColor()` or `UseColorOnce()` methods that temporarily changes used
* default color and allow to return to actual default color with
* `ResetColor()` method.
4 years ago
*
* This value is not synchronized with the global value from `ConsoleAPI`
* (or such value from any other `ConsoleWriter`) and affects only
* output produced by this `ConsoleWriter`.
*
* @param newDefaultColor New color to use when none specified by text itself.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter SetColor(Color newDefaultColor)
{
defaultColor = newDefaultColor;
4 years ago
displaySettings.defaultColor = newDefaultColor;
if (outputBuffer != none) {
outputBuffer.SetSettings(displaySettings);
}
return self;
}
/**
* Sets "temporary" default color that can be reverted to "real" default color
* with `ResetColor()` method.
*
* For quickly coloring certain parts of output:
* `console.UseColor(_.color.blue).Write(blueMessage)
* .Write(moreBlueMessage).ResetColor()`.
* Also see `UseColorOnce()` method.
*
* Consecutive calls do not "stack up" colors - only last one is remembered:
* `console.UseColor(_.color.blue).UseColor(_.color.green)` is the same as
* `console.UseColor(_.color.green)`.
*
* Use `SetColor()` to set both "real" and "temporary" color.
*
* @param temporaryColor Color to use as default one in the next console
* output calls until the `ResetColor()` method call.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter UseColor(Color temporaryColor)
{
needToResetColor = false;
displaySettings.defaultColor = temporaryColor;
if (outputBuffer != none) {
outputBuffer.SetSettings(displaySettings);
}
return self;
}
/**
* Sets "temporary" default color that will be automatically reverted to "real"
* default color after any "writing" method (i.e. `Write()`, `WriteLine()`,
* `WriteBlock()` or `Say()`) or when `ResetColor()` method is called.
*
* For quickly coloring certain parts of output:
* `console.UseColorOnce(_.color.blue).Write(blueMessage)`.
*
* Consecutive calls do not "stack up" colors - only last one is remembered:
* `console.UseColorOnce(_.color.blue).UseColorOnce(_.color.green)`
* is the same as `console.UseColorOnce(_.color.green)`.
*
* Use `SetColor()` to set both "real" and "temporary" color.
*
* @param temporaryColor Color to use as default one in the next console
* output calls until any "writing" method (or `ResetColor()` method)
* is called.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter UseColorOnce(Color temporaryColor)
{
needToResetColor = true;
displaySettings.defaultColor = temporaryColor;
if (outputBuffer != none) {
outputBuffer.SetSettings(displaySettings);
}
return self;
}
/**
* Resets "temporary" default text color to "real" default color.
* See `UseColor()` and `UseColorOnce()` for details.
*
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter ResetColor()
{
needToResetColor = false;
displaySettings.defaultColor = defaultColor;
if (outputBuffer != none) {
outputBuffer.SetSettings(displaySettings);
}
return self;
}
4 years ago
/**
* Return current visible limit that describes how many (at most)
* visible characters can be output in the console line.
*
* This value is not synchronized with the global value from `ConsoleAPI`
* (or such value from any other `ConsoleWriter`) and affects only
* output produced by this `ConsoleWriter`.
*
* @return Current global visible limit.
*/
public final function int GetVisibleLineLength()
{
return displaySettings.maxVisibleLineWidth;
}
/**
* Sets current visible limit that describes how many (at most) visible
* characters can be output in the console line.
*
* This value is not synchronized with the global value from `ConsoleAPI`
* (or such value from any other `ConsoleWriter`) and affects only
* output produced by this `ConsoleWriter`.
*
* @param newVisibleLimit New global visible limit.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter SetVisibleLineLength(
int newMaxVisibleLineWidth
)
{
displaySettings.maxVisibleLineWidth = newMaxVisibleLineWidth;
if (outputBuffer != none) {
outputBuffer.SetSettings(displaySettings);
}
return self;
}
/**
* Return current total limit that describes how many (at most)
* characters can be output in the console line.
*
* This value is not synchronized with the global value from `ConsoleAPI`
* (or such value from any other `ConsoleWriter`) and affects only
* output produced by this `ConsoleWriter`.
*
* @return Current global total limit.
*/
public final function int GetTotalLineLength()
{
return displaySettings.maxTotalLineWidth;
}
/**
* Sets current total limit that describes how many (at most)
* characters can be output in the console line.
*
* This value is not synchronized with the global value from `ConsoleAPI`
* (or such value from any other `ConsoleWriter`) and affects only
* output produced by this `ConsoleWriter`.
*
* @param newTotalLimit New global total limit.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter SetTotalLineLength(int newMaxTotalLineWidth)
{
displaySettings.maxTotalLineWidth = newMaxTotalLineWidth;
if (outputBuffer != none) {
outputBuffer.SetSettings(displaySettings);
}
return self;
}
/**
* Configures caller `ConsoleWriter` to output to all players.
* `Flush()` will be automatically called if target actually has to switch
* (before the switch occurs).
4 years ago
*
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter ForAll()
{
if (targetType != CWTARGET_All) {
Flush();
}
4 years ago
targetType = CWTARGET_All;
return self;
}
/**
* Configures caller `ConsoleWriter` to output only to the given player.
* `Flush()` will be automatically called if target actually has to switch
* (before the switch occurs).
4 years ago
*
* @param targetPlayer Player, to whom console we want to write.
4 years ago
* If `none` - caller `ConsoleWriter` would be configured to
* throw messages away.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
4 years ago
*/
public final function ConsoleWriter ForPlayer(APlayer targetPlayer)
4 years ago
{
if (targetPlayer == none)
{
Flush();
targetType = CWTARGET_None;
return self;
}
if (targetType != CWTARGET_Players) {
Flush();
}
outputTargets.length = 0;
targetType = CWTARGET_Players;
outputTargets[0] = targetPlayer;
return self;
}
/**
* Configures caller `ConsoleWriter` to output to one more player,
* given by `targetPlayer`.
* `Flush()` will be automatically called if target actually has to switch
* (before the switch occurs).
*
* @param targetPlayer Player, to whom console we want to write.
* If `none` - this method will do nothing.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter AndPlayer(APlayer targetPlayer)
{
local int i;
if (targetPlayer == none) return self;
if (!targetPlayer.IsConnected()) return self;
if (targetType != CWTARGET_Players)
{
Flush();
if (targetType == CWTARGET_None) {
outputTargets.length = 0;
}
else {
outputTargets.length = _.players.GetAll();
}
}
targetType = CWTARGET_Players;
for (i = 0; i < outputTargets.length; i += 1)
{
if (outputTargets[i] == targetPlayer) {
return self;
}
}
4 years ago
Flush();
outputTargets[outputTargets.length] = targetPlayer;
return self;
}
/**
* Configures caller `ConsoleWriter` to output to one less player,
* given by `targetPlayer`.
* `Flush()` will be automatically called if target actually has to switch
* (before the switch occurs).
*
* @param targetPlayer Player, to whom console we no longer want to write.
* If `none` - this method will do nothing.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter ButPlayer(APlayer playerToRemove)
{
local int i;
if (targetType == CWTARGET_None) return self;
if (playerToRemove == none) return self;
if (!playerToRemove.IsConnected()) return self;
if (targetType == CWTARGET_All)
4 years ago
{
Flush();
outputTargets = _.players.GetAll();
4 years ago
}
targetType = CWTARGET_Players;
while (i < outputTargets.length)
{
if (outputTargets[i] == playerToRemove)
{
Flush();
outputTargets.Remove(i, 1);
break;
}
i += 1;
4 years ago
}
return self;
}
/**
* Returns type of current target for the caller `ConsoleWriter`.
*
* @return `ConsoleWriterTarget` value, describing current target of
* the caller `ConsoleWriter`.
*/
public final function ConsoleWriterTarget CurrentTarget()
{
if (targetType == CWTARGET_Players && outputTargets.length == 0) {
4 years ago
targetType = CWTARGET_None;
}
return targetType;
}
/**
* Returns `APlayer` to whom console caller `ConsoleWriter` is
* outputting messages.
* If caller `ConsoleWriter` is setup to message several different players,
* returns an arbitrary one of them.
4 years ago
*
* @return Player (`APlayer` class) to whom console caller `ConsoleWriter` is
* outputting messages. Returns `none` iff it currently outputs to
* every player or to no one.
4 years ago
*/
public final function APlayer GetTargetPlayer()
4 years ago
{
if (targetType == CWTARGET_All) return none;
if (outputTargets.length <= 0) return none;
return outputTargets[0];
}
/**
* Returns `APlayer` to whom console caller `ConsoleWriter` is
* outputting messages.
* If caller `ConsoleWriter` is setup to message several different players,
* returns an arbitrary one of them.
*
* @return Player (`APlayer` class) to whom console caller `ConsoleWriter` is
* outputting messages. Returns `none` iff it currently outputs to
* every player or to no one.
*/
public final function array<APlayer> GetTargetPlayers()
{
local array<APlayer> emptyArray;
if (targetType == CWTARGET_None) return emptyArray;
if (targetType == CWTARGET_All) return _.players.GetAll();
return outputTargets;
4 years ago
}
/**
* Outputs all buffered input and moves further output onto a new line.
*
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter Flush()
{
outputBuffer.Flush();
SendBuffer();
return self;
}
/**
* Writes text's contents into console.
4 years ago
*
* Does not trigger console output, for that use `WriteLine()` or `Flush()`.
*
* @param message `Text` to output.
4 years ago
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter Write(optional Text message)
4 years ago
{
outputBuffer.Insert(message);
if (needToResetColor) {
ResetColor();
}
4 years ago
return self;
}
/**
* Writes text's contents into console.
4 years ago
* Result will be output immediately, starts a new line.
*
* @param message `Text` to output.
4 years ago
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter WriteLine(optional Text message)
4 years ago
{
return Write(message).Flush();
4 years ago
}
/**
* Writes text's indented contents into console.
*
* Acts like a `WriteLine()` call, except all output contents will be
* additionally indented by four whitespace symbols
* (including lines after line breaks).
*
* Result will be output immediately, starts a new line.
*
* @param message `Text` to output.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter WriteBlock(optional Text message)
{
outputBuffer.Insert(message).Flush();
SendBuffer(true);
if (needToResetColor) {
ResetColor();
}
return self;
}
/**
* Writes text's contents into console as a player's chat message, causing them
* to appear on screen in vanilla UI.
*
* All the buffer stored in caller `ConsoleWriter` so far will be flushed.
* Result will be output immediately. Starts a new line.
*
* @param message `Text` to output.
* @return Returns caller `ConsoleWriter` to allow for method chaining.
*/
public final function ConsoleWriter Say(optional Text message)
{
outputBuffer.Insert(message).Flush();
SendBuffer(, true);
if (needToResetColor) {
ResetColor();
}
return self;
}
// Send all completed lines from an `outputBuffer`.
// Setting `indented` to `true` will cause additional four whitespaces to
// be added to the output.
private final function SendBuffer(optional bool asIndented, optional bool asSay)
4 years ago
{
local string prefix;
local ConsoleBuffer.LineRecord nextLineRecord;
local array<PlayerController> recipients;
recipients = GetRecipientsControllers();
4 years ago
while (outputBuffer.HasCompletedLines())
{
nextLineRecord = outputBuffer.PopNextLine();
if (nextLineRecord.wrappedLine) {
prefix = NEWLINE_PREFIX;
}
else {
prefix = BROKENLINE_PREFIX;
}
if (asIndented) {
prefix $= INDENTATION;
}
SendConsoleMessage(recipients, prefix $ nextLineRecord.contents, asSay);
4 years ago
}
}
// Assumes `playerService != none` and `connectionService != none`,
// caller function must ensure that.
4 years ago
private final function SendConsoleMessage(
array<PlayerController> recipients,
string message,
bool asSay)
{
local int i;
for (i = 0; i < recipients.length; i += 1)
{
if (recipients[i] != none)
{
if (asSay) {
recipients[i].ClientMessage(message);
}
else {
recipients[i].TeamMessage(none, message, 'AcediaConsole');
}
}
}
}
// Method for retrieving `PlayerController`s of recipients at the moment
// of the call
private final function array<PlayerController> GetRecipientsControllers()
4 years ago
{
local int i;
local PlayerController nextRecipient;
local PlayerService playerService;
local ConnectionService connectionService;
local array<PlayerController> recipients;
4 years ago
local array<ConnectionService.Connection> connections;
// No targets
if (targetType == CWTARGET_None) {
return recipients;
}
// Single target case
4 years ago
if (targetType != CWTARGET_All)
{
playerService = PlayerService(class'PlayerService'.static.Require());
if (playerService == none) {
return recipients;
4 years ago
}
for (i = 0; i < outputTargets.length; i += 1)
{
nextRecipient = playerService.GetController(outputTargets[i]);
if (nextRecipient != none) {
recipients[recipients.length] = nextRecipient;
}
}
return recipients;
}
// All players target case
connectionService =
ConnectionService(class'ConnectionService'.static.Require());
if (connectionService == none) {
return recipients;
4 years ago
}
connections = connectionService.GetActiveConnections();
for (i = 0; i < connections.length; i += 1)
{
if (connections[i].controllerReference != none) {
recipients[recipients.length] = connections[i].controllerReference;
}
4 years ago
}
return recipients;
4 years ago
}
defaultproperties
{
NEWLINE_PREFIX = "| "
BROKENLINE_PREFIX = " "
INDENTATION = " "
4 years ago
}