Patrick Riley <pfr+@cs.cmu.edu>
Computer Science Department
Carnegie Mellon University
Copyright (C) 1999 Patrick Riley

Logplayer for Layered Extrospection

*************************************************************************************
Contents:
*************************************************************************************
*Legal Stuff
*Overview
*Installation
*Added Options
*Use of the Program
*Format for the Players' Logfiles
*Sample Code

*************************************************************************************
LEGAL STUFF
*************************************************************************************

This application was developed by Peter Stone, Manuela Veloso, and Patrick Riley

You may copy and distribute this program freely as long as you retain this notice.
If you make any changes or have any comments we would appreciate a message.


This program is a slightly modified version of the logplayer
application provided with the Soccer Server System (see
http://ci.etl.go.jp/~noda/soccer/server/index.html).  We made minimal
changes to logplayer from Soccer Server version 5.15 , and the Soccer
Server license still applies:


License of Soccer Server 

 Conditions for using Soccer Server: 

     1.This version of Soccer Server is still under developing and may have serious problem. Neither Electrotechnical Laboratory (ETL) nor development staffs of
        Soccer Server provides warranty. Use the software at your own risk. 
     2.Copyright of all program code and documentation included in source or binary package of Soccer Server belongs to ETL. 
     3.You can use Soccer Server for research and/or education purpose only, commercial use is not allowed. 
     4.If you want to re-distribute Soccer Server to someone, you should inform us of destination of re-distribution to the address noda@etl.go.jp. via e-mail. 


*************************************************************************************
OVERVIEW
*************************************************************************************

This application was originally developed for use with CMUnited'99 (see
http://www.cs.cmu.edu/afs/cs/usr/pstone/mosaic/RoboCup/CMUnited-sim.html)
This program is designed to read a record file from the soccer server
along with the recordings of the reasoning process by each of the
players and show both of them simultaneously. This greatly aids in
understanding why the players perform as they do, allowing better
debugging and tuning of behaviors. This process, which we call
Layered Extrospection, is described more fully in our
championship paper, which is available at
http://www.cs.cmu.edu/afs/cs/usr/pstone/mosaic/RoboCup/CMUnited-sim.html

A sample logfile with extrospection logs is available at the
CMUnited'99 web page (listed above).

*************************************************************************************
INSTALLATION
*************************************************************************************
First, run './configure'
Then run './make'

You should now have an executable 'logplayer'. You will need the
soccermonitor application of the Soccer Server System to use with this
modified logplayer.

*************************************************************************************
ADDED OPTIONS
*************************************************************************************

In addition to the options in the original logplayer, the
following options have been added

show_action_logs <on|off> : Default off. With this option off, the
                            program performs the same as the normal
                            logplayer distributed with Soccer Server
                            version 5.15. Turning this on instructs
                            the logplayer to look for player record
                            files also.

action_logs_dir <dir> : Default none. <dir> is the directory where the
                        players' record files reside.

Note that these can be provided on the command line (preceded by a
'-') or in an option file, just like the other options for the logplayer

*************************************************************************************
USE OF THE PROGRAM
*************************************************************************************

If you start the program with show_action_logs on, the logplayer
attempts to locate the player record files. It will then display the
appropriate information for the file for the selected player, output
level, and cycle. This information is displayed to the standard out of
the logplayer process (usually the terminal where you started the
logplayer).

The logplayer window will have 6 extra buttons. From left to right, the buttons are:
-Player number down
-Player number up
	These buttons change the currently selected player. To change
	teams, simply continue past the the normal range of player
	numbers (usually 1-11). For example if you are at Player Left
	11 and press P+, then you will be at Right 1.
	The currently selected player is printed to standard out after
	this button is pushed.

-Level of display down
-Level of display up
-Level of display to 0
-Level of display to maximum
	These buttons change the currently displayed level of
	output. Each line in the players' record files has a level
	associated with it. The higher numbers are considered to be
	deeper in the hierarchy, containing more detailed
	information. Therefore if your currently selected level is 50,
	all lines in the file for that cycle whose level is less than
	or equal to 50 is displayed. This allows us to proceed from a
	general description of the players' reasoning (for example, "I
	have the ball and should do something with it") to a slightly
	lower level ("I want to pass to player 8") to a lower level
	("I'll kick with power xxx and at angle yyy").

*************************************************************************************
FORMAT FOR THE PLAYERS' LOGFILES
*************************************************************************************
First, the record files for all the players should reside in the same
directory. The file name should be:
<TeamName><Number>-<side>-actions.log
where
 <TeamName>: the name of the team- case does matter
 <Number>  : the player's number
 <side>    : should be a single character ('l' or 'r')

The names can look a little weird. For example, player 11 of
CMUnited99 would generate a log file named
CMUnited9911-l-actions.log

Each line in the logfile should be of the format
<stime>.<ttime> <level ind><Text>
where
<stime>: the time indicated by the server
<ttime>: the time that the clock has been stopped
<level ind>: a sequence of dashes ('-') to indicate the level of the
             output. Each dash represents 10, so "-----" would be a
             level of 50
<Text>     : whatever text you want to logplayer to display.

The logplayer strips off the times, but displays the dashes and the
text.  The time format is described more fully in our description of
CMUnited98, but basically, the ttime increments while the clock is
stopped (after a goal for example).  

NOTE: In this version of the logplayer, only times with a 0 for the
ttime are displayed.

Here is a sample of what the logfile should look like.
8.0 ---facing only neck to point (2.0 2.1)
8.0 ---------------turn_neck -36.573605
8.0 --------------------Heard message of type 1 from 6
9.0 -----------------My Pos: (-8.06, 4.84)      angle: 20.42    rel_neck: -36.00
        vel: (0.00 0.00)        conf: 0.98      stamina: 3500.00
9.0 -----------------Ball Pos: (2.03, 2.11)conf: 0.95   Vel: (0.71,0.80)dx/dy = 
(1.07,48.41)sp/head conf: 0.95
9.0 --------------------Player pos known: team: 1234567_9_B     opp: _____6789A_
9.0 --------------ActiveBallIntercept: 100 50


*************************************************************************************
SAMPLE CODE
*************************************************************************************
Here is some of the C++ code we use for generating these logfiles.
Note that if NO_ACTION_LOG is defined then all calls to LogAction will
effectively disappear. This allows use to not waste CPU cycles during
competition games.

In the .h file:
  /* You can specify a flag at compile time so that all the LogAction calls
     disappear
     If you add a LogAction, make sure to add it in both places */
  /* The # at the end of the function name is the total # of args */
#ifdef NO_ACTION_LOG
  inline void nothing_func(void) {}
#define LogAction1(x1) nothing_func()	
#define LogAction2(x1,x2) nothing_func()	
#define LogAction3(x1,x2,x3) nothing_func()	
#define LogAction4(x1,x2,x3,x4) nothing_func()	
#define LogAction5(x1,x2,x3,x4,x5) nothing_func()	
#define LogAction6(x1,x2,x3,x4,x5,x6) nothing_func()	
#define LogAction7(x1,x2,x3,x4,x5,x6,x7) nothing_func()	
#define LogAction8(x1,x2,x3,x4,x5,x6,x7,x8) nothing_func()	
#define LogAction9(x1,x2,x3,x4,x5,x6,x7,x8,x9) nothing_func()	
#define LogAction10(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10) nothing_func()	
#else	
  void LogAction2(int level, char* str); /* will be timestamped automatically */
  void LogAction3(int level, char* str, char* param);
  void LogAction4(int level, char* str, char* param1, char* param2);
  void LogAction3(int level, char* str, char c1);
  void LogAction3(int level, char* str, float f1);
  void LogAction4(int level, char* str, float f1, int d1);
  void LogAction4(int level, char* str, float f1, float f2);
  void LogAction5(int level, char* str, float f1, float f2, float f3);
  void LogAction6(int level, char* str, float f1, float f2, float f3, float f4);
  void LogAction7(int level, char* str, float f1, float f2, float f3, float f4, float f5);
  void LogAction8(int level, char* str, float f1, float f2, float f3, float f4, float f5, float f6);
  void LogAction3(int level, char* str, int d1);
  void LogAction4(int level, char* str, int d1, int d2);
  void LogAction4(int level, char* str, int d1, float f1);
  void LogAction5(int level, char* str, int d1, float f1, float f2);
  void LogAction6(int level, char* str, int d1, float f1, float f2, float f3);
  void LogAction7(int level, char* str, int d1, float f1, float f2, float f3, float f4);

  void LogAction7(int level, char* str, int d1, int d2, float f1, float f2, float f3);
#endif	



In the .C file:

#ifndef NO_ACTION_LOG

#define MAX_LOG_LINE 150

/* will be timestamped automatically */
void PlayerInfo::LogAction2(int level, char* str)
{
  if (level <= 0 ||
      level > CP_save_action_log_level)
    return;

  if (!Initialized)
    return; /* the log files hasn't been opened yet! */

  fprintf(Mem->SaveActionLogFile, "%d.%d %s%s\n", CurrentTime.t, CurrentTime.s,
	  repeat_char('-', level / 10), str);
  if (Mem->SaveActionLogCounter++ % Mem->CP_save_action_freq == 0){
    fclose(Mem->SaveActionLogFile);
    Mem->SaveActionLogFile = fopen(Mem->SaveActionLogFileName,"a");
  }

}

void PlayerInfo::LogAction3(int level, char* str, char* param)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, param);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction4(int level, char* str, char* param1, char* param2)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, param1, param2);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction3(int level, char* str, char c1)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, c1);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction3(int level, char* str, float f1)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, f1);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction4(int level, char* str, float f1, int d1)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, f1, d1);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction4(int level, char* str, float f1, float f2)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, f1, f2);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction5(int level, char* str, float f1, float f2, float f3)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, f1, f2, f3);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction6(int level, char* str, float f1, float f2, float f3, float f4)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, f1, f2, f3, f4);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction7(int level, char* str, float f1, float f2, float f3, float f4, float f5)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, f1, f2, f3, f4, f5);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction8(int level, char* str, float f1, float f2, float f3, float f4, float f5, float f6)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, f1, f2, f3, f4, f5, f6);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction3(int level, char* str, int d1)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, d1);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction4(int level, char* str, int d1, int d2)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, d1, d2);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction4(int level, char* str, int d1, float f1)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, d1, f1);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction5(int level, char* str, int d1, float f1, float f2)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, d1, f1, f2);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction6(int level, char* str, int d1, float f1, float f2, float f3)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, d1, f1, f2, f3);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction7(int level, char* str, int d1, float f1, float f2, float f3, float f4)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, d1, f1, f2, f3, f4);
  LogAction2(level, outstring);
}

void PlayerInfo::LogAction7(int level, char* str, int d1, int d2, float f1, float f2, float f3)
{
  char outstring[MAX_LOG_LINE];
  sprintf(outstring, str, d1, d2, f1, f2, f3);
  LogAction2(level, outstring);
}


#endif /* ifndef NO_ACTION_LOG */
