//==============================================================================
// JGrass v2.13 - Smoking the Competition!
//==============================================================================

//=================
Change Log:
7/24/11		-	Fixed bug with GMutatorPlus.Register accessing none upon client startup. (minor)
			Fixed PlayerID variable not being properly set.	(possible major)
			Fixed GPlayerTemplate.PostRender accessing none upon client startup. (minor)

6/23/11		-	Fixed a bug with the summon command not forwarding complete information
				to the gametype (namely, what was to be summoned).

6/21/11		-	Fixed a bug in new player finalization logic. The bug was concerning
				the case where the playerpawn is rejected by the SecurityHandler after
				being fully spawned by the GameLogicHandler. In this case, the playerpawn
				object was not being cleaned up and persisted after the connection was
				dropped. It is now explicitly destroyed.

6/17/11		-	*Removed requirement of all players to be GPlayer based playerpawns.
				!!NOTE!! This may have negative side effects, including some framework
				functions not always being called as they should, but the effects
				should not be gameplay destructive. This problem can be averted by 
				following the steps in the "Custom Player Classes" section of the
				online help. Using GPlayer based classes are 100% guaranteed to 
				work in all cases.
				
				*As a result of above change, many minor interface changes have been
				made. This mainly includes changes typically from derived classes to
				more general parent classes (mainly GPlayer -> Playerpawn | Pawn ). This
				change requires a recompile of any mods that used the previously laid out
				interfaces.
				
				*As a further result of above change, Bots are now covered under all
				framework functions. Messages from Bots are now caught and forwarded to
				handler/mutator objects, Bots now get SecurityInfo object requests, etc.
				Bots (and non GPlayer playerclasses) are now fair game for any framework
				function call. 

4/8/11		-	*Fixed linking of mutators. Mutators are always auto linked
			upon spawn for both the server and the client. This resolves
			an issue observed in 227g with mutators.

2/6/11		-	*Added virtual method 'GetTags' in GSecurityInfo so that
			the GSI class can pass information that it wishes to
			be rendered to rendering elements (i.e. scoreboard, HUD)
			
			*Created GPlayerReplicationInfo class & basic ID setting
			functionality. All players (and bots) now initially spawn
			with an ID. I figured that this functionality is so
			common that it would be better to provide a common ID for
			both security and game logic handlers to reference.

			*Removed redundant variable in GenericGame GameReplicat-
			ionInfo.
			
			*Added GInfoBlock class. This allows Mutators and other objects
			to store useful metadata about players/bots in their GPlayerReplica-
			tionInfo objects.
			
			*Updated interfaces of GGameLogicHandler & GSecurityHandler. Added
			extra initialization parameter (options passed from commandline to
			unreal at server launch).
			
			*Removed EndTimer logic from JGrass.

12/25/10	-	Initial release. Merry xmas!

//=================
Abstract:
	JGrass is a gametype where the goal is to unlock as much modularity as
possible. JGrass creates an abstraction layer above the base GameInfo class that
divides into two main interfaces - Security and GameLogic. This allows server
owners a greater level of customizability, not requiring a server owner to use
a certain gametype for improved security over another gametype with superior
moddability (or vice versa). This model allows for limitless combinations of
security models and game mechanics definitions.

//=================
Installation:
	The following files should be included with this README:
	-JGrass.u		(Main file)
	-JGrass.ini
	-JGrass.int
	-DataStructures.u

	You should also download these additional files to provide basic example functionality:
	-GNoSecurity.u		(Basic security SecurityHandler)
	-GCoopGame.u		(Basic coop game GameLogicHandler)

