XData.pm


package XSTAB::XData;
# This module stores all data required to be shared across the modules.
# $Id: XData.pm,v 1.8 2003/03/24 02:20:38 dranok Exp $
# This module is released under the GPL
# Author: DranoK
# Email: dranok@users.sourceforge.net
###############################################################


NAME

XSTAB::XData;


DESCRIPTION

This is the global storage area for XStab.


INITIALIZATION

The following items are exported:

%Players
This is the main storage hash for player record data

%Global
This is the storage hash for non-player global data, mostly things loaded from the XStab configuration file

@Debug_log
The debug queue. XStab does not log things immediately, rather it pushes events into the debug array to be logged at a later time, improving efficiency.

@Voice_queue
The voice queue. XStab does not issue commands via the Voice module immediately, rather it pushes events into the voice array to be issued at a later time, improving efficiency.

@Admin_queue
The admin queue. XStab does not log admin commands immediately, rather it pushes these commands into the admin array to be issued at a later time, improving efficiency.

&load_config
&write_log
&do_log
&XSerialize
&XSerialStore
These are functions which are exported. Due to the global nature of this module, an OO approach does not make sense.

require Exporter;

use IO::File;
use strict;

our @ISA = qw(Exporter);
our @EXPORT = qw(%Players %Global @Debug_log @Voice_queue @Admin_queue load_config write_log do_log XSerialize XSerialStore);

my $VERSION = '0.9';

# Global variables
# (Other packages must use XSTAB::Xdata)
our %Players;
our @Debug_log;
our @Voice_queue;
our @Admin_queue;
our %Global;


EXPORTED FUNCTIONS

load_config (string file)
This function will load the configuration file specified. The format of the config file is simple enough; a line reading ``FOO = BAR'' would set ``$Global{FOO} = 'BAR''' Before returning, load_config sets global variables, such as ``$Global{sp}'', which is used to serialize data into a single scalar. I'm not quite sure what I meant by my idiot comment...
sub load_config
{
  my $cfile = shift;

  my $tmpbuf;
  my $fileh = IO::File->new($cfile) or die "Cannot open $cfile: $!\n";
  $fileh->sysread($tmpbuf, 65507);
  $fileh->close();

  my @tmpar = split('\n', $tmpbuf);
  foreach my $elem (@tmpar) {
    #                       KEY             =    VALUE
    if ($elem =~ /^[\s]*([a-zA-Z0-9_]+)[\s]*=[\s]*(.*)[\s]*$/) {
      my $key = $1;
      my $value = $2;
      print "INITIALIZATION: Setting Global{$key} = $value\n";
      $Global{$key} = $value;
    }
  }
  # Just in case someone's an idiot
  $Global{CFile} = $cfile;
  $Global{sp} = ":x:";
  $Global{sp2} = "::xxx::";
  $Global{MAX_WRITE} = 20;
}

write_log (int numlines)
This function will write up to numlines elements from @Debug_log to the log filehandle, as well as to the debug module (see debug module for details).

NOTE: This function uses blocking IO, despite its use of syswrite. This is because something is terribly, terribly wrong if we can't log, and thus the process probably SHOULD freeze. It's different than timing out a read, when we have log data we want to write we NEED to write it. See notes on blocking used in the XDbiMySQL storage module as well

sub write_log 
{
  my $lines = shift;

  my $time = time;
  while($lines)
  {
    last if (scalar(@Debug_log) < 1);
    my ($prio, $printline) = split($Global{sp}, shift(@Debug_log));
    $main::debug->pushlog($prio, $printline);
    if ($prio <= $Global{Debug_level})
    {
      $Global{logfh}->syswrite("[$time:$prio] $printline\n");
    }
    $lines--;
  }
}

do_log (string Message, int Priority)
This is the master do_log function, called from all overridden do_logs. This function will actually push the element into the @Debug_log queue.
sub do_log
{
  my $data = shift;
  my $prio = shift;

  # Instant debug info
  if ($Global{Use_debug}) {
    print "$prio: $data\n";
  }
  push(@Debug_log, "$prio$Global{sp}$data");
}

XSerialStore (int ClientID, string Field, string Data)
This function will take a serialized scalar Data (in the form of ``a:aval$Global{sp}bval$Global{sp}...$Global{sp}z:zval'' [``a:aval:x:b:bval:x:c:cval:x:...z:zval'']) and store $aval in $Players{ClientID}{Field}{a}, $bval in $Players{ClientID}{Field}{b}, ... $zval in $Players{ClientID}{Field}{z}
sub XSerialStore
{
  my $client = shift;
  my $field = shift;
  my $string = shift;

  my @list = split(',', $string);
  foreach my $elem (@list) {
    my ($f, $v) = split(':', $elem);
    $Players{$client}{$field}{$f} = $v;
  }
}

XSerialize (int ClientID, string Field)
This function will take loop through all keys of $Players{ClientID}{Field} and return a single scalar result, basically the reverse of what XSerialStore does.

For example:

        $Players
            |-ClientID 
                 |-Field
                     |---a = val1
                     |---b = valb
                     ...
                     |---c = valc

This structure would be returned as ``a:aval$Global{sp}b:bval$Global{sp}...$Global{sp}z:zval'' (``a:aval:x:b:bval:x:...:x:z:zval'')

sub XSerialize
{
  my $client = shift;
  my $field = shift;
  my $string;

  foreach my $elem (keys %{$Players{$client}{$field}}) {
    $string .= "$elem:$Players{$client}{$field}{$elem},";
  }

  $string =~ s/,$//;
  $string =~ s/^:$//;
  return $string;
}

1;


AUTHOR

This module was coded by DranoK and is part of the core XStab modules. You may directly contact DranoK at dranok@users.sourceforge.net, or by posting to the forums at:

        http://www.oltl.net/forums/forumdisplay.php?s=&forumid=25