// ==================================================================== // Class: xVoting.VotingReplicationInfo // // The VotingReplicationInfo is responsible for voting related network // communications between the server and the player. // // Written by Bruce Bickar // (c) 2003, Epic Games, Inc. All Rights Reserved // ==================================================================== class VotingReplicationInfo extends VotingReplicationInfoBase DependsOn(VotingHandler); enum RepDataType { REPDATATYPE_GameConfig, REPDATATYPE_MapList, REPDATATYPE_MapVoteCount, REPDATATYPE_KickVoteCount, REPDATATYPE_MatchConfig, REPDATATYPE_Maps, REPDATATYPE_Mutators }; struct TickedReplicationQueueItem { var RepDataType DataType; var int Index; var int Last; }; struct MutatorData { var string ClassName; var string FriendlyName; }; var array TickedReplicationQueue; var array MapList; var int MapCount; // total count of maps var array GameConfig; // game types var int GameConfigCount; // total count of game types var int CurrentGameConfig; var bool bWaitingForReply; // used in replication var array MapVoteCount; // holds vote counts var array KickVoteCount; // holds vote counts var int MapVote; // Index of the map that the owner has voted for var int VoteCount; var int GameVote; // Index of the Game type that the owner has voted for var int KickVote; // PlayerID of the that the owner has voted against to kick var PlayerController PlayerOwner; // player this RI belongs too var int PlayerID; // PlayerID of the owner. Needed to match up when player disconnects and owner == none var byte Mode; // voting mode enum var bool bMapVote; // Map voting enabled var bool bKickVote; // Kick voting enabled var bool bMatchSetup; // MatchSetup enabled var bool bMatchSetupPermitted; // owner is logged in as a MatchSetup user. var bool bMatchSetupAccepted; // owner has accept the current match settings var bool bSendingMatchSetup; // currently sending match setup stuff to client var int SecurityLevel; // matchsetup users security level var config bool bDebugLog; var() name CountDownSounds[60]; var int CountDown; var xVotingHandler VH; // localization var localized string lmsgSavedAsDefaultSuccess, lmsgNotAllAccepted; // Client Response Identifiers var string MapID, MutatorID, OptionID, GeneralID; var string URLID, StatusID, MatchSetupID, LoginID, CompleteID; var string AddID, RemoveID, UpdateID, FailedID, TournamentID, DemoRecID, GameTypeID; //------------------------------------------------------------------------------------------------ replication { // Variables the server should send to the client only initially reliable if( Role==ROLE_Authority && bNetInitial) PlayerOwner, MapCount, GameConfigCount, bKickVote, bMapVote, bMatchSetup, CurrentGameConfig; //bIsSpectator; // Variables or Functions the server should send to the client and keep updated if MapVoting enabled reliable if( Role==ROLE_Authority && bMapVote) ReceiveGameConfig, ReceiveMapInfo, CloseWindow, OpenWindow, ReceiveMapVoteCount, ReceiveKickVoteCount, Mode, PlayCountDown; // Functions the server should send to the client if KickVoting enabled reliable if( Role==ROLE_Authority && bKickVote) SendPlayerID; // Variables or Functions the server should send to the client // and keep updated if MatchSetup is enabled reliable if( Role==ROLE_Authority && bMatchSetup ) bMatchSetupPermitted, bMatchSetupAccepted, SecurityLevel; // functions the client calls on the server reliable if( Role < ROLE_Authority ) ReplicationReply, SendMapVote, SendKickVote, MatchSetupLogin, RequestMatchSettings, MatchSettingsSubmit, SaveAsDefault, RestoreDefaultProfile, MatchSetupLogout, RequestPlayerIP; } //------------------------------------------------------------------------------------------------ event PostBeginPlay() { Super.PostBeginPlay(); PlayerOwner = PlayerController(Owner); VH = xVotingHandler(Level.Game.VotingHandler); } simulated event PostNetBeginPlay() { DebugLog("____VotingReplicationInfo.PostNetBeginPlay"); Super.PostNetBeginPlay(); GetServerData(); } simulated event PostNetReceive() { bNetNotify = NeedNetNotify(); if ( !bNetNotify && Owner == None ) SetOwner(PlayerOwner); } simulated function bool NeedNetNotify() { return PlayerOwner == None; } simulated function GUIController GetController() { if ( Level.NetMode == NM_ListenServer || Level.NetMode == NM_Client ) { if ( PlayerOwner != None && PlayerOwner.Player != None ) return GUIController(PlayerOwner.Player.GUIController); } return None; } //------------------------------------------------------------------------------------------------ simulated function GetServerData() { // grab data from VotingHandler on server side if( Level.NetMode != NM_Client ) { bKickVote = VH.bKickVote; bMapVote = VH.bMapVote; bMatchSetup = VH.bMatchSetup; MapCount = VH.MapCount; GameConfigCount = VH.GameConfig.Length; if( bMapVote ) { Mode = byte(VH.bEliminationMode); Mode += byte(VH.bScoreMode) * 2; Mode += byte(VH.bAccumulationMode) * 4; CurrentGameConfig = VH.CurrentGameConfig; AddToTickedReplicationQueue(REPDATATYPE_GameConfig, GameConfigCount-1); AddToTickedReplicationQueue(REPDATATYPE_MapList, MapCount-1); if( VH.MapVoteCount.Length > 0 ) AddToTickedReplicationQueue(REPDATATYPE_MapVoteCount, VH.MapVoteCount.Length-1); } if( bKickVote && VH.KickVoteCount.Length > 0 ) AddToTickedReplicationQueue(REPDATATYPE_KickVoteCount, VH.KickVoteCount.Length-1); } } //------------------------------------------------------------------------------------------------ simulated function Tick(float DeltaTime) { local int i; local bool bDedicated, bListening; if( TickedReplicationQueue.Length == 0 || bWaitingForReply) return; bDedicated = Level.NetMode == NM_DedicatedServer || (Level.NetMode == NM_ListenServer && PlayerOwner != none && PlayerOwner.Player.Console == none ); bListening = Level.NetMode == NM_ListenServer && PlayerOwner != none && PlayerOwner.Player.Console != none; if( !bDedicated && !bListening ) return; i = TickedReplicationQueue.Length - 1; switch( TickedReplicationQueue[i].DataType ) { case REPDATATYPE_GameConfig: TickedReplication_GameConfig(TickedReplicationQueue[i].Index, bDedicated); break; case REPDATATYPE_MapList: TickedReplication_MapList(TickedReplicationQueue[i].Index, bDedicated); break; case REPDATATYPE_MapVoteCount: TickedReplication_MapVoteCount(TickedReplicationQueue[i].Index, bDedicated); break; case REPDATATYPE_KickVoteCount: TickedReplication_KickVoteCount(TickedReplicationQueue[i].Index, bDedicated); break; case REPDATATYPE_MatchConfig: TickedReplication_MatchConfig(TickedReplicationQueue[i].Index, bDedicated); break; case REPDATATYPE_Maps: TickedReplication_Maps(TickedReplicationQueue[i].Index, bDedicated); break; case REPDATATYPE_Mutators: TickedReplication_Mutators(TickedReplicationQueue[i].Index, bDedicated); break; } TickedReplicationQueue[i].Index++; if( TickedReplicationQueue[i].Index > TickedReplicationQueue[i].Last ) TickedReplicationQueue.Remove(i,1); } //------------------------------------------------------------------------------------------------ function AddToTickedReplicationQueue(RepDataType Type, int Last) { if( Last > -1 ) { TickedReplicationQueue.Insert(0,1); TickedReplicationQueue[0].DataType = Type; TickedReplicationQueue[0].Index = 0; TickedReplicationQueue[0].Last = Last; } } //------------------------------------------------------------------------------------------------ function TickedReplication_GameConfig(int Index, bool bDedicated) { local VotingHandler.MapVoteGameConfigLite GameConfigItem; GameConfigItem = VH.GetGameConfig(Index); DebugLog("___Sending " $ Index $ " - " $ GameConfigItem.GameName); if( bDedicated ) { ReceiveGameConfig(GameConfigItem); // replicate one GameConfig each tick bWaitingForReply = True; } else GameConfig[GameConfig.Length] = GameConfigItem; } //------------------------------------------------------------------------------------------------ function TickedReplication_MapList(int Index, bool bDedicated) { local VotingHandler.MapVoteMapList MapInfo; MapInfo = VH.GetMapList(Index); DebugLog("___Sending " $ Index $ " - " $ MapInfo.MapName); if( bDedicated ) { ReceiveMapInfo(MapInfo); // replicate one map each tick until all maps are replicated. bWaitingForReply = True; } else MapList[MapList.Length] = MapInfo; } //------------------------------------------------------------------------------------------------ function TickedReplication_MatchConfig(int Index, bool bDedicated) { local MatchConfig MatchProfile; local PlayInfo.PlayInfoData PIData; if( Index < 6 ) { MatchProfile = VH.MatchProfile; switch( Index ) { case 0: SendClientResponse( GeneralID, UpdateID $ Chr(27) $ GameTypeID, MatchProfile.GameClassString); break; case 1: SendClientResponse( MapID, UpdateID, MatchProfile.MapIndexList ); break; case 2: SendClientResponse( MutatorID, UpdateID, MatchProfile.MutatorIndexList ); break; case 3: SendClientResponse( GeneralID, UpdateId $ Chr(27) $ URLID, MatchProfile.Parameters ); break; case 4: SendClientResponse( GeneralID, UpdateId $ Chr(27) $ TournamentID, string(MatchProfile.bTournamentMode) ); break; case 5: SendClientResponse( GeneralID, UpdateID $ Chr(27) $ DemoRecID, MatchProfile.DemoRecFileName ); break; } bWaitingForReply = bDedicated; } else { DebugLog("___Sending " $ VH.MatchProfile.PInfo.Settings[Index-6].SettingName); PIData = VH.MatchProfile.PInfo.Settings[Index-6]; if( PIData.ArrayDim == -1) // no array properties (cant handle them) { SendClientResponse( OptionID, AddID, PIData.SettingName $ Chr(27) $ PIData.ClassFrom $ Chr(27) $ PIData.Value ); bWaitingForReply = bDedicated; } } } //------------------------------------------------------------------------------------------------ function TickedReplication_MapVoteCount(int Index, bool bDedicated) { DebugLog("___Sending MapVoteCountIndex " $ Index); if( bDedicated ) { ReceiveMapVoteCount(VH.MapVoteCount[Index], True); bWaitingForReply = True; } else MapVoteCount[MapVoteCount.Length] = VH.MapVoteCount[Index]; } //------------------------------------------------------------------------------------------------ function TickedReplication_KickVoteCount(int Index, bool bDedicated) { DebugLog("___Sending KickVoteCountIndex " $ Index); if( bDedicated ) { ReceiveKickVoteCount(VH.KickVoteCount[Index], True); bWaitingForReply = True; } else KickVoteCount[KickVoteCount.Length] = VH.KickVoteCount[Index]; } //------------------------------------------------------------------------------------------------ function TickedReplication_Maps(int Index, bool bDedicated) { DebugLog("TickedReplication_Maps " $ Index $ ", " $ VH.MatchProfile.Maps[Index].MapName); SendClientResponse(MapID, AddID, Index $ "," $ VH.MatchProfile.Maps[Index].MapName); bWaitingForReply = bDedicated; } //------------------------------------------------------------------------------------------------ function TickedReplication_Mutators(int Index, bool bDedicated) { local MatchConfig MatchProfile; local MutatorData M; MatchProfile = VH.MatchProfile; DebugLog("TickedReplication_Mutators " $ Index $ ", " $ MatchProfile.Mutators[Index].ClassName); M.ClassName = MatchProfile.Mutators[Index].ClassName; M.FriendlyName = MatchProfile.Mutators[Index].FriendlyName; SendClientResponse( MutatorID, AddID, Index $ "," $ M.ClassName $ Chr(27) $ M.FriendlyName ); bWaitingForReply = bDedicated; } //------------------------------------------------------------------------------------------------ simulated function ReceiveGameConfig(VotingHandler.MapVoteGameConfigLite p_GameConfig) { GameConfig[GameConfig.Length] = p_GameConfig; DebugLog("___Receiving - " $ p_GameConfig.GameName); ReplicationReply(); } //------------------------------------------------------------------------------------------------ simulated function ReceiveMapInfo(VotingHandler.MapVoteMapList MapInfo) { MapList[MapList.Length] = MapInfo; DebugLog("___Receiving - " $ MapInfo.MapName); ReplicationReply(); } //------------------------------------------------------------------------------------------------ simulated function ReceiveMapVoteCount(VotingHandler.MapVoteScore MVCData, bool bReply) { local int i; local bool bFound; for( i=0; i= MapList.Length) return ""; else return MapList[Index].MapName; } //------------------------------------------------------------------------------------------------ function MatchSetupLogin(string UserID, string Password) { local int SecLevel; if( VH.MatchSetupLogin(UserID,Password,PlayerOwner,SecLevel) ) { bMatchSetupPermitted=True; SecurityLevel = SecLevel; SendClientResponse(LoginID,"1"); } else { bMatchSetupPermitted=False; SendClientResponse(LoginID); } } //------------------------------------------------------------------------------------------------ function MatchSetupLogout() { bMatchSetupPermitted = false; bMatchSetupAccepted = false; bSendingMatchSetup = false; VH.MatchSetupLogout( PlayerOwner ); SendClientResponse("logout"); } //------------------------------------------------------------------------------------------------ function RequestMatchSettings(bool bRefreshMaps, bool bRefreshMutators) { DebugLog("____RequestConfigSettings"); if(bMatchSetupPermitted) { bMatchSetupAccepted = false; bSendingMatchSetup = true; // Send the full list of maps if ( bRefreshMaps ) AddToTickedReplicationQueue(REPDATATYPE_Maps, VH.MatchProfile.Maps.Length-1); // Send the full list of mutators if ( bRefreshMutators ) AddToTickedReplicationQueue(REPDATATYPE_Mutators, VH.MatchProfile.Mutators.Length-1); // Send the game configuration, including the active maps & mutators, command line params, and misc. settings AddToTickedReplicationQueue(REPDATATYPE_MatchConfig, VH.MatchProfile.PInfo.Settings.Length + 5); } else SendClientResponse(MatchSetupID, FailedID); } function SendClientResponse( string Identifier, optional string Response, optional string Data ) { if ( Identifier == "" ) return; if ( Response != "" ) Identifier $= ":" $ Response; if ( Data != "" ) Identifier $= ";" $ Data; SendResponse(Identifier); } function ReceiveCommand( string Command ) { local string Type, Info, Data; DecodeCommand( Command, Type, Info, Data ); HandleCommand( Type, Info, Data ); } static function DecodeCommand( string Response, out string Type, out string Info, out string Data ) { local string str; Type = ""; Info = ""; Data = ""; if ( Response == "" ) return; if ( Divide(Response, ":", Type, str) ) { if ( !Divide(str, ";", Info, Data) ) Info = str; } else Type = Response; } function HandleCommand( string Type, string Info, string Data ) { local bool bPropagate; if ( Type == "" ) return; log("HandleCommand Type: '"$Type$"' Info: '"$Info$"' Data: '"$Data$"'",'MapVoteDebug'); switch ( Type ) { case MapID: if ( bMatchSetupPermitted ) { bMatchSetupAccepted = false; bPropagate = VH.MatchProfile.ChangeSetting(Type, Info); } break; case MutatorID: if ( bMatchSetupPermitted ) { bMatchSetupAccepted = false; bPropagate = VH.MatchProfile.ChangeSetting( Type, Info ); } break; case GeneralID: if ( bMatchSetupPermitted ) { bMatchSetupAccepted = false; switch ( Info ) { case OptionID: case TournamentID: case DemoRecID: bPropagate = VH.MatchProfile.ChangeSetting( Info, Data ); } } break; } if ( bPropagate ) VH.PropagateValue(Self, Type, Info, Data); } simulated function SendResponse(string Response) { Super.SendResponse(Response); ReplicationReply(); } //------------------------------------------------------------------------------------------------ function MatchSettingsSubmit() { local int i; local bool bAllAccepted; DebugLog("____MatchSettingsSubmit()"); if(bMatchSetupPermitted) { bAllAccepted = true; bMatchSetupAccepted = true; // check if any match setup users did not accept the settings for( i=0; i 10 && Count <= 60 && CountDownSounds[Count-1] != '') PlayerOwner.PlayStatusAnnouncement( CountDownSounds[Count-1], 1); if( Count == 10 ) { t = GetSoundDuration(PlayerOwner.StatusAnnouncer.PreCacheSound(CountDownSounds[9])); if(t + 0.15 < 1) t = 1; SetTimer(t + 0.15,false); PlayerOwner.PlayStatusAnnouncement( CountDownSounds[9], 1); CountDown = 9; } } //------------------------------------------------------------------------------------------------ simulated function Timer() { local float t; t = GetSoundDuration(PlayerOwner.StatusAnnouncer.PreCacheSound(CountDownSounds[CountDown-1])); if(t + 0.15 < 1) t = 1; PlayerOwner.PlayStatusAnnouncement( CountDownSounds[CountDown-1], 1); CountDown--; if( CountDown > 0 ) SetTimer(t + 0.15,false); } //------------------------------------------------------------------------------------------------ function RequestPlayerIP( string PlayerName ) { local PlayerController P; if( PlayerOwner.PlayerReplicationInfo.bAdmin ) { foreach DynamicActors( class'PlayerController', P ) { if( P.PlayerReplicationInfo.PlayerName ~= PlayerName ) { SendPlayerID(P.GetPlayerNetworkAddress(), P.GetPlayerIDHash()); break; } } } } //------------------------------------------------------------------------------------------------ simulated function SendPlayerID(string IPAddress, string PlayerID) { local KickInfoPage Page; Page = KickInfoPage(GetController().ActivePage); if(Page != None) { Page.lb_PlayerInfoBox.Add(class'KickInfoPage'.default.IPText,IPAddress); Page.lb_PlayerInfoBox.Add(class'KickInfoPage'.default.IDText,PlayerID); } } //------------------------------------------------------------------------------------------------ simulated function DebugLog(string Text) { if(bDebugLog) log(Text,'MapVoteDebug'); } //------------------------------------------------------------------------------------------------ simulated function bool MatchSetupLocked() { return !bMatchSetupPermitted; } simulated function bool MapVoteEnabled() { return bMapVote; } simulated function bool KickVoteEnabled() { return bKickVote; } simulated function bool MatchSetupEnabled() { return bMatchSetup; } defaultproperties { RemoteRole=ROLE_SimulatedProxy NetPriority=1 bOnlyRelevantToOwner=True MapVote=-1 GameVote=-1 KickVote=-1 bDebugLog=false NetUpdateFrequency=1 bMatchSetupPermitted=False bNetNotify=True ProcessCommand=ReceiveCommand CountDownSounds(0)=one CountDownSounds(1)=two CountDownSounds(2)=three CountDownSounds(3)=four CountDownSounds(4)=five CountDownSounds(5)=six CountDownSounds(6)=seven CountDownSounds(7)=eight CountDownSounds(8)=nine CountDownSounds(9)=ten CountDownSounds(19)=20_seconds CountDownSounds(29)=30_seconds_remain CountDownSounds(59)=1_minute_remains lmsgSavedAsDefaultSuccess="Profile was saved as default successfully" lmsgNotAllAccepted="You have Accepted the current settings, Waiting for other users to accept." MapID="map" MutatorID="mutator" OptionID="option" GeneralID="general" URLID="url" StatusID="status" MatchSetupID="matchsetup" LoginID="login" FailedID="failed" CompleteID="done" AddID="add" RemoveID="remove" UpdateID="update" TournamentID="tournament" DemoRecID="demorec" GameTypeID="game" }