//=================
Help / Walkthrough:
	Please see the online documentation (found at http://udhq.org) for a full
walkthrough of how to set up JGrass and use its features. If the provided link
does not work, feel free to e-mail me for the correct link. (e-mail address
provided at end of document)

//=================
Features:
	In itself, JGrass does not provide any interesting features to server owners
other than its modular interface design. The interfaces are divided into two
main categories - Security and GameLogic. The following is a brief discussion
of each interface.

SecurityHandler:
	The SecurityHandler class provides an interface for authorization of game
actions & security related commands issued by players.

//***************************************************************************//
// BEGIN SecurityHandler

// GetSecurityInfoObject
//	Returns a newly created Security Info object for a specific player, Other.
//	Useful for attaching your own security info object to playerpawns so you
//	can record metadata about each player.
Function GSecurityInfo GetSecurityInfoObject(GPlayer Other);

// IsRelevant:
//	Return whether an actor should be destroyed in this type of game.
function bool IsRelevant( actor Other );

// LogGameParameters:
//	Called when gamestate needs to be logged. Override this to provide custom
//	logging support when the game needs to be logged.
function LogGameParameters(StatLog StatLog);

// PreLogin:
//	Handles preprocessing of join requests. Called when a player initially makes 
//	a connection attempt. Set Error to a non empty string to reject the login 
//	attempt. If mutators have voted against login, bMutatorsVotedToReject will
// 	be set to true, and Error may be a non empty string. Return true to allow, 
//	false and set error to reject.
Function bool PreLogin( out String PlayerOptions, bool bMutatorsVotedToReject, 
	out string Error );

// AllowLogin:
//	Handles preprocessing of login requests. Return true to allow the login to 
//	pass to GameLogic, false and set error to reject it from further processing.
//	This call happens efore mutators have had a chance to modify the login 
//	options of the incoming client, and before the GameLogic class has gotten 
//	the call.
Function bool AllowLogin( out string Portal, out string Options, 
	out string Error, out class<PlayerPawn> SpawnClass );

// AllowProcessedLogin:
//	Handles postprocessing of login requests. This call happens after mutators
//	have had a chance to modify the login options of the incoming client. This 
//	call only happens if the GameLogic class & mutators did not block the login.
Function bool AllowProcessedLogin( out GPlayer NewPlayer, string Portal, 
	string Options, out string Error, class<PlayerPawn> SpawnClass );

// FinalizeLogin:
//	Allows postprocessing and finalization for a new playerpawn object. It is
//	safe to replicate to the playerpawn at this point.
Function FinalizeLogin( GPlayer NewPlayer );

// HandleMessage:
//	Called when a message has been sent. Useful to record metadata about a
//	user's chat history. Could be used to detect spam for example.
Function HandleMessage( GPlayer Sender, Name MsgType, String Msg );

// Logout:
//	Handles postprocessing of logout requests. Call happens after all mutators 
//	and gamelogic have processed logout.
function Logout( pawn Exiting );

// ShouldRespawn:
//	Return whether an item should respawn. Useful to filter respawning of
//	certain items.
function bool ShouldRespawn( actor Other );

// LevelEnd:
//	Called when the level is about to end. Useful to perform final cleanup
//	or serialization before level switch.
function LevelEnd(GPlayer Other, coerce string URL);

// GameEnding:
//	Called when game shutsdown. Useful to perform final server-shutdown cleanup
//	or serialization. Not guaranteed to always be called when the server is
//	shutting down.
event GameEnding();



//===================
// Action Validation

// HasAuthority:
// 	Returns True if Other has authority to perform the action specified. Returns
//	false and sets Error equal to the reason why the validation failed if Other 
//	isn't allowed to perform the action.
// Parameters:
//	Other - The player that wishes to perform the action.
//	ActionType - A flag denoting the type of this action (Player, Security, or
//					Custom)
//	Action - A name corresponding to an action.
//	ActionData - Extra information relevant to the action given.
//	Error - A reason why authentication failed (if it failed)
Function bool HasAuthority( GPlayer Other, int ActionType, name Action, 
	optional coerce string ActionData, optional out string Error );

//
// HandleSecureCommand:
//	Allows handling of base secure commands. Useful to implement your own
//	security related commands, such as kick, kill, ban, etc...
Function HandleSecureCommand( GPlayer Other, name Command, 
	optional coerce string Options );

// AllowsBroadcast:
//	Called when a message wishes to be broadcasted. Return false to reject.
//	Useful for blocking unwanted messages.
function bool AllowsBroadcast( Actor Broadcaster, int Len );

// AllowChangeName:
//	Called after a pawn has requested to change their name. Return false to 
//	block, true to allow. Useful to block unwanted names or prevent name change
//	abuse.
function bool AllowChangeName( Pawn Other, coerce string S, bool bNameChange );

// AllowChangeTeam:
//	Return whether a team change is allowed. Return true to allow, false to 
//	deny.
function bool AllowChangeTeam(Pawn Other, int N);

// AllowRestartGame:
//	Return true to allow Gamelogic to restart the game, false to reject.
function bool AllowRestartGame();

// AllowLevelSwitch:
//	Return true to allow a level to switch. False to reject. Called before 
//	mutators or gamelogic can act on request.
function bool AllowLevelSwitch( GPlayer Other, String URL, 
	bool bTeleporterEnd );

// AllowSpectate:
//	Return whether Viewer is allowed to spectate from the
// point of view of ViewTarget.
function bool AllowSpectate( pawn Viewer, actor ViewTarget );

// END SecurityHandler
//***************************************************************************//

	Example usage of the SecurityHandler template can be found in the
GNoSecurity.u file. The provided example is an extremely basic SecurityHandler
that permits all actions by default and supports no extra security commands,
but serves to show how to use a SecurityHandler to create your own security
model.

GameLogicHandler:
	The GameLogicHandler template class operates on the same principles as the
SecurityHandler class. It can be used to provide definitions for key game
scripted events, such as when a pawn takes damage, gets killed, etc. It has all
of the functionality of a full-fledged gametype, allowing the user to create
any type of game they wish without having to worry about security implications.

//***************************************************************************//
// BEGIN GameLogicHandler

//=====================
// Game Event Handling
	// Startup functions
function PreBeginPlay();
function BeginPlay();
function PostBeginPlay();

// Initialize:
//	Gives a chance to initialize this handler to the main gametype. Subclasses
//	should call super.initialize(Game) before setting up their own variables.
Function Initialize( GenericGame Game )
{
	Super.Initialize(Game);
	UpdateGamestate();
}

// IsRelevant:
//	Return whether an actor should be destroyed in this type of game.
function bool IsRelevant( actor Other );

// LogGameParameters:
//	Called when gamestate needs to be logged.
function LogGameParameters(StatLog StatLog);

// ProcessServerTravel:
//	Optional handling of ServerTravel for network games.
function ProcessServerTravel( string URL, bool bItems );

// RestartGame:
//	Restart the game.
function RestartGame();

// DetailChange:
//	Called after setting low or high detail mode.
event DetailChange();

// LevelEnd:
//	Called when the level is about to end. Perform level transition here. 
//	(i.e. level.servertravel)
function LevelEnd(GPlayer Other, coerce string URL);

// GameEnding:
//	Called when game shutsdown.
event GameEnding();


//=========================
// Game Mechanics Handling

// ReduceDamage:
//	Called when an object is about to take damage. Allows for modification of 
//	damage before it's actually dealt. Called before mutators.
function int ReduceDamage( int Damage, name DamageType, pawn Injured, 
	pawn InstigatedBy );

// Killed:
//	Called when a pawn dies. Allows for custom handling of kills. Called before 
//	mutators.
function Killed(pawn Killer, pawn Killed, name DamageType);

// PickupQuery:
//	Called when pawn has a chance to pick Item up (i.e. when 
// the pawn touches a weapon pickup). Should return true if 
// he wants to pick it up, false if he does not want it.
function bool PickupQuery( Pawn Other, Inventory item );

// ShouldRespawn:
//	Return whether an item should respawn.
function bool ShouldRespawn( actor Other );

// GetRules:
//	Called when rules for server querying need to be obtained.
function string GetRules();

// GetBeaconText:
//	Return beacon text for serverbeacon.
event string GetBeaconText();

// ScoreEvent:
//	Award a score to an actor.
function ScoreEvent( name EventName, actor EventActor, pawn InstigatedBy );


//============================
// Player Management Handling

// InitGameReplicationInfo:
//	Called when the main gametype wishes to have its GameReplicationInfo 
//	initialized.
Function InitGameReplicationInfo(GameReplicationInfo GameReplicationInfo);

// PreLogin:
//	Called when a player is attempting to connect. Return false and set
//	error to non empty string to reject the player. Return true and do not 
//	set error to allow.
Function bool PreLogin(String Options, Out String Error);

// Login:
//	Called when a player requests login. 
Function GPlayer Login(String Portal, String Options, 
	class<PlayerPawn> SpawnClass, out string Error );

// FinalizeLogin:
//	Called when all checks have passed and the player will enter the game. It 
//	is safe to add this player to a list, or reference the player in other ways.
function FinalizeLogin( GPlayer NewPlayer );

// AddDefaultInventory:
//	Spawn any default inventory for the player.
function AddDefaultInventory( pawn PlayerPawn );

// ChangeName:
//	Called after a pawn has requested to change their name.
function ChangeName( Pawn Other, coerce string S, bool bNameChange );

// ChangeTeam:
//	Return whether a team change is allowed.
function bool ChangeTeam(Pawn Other, int N);

// StartPlayer:
//	Start a player.
function StartPlayer(PlayerPawn Other);

// RestartPlayer:
//	Called when a player should be restarted.
function bool RestartPlayer( pawn aPlayer );

// Logout:
//	Called when a player is leaving the game.
function Logout( pawn Exiting );


//=============================
// Player Interaction Handling

// HandleCustomCommand:
//	Called when a player wishes to execute a custom command.
Function HandleCustomCommand(GPlayer Other, name Command, 
	optional coerce string Params);

// AllowsBroadcast:
//	Called when a message wishes to be broadcasted. Return false to reject.
function bool AllowsBroadcast( Actor Broadcaster, int Len );

// HandleMessage:
//	Called when a message has been sent.
Function HandleMessage( GPlayer Sender, Name MsgType, String Msg );

// AllowLevelSwitch:
//	Return true to allow a level to switch. False to reject. 
//	Called before mutators can act on request.
function bool AllowLevelSwitch( GPlayer Other, String URL, 
	bool bTeleporterEnd );

// AllowSpectate:
//	Return whether Viewer is allowed to spectate from the
// point of view of ViewTarget.
function bool AllowSpectate( pawn Viewer, actor ViewTarget );

// SetGameSpeed:
//	Called when an actor requests gamespeed to be changed.
function SetGameSpeed( Float T );

// PlayerJumpZScaling:
//	Return the player jumpZ scaling for this gametype
function float PlayerJumpZScaling();

// DiscardInventory:
//	Discard a player's inventory after he dies.
function DiscardInventory( Pawn Other );

// PlaySpawnEffect:
//	Play an inventory respawn effect.
function float PlaySpawnEffect( inventory Inv );

// PlayTeleportEffect:
//	Play a teleporting special effect.
function PlayTeleportEffect( actor Incoming, bool bOut, bool bSound);


//================
// Message Output

// PlayerKillMessage:
//	Generate a player killled message.
function string PlayerKillMessage( name damageType, pawn Other );

// CreatureKillMessage;
//	Generate a killed by creature message.
function string CreatureKillMessage( name damageType, pawn Other );

// KillMessage:
//	Default death message.
function string KillMessage( name damageType, pawn Other );

// END GameLogicHandler
//***************************************************************************//

Caveats:
	There are a few important points to consider about the GameLogicHandler
class. 

1.)	Keep level.game's Variables Up-To-Date!
	First, it is important to ALWAYS use variables in Level.Game when
