diff --git a/LsoBot/LsoBot-Config.psd1 b/LsoBot/LsoBot-Config.psd1 index 77c7537..0822931 100644 --- a/LsoBot/LsoBot-Config.psd1 +++ b/LsoBot/LsoBot-Config.psd1 @@ -1,14 +1,18 @@ <# ////////////////////////////////////////////// LSO BOT ////////////////////////////////////////////// -Version: 1.1.0 dev +Version: 1.2.0 dev Join the Discord: https://discord.gg/nr9xb6YJfw -Contributors: +Original Contributors: YoloWingPixie | https://github.com/YoloWingPixie Auranis | https://github.com/Auranis +Current branch maintained by: +BadMojo11 | https://github.com/BadMojo11 +Japopich | https://github.com/japopich + Special Thanks to: Carrier Strike Group 8 - https://discord.gg/9h9QUA8 @@ -40,6 +44,12 @@ Carrier Strike Group 8 - https://discord.gg/9h9QUA8 webHookUrl = 'https://discord.com/api/webhooks/NOTAREALWEBHOOKCHANGEME' + # Enable debugging set flag to 1, else set to 0 + debug_flag = 1; + + # Second Webhook URL for use with debugging server + webHookUrl_debug = 'https://discord.com/api/webhooks/NOTAREALWEBHOOKCHANGEME' + logpath = '$env:USERPROFILE\Saved Games\DCS.openbeta_server\Logs\dcs.log' #Only the environment variable $env:USERPROFILE is supported @@ -47,6 +57,9 @@ Carrier Strike Group 8 - https://discord.gg/9h9QUA8 underlineStyle = "Underline" - hookStyle = "embed" + hookStyle = "embed" + + #Output grade points to Discord and logs; $true or $false + pointScoring = $false -} \ No newline at end of file +} diff --git a/LsoBot/LsoBot.ps1 b/LsoBot/LsoBot.ps1 index 9efea5d..1fc2eed 100644 --- a/LsoBot/LsoBot.ps1 +++ b/LsoBot/LsoBot.ps1 @@ -1,7 +1,7 @@ <# ///////////////////////////////////////////////////// LSO BOT ///////////////////////////////////////////////////// -Version: 1.1.0 dev +Version: 1.2.0 dev Join the Discord: https://discord.gg/nr9xb6YJfw @@ -9,6 +9,10 @@ Contributors: YoloWingPixie | https://github.com/YoloWingPixie Auranis | https://github.com/Auranis +Current branch maintained by: +BadMojo11 | https://github.com/BadMojo11 +Japopich | https://github.com/japopich + Special Thanks to: Carrier Strike Group 8 - https://discord.gg/9h9QUA8 @@ -28,7 +32,6 @@ function Get-Timestamp { [DateTime]$lsoStartTime = [DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss.fff') # END FUNCTIONS - $debugLog = "$LsoScriptRoot\Logs\lsoBot-debug.txt" $rawGradelog = "$LsoScriptRoot\Logs\lsoBot-rawGrades.txt" $reGradedLog = "$LsoScriptRoot\Logs\lsoBot-reGrades.txt" @@ -55,11 +58,16 @@ $lsoConfig = Import-PowerShellDataFile $configPath Write-Output "$(Get-Timestamp) $info Successfully imported config file" | Out-file $debugLog -append $dcsLogPath = $lsoConfig.logpath +Write-Output "$(Get-Timestamp) $info Log Path: $dcsLogPath" | Out-file $debugLog -append if ($dcsLogPath -match '\$env:USERPROFILE') { $dcsLogPath = $dcsLogPath -replace '\$env:USERPROFILE', $env:USERPROFILE } +$points = "0.0" +$pointScoring = $lsoConfig.pointScoring + + #Log Format Variables $info = "| INFO |" $warn = "| WARNING |" @@ -76,6 +84,10 @@ $lsoEventRegex = "^.*landing.quality.mark.*" # The regex to check log messages for takeoff events to detect bolters $takeoffEventRegex = "^.*takeoff.*$" +# The log index to iterate through +$logTrapIndex = 0 +$lastTrapTime = $null + <# $lsoStartTime : The time the job started @@ -193,15 +205,53 @@ Write-Output "$(Get-Timestamp) $info $lcTime Time target is $timeTarget" | Out-f $LLIW = "(_|\()?(?:LLIW)(_|\))?" $LRIW = "(_|\()?(?:LRIW)(_|\))?" $3PTSIW = "(_|\()?(?:3PTSIW)(_|\))?" - $BIW = "(_|\()?(?:BIW)(_|\))?" $EGTL = "(_|\()?(?:EGTL)(_|\))?" # //////////////////////////////////////////// MAIN LOOP STARTS HERE ///////////////////////////////////////////// [DateTime]$lsoInitTime = [DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss.fff') $lsoInitDur = New-TimeSpan -Start $lsoStartTime -End $lsoInitTime - + Write-Output "$(Get-Timestamp) $info $lcJob Start block loaded in $lsoInitDur" | Out-file $debugLog -append +#Iterate through previously logged traps in rawGrades and advance $logTrapIndex by one for every trap already logged to prevent relogging +Write-Output "$(Get-Timestamp) $info Iterating existing traps" | Out-file $debugLog -append +while ($true) { + + $lastTrapString = Select-String -Path $rawGradelog -Pattern "^.*GRADE:.*" | Select-Object -Last 1 + $lastTrapString = $lastTrapString -replace "^.*(?:.txt\:\d{0,5}\:)", "" + $lastTrapString = $lastTrapString -replace ",.*$", "" + [DateTime]$lastTrapTime = $lastTrapString + $lastTrapTime.ToUniversalTime() + + $landingEvent = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex | Select-Object -Index $logTrapIndex + $logTime = $landingEvent + $logTime = $logTime -replace "^.*(?:dcs\.log\:\d{1,5}\:)", "" + $logTime = $logTime -replace "\..*$", "" + [DateTime]$trapTime = $logTime + + Write-Output "$(Get-Timestamp) $Info Last registered trap in rawGrades at time:$lastTrapTime, examining DCS.log trap at time:$trapTime" | Out-file $debugLog -append + if ($null -eq $landingEvent) { + #No landing event exists at the current $logTrapIndex + Write-Output "$(Get-Timestamp) $Info No landing events at index; exiting with logTrapIndex: $logTrapIndex" | Out-file $debugLog -append + break + } + elseif ($null -eq $lastTrapTime) { + #No traps stored in rawGrades + Write-Output "$(Get-Timestamp) $Info No traps stored in rawGrades; exiting with logTrapIndex: $logTrapIndex" | Out-file $debugLog -append + break + } + elseif ($trapTime -le $lastTrapTime) { + #DCS.log trap at $logTrapIndex is older than $lastTrapTime, advance $logTrapIndex by 1 so it isn't logged again + Write-Output "$(Get-Timestamp) $info Trap at $trapTime already registered" | Out-file $debugLog -append + $logTrapIndex++ + } + else { + #Generic catch + Write-Output "$(Get-Timestamp) $info Generic catch, exiting with logTrapIndex: $logTrapIndex" | Out-file $debugLog -append + break + } +} + for ($i = 1; $i -le $timeTarget; $i++) { Write-Output "$(Get-Timestamp) $info $lcJob Begin cycle $i of $timeTarget" | Out-file $debugLog -append @@ -219,11 +269,6 @@ for ($i = 1; $i -le $timeTarget; $i++) { Exit } - # Is the loop duration null? (This happens on Run 0 of the job), set it to a fair 150ms. - if ($null -eq $lsoLoopDuration) { - $lsoLoopDuration = [TimeSpan]::FromMilliseconds(150) - - } <# Calculate the scan interval. To make a long story short, there is a small couple hundred millisecond gap between when the last job cycle opens the dcs.log and when it completes. @@ -238,624 +283,722 @@ for ($i = 1; $i -le $timeTarget; $i++) { If a bolter was detected on the previous cycle, the minimum runtime of the loop is 6000ms due to the wait time. We test for that first, and subtract out the BolterSleepTimer. #> - $scanInterval = New-TimeSpan -Seconds 15 - - #If this is the first loop in the job we need to account for the config loading time. - if ($i -eq 1) { - $scanInterval = $scanInterval + $lsoInitDur - } - - #Adjust the scan interval to account for the previous loop run duration, trimming out the bolter sleep time if it - #occured. - if ($lsoLoopDuration.TotalMilliseconds -gt $lsoBolterSleepTimer.TotalMilliseconds) { - $scanInterval = $scanInterval + ($lsoLoopDuration - $lsoBolterSleepTimer) + ($lsoLoopDuration - $lsoBolterSleepTimer) - } - else { - $scanInterval = $scanInterval + $lsoLoopDuration + $lsoLoopDuration - } + #Check for last logged trap time and store it for comparison + $lastTrapString = Select-String -Path $rawGradelog -Pattern "^.*GRADE:.*" | Select-Object -Last 1 + $lastTrapString = $lastTrapString -replace "^.*(?:.txt\:\d{0,5}\:)", "" + $lastTrapString = $lastTrapString -replace ",.*$", "" + [DateTime]$lastTrapTime = $lastTrapString #Check dcs.log for the last line that matches the landing quality mark regex. try { - - $landingEvent = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex | Select-Object -Last 1 - + $landingEvent = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex | Select-Object -Index $logTrapIndex } catch { - Write-Output "$(Get-Timestamp) $err Could not find dcs.log configured in $lsoConfig. Please check the file path configured in LsoBot.ps1." | Out-file $debugLog -append - - } - + Write-Output "$(Get-Timestamp) $info No new landing Event with log index" | Out-file $debugLog -append + } + #If dcs.log did not contain any lines that matched the LSO regex, stop, otherwise continue if ($null -eq $landingEvent ) { - - Write-Output "$(Get-Timestamp) $info $lcDect No landing event detected" | Out-file $debugLog -append + Write-Output "$(Get-Timestamp) $info $lcDect No landing events detected" | Out-file $debugLog -append #Do Nothing } else { - - # Strip the log message down to the time that the log event occurred. - $logTime = $landingEvent - $logTime = $logTime -replace "^.*(?:dcs\.log\:\d{1,5}\:)", "" - $logTime = $logTime -replace "\..*$", "" - Write-Output "$(Get-Timestamp) $info $lcDect Landing detected at $logTime UTC" | Out-file $debugLog -append - - #Convert the log time string to a usable time object - [DateTime]$trapTime = $logTime - - #Get the difference between the LSO event and the current time - $diff = New-TimeSpan -Start $trapTime -End $lsoLoopUtcTime - Write-Output "$(Get-Timestamp) $info $lcTime Time diference from the start of the loop is $diff" | Out-file $debugLog -append - - #Strip the log message down to the pilot name - $Pilot = $landingEvent - $Pilot = $Pilot -replace "^.*(?:initiatorPilotName=)", "" - $Pilot = $Pilot -replace ",.*$", "" - - #Strip the log message down to the landing grade and add escapes for _ - $Grade = $landingEvent - $Grade = $Grade -replace "^.*(?:comment=LSO:)", "" - $Grade = $Grade -replace ",.*$", "" - - $RawGrade = $Grade - Write-Output "$(Get-Timestamp) $info $lcRegex Raw Grade is $Grade" | Out-file $debugLog -append - - <# - ////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BEGIN REGRADING - ////////////////////////////////////////////////////////////////////////////////////////////////////////////// - #> - + + # Strip the log message down to the time that the log event occurred. + $logTime = $landingEvent + $logTime = $logTime -replace "^.*(?:dcs\.log\:\d{1,5}\:)", "" + $logTime = $logTime -replace "\..*$", "" + $lastTrapTime.ToUniversalTime() + Write-Output "$(Get-Timestamp) $info $lcDect Landing detected at $logTime UTC" | Out-file $debugLog -append + Write-Output "$(Get-Timestamp) $info Comparing to last trap at: $lastTrapTime" | Out-file $debugLog -append + + #Convert the log time string to a usable time object + [DateTime]$trapTime = $logTime + Write-Output "$(Get-Timestamp) $info DCS.log trap time: $trapTime" | Out-file $debugLog -append + $boolCheck = $trapTime -gt $lastTrapTime + Write-Output "$(Get-Timestamp) $info DCS.log trap is more recent than last logged trap: $boolCheck" | Out-file $debugLog -append + + if ($null -eq $lastTrapTime -or $trapTime -gt $lastTrapTime) { + #Get the difference between the LSO event and the current time + $diff = New-TimeSpan -Start $trapTime -End $lsoLoopUtcTime + Write-Output "$(Get-Timestamp) $info $lcTime Time diference from the start of the loop is $diff" | Out-file $debugLog -append + + #Strip the log message down to the pilot name + $Pilot = $landingEvent + $Pilot = $Pilot -replace "^.*(?:initiatorPilotName=)", "" + $Pilot = $Pilot -replace ",.*$", "" + + #Strip the log message down to the landing grade and add escapes for _ + $Grade = $landingEvent + $Grade = $Grade -replace "^.*(?:comment=LSO:)", "" + $Grade = $Grade -replace ",.*$", "" + + $RawGrade = $Grade + Write-Output "$(Get-Timestamp) $info $lcRegex Raw Grade is $Grade" | Out-file $debugLog -append + + <# + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + BEGIN REGRADING + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #> + + <#//////////////////// REMOVALS ////////////////////#> + + # Remove SLOX, EGIW, and BC from vocab + if ($Grade -match $SLOX ) { + $Grade = $Grade -replace $SLOX, "" + $Grade = $Grade -replace '\s+', ' ' + } + if ($Grade -match $EGIW) { + $Grade = $Grade -replace $EGIW, "" + $Grade = $Grade -replace '\s+', ' ' + } + if ($Grade -match $BC) { + $Grade = $Grade -replace $BC, "" + $Grade = $Grade -replace '\s+', ' ' + } - <# //////////////////// REMOVALS //////////////////// #> + <#//////////////////// REPLACEMENTS ////////////////////#> - # Remove SLOX, EGIW, and BC from vocab - if ($Grade -match $SLOX ) { - $Grade = $Grade -replace $SLOX, "" - $Grade = $Grade -replace '\s+', ' ' - } - if ($Grade -match $EGIW) { - $Grade = $Grade -replace $EGIW, "" - $Grade = $Grade -replace '\s+', ' ' - } - if ($Grade -match $BC) { - $Grade = $Grade -replace $BC, "" - $Grade = $Grade -replace '\s+', ' ' - } + #Find instances where DRX\DLX and LURX\LULX are called together, and replace with simply LURX\LULX + if ((($Grade -match $DRX) -and ($Grade -match $LURX)) -or (($Grade -match $DLX) -and ($Grade -match $LULX))) { + $Grade = $Grade -replace $DRX, "" + $Grade = $Grade -replace $DLX, "" + $Grade = $Grade -replace '\s+', ' ' - <# //////////////////// REPLACEMENTS //////////////////// #> + } - #Find instances where DRX\DLX and LURX\LULX are called together, and replace with simply LURX\LULX - if ((($Grade -match $DRX) -and ($Grade -match $LURX)) -or (($Grade -match $DLX) -and ($Grade -match $LULX))) { - $Grade = $Grade -replace $DRX, "" - $Grade = $Grade -replace $DLX, "" - $Grade = $Grade -replace '\s+', ' ' + #Find instances of _PIC_ _PPPIC_ and replace with _PPPIC_ + if (($Grade -match $PIC) -and ($Grade -match $PPPIC)) { + $Grade = $Grade -replace $PIC, "" + $Grade = $Grade -replace '\s+', ' ' + } - } + #Find instances of DRX and DLX appearing in grade and replace with the one that appeared first. While technically possible, this is usually the LSO mistaking a late line up. + if ($Grade -match -join($DRX, ".*", $DLX)) { + $Grade = $Grade -replace $DLX, "" + $Grade = $Grade -replace '\s+', ' ' + + } + if ($Grade -match -join($DLX, ".*", $DRX)) { + $Grade = $Grade -replace $DRX, "" + $Grade = $Grade -replace '\s+', ' ' + } - #Find instances of _PIC_ _PPPIC_ and replace with _PPPIC_ - if (($Grade -match $PIC) -and ($Grade -match $PPPIC)) { - $Grade = $Grade -replace $PIC, "" - $Grade = $Grade -replace '\s+', ' ' - } + #Find instances of LULX and LURX in grade and replace with the one that appeared first. + if ($Grade -match -join($LURX, ".*", $LULX)) { + $Grade = $Grade -replace $LULX, "" + $Grade = $Grade -replace '\s+', ' ' + + } + if ($Grade -match -join($LULX, ".*", $LURX)) { + $Grade = $Grade -replace $LURX, "" + $Grade = $Grade -replace '\s+', ' ' + } - #Find instances of DRX and DLX appearing in grade and replace with the one that appeared first. While technically possible, this is usually the LSO mistaking a late line up. - if ($Grade -match -join($DRX, ".*", $DLX)) { - $Grade = $Grade -replace $DLX, "" - $Grade = $Grade -replace '\s+', ' ' - - } - if ($Grade -match -join($DLX, ".*", $DRX)) { - $Grade = $Grade -replace $DRX, "" - $Grade = $Grade -replace '\s+', ' ' - } + <#//////////////////// GRADING ////////////////////#> + #Because of the nature of the grades in a server dcs.log, almost all grades will need to be re-evaluated + #Control variable to determine if the grade is open to being regraded or if a previous step has regraded the grade already. + $lockGrade = 0 - #Find instances of LULX and LURX in grade and replace with the one that appeared first. - if ($Grade -match -join($LURX, ".*", $LULX)) { - $Grade = $Grade -replace $LULX, "" - $Grade = $Grade -replace '\s+', ' ' - - } - if ($Grade -match -join($LULX, ".*", $LURX)) { - $Grade = $Grade -replace $LURX, "" - $Grade = $Grade -replace '\s+', ' ' - } + #Check for waveoffs - <# //////////////////// GRADING //////////////////// #> - #Because of the nature of the grades in a server dcs.log, almost all grades will need to be re-evaluated - #Control variable to determine if the grade is open to being regraded or if a previous step has regraded the grade already. - $lockGrade = 0 + # Check for WO(AFU)TL which should be a cut pass. These somtimes don't generate WIRE # + if ($Grade -match $WOAFUTL) { + Write-Output "$(Get-Timestamp) $info $lcReg Found WO(AFU)TL, grading pass as Cut" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $CUT + $points = "1.0" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } - #Check for waveoffs + # Check for a WO(AFU)(IC|AR|IM) that still resulted in WIRE # in the grade, indicating a land, which should be a cut pass. + if (($Grade -match $WOAFU) -and ($Grade -match $WIRE)) { + Write-Output "$(Get-Timestamp) $info $lcReg Found WO(AFU) and a WIRE caught, grading pass as Cut" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $CUT + $points = "1.0" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } - # Check for WO(AFU)TL which should be a cut pass. These somtimes don't generate WIRE # - if ($Grade -match $WOAFUTL) { - Write-Output "$(Get-Timestamp) $info $lcReg Found WO(AFU)TL, grading pass as Cut" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $CUT - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } + <# Check for a Wave Off in the grade. If an WO is detected, sleep for an amount of time + equal to the bolter timer. This should be about 6 seconds, or enough time for the plane to takeoff + from the bolter. Now get additional context from the log, look for a takeoff event from the same player + that was landing. If the $Pilot has taken off from the boat within 7 secounds of the grade, presume this is a bolter. + #> + if ($Grade -match $rWO) { + Write-Output "$(Get-Timestamp) $info $lcReg Found a wave off. Sleeping for 6 seconds to detect a bolter" | Out-file $debugLog -append + Start-Sleep -Seconds $lsoBolterSleepTimer.TotalSeconds + $getLandingContext = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex -Context 12 | Select-Object -Last 1 | Out-String + $getLandingContext = $getLandingContext -Split "`r`n" + if ($getLandingContext -match $takeoffEventRegex) { + Write-Output "$(Get-Timestamp) $info $lcReg Found a takeoff event within bolter timeframe." | Out-file $debugLog -append + $getTakeoffEventPilot = Select-String -Path $dcsLogPath -Pattern $takeoffEventRegex | Select-Object -Last 1 + $getTakeoffEventPilot = $getTakeoffEventPilot -replace "^.*(?:takeoff,initiatorPilotName=)", "" + $getTakeoffEventPilot = $getTakeoffEventPilot -replace ",.*$", "" + $getTakeoffEventTime = Select-String -Path $dcsLogPath -Pattern $takeoffEventTimeRegex | Select-Object Matches -Last 1 + if ($getTakeoffEventTime.Matches.Value -le $trapTime+7) { + Write-Output "$(Get-Timestamp) $info $lcReg Detected bolter, grading pass as Bolter" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $BOLTER + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + else { + Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $WO + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + } + else { + Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $WO + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + } - # Check for a WO(AFU)(IC|AR|IM) that still resulted in WIRE # in the grade, indicating a land, which should be a cut pass. + <# Check for an Own Wave Off in the grade. If an own wave off is detected, do the bolter detection process#> + if($lockGrade -eq 0){ + if ($Grade -match $rOWO) { + Write-Output "$(Get-Timestamp) $info $lcReg Found an own wave off. Sleeping for 6 seconds to detect a bolter" | Out-file $debugLog -append + Start-Sleep -Seconds $lsoBolterSleepTimer.TotalSeconds + $getLandingContext = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex -Context 12 | Select-Object -Last 1 | Out-String + $getLandingContext = $getLandingContext -Split "`r`n" + if ($getLandingContext -match $takeoffEventRegex) { + Write-Output "$(Get-Timestamp) $info $lcReg Found a takeoff event within bolter timeframe." | Out-file $debugLog -append + $getTakeoffEventPilot = Select-String -Path $dcsLogPath -Pattern $takeoffEventRegex | Select-Object -Last 1 + $getTakeoffEventPilot = $getTakeoffEventPilot -replace "^.*(?:takeoff,initiatorPilotName=)", "" + $getTakeoffEventPilot = $getTakeoffEventPilot -replace ",.*$", "" + $getTakeoffEventTime = Select-String -Path $dcsLogPath -Pattern $takeoffEventTimeRegex | Select-Object Matches -Last 1 + if ($getTakeoffEventTime.Matches.Value -le $trapTime+7) { + Write-Output "$(Get-Timestamp) $info $lcReg Detected bolter, grading pass as Bolter" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $BOLTER + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + else { + Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as OWO" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $OWO + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + } + else { + Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $OWO + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + } + } - if (($Grade -match $WOAFU) -and ($Grade -match $WIRE)) { - Write-Output "$(Get-Timestamp) $info $lcReg Found WO(AFU) and a WIRE caught, grading pass as Cut" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $CUT - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } + <# Check for a WO(AFU) that did not result in a landing allegedly, and make sure there was no take off, in which case, make it a bolter. #> + if ($lockGrade -eq 0) { + if ($Grade -match $WOAFU) { + Write-Output "$(Get-Timestamp) $info $lcReg Found a WO(AFU). Sleeping for 6 seconds to detect a bolter" | Out-file $debugLog -append + Start-Sleep -Seconds $lsoBolterSleepTimer.TotalSeconds + $getLandingContext = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex -Context 12 | Select-Object -Last 1 | Out-String + $getLandingContext = $getLandingContext -Split "`r`n" + if ($getLandingContext -match $takeoffEventRegex) { + Write-Output "$(Get-Timestamp) $info $lcReg Found a takeoff event within bolter timeframe." | Out-file $debugLog -append + $getTakeoffEventPilot = Select-String -Path $dcsLogPath -Pattern $takeoffEventRegex | Select-Object -Last 1 + $getTakeoffEventPilot = $getTakeoffEventPilot -replace "^.*(?:takeoff,initiatorPilotName=)", "" + $getTakeoffEventPilot = $getTakeoffEventPilot -replace ",.*$", "" + $getTakeoffEventTime = Select-String -Path $dcsLogPath -Pattern $takeoffEventTimeRegex | Select-Object Matches -Last 1 + if ($getTakeoffEventTime.Matches.Value -le $trapTime+7) { + Write-Output "$(Get-Timestamp) $info $lcReg Detected bolter, grading pass as Bolter" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $BOLTER + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + else { + Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $WO + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + + } + else { + Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $OWO + $points = "2.5" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + } + } - <# Check for a Wave Off in the grade. If an WO is detected, sleep for an amount of time - equal to the bolter timer. This should be about 6 seconds, or enough time for the plane to takeoff - from the bolter. Now get additional context from the log, look for a takeoff event from the same player - that was landing. If the $Pilot has taken off from the boat within 7 secounds of the grade, presume this is a bolter. - #> - if ($Grade -match $rWO) { - Write-Output "$(Get-Timestamp) $info $lcReg Found a wave off. Sleeping for 6 seconds to detect a bolter" | Out-file $debugLog -append - Start-Sleep -Seconds $lsoBolterSleepTimer.TotalSeconds - $getLandingContext = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex -Context 12 | Select-Object -Last 1 | Out-String - $getLandingContext = $getLandingContext -Split "`r`n" - if ($getLandingContext -match $takeoffEventRegex) { - Write-Output "$(Get-Timestamp) $info $lcReg Found a takeoff event within bolter timeframe." | Out-file $debugLog -append - $getTakeoffEventPilot = Select-String -Path $dcsLogPath -Pattern $takeoffEventRegex | Select-Object -Last 1 - $getTakeoffEventPilot = $getTakeoffEventPilot -replace "^.*(?:takeoff,initiatorPilotName=)", "" - $getTakeoffEventPilot = $getTakeoffEventPilot -replace ",.*$", "" - $getTakeoffEventTime = Select-String -Path $dcsLogPath -Pattern $takeoffEventTimeRegex | Select-Object Matches -Last 1 - if ($getTakeoffEventTime.Matches.Value -le $trapTime+7) { - Write-Output "$(Get-Timestamp) $info $lcReg Detected bolter, grading pass as Bolter" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $BOLTER + # Check for automatic Cuts + if ($lockGrade -eq 0) { + if (($Grade -match $LLIW) -or + ($Grade -match $LRIW) -or + ($Grade -match $LULIW) -or + ($Grade -match $LURIW) -or + ($Grade -match $SLOIC) -or + ($Grade -match $SLOAR) -or + ($Grade -match $SLOIW) -or + ($Grade -match $PPPIC)) { + Write-Output "$(Get-Timestamp) $info $lcReg Found grossly unsafe deviation. Grading pass as Cut." | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $CUT $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - else { - Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $WO + $lockGrade = 1 + } + } + + # Check for TMRDIC or TMRDAR and EGTL or 3PTS for a cut pass OR if TMRDIC or TMRDAR were major deviations + if ($lockGrade -eq 0) { + if ((($Grade -match $TMRDIC) -or ($Grade -match $TMRDAR)) -and (($Grade -match $EGTL) -or ($Grade -match $3PTSIW)) ) { + $Grade = $Grade -replace $rGRADE, $CUT + $points = "1.0" $Grade = $Grade -replace '\s+', ' ' $lockGrade = 1 - } } - else { - Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $WO + elseif ($Grade -match "_TMRD(IC|AR)_") { + $Grade = $Grade -replace $rGRADE, $CUT + $points = "1.0" $Grade = $Grade -replace '\s+', ' ' - $lsoNoBolter = 1 $lockGrade = 1 } + } - <# Check for an Own Wave Off in the grade. If an own wave off is detected, do the bolter detection process - #> - - if($lockGrade -eq 0){ - if ($Grade -match $rOWO) { - Write-Output "$(Get-Timestamp) $info $lcReg Found an own wave off. Sleeping for 6 seconds to detect a bolter" | Out-file $debugLog -append - Start-Sleep -Seconds $lsoBolterSleepTimer.TotalSeconds - $getLandingContext = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex -Context 12 | Select-Object -Last 1 | Out-String - $getLandingContext = $getLandingContext -Split "`r`n" - if ($getLandingContext -match $takeoffEventRegex) { - Write-Output "$(Get-Timestamp) $info $lcReg Found a takeoff event within bolter timeframe." | Out-file $debugLog -append - $getTakeoffEventPilot = Select-String -Path $dcsLogPath -Pattern $takeoffEventRegex | Select-Object -Last 1 - $getTakeoffEventPilot = $getTakeoffEventPilot -replace "^.*(?:takeoff,initiatorPilotName=)", "" - $getTakeoffEventPilot = $getTakeoffEventPilot -replace ",.*$", "" - $getTakeoffEventTime = Select-String -Path $dcsLogPath -Pattern $takeoffEventTimeRegex | Select-Object Matches -Last 1 - if ($getTakeoffEventTime.Matches.Value -le $trapTime+7) { - Write-Output "$(Get-Timestamp) $info $lcReg Detected bolter, grading pass as Bolter" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $BOLTER - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - else { - Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as OWO" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $OWO + # Check for No Grades + if ($lockGrade -eq 0) { + if (($Grade -match $TMRDAR) -or + ($Grade -match $TMRDIC) -or + ($Grade -match $3PTSIW) -or + ($Grade -match $EGTL) -or + ($Grade -match $TMRDIM) -or + ($Grade -match $SLOIM) -or + ($Grade -match $PPPIC) -or + ($Grade -match $PIC) -or + ($Grade -match $PAR) -or + ($Grade -match $DRIC) -or + ($Grade -match $DLIC) -or + ($Grade -match $LULIC) -or + ($Grade -match $LURIC) -or + ($Grade -match $NERDIC) -or + ($Grade -match $DRAR) -or + ($Grade -match $DLAR) -or + ($Grade -match $NERDAR) -or + ($Grade -match $LURAR) -or + ($Grade -match $LULAR) -or + ($Grade -match $LOAR) -or + ($Grade -match $LOIW) -or + ($Grade -match $WAR) -or + ($Grade -match $1WIRE) -or + ($Grade -match $FIW)) { + + Write-Output "$(Get-Timestamp) $info $lcReg Found unsafe deviation. Grading pass as No Grade." | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $NOGRADE + $points = "2.0" $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - } - else { - Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $OWO + $lockGrade = 1 + } + } + + #Check for oscillating flight paths and No Grade + if ($lockGrade -eq 0) { + if (($Grade -match $LEFT) -and ($Grade -match $RIGHT)) { + Write-Output "$(Get-Timestamp) $info $lcReg Found oscillating flight path. Grading pass as NO Grade." | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $NOGRADE + $points = "2.0" + $Grade = $Grade -replace '\s+', ' ' + $lockGrade = 1 + } + } + + # Check for fair passes + if ($lockGrade -eq 0) { + if (($Grade -match $DRX) -or + ($Grade -match $DLX) -or + ($Grade -match $DRIM) -or + ($Grade -match $DLIM) -or + ($Grade -match $LURIM) -or + ($Grade -match $LULIM) -or + ($Grade -match $NERDIM) -or + ($Grade -match $FIM) -or + ($Grade -match $WIM) -or + ($Grade -match $FIC) -or + ($Grade -match $HIC) -or + ($Grade -match $LOIC) -or + ($Grade -match $PIC) -or + ($Grade -match $WIC) -or + ($Grade -match $HAR) -or + ($Grade -match $FAR)) { + Write-Output "$(Get-Timestamp) $info $lcReg Found deviations that were corrected before landing. Graded as Fair." | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $FAIR + $points = "3.0" $Grade = $Grade -replace '\s+', ' ' - $lsoNoBolter = 1 $lockGrade = 1 - } } } - <# Check for a WO(AFU) that did not result in a landing allegedly, and make sure there was no take off, - in which case, make it a bolter. #> - if ($lockGrade -eq 0) { - if ($Grade -match $WOAFU) { - Write-Output "$(Get-Timestamp) $info $lcReg Found a WO(AFU). Sleeping for 6 seconds to detect a bolter" | Out-file $debugLog -append - Start-Sleep -Seconds $lsoBolterSleepTimer.TotalSeconds - $getLandingContext = Select-String -Path $dcsLogPath -Pattern $lsoEventRegex -Context 12 | Select-Object -Last 1 | Out-String - $getLandingContext = $getLandingContext -Split "`r`n" - if ($getLandingContext -match $takeoffEventRegex) { - Write-Output "$(Get-Timestamp) $info $lcReg Found a takeoff event within bolter timeframe." | Out-file $debugLog -append - $getTakeoffEventPilot = Select-String -Path $dcsLogPath -Pattern $takeoffEventRegex | Select-Object -Last 1 - $getTakeoffEventPilot = $getTakeoffEventPilot -replace "^.*(?:takeoff,initiatorPilotName=)", "" - $getTakeoffEventPilot = $getTakeoffEventPilot -replace ",.*$", "" - $getTakeoffEventTime = Select-String -Path $dcsLogPath -Pattern $takeoffEventTimeRegex | Select-Object Matches -Last 1 - if ($getTakeoffEventTime.Matches.Value -le $trapTime+7) { - Write-Output "$(Get-Timestamp) $info $lcReg Detected bolter, grading pass as Bolter" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $BOLTER - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - else { - Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $WO + # Check for OK passes + if ($lockGrade -eq 0) { + if (($Grade -match $LULX) -or + ($Grade -match $LURX) -or + ($Grade -match $FX) -or + ($Grade -match $HX) -or + ($Grade -match $LOX) -or + ($Grade -match $HIM) -or + ($Grade -match $LOIM) -or + ($Grade -match $NX) -or + ($Grade -match $WX)) { + + Write-Output "$(Get-Timestamp) $info $lcReg Found minor deviations that were corrected before landing. Graded as OK." | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $OK + $points = "4.0" $Grade = $Grade -replace '\s+', ' ' $lockGrade = 1 - } - - } - else { - Write-Output "$(Get-Timestamp) $info $lcReg Did not detect bolter, grading pass as WO" | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $OWO - $Grade = $Grade -replace '\s+', ' ' - $lsoNoBolter = 1 - $lockGrade = 1 } } - } - # Check for automatic Cuts - if ($lockGrade -eq 0) { - if (($Grade -match $LLIW) -or - ($Grade -match $LRIW) -or - ($Grade -match $LULIW) -or - ($Grade -match $LURIW) -or - ($Grade -match $SLOIC) -or - ($Grade -match $SLOAR) -or - ($Grade -match $SLOIW) -or - ($Grade -match $PPPIC)) { - Write-Output "$(Get-Timestamp) $info $lcReg Found grossly unsafe deviation. Grading pass as Cut." | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $CUT - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - } + # Check for empty #3 wires and change to _OK_ + if ($Grade -match "GRADE:\S{1,4}\s*?:\s*WIRE#\s*3") { + Write-Output "$(Get-Timestamp) $info $lcReg Found no deviations and a 3# WIRE. Graded pass as Excellent." | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $PERFECT + $points = "5.0" + } + # Check for empty #2 and #4 wires and switch to OK + if ($Grade -match "GRADE:\S{1,4}\s*?:\s*WIRE#\s*(2|4)") { + Write-Output "$(Get-Timestamp) $info $lcReg Found no deviations and a #2 or #4 WIRE. Graded as OK." | Out-file $debugLog -append + $Grade = $Grade -replace $rGRADE, $OK + $points = "4.0" + } - # Check for TMRDIC or TMRDAR and EGTL or 3PTS for a cut pass OR if TMRDIC or TMRDAR were major deviations + # Trim : + if ($Grade -match ":\s?(\(|\)|__|_|\s*)\s?:") { + $Grade = $Grade -replace ":\s?(\(|\)|__|_|\s*)\s?:", ":" + } - if ($lockGrade -eq 0) { - if ((($Grade -match $TMRDIC) -or ($Grade -match $TMRDAR)) -and (($Grade -match $EGTL) -or ($Grade -match $3PTSIW)) ) { - $Grade = $Grade -replace $rGRADE, $CUT - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - elseif ($Grade -match "_TMRD(IC|AR)_") { - $Grade = $Grade -replace $rGRADE, $CUT + Write-Output "$(Get-Timestamp) $info $lcReg Regraded Grade: $Grade" | Out-file $debugLog -append + + <# + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + END REGRADING + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + FINAL FORMATTING + + #> + + #Reordering. Pulls apart grade in to the Grade, X, IM, IC, AR, IW, and Wire and then joins them back together. + #This needs to be done because the AI LSO has a habit of writing comments out of order. + $xGrade = $Grade.Split() + $yGrade = ($Grade -split '(?=:)')[0] + ":" + $xX = $xGrade | Where-Object {$_ -match "\w*X(_|\))?\b"} + $xIM = $xGrade | Where-Object {$_ -match "\w*IM(_|\))?\b"} + $xIC = $xGrade | Where-Object {$_ -match "\w*IC(_|\))?\b"} + $xAR = $xGrade | Where-Object {$_ -match "\w*AR(_|\))?\b"} + $xIW = $xGrade | Where-Object {$_ -match "\w*IW(_|\))?\b"} + $xTL = $xGrade | Where-Object {$_ -match "\w*TL(_|\))?\b"} + $xAW = $xGrade | Where-Object {$_ -match "\w*AW(_|\))?\b"} + $xWIRE = ($xGrade | Where-Object {$_ -match "(?:WIRE#)"}) + " " + ($xGrade | Where-Object {$_ -match "\d(?!PTS)"}) + + if ($xX) { $xX = [String]::Join(" ",$xX) } + if ($xIM) { $xIM = [String]::Join(" ",$xIM) } + if ($xIC) { $xIC = [String]::Join(" ",$xIC) } + if ($xAR) { $xAR = [String]::Join(" ",$xAR) } + if ($xIW) { $xIW = [String]::Join(" ",$xIW) } + if ($xTL) { $xTL = [String]::Join(" ",$xTL) } + if ($xAW) { $xAW = [String]::Join(" ",$xAW) } + + $Grade = $yGrade + " " + $xX + " " + $xIM + " " + $xIC + " " + $xAR + " " + $xIW + " " + $xAW + " " + $xTL + " " + $xWIRE + + # IW Cleanup. None of these comments need IW in them. DO NOT move this above reordering or these comments will disappear. + $Grade = $Grade -replace 'LLWDIW', 'LLWD' + $Grade = $Grade -replace 'LLIW', 'LL' + $Grade = $Grade -replace 'LRIW', 'LR' + $Grade = $Grade -replace 'LRWDIW', 'LRWD' + $Grade = $Grade -replace '3PTSIW', '3PTS' + $Grade = $Grade -replace 'LNFIW', 'LNF' + + # WO Cleanup. + $Grade = $Grade -replace 'WO\(AFU\)(X|IM|IC|AR)', 'WO(AFU)' + $Grade = $Grade -replace 'WOFD(X|IM|IC|AR)', 'WO(FD)' + $Grade = $Grade -replace 'WONSUX', 'WO(NSU)' + + #Remove major marks from TMRD + $Grade = $Grade -replace '_(?=TMRD(X|IM|IC|AR))', '' + $Grade = $Grade -replace '(?<=TMRD\w{2})_', '' + + #One final extraneous white space trim $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - - } - # Check for No Grades - if ($lockGrade -eq 0) { - if (($Grade -match $TMRDAR) -or - ($Grade -match $TMRDIC) -or - ($Grade -match $3PTSIW) -or - ($Grade -match $EGTL) -or - ($Grade -match $TMRDIM) -or - ($Grade -match $SLOIM) -or - ($Grade -match $PPPIC) -or - ($Grade -match $PIC) -or - ($Grade -match $PAR) -or - ($Grade -match $DRIC) -or - ($Grade -match $DLIC) -or - ($Grade -match $LULIC) -or - ($Grade -match $LURIC) -or - ($Grade -match $NERDIC) -or - ($Grade -match $DRAR) -or - ($Grade -match $DLAR) -or - ($Grade -match $NERDAR) -or - ($Grade -match $LURAR) -or - ($Grade -match $LULAR) -or - ($Grade -match $LOAR) -or - ($Grade -match $LOIW) -or - ($Grade -match $WAR) -or - ($Grade -match $1WIRE) -or - ($Grade -match $FIW)) { - - Write-Output "$(Get-Timestamp) $info $lcReg Found unsafe deviation. Grading pass as No Grade." | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $NOGRADE - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - } + #Underline style as defined by $lsoConfig.underlineStyle + if ($lsoConfig.underlineStyle -eq "Underline") { + $Grade = $Grade -replace "_", "__" + } + elseif ($lsoConfig.underlineStyle -eq "APARTS") { + $Grade = $Grade -replace "_", "\_" + } + else { + $Grade = $Grade -replace "_", "\_" + } - #Check for oscillating flight paths and No Grade - if ($lockGrade -eq 0) { - if (($Grade -match $LEFT) -and ($Grade -match $RIGHT)) { - Write-Output "$(Get-Timestamp) $info $lcReg Found oscillating flight path. Grading pass as NO Grade." | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $NOGRADE - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - } + #If the $Pilot or $Grade somehow turned up $null or blank, stop + if (($Pilot -eq "System.Object[]") -or ($Grade -eq "System.Object[]")) { - # Check for fair passes - if ($lockGrade -eq 0) { - if (($Grade -match $DRX) -or - ($Grade -match $DLX) -or - ($Grade -match $DRIM) -or - ($Grade -match $DLIM) -or - ($Grade -match $LURIM) -or - ($Grade -match $LULIM) -or - ($Grade -match $NERDIM) -or - ($Grade -match $FIM) -or - ($Grade -match $WIM) -or - ($Grade -match $FIC) -or - ($Grade -match $HIC) -or - ($Grade -match $LOIC) -or - ($Grade -match $PIC) -or - ($Grade -match $WIC) -or - ($Grade -match $HAR) -or - ($Grade -match $FAR)) { - Write-Output "$(Get-Timestamp) $info $lcReg Found deviations that were corrected before landing. Graded as Fair." | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $FAIR - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - } + Write-Output "$(Get-Timestamp) $err $lcJob Landing detected at $logTime is malformed. Something went wrong with the regex steps." | Out-file $debugLog -append + } - # Check for OK passes - if ($lockGrade -eq 0) { - if (($Grade -match $LULX) -or - ($Grade -match $LURX) -or - ($Grade -match $FX) -or - ($Grade -match $HX) -or - ($Grade -match $LOX) -or - ($Grade -match $HIM) -or - ($Grade -match $LOIM) -or - ($Grade -match $NX) -or - ($Grade -match $WX)) { - - Write-Output "$(Get-Timestamp) $info $lcReg Found minor deviations that were corrected before landing. Graded as OK." | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $OK - $Grade = $Grade -replace '\s+', ' ' - $lockGrade = 1 - } - } + #If the $Pilot or $Grade has a date in the format of ####-##-##, stop. + #This will happen when AI land as the regex doesn't work correctly without a pilot field in the log event. + elseif (($Pilot -match "^.*\d{4}\-\d{2}\-\d{2}.*$") -or ($Grade -match "^.*\d{4}\-\d{2}\-\d{2}.*$")) { - # Check for empty #3 wires and change to _OK_ - if ($Grade -match "GRADE:\S{1,4}\s*?:\s*WIRE#\s*3") { - Write-Output "$(Get-Timestamp) $info $lcReg Found no deviations and a 3# WIRE. Graded pass as Excellent." | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $PERFECT - } - # Check for empty #2 and #4 wires and switch to OK - if ($Grade -match "GRADE:\S{1,4}\s*?:\s*WIRE#\s*(2|4)") { - Write-Output "$(Get-Timestamp) $info $lcReg Found no deviations and a #2 or #4 WIRE. Graded as OK." | Out-file $debugLog -append - $Grade = $Grade -replace $rGRADE, $OK - } + Write-Output "$(Get-Timestamp) $warn $lcJob Landing detected at $logTime contained a date in the pilot name." + + "This indicates that Regex failed, usually because the initiatorPilot field was missing in the landing event. Likely AI landing." | Out-file $debugLog -append + } - # Trim : - if ($Grade -match ":\s?(\(|\)|__|_|\s*)\s?:") { - $Grade = $Grade -replace ":\s?(\(|\)|__|_|\s*)\s?:", ":" - } + #Create the webhook and send it + else { + $logString = "" + if ($pointScoring) { + $logString = "$trapTime,$Pilot,$points," + } + else { + $logString = "$trapTime,$Pilot," + } + Write-Output "$logString$RawGrade" | Out-file $rawGradelog -append + Write-Output "$logString$Grade" | Out-file $reGradedLog -append - Write-Output "$(Get-Timestamp) $info $lcReg Regraded Grade: $Grade" | Out-file $debugLog -append + + #EMBED WEBHOOK - <# - ////////////////////////////////////////////////////////////////////////////////////////////////////////////// - END REGRADING - ////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - FINAL FORMATTING + if ($lsoConfig.hookStyle -eq "embed") { + [System.Collections.ArrayList]$lsoHookEmbedArray = @() + + #Split the comments from the grade + [String]$lsoComments = $Grade.Split(":")[-1] + if ($lsoComments -eq "") { + $lsoComments = 'n/a' + $Grade = $Grade.Split(":")[1] + } + else{ + $Grade = $Grade.Split(":")[0] + } + + <# Accent color of the embed based on the landing: + + _OK_ = Very Green + OK = Green + (OK) = Subdued Green + B = Brighter Orange + --- = Orange + CUT = Disappointed LSO Red + + #> + + if ($Grade -Match "_OK_") { + $embedColor = "835704" + } + elseif ($Grade -Match "(? + [PSCustomObject]@{ + name = "**Comments**" + value = $lsoComments + inline = $true + } + ) + } + } - #Reordering. Pulls apart grade in to the Grade, X, IM, IC, AR, IW, and Wire and then joins them back together. - #This needs to be done because the AI LSO has a habit of writing comments out of order. - $xGrade = $Grade.Split() - $yGrade = ($Grade -split '(?=:)')[0] + ":" - $xX = $xGrade | Where-Object {$_ -match "\w*X(_|\))?\b"} - $xIM = $xGrade | Where-Object {$_ -match "\w*IM(_|\))?\b"} - $xIC = $xGrade | Where-Object {$_ -match "\w*IC(_|\))?\b"} - $xAR = $xGrade | Where-Object {$_ -match "\w*AR(_|\))?\b"} - $xIW = $xGrade | Where-Object {$_ -match "\w*IW(_|\))?\b"} - $xTL = $xGrade | Where-Object {$_ -match "\w*TL(_|\))?\b"} - $xAW = $xGrade | Where-Object {$_ -match "\w*AW(_|\))?\b"} - $xWIRE = ($xGrade | Where-Object {$_ -match "(?:WIRE#)"}) + " " + ($xGrade | Where-Object {$_ -match "\d(?!PTS)"}) - - if ($xX) { $xX = [String]::Join(" ",$xX) } - if ($xIM) { $xIM = [String]::Join(" ",$xIM) } - if ($xIC) { $xIC = [String]::Join(" ",$xIC) } - if ($xAR) { $xAR = [String]::Join(" ",$xAR) } - if ($xIW) { $xIW = [String]::Join(" ",$xIW) } - if ($xTL) { $xTL = [String]::Join(" ",$xTL) } - if ($xAW) { $xAW = [String]::Join(" ",$xAW) } - - $Grade = $yGrade + " " + $xX + " " + $xIM + " " + $xIC + " " + $xAR + " " + $xIW + " " + $xAW + " " + $xTL + " " + $xWIRE - - # IW Cleanup. None of these comments need IW in them. DO NOT move this above reordering or these comments will disappear. - $Grade = $Grade -replace 'LLWDIW', 'LLWD' - $Grade = $Grade -replace 'LLIW', 'LL' - $Grade = $Grade -replace 'LRIW', 'LR' - $Grade = $Grade -replace 'LRWDIW', 'LRWD' - $Grade = $Grade -replace '3PTSIW', '3PTS' - $Grade = $Grade -replace 'LNFIW', 'LNF' - - # WO Cleanup. - $Grade = $Grade -replace 'WO\(AFU\)(X|IM|IC|AR)', 'WO(AFU)' - $Grade = $Grade -replace 'WOFD(X|IM|IC|AR)', 'WO(FD)' - $Grade = $Grade -replace 'WONSUX', 'WO(NSU)' - - #Remove major marks from TMRD - $Grade = $Grade -replace '_(?=TMRD(X|IM|IC|AR))', '' - $Grade = $Grade -replace '(?<=TMRD\w{2})_', '' - - #One final extraneous white space trim - $Grade = $Grade -replace '\s+', ' ' - - #Underline style as defined by $lsoConfig.underlineStyle - if ($lsoConfig.underlineStyle -eq "Underline") { - $Grade = $Grade -replace "_", "__" - } - elseif ($lsoConfig.underlineStyle -eq "APARTS") { - $Grade = $Grade -replace "_", "\_" - } - else { - $Grade = $Grade -replace "_", "\_" - } + #Add embed object to array + $lsoHookEmbedArray.Add($script:hookEmbedObject) | Out-Null - #If the difference between the system time and log event time is greater than the time target, stop. + #Create the payload + $hookPayload = [PSCustomObject]@{ - if ($diff -gt $scanInterval) { + embeds = $lsoHookEmbedArray - Write-Output "$(Get-Timestamp) $warn $lcTime Landing detected at $logTime is too old. Excepted interval was $scanInterval. Discarding." | Out-file $debugLog -append - # Do Nothing - } + } - #If the $Pilot or $Grade somehow turned up $null or blank, stop - elseif (($Pilot -eq "System.Object[]") -or ($Grade -eq "System.Object[]")) { + <# Update Google Sheets with LSO Grades - START #> - Write-Output "$(Get-Timestamp) $err $lcJob Landing detected at $logTime is malformed. Something went wrong with the regex steps." | Out-file $debugLog -append - } + $GoogleWebAppURL = 'INSERT_GOOGLE_WEB_APP_URL' - #If the $Pilot or $Grade has a date in the format of ####-##-##, stop. - #This will happen when AI land as the regex doesn't work correctly without a pilot field in the log event. - elseif (($Pilot -match "^.*\d{4}\-\d{2}\-\d{2}.*$") -or ($Grade -match "^.*\d{4}\-\d{2}\-\d{2}.*$")) { + $Column1Name = 'Date/Time' + $Column1Value = $(Get-Timestamp) - Write-Output "$(Get-Timestamp) $warn $lcJob Landing detected at $logTime contained a date in the pilot name." + - "This indicates that Regex failed, usually because the initiatorPilot field was missing in the landing event. Likely AI landing." | Out-file $debugLog -append - } - #Create the webhook and send it - else { - Write-Output "$(Get-Timestamp) $RawGrade" | Out-file $rawGradelog -append - Write-Output "$(Get-Timestamp) $Grade" | Out-file $reGradedLog -append - - #EMBED WEBHOOK + $Column2Name = 'Pilot' + $Column2Value = $Pilot - if ($lsoConfig.hookStyle -eq "embed") { - [System.Collections.ArrayList]$lsoHookEmbedArray = @() - - #Split the comments from the grade - [String]$lsoComments = $Grade.Split(":")[-1] - if ($lsoComments -eq "") { - $lsoComments = 'n/a' - $Grade = $Grade.Split(":")[1] - } - else{ - $Grade = $Grade.Split(":")[0] - } + $Column3Name = 'Grade' + $Column3Value = $Grade - <# Accent color of the embed based on the landing: + $Column4Name = 'Comments' + $Column4Value = $lsoComments - _OK_ = Very Green - OK = Green - (OK) = Subdued Green - B = Brighter Orange - --- = Orange - CUT = Disappointed LSO Red - - #> - - if ($Grade -Match "_OK_") { - $embedColor = "835704" - } - elseif ($Grade -Match "(? - #Create the payload - $hookPayload = [PSCustomObject]@{ + #Send webhook + try { + Invoke-RestMethod -Uri $lsoConfig.webHookUrl -Body ($hookPayload | ConvertTo-Json -Depth 5) -Method Post -ContentType 'application/json' + Write-Output "$(Get-Timestamp) $info $lcDiscord A landing event was detected and sent successfully via Discord." | Out-file $debugLog -append - embeds = $lsoHookEmbedArray + # If the debug flag is enabled send payload to debug server too + if ($lsoConfig.debug_flag -eq 1){ + Invoke-RestMethod -Uri $lsoConfig.webHookUrl_debug -Body ($hookPayload | ConvertTo-Json -Depth 5) -Method Post -ContentType 'application/json' + Write-Output "$(Get-Timestamp) $info $lcDiscord A landing event was detected and sent successfully to debug Discord." | Out-file $debugLog -append + } + } + #If the error was specifically a network exception or IO exception, write friendly log message + catch [System.Net.WebException],[System.IO.IOException] { + Write-Output "$(Get-Timestamp) $err $lcDiscord Failed to establish connection to Discord webhook. Please check that the webhook URL is correct, and activated in Discord." | Out-file $debugLog -append + } + catch { + Write-Output "$(Get-Timestamp) $err $lcDiscord An unknown error occurred attempting to invoke the API request to Discord." | Out-file $debugLog -append + } } - #Send webhook - try { - Invoke-RestMethod -Uri $lsoConfig.webHookUrl -Body ($hookPayload | ConvertTo-Json -Depth 5) -Method Post -ContentType 'application/json' - Write-Output "$(Get-Timestamp) $info $lcDiscord A landing event was detected and sent successfully via Discord." | Out-file $debugLog -append - } - #If the error was specifically a network exception or IO exception, write friendly log message - catch [System.Net.WebException],[System.IO.IOException] { - Write-Output "$(Get-Timestamp) $err $lcDiscord Failed to establish connection to Discord webhook. Please check that the webhook URL is correct, and activated in Discord." | Out-file $debugLog -append - } - catch { - Write-Output "$(Get-Timestamp) $err $lcDiscord An unknown error occurred attempting to invoke the API request to Discord." | Out-file $debugLog -append - } - } + # BASIC WEBHOOK - # BASIC WEBHOOK + else { + $logString = "" + if ($pointScoring) { + $logString = "$trapTime,$Pilot,$points," + } + else { + $logString = "$trapTime,$Pilot," + } + Write-Output "$logString$RawGrade" | Out-file $rawGradelog -append + Write-Output "$logString$Grade" | Out-file $reGradedLog -append - else { - Write-Output "$(Get-Timestamp) $RawGrade" | Out-file $rawGradelog -append - Write-Output "$(Get-Timestamp) $Grade" | Out-file $reGradedLog -append + #Message content + $messageContent = "" + if ($pointScoring) { + $messageContent = -join("**Pilot: **", $Pilot, " **Points:** ", $points, " **Grade:** ", $Grade ) + } + else { + $messageContent = -join("**Pilot: **", $Pilot, " **Grade:** ", $Grade ) + } - #Message content - $messageContent = -join("**Pilot: **", $Pilot, " **Grade:** ", $Grade ) + #json payload + $hookPayload = [PSCustomObject]@{ + content = $messageContent + } + #The webhook + try { + Invoke-RestMethod -Uri $lsoConfig.webHookUrl -Method Post -Body ($hookPayload | ConvertTo-Json) -ContentType 'application/json' + Write-Output "$(Get-Timestamp) $info $lcDiscord A landing event was detected and sent successfully via Discord." | Out-file $debugLog -append - #json payload - $hookPayload = [PSCustomObject]@{ - content = $messageContent - } - #The webhook - try { - Invoke-RestMethod -Uri $lsoConfig.webHookUrl -Method Post -Body ($hookPayload | ConvertTo-Json) -ContentType 'application/json' - Write-Output "$(Get-Timestamp) $info $lcDiscord A landing event was detected and sent successfully via Discord." | Out-file $debugLog -append - } - #If the error was specifically a network exception or IO exception, write friendly log message - catch [System.Net.WebException],[System.IO.IOException] { - Write-Output "$(Get-Timestamp) $err $lcDiscord Failed to establish connection to Discord webhook. Please check that the webhook URL is correct, and activated in Discord." | Out-file $debugLog -append - } - catch { - Write-Output "$(Get-Timestamp) $err $lcDiscord An unknown error occurred attempting to invoke the API request to Discord." | Out-file $debugLog -append + # If the debug flag is enabled send payload to debug server too + if ($lsoConfig.debug_flag -eq 1){ + Invoke-RestMethod -Uri $lsoConfig.webHookUrl_debug -Body ($hookPayload | ConvertTo-Json -Depth 5) -Method Post -ContentType 'application/json' + Write-Output "$(Get-Timestamp) $info $lcDiscord A landing event was detected and sent successfully to debug Discord." | Out-file $debugLog -append + } + + } + #If the error was specifically a network exception or IO exception, write friendly log message + catch [System.Net.WebException],[System.IO.IOException] { + Write-Output "$(Get-Timestamp) $err $lcDiscord Failed to establish connection to Discord webhook. Please check that the webhook URL is correct, and activated in Discord." | Out-file $debugLog -append + } + catch { + Write-Output "$(Get-Timestamp) $err $lcDiscord An unknown error occurred attempting to invoke the API request to Discord." | Out-file $debugLog -append + } } + } + + $logTrapIndex++ + + } + else { + Write-Output "$(Get-Timestamp) $info After closer inspection, no new landing events" | Out-file $debugLog -append } } + <# Get the run duration of the loop, and convert to the amount of milliseconds the loop should sleep, which is the scan interval minus the loop duration. This means that, in a perfect world with a perfectly coded script, @@ -863,14 +1006,11 @@ for ($i = 1; $i -le $timeTarget; $i++) { which as described earlier creates timing issues. #> $lsoLoopEndSysTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss.fff" - $lsoLoopDuration = $lsoLoopDuration = New-TimeSpan -Start $lsoLoopStartSysTime -End $lsoLoopEndSysTime + $lsoLoopDuration = New-TimeSpan -Start $lsoLoopStartSysTime -End $lsoLoopEndSysTime Write-Output "$(Get-Timestamp) $info $lcJob LSO BOT loop duration was $lsoLoopDuration" | Out-file $debugLog -append + Write-Output "$(Get-Timestamp) $info $lcTime LSO BOT Cycle Ran. Sleeping for $scanInterval seconds" | Out-file $debugLog -append - $lsoSleepTime = ($scanInterval.TotalMilliseconds - $lsoLoopDuration.TotalMilliseconds) - Write-Output "$(Get-Timestamp) $info $lcTime Sleep duration is now $lsoSleepTime based on $scanInterval - $lsoLoopDuration" | Out-file $debugLog -append - Write-Output "$(Get-Timestamp) $info $lcTime LSO BOT Cycle Ran. Sleeping for $lsoSleepTime milliseconds" | Out-file $debugLog -append - - Start-Sleep -Milliseconds $lsoSleepTime + Start-Sleep -Seconds $scanInterval.TotalSeconds } #Garbage Collection -[system.gc]::Collect() \ No newline at end of file +[system.gc]::Collect() diff --git a/code.gs b/code.gs new file mode 100644 index 0000000..603a1ca --- /dev/null +++ b/code.gs @@ -0,0 +1,152 @@ +/******************************************************************************************************************************** +* Copyright 2021 BadMojo11 +* https://github.com/BadMojo11 +* +* License Info +* +* +* Setup/Config +* +* 1. Copy and overwrite any code in the code.gs file into App Script of your spreadsheet +* +* 2. Enter sheet name where data is to be written in the GLOBAL VARIABLES section +* +* 3. Publish > Deploy as web app +* - Enter Project Version name and click 'Save New Version' +* - Set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously) +* +* 4. Copy the 'Current web app URL' and post this in your LsoBot.ps1 form/script action +* +* 5. Insert column names on your destination sheet matching the parameter names of the data you are passing in (exactly matching case) +* +***************************************************************************************************************************************/ + +/******************** + * GLOBAL VARIABLES * + ********************/ + +// New script property service for handling data +var script_properties = PropertiesService.getScriptProperties(); + +// Define target sheet - Replace with your target sheet name +var sheet_name = "Grades"; + +/************ + * METHODS * + ************/ + +// Comment out if you do not want to expose get method +function doGet(e){ + return handleResponse(e); +} + +// Comment out if you do not want to expose post method +function doPost(e){ + return handleResponse(e); +} + +// Main method: handle response +function handleResponse(e) { + + // Prevents overwriting data by preventing concurrent access + var public_lock = LockService.getPublicLock(); + + // Define lock wait time: currently set to 30 seconds + public_lock.waitLock(30000); + + try { + + // next set where we write the data - you could write to multiple/alternate destinations + var doc = SpreadsheetApp.openById(script_properties.getProperty("key")); + + // Get sheet by name + var sheet = doc.getSheetByName(sheet_name); + + // Define header as first row + var headRow = e.parameter.header_row || 1; + + // Get header columns + var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]; + + // Get next available row in sheet + var nextRow = sheet.getLastRow()+1; + + // Create array 'row' + var row = []; + + // For statement to loop through header columns + for (i in headers){ + + // Automatically add timestamp to row if your column is named Timestamp + if (headers[i] == "Timestamp"){ + + // Add timestamp to the new row + row.push(new Date()); + + } else { + + // Else use the header name to get the data + row.push(e.parameter[headers[i]]); + } + } + + //Set values in row + sheet.getRange(nextRow, 1, 1, row.length).setValues([row]); + + // Return JSON success results + return ContentService + .createTextOutput(JSON.stringify({"result":"success", "row": nextRow})) + .setMimeType(ContentService.MimeType.JSON); + } catch(e){ + // IF error, return error result + return ContentService + .createTextOutput(JSON.stringify({"result":"error", "error": e})) + .setMimeType(ContentService.MimeType.JSON); + } finally { + + //call reGrade here? + + //call function getWire + getWire(); + + // Release the lock on the sheet + public_lock.releaseLock(); + } +} + +function getWire() { + + // Get the grades sheet - replace with name of your sheet + var grades_sheet = SpreadsheetApp.getActive().getSheetByName('Grades'); + + // Set these values to match the columns in your sheet + var col_id_comments = "D"; + var col_id_wire = "F"; + + // Get the current row where the edit is happening + var row_id = grades_sheet.getLastRow(); + + //Get range of comments cell + var commentsCell = grades_sheet.getRange(col_id_comments + row_id); + + if (commentsCell.isBlank()){ + return; + } + else{ + + var comments = grades_sheet.getRange(col_id_comments + row_id).getValue(); + + var wire = grades_sheet.getRange(col_id_wire + row_id); + + var strlength = comments.length -1; + + var lastChar = comments.charAt(strlength); + + if (lastChar=="1" || lastChar=="2" || lastChar=="3" || lastChar=="4"){ + wire.setValue(lastChar); + } + else{ + wire.setValue("-"); + } + } +}