// Simple sectioned recording script // by David Dunscombe 12/2002 // done as a 1 second schedule instead of one 120 second timer // so that multiple stop/start demo schedules cant be accidently ran // version 1.01 // start demo every MaxCycleTime seconds $MaxCycleTime = 29; // count that is set to MaxCycleTime after every demo start $CurrentCycleTime = 0; // 1 second schedule running $ScheduleRunning = false; // initial time $T2TVTimeLeftMS = 0; // safety flags $StartAfterStopped = false; $DemoStopped = false; function AddT2TVNetworkMonitor() { $NetBarHudTV = new HudNetDisplay(NetBarHudTV) { profile = "GuiDefaultProfile"; horizSizing = "left"; vertSizing = "bottom"; position = "1 1"; extent = "174 48"; minExtent = "8 8"; visible = "0"; hideCursor = "0"; bypassHideCursor = "0"; helpTag = "0"; fillColor = "0.250000 0.250000 0.250000 0.250000"; frameColor = "0.000000 1.000000 0.000000 1.000000"; opacity = "1"; historySize = "2"; updatePeriod = "50"; renderField[0] = "1"; renderField[1] = "1"; renderField[2] = "1"; renderField[3] = "1"; renderField[4] = "1"; renderField[5] = "1"; fieldColors[0] = "0 220 0 255"; fieldColors[1] = "220 0 0 255"; fieldColors[2] = "220 220 220 255"; fieldColors[3] = "120 120 120 255"; fieldColors[4] = "0 190 240 255"; fieldColors[5] = "0 120 170 255"; lowerBound[0] = "0"; lowerBound[1] = "0"; lowerBound[2] = "0"; lowerBound[3] = "0"; lowerBound[4] = "0"; lowerBound[5] = "0"; upperBound[0] = "500"; upperBound[1] = "100"; upperBound[2] = "32"; upperBound[3] = "4096"; upperBound[4] = "32"; upperBound[5] = "4096"; infoCallback = "1"; renderGraph = "0"; }; PlayGui.add($NetBarHudTV); } //-------------------------------------------------------------------------- // automatically adjusts the connection rate of a filmer to stop demos // becoming to large. //-------------------------------------------------------------------------- function NetBarHudTV::infoUpdate(%this, %ping, %packetLoss, %sendPackets, %sendBytes, %receivePackets, %receiveBytes) { if ( $SamplesTaken < 100 ) { $SamplesTaken++; } // calculate running average $AverageReceiveBytes = (($AverageReceiveBytes*($SamplesTaken-1)) + %receiveBytes)/$SamplesTaken; // do t2tv stuff - resetict to just below 2500 bytes per second receive if ($ScheduleRunning && $SamplesTaken == 100 && GetSimTime() - $LastRateCheck > 3000 ) { $LastRateCheck = GetSimTime(); // calculate change factor if ( $AverageReceiveBytes > 5500 ) %RateDifference = 4; if ( $AverageReceiveBytes > 4500 ) %RateDifference = 3; else if ( $AverageReceiveBytes > 3500 ) %RateDifference = 2; else if ( $AverageReceiveBytes > 2500 ) %RateDifference = 1; else if ( $AverageReceiveBytes < 2000 ) %RateDifference = -1; else %RateDifference = 0; if ( %RateDifference != 0 ) { // rate two high decrease $pref::Net::PacketRateToClient = $pref::Net::PacketRateToClient - %RateDifference; $pref::Net::PacketSize = $pref::Net::PacketSize - (%RateDifference*16); $pref::Net::PacketRateToServer = $pref::Net::PacketRateToServer - %RateDifference; } else { return; } // check the max rate: if ( isObject( ServerConnection ) ) ServerConnection.checkMaxRate(); } } //-------------------------------------------------------------------------- // To avoid conflict with any existing demo recording scripts the demo recording // is a completely different function name //-------------------------------------------------------------------------- function beginT2TVDemoRecord() { if(isDemo()) return; // make sure that current recording stream is stopped stopT2TVDemoRecord(); for(%i = 0; %i < 1000; %i++) { %num = %i; if(%num < 10) %num = "0" @ %num; if(%num < 100) %num = "0" @ %num; %file = "recordings/demo" @ %num @ ".rec"; if(!isfile(%file)) break; } if(%i == 1000) return; $DemoFile = %file; saveT2TVDemoSettings(); startRecord(%file); // make sure start worked if(!isRecordingDemo()) { deleteFile("recordings/" @ $DemoFile @ ".rec"); addMessageHudLine( "\c3 *** Failed to record to file [\c2" @ $DemoFile @ "\cr]."); $DemoFile = ""; } } function stopT2TVDemoRecord() { if(isDemo()) return; // make sure we are recording (and have a valid file) if(isRecordingDemo()) stopRecord(); } function stopRecordingDemo( %val ) { if ( %val ) stopDemoRecordTimer(); } function stopDemoRecordTimer() { $DemoStopped = true; schedule( 3000, 0, "clearStoppedFlag" ); if(isDemo()) return; // make sure we are recording (and have a valid file) if(isRecordingDemo()) stopRecord(); } // just to make sure the the filmer does not press start demo again to quickly after // stoppping, there needs to be at least a 2 second gap between new streams function clearStoppedFlag() { $DemoStopped = false; // did the user press the t2tv start key while this schedule was running ? if ( $StartAfterStopped ) { $StartAfterStopped = false; startDemoCycle(); } } //------------------------------------------------------------------------- // sequential variables named $DemoValue[?] will be stored in the demo stream // and accessable right after the demo has been loaded function saveT2TVDemoSettings() { $DemoValueIdx = 0; getT2TVState(MISC); // store the playergroup getT2TVState(PLAYERLIST); // get the states for all the gui's of interest getT2TVState(RETICLE); getT2TVState(BACKPACK); getT2TVState(WEAPON); getT2TVState(INVENTORY); getT2TVState(SCORE); getT2TVState(CLOCK); getT2TVState(CHAT); // KP: save gravity getT2TVState(GRAVITY); } function nextT2TVSection() { // time to next demo $CurrentCycleTime = $MaxCycleTime; %TimeLeft = clockHud.GetTime(); %mins = mfloor(%TimeLeft); %secs = mfloor((%TimeLeft-%mins)*60); // from formatTime if(%mins < 1) %timeString = "00:"; else if(%mins < 10) %timeString = "0" @ %mins @ ":"; else %timeString = %mins @ ":"; if(%secs < 1) %timeString = %timeString @ "00"; else if(%secs < 10) %timeString = %timeString @ "0" @ %secs; else %timeString = %timeString @ %secs; %count = PlayerListGroup.getCount(); %bestTag[1] = "Storm"; %bestTag[2] = "Inferno"; for(%i = 0; %i < %count; %i++) { %obj = PlayerListGroup.getObject(%i); // ignore smurfs if ( !%obj.isSmurf ) { %name = %obj.name; %teamid = %obj.teamId; %pos1 = strStr(%name, "\c6"); if(%pos1 > 0) { %pos2 = strStr(%name, "\c7"); if(%pos2 < %pos1) { %Tag = getSubStr(%name, %pos2 + 1, %pos1 - %pos2 - 1); } else { %pos3 = strStr(%name, "\x11"); %Tag = getSubStr(%name, %pos2 + 1, %pos3 - %pos2 - 1); } } if ( %Tag !$= "" ) { %tagCounts[%teamid, %Tag]++; if ( %tagCounts[%teamid, %Tag] > %bestTagCount[%teamid] ) { %bestTagCount[%teamid] = %tagCounts[%teamid, %Tag]; %bestTag[%teamid] = %Tag; } } } } objectiveHud.teamName[1].setValue(%bestTag[1]); objectiveHud.teamName[2].setValue(%bestTag[2]); // names of teams used to replace objective hud text, as doing objectiveHud.setValue // is not instant??? $T2TVTeamName[1]=%bestTag[1]; $T2TVTeamName[2]=%bestTag[2]; %teamScore[1] = objectiveHud.teamScore[1].getValue(); %teamScore[2] = objectiveHud.teamScore[2].getValue(); // start the demo recording beginT2TVDemoRecord(); // show status message schedule( 250, 0, "showT2TVStatus" ); // write out info file new fileObject( "fileeditor" ); fileeditor.openForWrite($DemoFile @ ".log"); fileeditor.writeline("Time,Map,Team 1,Team 1 Score,Team 2,Team 2 Score"); fileeditor.writeline(%timeString @"," @ $MissionName @ "," @ %bestTag[1] @ "," @ %teamScore[1] @ "," @ %bestTag[2] @ "," @ %teamScore[2]); fileeditor.close(); fileeditor.delete(); } function demoCycle() { // only do next section if we are currently recording - so F4 will stop // the stop/record repeating if ( isRecordingDemo() && $CurrentCycleTime == 0 ) { nextT2TVSection(); } else if ( $CurrentCycleTime > 0 ) { $CurrentCycleTime = $CurrentCycleTime -1; } schedule( 1000, 0, "demoCycle" ); } // for some reason the stop record message seems to be on some sort of schedule // so you can get the stop record message after the starting recording message // to get around this the section start message is set to be 250 milis after // it was really started - bit of a hacky way to do it, but... =/ function showT2TVStatus() { // indicate we are starting demo addMessageHudLine( "\c4Started T2TV Section...next section in \c2" @ $MaxCycleTime @ " seconds \cr."); } function startDemoCycle() { if ($DemoStopped) { addMessageHudLine( "\c4Waiting for previous T2TV stream to complete...\cr"); $StartAfterStopped = true; return; } if( !isRecordingDemo() ) { // start first section nextT2TVSection(); // start schedule if its not already if ( !$ScheduleRunning ) { $LastRateCheckTime = 0; $SamplesTaken = 0; $AverageReceiveBytes = 0; $LastRateCheck = 0; AddT2TVNetworkMonitor(); $ScheduleRunning = true; schedule( 1000, 0, "demoCycle" ); } } } function toggleTRObs( %val ) { // on team rabbit 2, allow spec mode to be toggled if ( %val ) commandToServer('startNewVote', "toggleSpecMode", 0, 0, 0, 0, 0); } function getT2TVState(%type) { switch$(%type) { case MISC: addDemoValue( $HudMode TAB $HudModeType TAB $HudModeNode TAB voteHud.voting TAB isObject(passengerKeys) TAB musicPlayer.currentTrack ); case PLAYERLIST: %count = PlayerListGroup.getCount(); addDemoValue(%count); for(%i = 0; %i < %count; %i++) { %obj = PlayerListGroup.getObject(%i); addDemoValue( %obj.name TAB %obj.guid TAB %obj.clientId TAB %obj.targetId TAB %obj.teamId TAB %obj.score TAB %obj.ping TAB %obj.packetLoss TAB %obj.chatMuted TAB %obj.canListen TAB %obj.voiceEnabled TAB %obj.isListening TAB %obj.isBot TAB %obj.isAdmin TAB %obj.isSuperAdmin TAB %obj.isSmurf ); } case RETICLE: addDemoValue( reticleHud.bitmap TAB reticleHud.isVisible() TAB retCenterHud.isVisible() TAB ammoHud.isVisible() TAB ammoHud.getValue() TAB deploySensor.isVisible() TAB reticleFrameHud.isVisible() ); case BACKPACK: addDemoValue( backpackIcon.bitmap TAB backpackFrame.isVisible() TAB backpackText.getValue() TAB backpackText.isVisible TAB backpackFrame.pack ); case WEAPON: %count = weaponsHud.getNumItems(); %slotCount = weaponsHud.getNumSlots(); %active = weaponsHud.getActiveItem(); // visible/bitmaps(3)/count/slotcount/active addDemoValue( weaponsHud.isVisible() TAB weaponsHud.getBackgroundBitmap() TAB weaponsHud.getHighLightBitmap() TAB weaponsHud.getInfiniteBitmap() TAB %count TAB %slotCount TAB %active ); // images for(%i = 0; %i < %count; %i++) addDemoValue( $WeaponNames[%i] TAB weaponsHud.getItemBitmap(%i) ); // items for(%i = 0; %i < %slotCount; %i++) addDemoValue( weaponsHud.getSlotId(%i) TAB weaponsHud.getSlotCount(%i) ); case INVENTORY: // count/active %count = inventoryHud.getNumItems(); %slotCount = inventoryHud.getNumSlots(); %active = inventoryHud.getActiveItem(); // visible/bitmaps(3)/count/slotCount/active addDemoValue( inventoryHud.isVisible() TAB inventoryHud.getBackgroundBitmap() TAB inventoryHud.getHighLightBitmap() TAB inventoryHud.getInfiniteBitmap() TAB %count TAB %slotCount TAB %active ); // images for(%i = 0; %i < %count; %i++) addDemoValue( inventoryHud.getItemBitmap(%i) ); // items for(%i = 0; %i < %slotCount; %i++) addDemoValue( inventoryHud.getSlotId(%i) TAB inventoryHud.getSlotCount(%i) ); case SCORE: %objCount = objectiveHud.getCount(); // visible/gametype/numobjects addDemoValue( objectiveHud.isVisible() TAB objectiveHud.gameType TAB %objCount ); // only text ctrls exist in this thing.. so just dump the strings for(%i = 0; %i < %objCount; %i++) { if ( %i == 0 ) { addDemoValue($T2TVTeamName[1]); } else if ( %i == 4 ) { addDemoValue($T2TVTeamName[2]); } else { addDemoValue(objectiveHud.getObject(%i).getValue()); } } case CLOCK: addDemoValue( clockHud.isVisible() TAB clockHud.getTime() ); case CHAT: // store last 10 messages %numLines = HudMessageVector.getNumLines(); for(%i = (%numLines - 10); %i < %numLines; %i++) { if(%i < 0) addDemoValue(""); else addDemoValue(HudMessageVector.getLineText(%i)); } case GRAVITY: // KP // If the current gravity isn't the default gravity, then we've gotta // store it. This shouldn't affect backwards compatibility since we // don't add it if it hasn't changed. %gravity = getGravity(); if (%gravity != $DefaultGravity) addDemoValue(%gravity); } } package t2tvpackage{ function setUpFavPrefs(){ $RemapName[$RemapCount]="T2TV Demo Cycle"; $RemapCmd[$RemapCount]="startDemoCycle"; $RemapCount++; $RemapName[$RemapCount]="TR2 Observer Toggle"; $RemapCmd[$RemapCount]="toggleTRObs"; $RemapCount++; return parent::setUpFavPrefs(); } }; activatePackage(t2tvpackage);