possible (like NumPlayers, MaxPlayers, bTeamGame, etc.) instead of creating
your own local variables. The function UpdateGamestate is useful for this (not
shown here for brevity - see the source itself). The GameLogicHandler class has
a copy of all of the editable variables in GameInfo so your subclass can be
easily edited through default properties just as a gametype would.
UpdateGamestate is called upon Initialize, which performs a block copy of all
the variables in your subclass to level.game. When possible, you should always
use level.game variables instead of declaring your own mirrors. For example,
in Login, you should increase Level.Game.numplayers -- not a variable in your
class that you declared yourself called numplayers. 

	The reason for this is to maintain compatibility with other classes. 
Many of Unreal 1's base classes (and classes in various mods) freely read from
level.game's variables to assess the current gamestate. For example, there are
many mods that read Level.Game.numplayers to try to determine how to act (like
monster spawner mutators). If you do not keep Level.Game's variables up to date,
then these mods will function incorrectly. In general, there aren't many such
variables that should be kept up-to-date, but it is always good practice to
use level.game variables whenever applicable as opposed to creating your own
mirror variables.

2.)	Your Class Does Not Subclass Gameinfo!
	Remember that your handler is a subclass of GameLogicHandler - not GameInfo.
This means that calling Super.function() will never reference GameInfo's (or any
of GameInfo's descendants') function. As a result, you must copy the function
from GameInfo and/or UnrealIGame manually to your new class instead of calling
super. For example, if you wanted to call Super.Login, you would have to go to
GameInfo and copy the entire Login function into your new Login function instead
and then write your modification to Login afterwards. Of course, this introduces
a problem - if the copied code returns early, then your code may never be
reached, which does not preserve the purpose of calling super. An alternative
would be to create a new function, say, GameInfo_Login(), that contains the
entire function copied from GameInfo, which you would then call instead of
calling super. I have not yet experimented with simply calling level.game.login
in this case, but this _might_ also work. Your safest bet around the super
conundrum is to copy the target class's function into a new function which you
then call instead of calling super.

