view release on metacpan or search on metacpan
lib/Games/Axmud/Client.pm view on Meta::CPAN
use warnings;
# use diagnostics;
use Glib qw(TRUE FALSE);
# Include module here, as well as in axmud.pl, so that .../t/00-compile.t won't fail
use Archive::Tar;
our @ISA = qw(Games::Axmud);
##################
# Constructors
sub new {
# Called by axmud.pl on startup
#
# Expected arguments
# (none besides $class)
#
# Return values
# 'undef' on improper arguments
# Blessed reference to the newly-created object on success. The calling function sets the
# $CLIENT global variable
my ($class, $check) = @_;
# Local variables
my (
$urlRegex, $shortRegex, $emailRegex,
@cmdList,
%soundHash, %msspHash,
);
# Check for improper arguments
if (! defined $class || defined $check) {
# Global variable $axmud::CLIENT not set yet, so we'll just have to print the
# improper arguments message
print "IMPROPER ARGUMENTS: Games::Axmud::Client->new " . join(' ', @_) . "\n";
return undef;
}
# Set regexes to recognise URLs
$urlRegex = 'http(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)'
. '([a-zA-Z0-9\-?\.\?\,\'\/\\\+&%\$#_\=\~]*)?';
$shortRegex = '[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*\.(com|org|net|int|edu|gov|mil|io|uk)';
# Set a regex to recognise email addresses
$emailRegex = '\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b';
# Setup
my $self = {
_objName => 'client',
_objClass => $class,
_parentFile => undef, # No parent file object
_parentWorld => undef, # No parent file object
_privFlag => TRUE, # All IVs are private
# Perl object components
# ----------------------
# The main desktop object (GA::Obj::Desktop), which arranges windows on the desktop
# across one or more workspaces
desktopObj => undef,
# An IV which stores a 'main' window. First set when Axmud starts, and a spare 'main'
# window, not belonging to any session, opens before the Connections window opens
# Briefly set back to 'undef' when the spare 'main' window is destroyed, just before a
# new 'main' window for a new session is created to replace it
# Then set whenever $self->currentSession is set
mainWin => undef,
# The About window (only one can be open at a time)
aboutWin => undef, # Set by $self->set_aboutWin
# A 'dialogue' window created by a call to GA::Generic::Win->showBusyWin, e.g. the
# 'Loading...' window created by $self->start
busyWin => undef, # Set by $self->set_busyWin
# The Connections window (only one can be open at a time)
connectWin => undef, # Set by $self->set_connectWin
# The Client Console window (only one can be open at a time)
consoleWin => undef, # Set by $self->set_consoleWin
# Instance variable constants
# ---------------------------
# All of Axmud's Perl objects have instance variables (IVs); the vast majority of them
# are either scalar IVs (including references stored in scalar variables), list IVs or
# hash IVs. There are a few more complex structures (e.g. arrays of arrays, hashes of
# arrays, etc), but besides that, there no other data structures (globs, etc)
#
# All objects have five standard 'constant' IVs which should not be modified, namely
# ->_objName, ->_objClass, ->_parentFile, ->_parentWorld and ->privFlag.
# ->_objName gives a name to an object, even if it doesn't have a ->name IV.
# ->_objName is not necessarily unique
# ->_objectClass is the same as the package name for the object (e.g. GA::Client)
# ->_parentFile matches a key in the file object registry, $self->fileObjHash (see
# further below). It tells us which data file is used to save this object. (A few
# objects don't have a parent file; in these casees, ->_parentFile is set to 'undef')
# ->_parentWorld is the name of the current world profile, in the GA::Session to which
# the object belongs. (Some objects don't belong to a particular GA::Session; in these
# cases, ->_parentWorld is set to 'undef')
# ->_privFlag is set to TRUE if the object's IVs are private; FALSE if they are public.
# (See the comments at the top of generic_obj.pm)
#
# In addition, any IV whose name begins with 'const' is treated as a constant value
# which should not be modified
#
# The generic object, Games::Axmud, from which all Axmud objects inherit, provides
# several useful functions for accessing and storing values for all IVs, such as
# ->ivPush, ->ivSplice and ->ivPeek
# The most important one is ->ivPoke. When an IV's value (or values) are set, it should
# not be done with a call to
# $self->{iv_name} = $value
# but with a call to
# $self->ivPoke('iv_name', $value)
# ->ivPoke (like all the generic object's IV functions) tells the equivalent
# GA::Obj::File that its data has been modified, and that it needs to be saved
# ->ivPoke, etc, can't be used to modify constant IVs (the five mentioned above, and any
# IV whose names starts 'const'
#
# Constant registry hash of constant instance variables (IVs) required by every Perl
# object. A hash in the form
# $constIVHash{iv_name} = undef
constIVHash => {
'_objName' => undef,
'_objClass' => undef,
'_parentFile' => undef,
'_parentWorld' => undef,
'_privFlag' => undef,
},
# Constant registry hash of reserved names that can't be used by profiles and other
# Perl objects which have unique names (case-insensitive; these values never change)
# Hash in the form
# $constReservedHash{string} = undef
# NB Plurals have been added only when necessary, specifically because there's a file
# object with a name in the plural
constReservedHash => {
'about' => undef,
'alias' => undef,
'amud' => undef,
'axmud' => undef,
'automap' => undef,
'automapper' => undef,
'buffer' => undef,
'cage' => undef,
'client' => undef,
'cmd' => undef,
'colour' => undef,
'color' => undef, # American too
'component' => undef,
'config' => undef,
'connect' => undef,
'console' => undef,
'contact' => undef,
'contacts' => undef,
'current' => undef,
'custom' => undef,
'default' => undef,
'defn' => undef,
'definition' => undef,
'delete' => undef,
'desktop' => undef,
'dict' => undef,
'dictionary' => undef,
'dicts' => undef,
'edit' => undef,
'exit' => undef,
'external' => undef,
'favourite' => undef,
'favorite' => undef, # American too
'file' => undef,
'fixed' => undef,
'flag' => undef,
'free' => undef,
'gauge' => undef,
'generic' => undef,
'grid' => undef,
'gui' => undef,
'hash' => undef,
'help' => undef,
'hook' => undef,
'icon' => undef,
'init' => undef,
'interface' => undef,
'internal' => undef,
'jmud' => undef, # Old JMud plugin for KildClient
'keycode' => undef,
'keycodes' => undef,
'label' => undef,
'link' => undef,
'list' => undef,
'load' => undef,
'localhost' => undef,
'login' => undef,
'loop' => undef,
'macro' => undef,
'main' => undef,
'map' => undef,
'misc' => undef,
'mission' => undef,
'model' => undef,
'name' => undef,
'node' => undef,
'not_applicable' => undef, # Used in data files to represent assoc'd world
'obj' => undef,
'other' => undef,
'otherdefn' => undef,
'otherprof' => undef,
'package' => undef,
'phrasebook' => undef,
'plugin' => undef,
'pref' => undef,
'preference' => undef,
'profile' => undef,
'pseudo' => undef,
'quest' => undef,
'region' => undef,
'regionmap' => undef,
'regionpath' => undef,
'room' => undef,
'save' => undef,
'scalar' => undef,
lib/Games/Axmud/Client.pm view on Meta::CPAN
'kp_subtract' => chr(27) . 'OS', # PF4
},
# Constant hash of Axmud keycodes which must be intercepted by a ->signal_connect in
# GA::Win::Internal->setKeyPressEvent and sent to the world, whenever a session's
# special echo mode is enabled
constDirectSpecialKeysHash => {
'escape' => chr(27),
'tab' => chr(11),
'backspace' => chr(8),
'delete' => chr(127),
},
# Debugging flag set to TRUE if invalid escape sequences should be displayed as 'debug'
# messages, FALSE otherwise
debugEscSequenceFlag => FALSE, # [config]
# Debugging flag set to TRUE if incoming option negotiations should be displayed as
# 'debug' messages, FALSE otherwise
debugTelnetFlag => FALSE, # [config]
# Parallel debugging flag set to TRUE if a very short 'debug' message should be
# displayed for incoming option negotiations (ignored if ->debugTelnetFlag is TRUE)
debugTelnetMiniFlag => FALSE, # [config]
# Debugging flag set to TRUE if GA::Obj::Telnet should write its own logfile for
# option negotiations, telopt.log (store in Axmud's base directory)
debugTelnetLogFlag => FALSE, # [config]
# Debugging flag set to TRUE if MSDP data sent to Status/Locator tasks should be
# displayed as 'debug' messages, FALSE otherwise
debugMsdpFlag => FALSE, # [config]
# Debugging flag set to TRUE if MXP errors should be displayed as 'debug' messages,
# FALSE otherwise
debugMxpFlag => FALSE, # [config]
# Debugging flag set to TRUE if MXP comment elements should be displayed as 'debug'
# messages, FALSE otherwise
debugMxpCommentFlag => FALSE, # [config]
# Debugging flag set to TRUE if Pueblo errors should be displayed as 'debug' messages,
# FALSE otherwise
debugPuebloFlag => FALSE, # [config]
# Debugging flag set to TRUE if Pueblo comment elements should be displayed as 'debug'
# messages, FALSE otherwise
debugPuebloCommentFlag => FALSE, # [config]
# Debugging flag set to TRUE if ZMP data should be displayed as 'debug' messages, FALSE
# otherwise
debugZmpFlag => FALSE, # [config]
# Debugging flag set to TRUE if incoming ATCP data should be displayed as 'debug'
# messages, FALSE otherwise
debugAtcpFlag => FALSE, # [config]
# Debugging flag set to TRUE if incoming GMCP data should be displayed as 'debug'
# messages, FALSE otherwise
debugGmcpFlag => FALSE, # [config]
# Debugging flag set to TRUE if MCP errors should be displayed as 'debug' messages,
# FALSE otherwise
debugMcpFlag => FALSE, # [config]
# Desktop and display settings
# ----------------------------
# Display variables
# Axmud makes use of a number of windows, both those it creates and 'external' windows
# it doesn't create
# 'grid' windows are permanent (or semi-permanent). Axmud tries to arrange these windows
# so they don't overlap or, if there isn't enough room on the workspace, to make them
# overlap in sensible ways. Axmud tries to take account of the different desktop
# environments in getting the positioning of its windows right. 'grid' windows can
# include 'external' windows, such as media players, so that they don't overlap
# Axmud's own windows (if required)
# 'free' windows are temporary, and are displayed in the middle of the workspace without
# regard for the positioning of any 'grid' windows
# If your system has multiple workspaces available, 'grid' windows can be arranged on
# each one of them. Each workspace can have one or more 'workspace grids' on which
# 'grid' windows for that workspace are arranged
#
# NB Recent Axmud versions can draw task windows and the Automapper window inside the
# 'main' window, as well as in separate 'grid' windows, as before. These are called
# 'pseudo-windows'. Their ->number IV is always -1, and they don't appear in registry
# hashes of windows. This feature is experimental, so in general comments don't
# mention them
#
# There are two modes for handling windows in multiple sessions, according to the
# setting of this flag:
# TRUE (traditional) : All sessions share a single 'main' window. The 'main'
# window's Gtk3::Grid contains one table object, a pane object
# (GA::Table::Pane) which displays text received from each session's world
# in a separate tab. No other widgets are allowed on the table. Other
# 'internal' windows may be visible; on each workspace, they are arranged on
# workspace grids belonging to their session (on every workspace, one
# workspace grid for every session). The current session is the one whose tab
# is visible; only its 'internal' windows are visible; 'internal' windows
# controlled by other sessions are not visible (usually minimised)
# FALSE: All sessions have their own 'main' window. The 'main' window's
# Gtk3::Grid contains at least one pane object, but can also contain other
# table widgets (including other pane objects). Other 'internal' windows are
# arranged on a workspace grid shared by all sessions (one workspace grid for
# every workspace in use). When the current session changes, no windows are
# made visible or invisible (usually minimised or un-minimised)
shareMainWinFlag => TRUE, # [config]
# When the user wants to change the setting of ->shareMainWinFlag, the change can't be
# applied immediately.
# Instead, this IV is set to 'on' or 'off'. When Axmud next starts, if this IV is not
# set to 'default', ->shareMainWinFlag is set to TRUE (for 'on') or FALSE (for 'off');
# ->restartShareMainWinMode is then set back to 'default'
restartShareMainWinMode => 'default', # [config]
# Workspace grids can be available, or not. GA::Obj::Desktop->gridPermitFlag is set to
# FALSE if workspace grids are not available at all (because the desktop is too small,
# because Axmud is running on MS Windows or running in blind mode, etc)
# Independent of that flag is this one, which the user can set with
# ';activategrid' and ';disactivategrid'. When Axmud starts, it tries to create
# workspace grids if this flag and GA::Obj::Desktop->gridPermitFlag are both TRUE
activateGridFlag => TRUE, # [config]
# When workspace grids are not available, Axmud can try to remember the size and
# position of its 'grid' windows. Users can adjust the size/positions manually, and
# have those settings applied in future sessions
# Flag set to TRUE if Axmud should try to remember the size and position of 'grid'
# windows, FALSE if not (can be TRUE even if workspace grids are available)
storeGridPosnFlag => FALSE, # [config]
# When ->storeGridPosnFlag is TRUE, Axmud uses this hash to store the size/position of
# each 'grid' window with a unique ->winName (e.g. 'main', 'status_task', 'map').
# When it's FALSE, this hash is not updated at all
# A key-value pair is created when a 'grid' window is created, if there's not already a
# matching entry in the hash
# If a 'grid' window is created when workspace grids are not available, and if there's
# an entry in this hash with the same ->winName, that entry is used for the size and
# position of the new 'grid' window. If, on the other hand, workspace grids are
# available, then the new window's size and position is set by the workspace grid code
# If a 'grid' window is resized (by code or manually by the user) and it's either the
# only window with the same ->winName open, or the first one of that ->winName that
# was opened, then the entry in this hash is updated
# 'External' windows are never added to this hash
# Hash in the form
# ->storeGridPosnHash{window_name} = list_reference
# ...where 'list_reference' is a reference to a list in the form (x y width height). At
# least one of the four values must be defined. When a 'grid' window is created and
# workspace grids aren't available, the posn is only used if both 'x' and 'y' are
# defined, and the size is only used if both 'width' and 'height' are defined. Those
# are the minimum requirements; in actual use, Axmud's code almost certainly delivers
# an entry with all four values defined
storeGridPosnHash => {}, # [config]
#
# Constant hash of standard 'grid' window types (any type of window that can be put onto
# a workspace grid; includes 'external' windows, but doesn't include the data viewer
# window, 'edit' windows, 'pref' windows, 'dialogue' windows etc)
# NB 'Internal' windows are a sub-class of 'grid' window handled by GA::Win::Internal,
# consisting of the window types 'main', 'protocol' and 'custom'
# Hash in the form
# $constWinTypeHash{window_type} = 'undef'
# ...where 'window_type' matches GA::Generic::GridWin->winType
constGridWinTypeHash => {
# Any 'grid' window used as a 'main' window by any session (can be created only by
# GA::Client or GA::Session)
'main' => undef,
# Any 'grid' window used as an Automapper window (can be created by any code)
'map' => undef,
# Any 'grid' window created by a MUD protocol such as MXP (can be created only by
# GA::Session)
'protocol' => undef,
# Any 'grid' window NOT used as a 'main' window by any session (besides 'map' and
# 'protocol' windows), whose widgets can't be customised (can be created by any
# code)
'fixed' => undef,
# Any 'grid' window NOT used as a 'main' window by any session (besides 'map' and
# 'protocol' windows), whose widgets can be customised (e.g. windows controlled
# by individual tasks; can be created by any code)
'custom' => undef,
# Any 'external' window (not created by Axmud, but which has been placed on a
lib/Games/Axmud/Client.pm view on Meta::CPAN
return undef;
}
$dir = $axmud::SHARE_DIR . '/items/sounds/';
if (! -e $dir) {
return undef;
}
# Get a list of text files in this directory
if (! opendir ($dirHandle, $dir)) {
return undef;
} else {
@fileList = readdir ($dirHandle);
closedir $dirHandle;
}
# Filter out non-sound files
$regex = '\.(' . join('|', $self->ivKeys('constSoundFormatHash')) . ')$';
foreach my $file (@fileList) {
my $name;
if ($file =~ m/$regex/) {
$name = $file;
$name =~ s/$regex//;
$hash{$name} = $file;
}
}
# Set the IV
$self->{constExtendedSoundHash} = \%hash;
return 1;
}
# Start / stop
sub start {
# Called by axmud.pl on startup, immediately after the call to GA::Client->new
# Starts the client. Opens the first 'main' window, and prompts the user to connect to a
# world
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if setup fails
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my (
$warningFlag, $roomObj, $exitObj, $desktopObj, $host, $engine, $port, $world, $profObj,
$taskObj, $offlineFlag,
@list,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->start', @_);
}
# Set the date/time at which the client started
$self->ivPoke('startTime', $self->localTime());
$self->ivPoke('startClock', $self->localClock());
$self->ivPoke('startDate', $self->localDate());
$self->ivPoke('startClockString', $self->localClockString());
$self->ivPoke('startDateString', $self->localDateString());
# In Axmud test mode, blind mode is always disabled
if ($axmud::TEST_MODE_FLAG) {
$axmud::BLIND_MODE_FLAG = FALSE;
}
# In Axmud blind mode, TTS is always enabled
if ($axmud::BLIND_MODE_FLAG) {
$self->ivPoke('systemAllowTTSFlag', TRUE);
}
# Load the basic mudlist, and store the data in GA::Obj::BasicWorld objects. The data
# isn't important, so don't disable loading/saving of data files if the operation fails
if (! $self->loadBasicWorlds()) {
$warningFlag = TRUE;
$self->writeWarning(
'Could not load basic mudlist (files possible corrupted)',
$self->_objClass . '->start',
);
}
# Load phrasebooks, and store the data in GA::Obj::PhraseBook objects. The data isn't
# important, so don't disable loading/saving of data files if the operation fails
if (! $self->loadPhrasebooks()) {
$warningFlag = TRUE;
$self->writeWarning(
'Could not load phrasebooks (files possible corrupted)',
$self->_objClass . '->start',
);
}
# Create the file objects stored by this GA::Client object
if (! $self->createFileObjs()) {
$warningFlag = TRUE;
$self->writeWarning(
'Could not create file objects for the client - loading/saving disabled',
$self->_objClass . '->start',
);
lib/Games/Axmud/Client.pm view on Meta::CPAN
$self->setupKeycodes();
# Create default TTS objects
$self->ttsCreateStandard();
# Create a room object and an exit object with default values for their IVs, used to supply
# default values for all other room/exit objects
$roomObj = Games::Axmud::ModelObj::Room->new($self, 'default', 'global');
$exitObj = Games::Axmud::Obj::Exit->new($self, 'default', 'global');
if (! $roomObj || ! $exitObj) {
return $self->writeError(
'Could not initialise the default room and exit objects',
$self->_objClass . '->start',
);
} else {
$axmud::DEFAULT_ROOM = $roomObj;
$axmud::DEFAULT_EXIT = $exitObj;
}
# Load (or create) the config file (if allowed)
if (! $self->configFileObj->setupConfigFile()) {
$warningFlag = TRUE;
$self->writeWarning(
'Error reading (or creating) the ' . $axmud::SCRIPT . ' config file - loading'
. '/saving disabled',
$self->_objClass . '->start',
);
# Disable all loading/saving of data files (the TRUE argument means 'don't prompt the
# user to do an emergency save')
$self->disableAllFileAccess(TRUE);
}
# Any changes to IV values which could not be applied immediately, the last time Axmud was
# running, should be applied now
# (->restartShareMainWinMode is 'default' if no change is required, or 'off' / 'on' if a
# change is required)
if ($self->restartShareMainWinMode ne 'default') {
if ($self->restartShareMainWinMode eq 'off') {
$self->ivPoke('shareMainWinFlag', FALSE);
} else {
$self->ivPoke('shareMainWinFlag', TRUE);
}
$self->ivPoke('restartShareMainWinMode', 'default');
}
# Initialise the default set of toolbar button objects
if (! $self->initialiseToolbar()) {
return $self->writeError(
'Could not initialise toolbar button objects',
$self->_objClass . '->start',
);
}
# Create the main desktop object. Set up the default workspace, set up window icons, prepare
# rc-file styles for each kind of window, create the first 'main' window
$desktopObj = Games::Axmud::Obj::Desktop->new();
if (! $desktopObj) {
return $self->writeError(
'Could not set up the desktop',
$self->_objClass . '->start',
);
} else {
$self->ivPoke('desktopObj', $desktopObj);
if (! $desktopObj->start()) {
return $self->writeError(
'Could not set up the desktop',
$self->_objClass . '->start',
);
} else {
# Loading of data files and plugins could take some seconds; make the whole 'main'
# window visible in the meantime
$desktopObj->updateWidgets($self->_objClass . '->start');
}
}
# Perform an auto-backup of Axmud's data directory, if required
if (
$self->autoBackupMode eq 'all_start'
|| (
$self->autoBackupMode eq 'interval_start' && $self->checkBackupInterval()
)
) {
$self->doAutoBackup();
}
# Display a 'dialogue' window while loading data files/plugins
if (! $axmud::TEST_MODE_FLAG && ! $axmud::BLIND_MODE_FLAG) {
$self->mainWin->showBusyWin();
}
# If the user is using a new version of Axmud, check if there are any new pre-configured
# worlds in this version. If so, insert them into Axmud's data directory
if (
$self->convertVersion($axmud::VERSION) > $self->convertVersion($self->prevClientVersion)
) {
$self->insertPreConfigWorlds();
# Don't perform this operation again until the next Axmud release
$self->ivPoke('prevClientVersion', $axmud::VERSION);
}
# Load world profiles, creating a file object for each (if allowed, and if there are any to
# load)
if ($self->loadDataFlag && $self->configWorldProfList && ! $axmud::TEST_PRE_CONFIG_FLAG) {
if (! $self->loadWorldProfs() ) {
$warningFlag = TRUE;
$self->writeWarning(
'Error loading the world profiles expected after reading the \'config\''
. ' file',
$self->_objClass . '->start',
);
}
}
# Load data for the remaining file objects ('tasks', 'scripts', 'contacts', 'dicts',
# 'toolbar', 'usercmds', 'zonemaps', 'winmaps', 'tts')
if ($self->loadDataFlag && ! $self->loadOtherFiles()) {
$warningFlag = TRUE;
$self->writeWarning(
'Error reading (or creating) data files - loading/saving disabled',
$self->_objClass . '->start',
);
# Disable all loading/saving of data files (the TRUE argument means 'don't prompt the
# user to do an emergency save')
$self->disableAllFileAccess(TRUE);
}
# Add remaining workspaces, if any are specified
$desktopObj->setupWorkspaces();
# Set up client commands
if (! $self->setupCmds()) {
# (Allow writing to something other than GA::Session - there are no sessions yet)
return $self->writeError(
'Could not initialise ' . $axmud::SCRIPT . ' client commands',
$self->_objClass . '->start',
);
}
# Delete the contents of log directories (leaving files inside worlds' own log directories
# intact), if the flag is set (but don't delete directories if this function has produced
# any warning messages - so that the messages aren't lost
if ($self->deleteStandardLogsFlag && ! $warningFlag) {
$self->deleteStandardLogs();
}
# Load plugins in the /private directory, if it exists (will not exist in any public release
# of Axmud)
if (-e $axmud::SHARE_DIR . '/private') {
$self->loadPrivatePlugins();
}
# Load initial plugins
if ($self->initPluginList) {
foreach my $pluginPath ($self->initPluginList) {
if (! $self->loadPlugin($pluginPath)) {
$self->writeWarning(
'Error loading the plugin \'' . $pluginPath . '\'',
$self->_objClass . '->start',
);
}
}
}
# Close the 'dialogue' window and reset the Client IV that stores it
if ($self->busyWin) {
$self->mainWin->closeDialogueWin($self->busyWin);
}
# Start the client loop
if (! $self->startClientLoop()) {
return $self->writeError(
'Could not start the client loop',
$self->_objClass . '->start',
);
}
# Prepare to initialise connections
if ($self->showSetupWizWinFlag) {
# When Axmud runs for the first time (specifically, when there is no Axmud config file)
# this flag will be set to TRUE, instructing us to open the Setup 'wiz' window so the
# new user can initialise a few settings
if ($axmud::TEST_MODE_FLAG) {
# In Axmud test mode, don't show the Setup window at all; just insert a couple of
# tasks into the global initial tasklist
$self->addGlobalInitTask('status_task');
$self->addGlobalInitTask('locator_task');
# Don't show the setup window twice
$self->set_showSetupWizWinFlag(FALSE);
} elsif ($axmud::BLIND_MODE_FLAG) {
# In Axmud blind mode, don't show the Setup window at all; instead, insert a few
# tasks into the global initial tasklist, and modify a few of their settings
# (specifically, none of them open a task window)
$taskObj = $self->addGlobalInitTask('status_task');
if ($taskObj) {
$taskObj->set_startWithWinFlag(FALSE);
}
$taskObj = $self->addGlobalInitTask('locator_task');
if ($taskObj) {
$taskObj->set_startWithWinFlag(FALSE);
}
$taskObj = $self->addGlobalInitTask('compass_task');
if ($taskObj) {
$taskObj->set_startWithWinFlag(FALSE);
}
$taskObj = $self->addGlobalInitTask('divert_task');
if ($taskObj) {
$taskObj->set_requireWinFlag(FALSE);
$taskObj->set_startWithWinFlag(FALSE);
# Turn off sound effects, since TTS is used instead
$taskObj->ivUndef('tellAlertSound');
$taskObj->ivUndef('socialAlertSound');
$taskObj->ivUndef('customAlertSound');
$taskObj->ivUndef('warningAlertSound');
$taskObj->ivUndef('otherAlertSound');
}
# Don't show the setup window twice
$self->set_showSetupWizWinFlag(FALSE);
} else {
# Open the setup window. When it closes, it will open the Connections window for us
$self->mainWin->quickFreeWin('Games::Axmud::WizWin::Setup');
# Disable most main window toolbar/menu items, while the window is open
$self->desktopObj->restrictWidgets();
# Don't show the setup window twice
$self->set_showSetupWizWinFlag(FALSE);
return 1;
}
}
if (@ARGV) {
# The user started Axmud with arguments, e.g. from a Linux terminal:
# ./axmud.pl deathmud.com 5000
# If the port is not specified, the generic port is used:
# ./axmud.pl deathmud.com (use port 23)
# The user can also specify a world profile name:
# ./axmud.pl deathmud
#
# Any of those formats can use baxmud.pl rather than axmud.pl
# Any of those formats can specify one of Axmud's supported text-to-speech engines,
# after all the other arguments (any of the items in $self->constTTSList, e.g.
# 'festival'). If a recognised speech engine is specified, that engine is used for
# all text-to-speech while Axmud is running
$engine = $ARGV[-1];
if (defined $engine && defined $self->ivFind('constTTSList', $engine)) {
pop @ARGV;
$self->ivPoke('forceTTSEngine', $engine);
}
}
if (@ARGV) {
$host = shift @ARGV;
$port = shift @ARGV;
if (@ARGV) {
# (Allow writing to something other than GA::Session - there are no sessions yet)
return $self->writeError(
'Invalid command line arguments (try \'<host> <port>\', \'<host>\' or'
. ' \'<world_name>\')',
$self->_objClass . '->start',
);
}
if (! $port && $self->ivExists('worldProfHash', $host)) {
# $host is a world profile name
$world = $host;
$profObj = $self->ivShow('worldProfHash', $world);
($host, $port) = $profObj->getConnectDetails();
if (! $self->startSession($world, $host, $port)) {
# (Allow writing to something other than GA::Session - there are no sessions
# yet)
return $self->writeError(
'Could not open a session connecting to \'' . $host . '\'',
$self->_objClass . '->start',
);
}
lib/Games/Axmud/Client.pm view on Meta::CPAN
return $axmud::CLIENT->writeImproper($self->_objClass . '->stop', @_);
}
# The END() function will call this function again, before terminating the script, unless
# we set this flag
# (The TRUE value also gives GA::Obj::WorkspaceGrid->stop to destroy a shared 'main'
# window, rather than just disengaging it)
$self->ivPoke('shutdownFlag', TRUE);
# This flag prevents multiple concurrent calls to this function if, for example, the user
# is repeatedly clicking the 'main' window's close button
if ($self->terminatingFlag) {
return undef;
} else {
$self->ivPoke('terminatingFlag', TRUE);
}
# If any text is being convertd to speech right now, interrupt it
$self->ttsInterruptJob();
# Perform an auto-backup of Axmud's data directory, if required
if (
$self->autoBackupMode eq 'all_stop'
|| (
$self->autoBackupMode eq 'interval_stop' && $self->checkBackupInterval()
)
) {
$self->doAutoBackup();
}
# Fire any hooks in any session that are using the 'close_disconnect' hook event
foreach my $sessionObj ($self->listSessions()) {
$sessionObj->checkHooks('close_disconnect');
}
# Stop every current session
if ($self->sessionHash && ! $self->stopAllSessions()) {
return $self->writeError(
'Could not stop all sessions',
$self->_objClass . '->stop',
);
}
# Stop the client loop (if running)
if ($self->clientLoopObj && ! $self->stopClientLoop()) {
return $self->writeError(
'Could not stop the client loop',
$self->_objClass . '->stop',
);
}
# Close any remaining 'internal' windows, restore 'external' windows to their original size/
# position, close any remaining 'free' windows
if (! $self->desktopObj->stop()) {
return $self->writeError(
'Could not stop the desktop object',
$self->_objClass . '->stop',
);
}
# Delete everything in the temporary directories
# (The former is for plugins; the latter is for Axmud code)
foreach my $tempDir ($axmud::DATA_DIR . '/tmp/', $axmud::DATA_DIR . '/data/temp/') {
# Simplest way to empty the directory and all its sub-directories seems to be to
# destroy the directory and make a new one
File::Path::remove_tree($tempDir);
mkdir ($tempDir, 0755);
}
# Halt Gtk3, which halts Axmud
Gtk3->main_quit();
return 1;
}
# Setup
sub loadBasicWorlds {
# Called by $self->start
# Loads data from the basic mudlist and stores it in GA::Obj::BasicWorld objects, ready for
# the Connections window to display
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments, if the file can't be read or if it appears to be
# corrupted
# 1 on success
my ($self, $check) = @_;
# Local variables
my (
$path, $fileHandle, $exitFlag,
@list,
%hash,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->loadBasicWorlds', @_);
}
$path = $axmud::SHARE_DIR . '/items/mudlist/mudlist.txt';
if (! -e $path) {
return undef;
}
# Open the file for reading
if (! open ($fileHandle, "<$path")) {
lib/Games/Axmud/Client.pm view on Meta::CPAN
do {
$count++;
if (! $self->ivExists('zonemapHash', 'temp_' . $count)) {
$name = 'temp_' . $count;
}
} until ($name);
# Unlikely in the extreme that we'll ever use a trillion zonemaps, but let's check anyway
if (! $self->nameCheck($name, 16)) {
return undef;
}
# Create the temporary zonemap
$zonemapObj = Games::Axmud::Obj::Zonemap->new($name, TRUE, $session);
if (! $zonemapObj) {
return undef;
}
# Add the zonemap to the client's registries
$self->ivAdd('zonemapHash', $zonemapObj->name, $zonemapObj);
# Add a single zone model, covering the whole of the zonemap's internal grid
$modelObj = Games::Axmud::Obj::ZoneModel->new($zonemapObj);
$modelObj->{left} = 0;
$modelObj->{right} = 59;
$modelObj->{top} = 0;
$modelObj->{bottom} = 59;
$modelObj->{width} = 60;
$modelObj->{height} = 60;
$zonemapObj->addZoneModel($modelObj);
return $zonemapObj;
}
sub checkCurrentZonemap {
# Called by GA::EditWin::ZoneModel and GA::Cmd::ModifyZoneModel->do
# Checks whether the specified zonemap is being used by any workspace grid (a
# GA::Obj::WorkspaceGrid object), because a zonemap in use cannot be modified
#
# Expected arguments
# $zonemap - The name of the zonemap to check
#
# Return values
# 'undef' in improper arguments or if $zonemap isn't in use by any workspace grid
# 1 if $zonemap is in use by any workspace grid
my ($self, $zonemap, $check) = @_;
# Check for improper arguments
if (! defined $zonemap || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->checkCurrentZonemap', @_);
}
foreach my $workspaceGridObj ($self->desktopObj->ivValues('gridHash')) {
if ($workspaceGridObj->zonemap && $workspaceGridObj->zonemap eq $zonemap) {
return 1;
}
}
# $zonemap isn't in use by any workspace grid
return undef;
}
sub createStandardWinmaps {
# Called by $self->start
# Makes sure the standard GA::Obj::Winmap objects specified by
# $self->constWinmapNameHash (e.g. 'main_fill', 'entry_empty') exist and, if not, create
# them
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if one of the standard winmaps doesn't exist and can't
# be created
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my $modFlag;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->createStandardWinmaps', @_);
}
foreach my $winmapName ($self->ivKeys('constWinmapNameHash')) {
my $winmapObj;
# If this standard winmap hasn't already been created...
if (! $self->ivExists('winmapHash', $winmapName)) {
# ...then create it
$winmapObj = Games::Axmud::Obj::Winmap->new($winmapName);
if (! $winmapObj) {
return $self->writeError(
'Cannot set up the standard \'' . $winmapName . '\' winmap',
$self->_objClass . '->createStandardWinmaps',
);
} else {
# Add the winmap to the client's registries
$self->ivAdd('winmapHash', $winmapObj->name, $winmapObj);
$self->ivAdd('standardWinmapHash', $winmapObj->name, $winmapObj);
$modFlag = TRUE;
lib/Games/Axmud/Client.pm view on Meta::CPAN
# Create a new toolbar button object
my $obj = Games::Axmud::Obj::Toolbar->new(
$name,
$descrip,
FALSE, # Default, not custom, toolbar button
$iconPath,
$instruct,
$sessionFlag,
$connectFlag,
);
if (! $obj) {
return undef;
} else {
$self->ivAdd('toolbarHash', $obj->name, $obj);
$self->ivPush('toolbarList', $obj->name);
}
}
}
} until (! @defaultList);
}
return 1;
}
sub connectBlind {
# Called by $self->start in Axmud blind mode
# Open a series of standard 'dialogue' windows, allowing the visually-impaired user to
# select a world and/or character
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 on success
my ($self, $check) = @_;
# Local variables
my (
$newWorldString, $newCharString, $title, $choice, $connectWorld, $connectWorldObj,
$connectHost, $connectPort, $loginMode, $connectChar, $connectPwd, $connectAccount,
$startFlag,
@faveList, @visitedList, @otherList, @comboList, @comboList2, @comboList3,
%worldHash, %nameHash, %checkHash, %loginHash,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->connectBlind', @_);
}
# Make sure the test window for finding desktop panels has been removed
$self->desktopObj->updateWidgets($self->_objClass . '->connectBlind');
# Get a list of worlds, favourite worlds first, then all visited worlds sorted by number
# of visits, finally unvisited worlds sorted alphabetically
# (Code borrowed from GA::OtherWin::Connect->resetTreeView)
$newWorldString = 'Create new world';
$newCharString = 'Create new character';
# For each world, decide which name to use. Create a hash in the form
# $nameHash{profile_name} = displayed_name
# (where 'displayed_name' is the long name, if available, or the profile name, if not
# At the same time, create a parallel hash to check for duplicate long names, in the form
# $checkHash{long_name} = profile_name
# If duplicate long names are found, 'displayed_name' should include both the long name and
# the profile name
%worldHash = $self->worldProfHash;
foreach my $worldObj (values %worldHash) {
my ($otherWorld, $otherWorldObj);
if ($worldObj->longName) {
if ($worldObj->longName eq $newWorldString) {
$nameHash{$worldObj->name} = $worldObj->longName . ' (' . $worldObj->name . ')';
$checkHash{$worldObj->longName} = $worldObj->name;
} elsif (exists $checkHash{$worldObj->longName}) {
# Amend both entries to include the long name and the profile name
$otherWorld = $checkHash{$worldObj->longName};
$otherWorldObj = $worldHash{$otherWorld};
$nameHash{$worldObj->name} = $worldObj->longName . ' (' . $worldObj->name . ')';
# (There's already an entry in $checkHash matching ->longName)
$nameHash{$otherWorld}
= $otherWorldObj->longName . ' (' . $otherWorldObj->name . ')';
} else {
# Not a duplicate, so just display the long name
$nameHash{$worldObj->name} = $worldObj->longName;
$checkHash{$worldObj->longName} = $worldObj->name;
}
} else {
# Just display the profile name
$nameHash{$worldObj->name} = $worldObj->name;
}
}
# Remove all favourite worlds from %worldHash, so they can be displayed first
foreach my $name ($self->favouriteWorldList) {
if (exists $worldHash{$name}) {
push (@faveList, $worldHash{$name});
delete $worldHash{$name};
}
}
lib/Games/Axmud/Client.pm view on Meta::CPAN
return undef;
}
# Stop the loop
$result = $self->clientLoopObj->stopLoop();
# Update IVs
$self->ivUndef('clientLoopObj');
return $result;
}
sub spinClientLoop {
# Called by $self->clientLoopObj->spinLoop when the client loop spins
# Updates 'internal' windows and some of their strip objects. Makes blinking text in
# Gtk3::Textviews blink on or off. Checks file objects and, if any need to be saved,
# updates the title of 'main' windows
#
# Expected arguments
# $loopObj - The GA::Obj::Loop object handling the client loop
#
# Return values
# 'undef' on improper arguments, if the client loop isn't running or if $loopObj is the
# wrong loop object
# 1 otherwise
my ($self, $loopObj, $check) = @_;
# Local variables
my (
$connectInfoFlag, $result,
@bufferList,
);
# Check for improper arguments
if (! defined $loopObj || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->spinClientLoop', @_);
}
if (
! $self->clientLoopObj
|| $self->clientLoopObj ne $loopObj
|| $self->suspendSessionLoopFlag
) {
return undef;
}
# Update IVs
$self->ivPoke('clientTime', $loopObj->spinTime);
# Update blinkers states for each session
foreach my $session ($self->listSessions()) {
$session->updateBlinkers();
}
# Update 'internal' windows
foreach my $winObj ($self->desktopObj->listGridWins()) {
my (
$stripObj,
%hash,
);
if (
$winObj->winType eq 'main'
|| $winObj->winType eq 'protocol'
|| $winObj->winType eq 'custom'
) {
# If the GA::Strip::GaugeBox strip object's gauge box has been empty for too long,
# remove it
$stripObj = $winObj->ivShow('firstStripHash', 'Games::Axmud::Strip::GaugeBox');
if (
$stripObj
&& defined $stripObj->gaugeCheckTime
&& $stripObj->gaugeCheckTime < $self->clientTime
) {
$stripObj->removeGaugeBox();
}
# If the GA::Strip::Entry strip object's console button is in flashing mode, make
# it flash once
if ($winObj->visibleSession && $winObj->visibleSession->systemMsgCheckTime) {
$stripObj = $winObj->ivShow('firstStripHash', 'Games::Axmud::Strip::Entry');
if ($stripObj) {
$stripObj->set_consoleIconFlash();
}
}
# Update the GA::Strip::ConnectInfo strip object in every 'internal' window
# approximately every second
# (GA::Strip::ConnectInfo are allowed in 'internal' windows besides 'main' windows,
# but they don't display connection data)
if ($winObj->visibleSession) {
if (
! $winObj->visibleSession->connectInfoCheckTime
|| $winObj->visibleSession->connectInfoCheckTime
< int($winObj->visibleSession->sessionTime)
) {
$winObj->setTimeLabel($winObj->visibleSession->getTimeLabelText());
}
} else {
$winObj->setTimeLabel('');
}
# Re-draw blinkers in any 'internal' window which uses them, as appropriate
# (GA::Strip::ConnectInfo are allowed in 'internal' windows besides 'main' windows,
# but blinkers are only updated in the session's 'main' window)
if ($winObj->visibleSession) {
$stripObj
= $winObj->ivShow('firstStripHash', 'Games::Axmud::Strip::ConnectInfo');
if ($stripObj) {
# Import the visible session's blinker state hash (for convenience)
%hash = $winObj->visibleSession->blinkerStateHash;
# Redraw each blinker that is off, but should be on (and vice-versa)
foreach my $blinkerNum (keys %hash) {
my ($blinkerState, $blinkerObj);
$blinkerState = $hash{$blinkerNum};
$blinkerObj = $stripObj->ivShow('blinkerHash', $blinkerNum);
if (
$blinkerObj
&& (
(defined $blinkerState && ! $blinkerObj->onFlag)
|| (! defined $blinkerState && $blinkerObj->onFlag)
)
) {
# Redraw this blinker
$stripObj->drawBlinker($blinkerNum, ! ($blinkerObj->onFlag));
}
}
}
}
}
}
# Get a list of textview buffers which might contain blinking text
foreach my $textViewObj ($self->desktopObj->ivValues('textViewHash')) {
push (@bufferList, $textViewObj->buffer);
}
# Update the buffers' text tags (if it's time to do so), making the text appear or disappear
# on cue
if ($self->clientTime > $self->blinkSlowCheckTime) {
foreach my $buffer (@bufferList) {
my ($blinkTag, $cursorTag);
$blinkTag = $buffer->get_tag_table->lookup('blink_slow');
$cursorTag = $buffer->get_tag_table->lookup('cursor');
if ($blinkTag) {
$blinkTag->set_property('foreground-set', $self->blinkSlowFlag);
$blinkTag->set_property('background-set', $self->blinkSlowFlag);
}
# The textview object's cursor is updated at the same time
if ($cursorTag && ! $self->useFastCursorFlag) {
if ($self->blinkSlowFlag) {
$cursorTag->set_property('underline', 'single');
} else {
$cursorTag->set_property('underline', 'none');
}
}
}
if ($self->blinkSlowFlag) {
$self->ivPoke('blinkSlowFlag', FALSE);
} else {
$self->ivPoke('blinkSlowFlag', TRUE);
}
$self->ivPoke('blinkSlowCheckTime', $self->clientTime + ($self->blinkSlowTime / 2));
}
if ($self->clientTime > $self->blinkFastCheckTime) {
foreach my $buffer (@bufferList) {
my ($blinkTag, $cursorTag);
$blinkTag = $buffer->get_tag_table->lookup('blink_fast');
$cursorTag = $buffer->get_tag_table->lookup('cursor');
if ($blinkTag) {
$blinkTag->set_property('foreground-set', $self->blinkFastFlag);
$blinkTag->set_property('background-set', $self->blinkFastFlag);
}
# The textview object's cursor is updated at the same time
if ($cursorTag && $self->useFastCursorFlag) {
if ($self->blinkFastFlag) {
lib/Games/Axmud/Client.pm view on Meta::CPAN
# Restarts client/session loops stopped by a call to $self->haltSessionLoops
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->restoreSessionLoops', @_);
}
$self->ivPoke('suspendSessionLoopFlag', FALSE);
# The Glib::Timeout might have stopped, or not (depending on what caused the error), so we
# need to formally stop it
foreach my $session ($self->ivValues('sessionHash')) {
$session->startSessionLoop();
}
return 1;
}
sub checkMainWinTitles {
# Called by $self->spinClientLoop
# This titles of all 'main' windows need to be changed from time to time (all 'main' windows
# have the same title, and any changes are performed on all 'main' windows at the same
# time)
# This function checks whether it's necessary to change them and performs the operation, if
# so
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my (
$exitFlag,
@winObjList,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->checkMainWinTitles', @_);
}
# Get an ordered list of all 'main' windows
@winObjList = $self->desktopObj->listGridWins('main');
# Check file objects for the client
if ($self->showModFlag) {
# 'main' window titles contain an asterisk, meaning that some files need to be saved. If
# they have all been saved, we change the titles
OUTER: foreach my $fileObj ($self->ivValues('fileObjHash')) {
if ($fileObj->modifyFlag) {
$exitFlag = TRUE;
last OUTER;
}
}
if (! $exitFlag) {
# All files already saved; change 'main' windows titles
foreach my $winObj (@winObjList) {
$winObj->setMainWinTitle(FALSE);
}
# Update IVs
$self->ivPoke('showModFlag', FALSE);
}
} else {
# 'main' window titles don't contain an asterisk, meaning that no files need to be
# saved. If any of them now need to be saved, we change the titles
OUTER: foreach my $fileObj ($self->ivValues('fileObjHash')) {
if ($fileObj->modifyFlag) {
$exitFlag = TRUE;
last OUTER;
}
}
if ($exitFlag) {
# At least one file needs to be saved; change the label (the window's ->showModFlag
# is automatically updated)
# All files already saved; change 'main' window titles
foreach my $winObj (@winObjList) {
$winObj->setMainWinTitle(TRUE);
}
# Update IVs
$self->ivPoke('showModFlag', TRUE);
}
}
return 1;
}
sub paneModifyBorder {
lib/Games/Axmud/Client.pm view on Meta::CPAN
# Immediately restore the border size of any other pane object in this window
foreach my $time ($self->ivKeys('paneRestoreHash')) {
my $otherPaneObj = $self->ivShow('paneRestoreHash', $time);
if ($otherPaneObj->winObj && $otherPaneObj->winObj eq $paneObj->winObj) {
# Restore this pane object's border size immediately
$otherPaneObj->set_borderWidth(FALSE);
$self->ivDelete('paneRestoreHash', $time);
}
}
# Modify the pane's border size
$paneObj->set_borderWidth(TRUE);
# Add an entry for this pane object, setting the time at which its border will be restored
# Pane object numbers are not unique to the client, so in this hash we take the unusual
# step of using a system time as a key, matching the time at which the border size
# should be restored
$self->ivAdd('paneRestoreHash', ($self->clientTime + $self->paneDelay), $paneObj);
return 1;
}
sub paneRestoreBorder {
# Called by $self->spinClientLoop
# In 'internal' windows, the strip object GA::Strip::Entry includes a switcher button to
# switch between pane objects (GA::Table::Pane); the scroll lock/split screen buttons
# then apply to the selected pane object
# When a pane object is selected, $self->paneModifyBorder is called to briefly increase the
# pane's border size; the client loop calls this function to check whether it's time to
# restore any border sizes, and to restore them if so
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->paneRestoreBorder', @_);
}
foreach my $time ($self->ivKeys('paneRestoreHash')) {
my $paneObj;
if ($time < $self->clientTime) {
$paneObj = $self->ivShow('paneRestoreHash', $time);
# Check the pane object and its window still exist (just in case)
if (
$paneObj->winObj
&& $self->desktopObj->ivExists('gridWinHash', $paneObj->winObj->number)
) {
# Restore this pane object's border size immediately
$paneObj->set_borderWidth(FALSE);
$self->ivDelete('paneRestoreHash', $time);
}
}
}
return 1;
}
# Session methods
sub startSession {
# Called initially by GA::OtherWin::Connect->connectWorldCallback or $self->connectBlind,
# thereafter by GA::Cmd::Connect->do, Reconnect->do, XConnect->do, Telnet->do, SSH->do and
# SSL->do
# Starts a session (managing a single connection to a world)
#
# Expected arguments
# $world - The world's name (matches a world profile name)
#
# Optional arguments
# $host - The world's host address (if 'undef', default host address used)
# $port - The world's port (if 'undef', default host port used)
# $char - A character name (matches a character profile name (if 'undef', no
# character profile used)
# $pass - The corresponding password (if 'undef', the world profile is consulted
# to provide the password, if possible)
# $account - The character's associated account name, for worlds that use both
# (if 'undef', no account name used)
# $protocol - If set to 'telnet', 'ssh' or 'ssl', that protocol is used; if 'undef'
# or an unrecognised value, the world profile's ->protocol is used
# $loginMode - Set when called by $self->connectBlind, when a new world profile is to
# be created, and the user has specified what type of ->loginMode this
# world uses; otherwise set to 'undef'
# $offlineFlag - If TRUE, the session doesn't actually connect to the world, but still
# loads all data and makes some client commands available. If FALSE
# (or 'undef'), the session tries to connect to the world
# $tempFlag - If set to TRUE, the world profile is a temporary world profile,
# created because the user didn't specify a world name. File saving
# in the session will be disabled. Otherwise set to FALSE (or
# 'undef')
#
# Return values
# 'undef' on improper arguments or if the GA::Session object can't be created or started
# The new GA::Session object on success
my (
$self, $world, $host, $port, $char, $pass, $account, $protocol, $loginMode,
$offlineFlag, $tempFlag, $check,
) = @_;
# Local variables
my ($actualCount, $tempName, $successFlag, $worldObj, $newSession, $index);
# Check for improper arguments
if (! defined $world || defined $check) {
lib/Games/Axmud/Client.pm view on Meta::CPAN
# Plugin not found
return undef;
}
# Enable the plugin
$pluginObj->set_enabledFlag(TRUE);
# If any of this plugin's tasks defined text-to-speech attributes (TTS), update the
# our customisable attribute hashes, re-assigning existing attributes to these tasks, if
# necessary
foreach my $taskName ($self->ivKeys('pluginTaskHash')) {
if ($plugin eq $self->ivShow('pluginTaskHash', $taskName)) {
$self->ttsAssignAttribs($taskName);
}
}
# Restore the plugin's client commands. If there are any (built-in) client commands of the
# same name, move them somewhere else, in case this plugin is disabled again at some point
# in the future
foreach my $pluginCmd ($self->ivKeys('pluginCmdHash')) {
my ($otherPlugin, $pluginCmdObj, $originalCmdObj);
$otherPlugin = $self->ivShow('pluginCmdHash', $pluginCmd);
if ($otherPlugin eq $plugin) {
if ($self->ivExists('clientCmdHash', $pluginCmd)) {
# Restore the plugin command, and move the original to a special IV, so that it
# too can be restored if the plugin is re-disabled at some point
$pluginCmdObj = $self->ivShow('replaceClientCmdHash', $pluginCmd);
$originalCmdObj = $self->ivShow('clientCmdHash', $pluginCmd);
$self->ivAdd('replaceClientCmdHash', $pluginCmd, $originalCmdObj);
$self->ivAdd('clientCmdHash', $pluginCmd, $pluginCmdObj);
} else {
# Just restore the plugin command
$pluginCmdObj = $self->ivShow('replaceClientCmdHash', $pluginCmd);
$self->ivAdd('clientCmdHash', $pluginCmd, $pluginCmdObj);
$self->ivDelete('replaceClientCmdHash', $pluginCmd);
}
}
}
# Also restore the plugin's client commands (along with any group headings) to
# $self->clientCmdPrettyList
if ($self->ivExists('clientCmdReplacePrettyHash', $plugin)) {
$listRef = $self->ivShow('clientCmdReplacePrettyHash', $plugin);
if (defined $listRef && @$listRef) {
$self->ivPush('clientCmdPrettyList', @$listRef);
}
}
# Sensitise/desensitise menu bar/toolbar items, depending on current conditions
$self->desktopObj->restrictWidgets();
# Operation complete
return 1;
}
sub disablePlugin {
# Called by GA::Cmd::DisablePlugin->do
# Disables a loaded plugin. Halts all of the plugin's tasks (new tasks from the plugin
# can't start). Closes any windows of the types added by the plugin. Disables any client
# commands added by the plugin
#
# Expected arguments
# $plugin - The name of the plugin to disable
#
# Return values
# 'undef' on improper arguments or if a plugin called $plugin has not been loaded
# 1 otherwise
my ($self, $plugin, $check) = @_;
# Local variables
my ($pluginObj, $listRef, $index, $matchFlag);
# Check for improper arguments
if (! defined $plugin || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->disablePlugin', @_);
}
# Find the plugin object
$pluginObj = $self->ivShow('pluginHash', $plugin);
if (! $pluginObj) {
# Plugin not found
return undef;
}
# Disable the plugin
$pluginObj->set_enabledFlag(FALSE);
# If any of this plugin's tasks are running, in any session, halt them
foreach my $session ($self->listSessions()) {
foreach my $taskObj ($session->ivValues('currentTaskHash')) {
my $thisPlugin = $self->ivShow('pluginTaskHash', $taskObj->name);
if (defined $thisPlugin && $thisPlugin eq $plugin) {
# Halt the task
$session->pseudoCmd('halttask ' . $taskObj->uniqueName);
}
}
}
# If any of our customisable text-to-speech (TTS) hashes have assigned an attribute to
# this plugin's tasks, re-assign the attributes to a built-in task, if possible, or
# otherwise remove the attributes completely
foreach my $taskName ($self->ivKeys('pluginTaskHash')) {
if ($plugin eq $self->ivShow('pluginTaskHash', $taskName)) {
$self->ttsResetAttribs($taskName);
}
}
# Close any 'free' windows added by the plugin
foreach my $winObj
(sort {$a->number <=> $b->number} ($self->desktopObj->ivValues('freeWinHash')))
{
my $thisPlugin = $self->ivShow('pluginFreeWinHash', $winObj->_objClass);
if (defined $thisPlugin && $thisPlugin eq $plugin) {
# Close the window
$winObj->winDestroy();
}
}
# Close any 'grid' windows added by the plugin
foreach my $winObj
(sort {$a->number <=> $b->number} ($self->desktopObj->ivValues('freeWinHash')))
{
my $thisPlugin = $self->ivShow('pluginGridWinHash', $winObj->_objClass);
if (defined $thisPlugin && $thisPlugin eq $plugin) {
# For 'main' windows, terminate any session using the window
if ($winObj->winType eq 'main') {
foreach my $session
(sort {$a->number <=> $b->number} ($self->ivValues('sessionHash')))
{
if ($session->mainWin && $session->mainWin eq $winObj) {
$self->stopSession($session);
}
}
}
# Close the window
$winObj->winDestroy();
}
}
# If the plugin loaded any client commands that replaced an existing client command of the
# same name, restore the original. Otherwise, remove the command completely
foreach my $pluginCmd ($self->ivKeys('pluginCmdHash')) {
my ($otherPlugin, $pluginCmdObj, $originalCmdObj);
$otherPlugin = $self->ivShow('pluginCmdHash', $pluginCmd);
if ($otherPlugin eq $plugin) {
if ($self->ivExists('replaceClientCmdHash', $pluginCmd)) {
# Restore the original, and move the plugin command to a special IV, so that it
# too can be restored if the plugin is re-enabled at some point
$originalCmdObj = $self->ivShow('replaceClientCmdHash', $pluginCmd);
$pluginCmdObj = $self->ivShow('clientCmdHash', $pluginCmd);
$self->ivAdd('replaceClientCmdHash', $pluginCmd, $pluginCmdObj);
$self->ivAdd('clientCmdHash', $pluginCmd, $originalCmdObj);
} else {
# Just move the plugin command to a special IV, so that it can be restored if
# the plugin is re-enabled
$pluginCmdObj = $self->ivShow('clientCmdHash', $pluginCmd);
$self->ivAdd('replaceClientCmdHash', $pluginCmd, $pluginCmdObj);
$self->ivDelete('clientCmdHash', $pluginCmd);
}
}
}
# Any plugin client commands should also have been added to $self->clientCmdPrettyList.
# Attempt to remove them
if ($self->ivExists('clientCmdReplacePrettyHash', $plugin)) {
$listRef = $self->ivShow('clientCmdReplacePrettyHash', $plugin);
if (defined $listRef && @$listRef) {
# Search through $self->clientCmdPrettyList, looking for an exact match for the
# contents of the list in $listRef
$index = -1;
do {
my $failFlag;
$index++;
if ($self->ivIndex('clientCmdPrettyList', $index) eq $$listRef[0]) {
# Found the first item in $listRef; do the rest of the items match?
OUTER: for (my $count = $index; $count < scalar @$listRef; $count++) {
if (
$self->ivIndex('clientCmdPrettyList', $count) ne $$listRef[$count]
) {
# Nope! Try again on the next iteration of the do loop
$failFlag = TRUE;
last OUTER;
}
}
if (! $failFlag) {
# Found a complete match
$matchFlag = TRUE;
}
}
} until ($matchFlag || $index == ((scalar $self->clientCmdPrettyList) - 1));
if ($matchFlag) {
# Remove the group headings and client commands from this plugin
$self->ivSplice('clientCmdPrettyList', $index, scalar @$listRef);
}
}
}
# Sensitise/desensitise menu bar/toolbar items, depending on current conditions
$self->desktopObj->restrictWidgets();
# Operation complete
return 1;
}
sub addPluginCmds {
# Called by any Axmud plugin
# Adds client commands defined in the plugin
#
# Expected arguments
# $plugin - The plugin's main package (declared in the file header)
#
# Optional arguments
# @list - A list of client commands, grouped thematically (using the same format as
# $self->clientCmdPrettyList uses). If the list is empty, no commands are
# added
#
# Return values
# 'undef' on improper arguments or if a client command object can't be created
# Otherwise returns the number of client command objects created (may be 0)
my ($self, $plugin, @list) = @_;
# Local variables
my (
$pluginObj, $count,
@clientCmdList, @clientCmdPrettyList,
%clientCmdHash, %replaceClientCmdHash, %userCmdHash, %pluginCmdHash,
);
# Check for improper arguments
if (! defined $plugin) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addPluginCmds', @_);
}
# Find the plugin object
$pluginObj = $self->ivShow('pluginHash', $plugin);
if (! $pluginObj) {
# Plugin not found - a very unlikely occurrence for this function, but it's worth
# checking anyway
return undef;
}
# If no commands specified, nothing to add
if (! @list) {
return 0;
}
# Import GA::Client IVs; they are only updated if all commands are sucessfully added
%clientCmdHash = $self->clientCmdHash;
%replaceClientCmdHash = $self->replaceClientCmdHash;
@clientCmdList = $self->clientCmdList;
%userCmdHash = $self->userCmdHash;
@clientCmdPrettyList = $self->clientCmdPrettyList;
%pluginCmdHash = $self->pluginCmdHash;
lib/Games/Axmud/Client.pm view on Meta::CPAN
}
}
# Operation complete
return $count;
}
sub addPluginMenus {
# Called by any Axmud plugin
# Adds menu items defined in the plugin to any menu strip object (GA::Strip::MenuBar)
# displayed in any 'internal' window while the client is running (and the plugin is
# enabled)
#
# Expected arguments
# $plugin - The plugin's main package (declared in the file header)
#
# Optional arguments
# $funcRef - Reference to a function which contain the code to add menu items to a
# Gtk3::Menu widget, pre-existing or created by this function. The
# referenced function must accept the strip object and Gtk3::Menu as
# arguments, and return 'undef' on failure or 1 on success
#
# Return values
# 'undef' on improper arguments or if the menu items can't be added
# 1 otherwise
my ($self, $plugin, $funcRef, $check) = @_;
# Local variables
my ($pluginObj, $subMenu);
# Check for improper arguments
if (! defined $plugin || ! defined $funcRef || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addPluginWidgets', @_);
}
# Find the plugin object
$pluginObj = $self->ivShow('pluginHash', $plugin);
if (! $pluginObj) {
# Plugin not found - a very unlikely occurrence for this function, but it's worth
# checking anyway
return undef;
}
# Each plugin can only call this function once
if ($self->ivExists('pluginMenuFuncHash', $plugin)) {
return undef;
} else {
$self->ivAdd('pluginMenuFuncHash', $plugin, $funcRef);
}
# Any 'internal' windows which already exist and which have a menu strip object should add a
# sub-menu for this plugin now; any new 'internal' windows created from now will
# automatically call the referenced function to add their own sub-menus
foreach my $winObj ($self->desktopObj->ivValues('gridWinHash')) {
my ($stripObj, $subMenu);
if (
$winObj->winType eq 'main'
|| $winObj->winType eq 'protocol'
|| $winObj->winType eq 'custom'
) {
$stripObj = $winObj->ivShow('firstStripHash', 'Games::Axmud::Strip::MenuBar');
if ($stripObj) {
$subMenu = $stripObj->addPluginWidgets($plugin);
if (! $subMenu) {
return undef;
}
# Call the referenced function to add menu items to this sub-menu
if (! &$funcRef($stripObj, $subMenu)) {
return undef;
}
# Update the window to show the new menu items
$winObj->winShowAll($self->_objClass . '->addPluginMenus');
}
}
}
return 1;
}
sub addPluginMxpFilters {
# Called by any Axmud plugin
# Adds the plugin function that's used to apply MXP file filters
#
# Expected arguments
# $plugin - The plugin's main package (declared in the file header)
# $funcRef - Reference to the function that does the conversion
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $plugin, $funcRef, $check) = @_;
# Local variables
my $pluginObj;
# Check for improper arguments
if (! defined $plugin || ! defined $funcRef || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addPluginMxpFilters', @_);
}
# Find the plugin object
$pluginObj = $self->ivShow('pluginHash', $plugin);
if (! $pluginObj) {
lib/Games/Axmud/Client.pm view on Meta::CPAN
$self->ivPoke('allowSoundFlag', FALSE);
}
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->set_allowSoundFlag');
# Any sessions which are connected to a world, and which are using MXP, should re-issue
# their <SUPPORTS> tag (this isn't part of the MXP spec, but it can't do any damage; the
# world will either implement an unsolicited <SUPPORTS> tag, or it won't)
foreach my $session ($self->ivValues('sessionHash')) {
if ($session->status eq 'connected' && $session->mxpMode eq 'client_agree') {
# Process a fake <SUPPORT> tag, as if the world had sent one
$session->processMxpSupportElement('<SUPPORT>', 0, 'SUPPORT');
}
}
return 1;
}
sub set_audioCmd {
my ($self, $cmd, $check) = @_;
# Check for improper arguments
if (! defined $cmd || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->set_audioCmd', @_);
}
$self->ivPoke('audioCmd', $cmd);
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->set_audioCmd');
return 1;
}
sub set_autoCompleteMode {
my ($self, $mode, $check) = @_;
# Check for improper arguments
if (! defined $mode || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->set_autoCompleteMode', @_);
}
# Update IVs
$self->ivPoke('autoCompleteMode', $mode);
$self->ivUndef('instructBufferPosn');
$self->ivUndef('cmdBufferPosn');
foreach my $session ($self->listSessions()) {
$session->set_instructBufferPosn();
$session->set_cmdBufferPosn();
}
foreach my $winObj ($self->desktopObj->ivValues('gridWinHash')) {
$winObj->resetEntry();
}
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->set_autoCompleteMode');
return 1;
}
sub set_autoCompleteParent {
my ($self, $parent, $check) = @_;
# Check for improper arguments
if (! defined $parent || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->set_autoCompleteParent', @_);
}
# Update IVs
if ($parent eq 'client') {
$self->ivPoke('autoCompleteParent', 'combined');
} else {
$self->ivPoke('autoCompleteParent', 'session'); # Initial value
}
$self->ivUndef('instructBufferPosn');
$self->ivUndef('cmdBufferPosn');
foreach my $session ($self->listSessions()) {
$session->set_instructBufferPosn();
$session->set_cmdBufferPosn();
}
foreach my $winObj ($self->desktopObj->ivValues('gridWinHash')) {
$winObj->resetEntry();
}
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->set_autoCompleteParent');
return 1;
}
sub set_autoCompleteType {
my ($self, $type, $check) = @_;
# Check for improper arguments
if (! defined $type || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->set_autoCompleteType', @_);
}
# Update IVs
if ($type eq 'instruct') {
$self->ivPoke('autoCompleteType', 'instruct');
} else {
$self->ivPoke('autoCompleteType', 'cmd'); # Initial value
}
$self->ivUndef('instructBufferPosn');
$self->ivUndef('cmdBufferPosn');
foreach my $session ($self->listSessions()) {
$session->set_instructBufferPosn();
$session->set_cmdBufferPosn();
}
foreach my $winObj ($self->desktopObj->ivValues('gridWinHash')) {
$winObj->resetEntry();
}
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->set_autoCompleteType');
return 1;
}
sub set_autoConnectList {
my ($self, @args) = @_;
# (No improper arguments to check; @args can be an empty list)
$self->ivPoke('autoConnectList', @args);
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->set_autoConnectList');
return 1;
}
sub set_autoRetainFileFlag {
my ($self, $flag, $check) = @_;
# Check for improper arguments
if (! defined $flag || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->set_autoRetainFileFlag', @_);
}
if ($flag) {
$self->ivPoke('autoRetainFileFlag', TRUE);
} else {
$self->ivPoke('autoRetainFileFlag', FALSE);
}
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->set_autoRetainFileFlag');
return 1;
}
sub set_autoSaveFlag {
my ($self, $flag, $check) = @_;
# Check for improper arguments
if (! defined $flag || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->set_autoSaveFlag', @_);
}
if ($flag) {
$self->ivPoke('autoSaveFlag', TRUE);
} else {
$self->ivPoke('autoSaveFlag', FALSE);
lib/Games/Axmud/Client.pm view on Meta::CPAN
if ($type eq 'before') {
$self->ivPoke('statusEventBeforeCount', $number);
} else {
$self->ivPoke('statusEventAfterCount', $number);
}
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->set_statusEvent');
return 1;
}
sub set_storeGridPosnFlag {
my ($self, $flag, $check) = @_;
# Check for improper arguments
if (! defined $flag || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->set_storeGridPosnFlag', @_);
}
if ($flag) {
$self->ivPoke('storeGridPosnFlag', TRUE);
} else {
$self->ivPoke('storeGridPosnFlag', FALSE);
}
return 1;
}
sub add_storeGridPosn {
# Called by GA::Win::Internal->setConfigureEvent and GA::Win::Map->setConfigureEvent
# Also called by GA::Obj::Workspace->createGridWin and ->createSimpleGridWin
my ($self, $winObj, $xPos, $yPos, $width, $height, $ignoreFlag, $check) = @_;
# Check for improper arguments
if (! defined $winObj || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->add_storeGridPosn', @_);
}
# Do nothing if the storage flag isn't set, if it's not a 'grid' window or if it's an
# 'external' window
# Allow storing of position but not size, or size but not position, but not both
if (
(! $self->storeGridPosnFlag && ! $ignoreFlag)
|| $winObj->winCategory ne 'grid'
|| $winObj->winType eq 'external'
|| (! defined $xPos && ! defined $yPos && ! defined $width && ! defined $height)
) {
return undef;
}
# An entry is added/replaced in $self->storeGridPosnHash for any 'grid' window, but if there
# are several windows with the same ->winName open, only the one which was opened first is
# used
foreach my $otherWinObj ($self->desktopObj->ivValues('gridWinHash')) {
if (
$otherWinObj ne $winObj
&& $otherWinObj->winName eq $winObj->winName
&& $otherWinObj->number < $winObj->number
) {
return undef;
}
}
# Update the hash IV
$self->ivAdd(
'storeGridPosnHash',
$winObj->winName,
[$xPos, $yPos, $width, $height],
);
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->add_storeGridPosn');
return 1;
}
sub del_storeGridPosn {
my ($self, $winName, $check) = @_;
# Check for improper arguments
if (! defined $winName || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->del_storeGridPosn', @_);
}
$self->ivDelete('storeGridPosnHash', $winName);
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->del_storeGridPosn');
return 1;
}
sub reset_storeGridPosn {
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->reset_storeGridPosn', @_);
}
$self->ivEmpty('storeGridPosnHash');
# The data stored in this IV is saved in the 'config' file
$self->setModifyFlag('config', TRUE, $self->_objClass . '->reset_storeGridPosn');
return 1;
}
sub add_systemMsg {
lib/Games/Axmud/Client.pm view on Meta::CPAN
return $axmud::CLIENT->writeImproper($self->_objClass . '->add_zmpPackage', @_);
}
# Can't replace an existing package object using one with the same name
if ($self->ivExists('zmpPackageHash', $obj->name)) {
return undef;
} else {
$self->ivAdd('zmpPackageHash', $obj->name, $obj);
return $obj;
}
}
sub add_zonemap {
my ($self, $obj, $check) = @_;
# Check for improper arguments
if (! defined $obj || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->add_zonemap', @_);
}
# Update IVs
$self->ivAdd('zonemapHash', $obj->name, $obj);
# The data stored in this IV is saved in the 'zonemaps' file
$self->setModifyFlag('zonemaps', TRUE, $self->_objClass . '->add_zonemap');
return 1;
}
sub del_zonemap {
# Called by GA::Cmd::DeleteZonemap->do and, for temporary zonemaps, GA::Session->stop
# (only; if a zonemap in use by a workspace grid is deleted, bad things can happen)
my ($self, $zonemapName, $check) = @_;
# Check for improper arguments
if (! defined $zonemapName || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->del_zonemap', @_);
}
# Update IVs
$self->ivDelete('zonemapHash', $zonemapName);
# The data stored in this IV is saved in the 'zonemaps' file
$self->setModifyFlag('zonemaps', TRUE, $self->_objClass . '->del_zonemap');
return 1;
}
##################
# Accessors - get
sub desktopObj
{ $_[0]->{desktopObj} }
sub mainWin
{ $_[0]->{mainWin} }
sub aboutWin
{ $_[0]->{aboutWin} }
sub busyWin
{ $_[0]->{busyWin} }
sub connectWin
{ $_[0]->{connectWin} }
sub consoleWin
{ $_[0]->{consoleWin} }
sub constIVHash
{ my $self = shift; return %{$self->{constIVHash}}; }
sub constReservedHash
{ my $self = shift; return %{$self->{constReservedHash}}; }
sub loadConfigFlag
{ $_[0]->{loadConfigFlag} }
sub saveConfigFlag
{ $_[0]->{saveConfigFlag} }
sub loadDataFlag
{ $_[0]->{loadDataFlag} }
sub saveDataFlag
{ $_[0]->{saveDataFlag} }
sub deleteFilesAtStartFlag
{ $_[0]->{deleteFilesAtStartFlag} }
sub fileFailFlag
{ $_[0]->{fileFailFlag} }
sub emergencySaveFlag
{ $_[0]->{emergencySaveFlag} }
sub autoSaveFlag
{ $_[0]->{autoSaveFlag} }
sub autoSaveWaitTime
{ $_[0]->{autoSaveWaitTime} }
sub autoRetainFileFlag
{ $_[0]->{autoRetainFileFlag} }
sub autoBackupMode
{ $_[0]->{autoBackupMode} }
sub autoBackupDir
{ $_[0]->{autoBackupDir} }
sub autoBackupInterval
{ $_[0]->{autoBackupInterval} }
sub autoBackupDate
{ $_[0]->{autoBackupDate} }
sub autoBackupFileType
{ $_[0]->{autoBackupFileType} }
sub autoBackupAppendFlag
{ $_[0]->{autoBackupAppendFlag} }
sub fileObjHash
{ my $self = shift; return %{$self->{fileObjHash}}; }
sub configFileObj
{ $_[0]->{configFileObj} }
sub configWorldProfList
{ my $self = shift; return @{$self->{configWorldProfList}}; }