GMutatorPlus:
	Taken from xCoop, GMutatorPlus provides enhanced mutator functionality for
those who wish to code mutators to do more than simply replace actors.

	GMutatorPlus contains many functions that can change the gamestate in 
interesting ways, such as modifying login options, preventing levels from
ending, and doing things upon player/pawn death. The interface is preserved from
xCoop and is thus largely unchanged. That said, most mutators can be converted
from xCoop's MutatorPlus class to the new GMutatorPlus relatively painlessly.

//***************************************************************************//
// BEGIN GMutatorPlus

// IsRegistered:
//	Returns true if this mutator has been registered client-side.
simulated final function bool IsRegistered()
{
	return Registered;
}

// RegisterConfirm:
//	When called, this mutator has been completely registered.
simulated final function RegisterConfirm()
{
	Registered=true;
	Initialize();
}

// ForwardMutateToServer:
//	To forward Mutate calls to the server, call this function.
simulated final function ForwardMutateToServer(GPlayer Other, coerce string S)
{
	Other.ServerMutate(S);
}

//====================
// Template methods

// Initialize:
//	Called when it is safe to use this mutator.
Simulated Function Initialize();

// MutatorHandleMessage:
//  Called when a text message is issued in game to all clients.
//	Processed after GameLogic.
Function MutatorHandleMessage( Pawn Sender, name MsgType, Coerce String S);	

// PermitLevelEnd:
//	Called when a level end request has been made. Return true to allow, false 
//	to deny. Processed after GameLogic.
Function bool MutatorPermitLevelEnd(){ return true; }

// MutateLevelEndURL:
//	Called after all mutators & handlers have validated the login. Allows for 
//	mutators to swap the URL before a level switch actually occurs.
function MutateLevelEndURL( GPlayer Other, out coerce string URL );

// LevelEnd:
//	Called right when the level transition has been finalized.
//	Processed after GameLogic.
function LevelEnd(GPlayer Other, coerce string URL);

// GameEnd:
//	Called right when the server is shutting down.
//	Processed after GameLogic.
function GameEnd();

// Mutate:
//	Executes client side. Called by clients that wish to use custom commands. 
//	Parse the input string 'S' to act on client's commands. Invoke 
//	'ForwardMutateToServer' to forward execution to the server. Processes 
//	independently of GameLogic.
simulated function Mutate( Pawn Sender, Coerce string S );

// ServerMutate:
//	Same as Mutate, but executes server side.
//	Processes independently of GameLogic.
Function ServerMutate( Pawn Sender, Coerce String S );

// MutatePreLogin:
//	Allows preprocessing of player connections. Return false to immediately stop
//	a player's connection. Processed before GameLogic.
function bool MutatePreLogin( String Options, out string Error ){ return True; }	

// ModifyLoginOptions:
//	Called when a player has just attempted login. This allows mutators to swap 
//	options around before the processing actually happens.Processed before 
//	GameLogic.
function bool ModifyLoginOptions( out String portal, out String Options, 
	out string Error, out class<PlayerPawn> SpawnClass );	

// MutatorReduceDamage:
//	Called when a pawn takes damage in game.
//	Processed after GameLogic.
function MutateReduceDamage( out int Damage, name Type, pawn Injured, 
	pawn InstigatedBy );

// MutatorScoreKill:
//	Called when a pawn dies in game.
//	Processed after GameLogic.
function MutateScoreKill( Pawn Killer, Pawn Other, name DamageType );

// MutateRestartPlayer:
//	Called when a player should be restarted.
//	Processed after GameLogic.
function MutateRespawningPlayer( Pawn Spawner );	

// MutateNewPlayer:
//	Called when a new player connects to the game. This is after the playerpawn 
//	is completely initialized. Processed after GameLogic.
function MutateNewPlayer( GPlayer NewPlayer );

// MutateExitingPlayer:
//	Called when a pawn is exiting the game (includes bots)
//	Processed after GameLogic.
function MutateExitingPlayer( pawn Exiting );

// PostRender:
//	Called upon post-world-rendering each frame. Use to draw to canvas.
//	Processed independently of GameLogic.
simulated function PostRender(Canvas C);

// END GMutatorPlus
//***************************************************************************//

Conclusion:
	That concludes the brief overview of JGrass's features. If you have any
questions or comments, feel free to email me at 
	pravin_prabhu at hotmail.com.

You can also post on the UDHQ forums, found at 
	http://udhq.falconpunch.net/phpBB3/

Keep it Unreal!
-Pravin "Pcube" Prabhu
http://udhq.com

END





