Created
January 8, 2013 02:28
-
-
Save EdGruberman/4480548 to your computer and use it in GitHub Desktop.
Minecraft Server Wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
powershell.exe -noexit ". 'D:\Documents\Personal\Games\Minecraft\Server\MCS.ps1'" | |
#> | |
Add-Type -AssemblyName 'System.Messaging' | |
Add-Type -AssemblyName 'System.Web' | |
Add-Type -AssemblyName 'System.Web.Extensions' | |
Function Initialize | |
{ | |
$Global:datLastStarted = Get-Date | |
$Global:Players = @{} | |
$Global:TaskQueue = New-Object Collections.Queue | |
$Global:TimerStarts = @{} | |
#--Setup automatic world saving | |
If ((GetConfiguration('AutoSave')) -ne [DBNull]::Value) { | |
#--Start based on last start, but not longer than normal | |
$Initial = (GetConfiguration('AutoSave')) * 60 * 1000 | |
$Last = (New-TimeSpan (GetStatus('LastSaveRequest')) $Global:datLastStarted.ToUniversalTime()).TotalMilliseconds | |
If ($Last -lt $Initial) { $Initial = $Initial - $Last } Else { $Initial = 5 * 60 * 1000 } | |
$Global:timAutoSave = New-Object System.Timers.Timer | |
$Global:timAutoSave.Interval = $Initial | |
$Global:timAutoSave.Enabled = $True | |
Register-ObjectEvent $timAutoSave 'Elapsed' -SourceIdentifier 'AutoSave' -Action { timAutoSave_Elapsed @Args } | Out-Null | |
$Global:timAutoSave.Start() | |
$Global:TimerStarts.Save = Get-Date | |
} | |
#--Setup automatic backup | |
If ((GetConfiguration('AutoBackup')) -ne [DBNull]::Value) { | |
#--Start based on last start, but not longer than normal | |
$Initial = (GetConfiguration('AutoBackup')) * 60 * 1000 | |
$Last = (New-TimeSpan (GetStatus('LastBackupRequest')) $Global:datLastStarted.ToUniversalTime()).TotalMilliseconds | |
If ($Last -lt $Initial) { $Initial = $Initial - $Last } Else { $Initial = 5 * 60 * 1000 } | |
$Global:timAutoBackup = New-Object System.Timers.Timer | |
$Global:timAutoBackup.Interval = $Initial | |
$Global:timAutoBackup.Enabled = $True | |
Register-ObjectEvent $timAutoBackup 'Elapsed' -SourceIdentifier 'AutoBackup' -Action { timAutoBackup_Elapsed @Args } | Out-Null | |
$Global:timAutoBackup.Start() | |
$Global:TimerStarts.Backup = Get-Date | |
} | |
#--Setup automatic image creation | |
If ((GetConfiguration('AutoImages')) -ne [DBNull]::Value) { | |
#--Start based on last start, but not longer than normal | |
$Initial = (GetConfiguration('AutoImages')) * 60 * 1000 | |
$Last = (New-TimeSpan (GetStatus('LastImagesRequest')) $Global:datLastStarted.ToUniversalTime()).TotalMilliseconds | |
If ($Last -lt $Initial) { $Initial = $Initial - $Last } Else { $Initial = 5 * 60 * 1000 } | |
$Global:timAutoImages = New-Object System.Timers.Timer | |
$Global:timAutoImages.Interval = $Initial | |
$Global:timAutoImages.Enabled = $True | |
Register-ObjectEvent $timAutoImages 'Elapsed' -SourceIdentifier 'AutoImages' -Action { timAutoImages_Elapsed @Args } | Out-Null | |
$Global:timAutoImages.Start() | |
$Global:TimerStarts.Images = Get-Date | |
} | |
#--Setup automatic backup pruning | |
If ((GetConfiguration('AutoPrune')) -ne [DBNull]::Value) { | |
#--Start based on last start, but not longer than normal | |
$Initial = (GetConfiguration('AutoPrune')) * 60 * 1000 | |
If (GetStatus('LastPruneRequest')) | |
{ $Last = (New-TimeSpan (GetStatus('LastPruneRequest')) $Global:datLastStarted.ToUniversalTime()).TotalMilliseconds } | |
If ($Last -lt $Initial) { $Initial = $Initial - $Last } | |
$Global:timAutoPrune = New-Object System.Timers.Timer | |
$Global:timAutoPrune.Interval = $Initial | |
$Global:timAutoPrune.Enabled = $True | |
Register-ObjectEvent $timAutoPrune 'Elapsed' -SourceIdentifier 'AutoPrune' -Action { timAutoPrune_Elapsed @Args } | Out-Null | |
$Global:timAutoPrune.Start() | |
$Global:TimerStarts.Prune = Get-Date | |
} | |
#--Setup live player data monitor | |
$LivePlayerData = GetConfiguration 'LivePlayerData' | |
If ($LivePlayerData -ne [DBNull]::Value) { | |
$FSW = New-Object System.IO.FileSystemWatcher (Split-Path -Parent $LivePlayerData), (Split-Path -Leaf $LivePlayerData) | |
$FSW.NotifyFilter = [System.IO.NotifyFilters]::LastWrite | |
Get-EventSubscriber | Where-Object { $_.SourceIdentifier -eq 'LivePlayerData_Changed' } | Unregister-Event | |
Get-Job | Where-Object { $_.Name -eq 'LivePlayerData_Changed' } | Remove-Job | |
Register-ObjectEvent $FSW 'Changed' -SourceIdentifier 'LivePlayerData_Changed' -Action { LivePlayerData_Changed @Args } | Out-Null | |
} | |
$Global:blnMCSPrepared = $True | |
#Twitter_Initialize | |
} | |
Function Deinitialize | |
{ | |
#Get-EventSubscriber | Where-Object { $_.SourceIdentifier -eq 'LivePlayerData_Changed' } | Unregister-Event | |
#Get-Job | Where-Object { $_.Name -eq 'LivePlayerData_Changed' } | Remove-Job | |
Unregister-Event 'AutoSave' -ErrorAction:SilentlyContinue; Remove-Job 'AutoSave' -ErrorAction:SilentlyContinue | |
Unregister-Event 'AutoBackup' -ErrorAction:SilentlyContinue; Remove-Job 'AutoBackup' -ErrorAction:SilentlyContinue | |
Unregister-Event 'AutoImages' -ErrorAction:SilentlyContinue; Remove-Job 'AutoImages' -ErrorAction:SilentlyContinue | |
Unregister-Event 'AutoPrune' -ErrorAction:SilentlyContinue; Remove-Job 'AutoPrune' -ErrorAction:SilentlyContinue | |
If ($Global:TaskQueue) { If ($Global:TaskQueue.GetType().Name -eq 'Queue') { $Global:TaskQueue.Clear() } } | |
$Global:TaskInProgress = $False | |
#Twitter_Deinitialize | |
} | |
Function LivePlayerData_Changed ([System.IO.FileSystemWatcher]$Sender, [System.IO.FileSystemEventArgs]$e) { | |
$Last = (Get-ChildItem $e.FullPath).LastWriteTimeUtc | |
If ($Last -ne $Global:LastLivePlayerData ) { | |
$Global:LastLivePlayerData = $Last | |
ProcessLivePlayerData (Get-Content $e.FullPath) | |
} | |
Trap | |
{ | |
Write-Host "Error in LivePlayerData_Changed" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
Continue | |
} | |
} | |
Function ProcessLivePlayerData ([String]$JSON) { | |
$Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer | |
$Markers = $Serializer.DeserializeObject($JSON) | |
If ($Markers -eq $Null) { Return } | |
ForEach ($Player In $Markers) { | |
#--Update player coordinates in database | |
$Command = New-Object System.Data.SqlClient.SqlCommand("UpdatePlayerLocation", $SQL) | |
$Command.CommandType = [System.Data.CommandType]::StoredProcedure | |
$Command.Parameters.Add('@PlayerName', [System.Data.SqlDbType].NVarChar).Value = $Player.msg | |
$Command.Parameters.Add('@Updated' , [System.Data.SqlDbType].String).Value = (Get-Date $Player.timestamp).ToUniversalTime() | |
$Command.Parameters.Add('@World' , [System.Data.SqlDbType].NVarChar).Value = $Player.world | |
$Command.Parameters.Add('@X' , [System.Data.SqlDbType].Float).Value = $Player.x | |
$Command.Parameters.Add('@Y' , [System.Data.SqlDbType].Float).Value = $Player.y | |
$Command.Parameters.Add('@Z' , [System.Data.SqlDbType].Float).Value = $Player.z | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
[Void]$Command.ExecuteNonQuery() | |
$SQL.Close() | |
} | |
} | |
Function GetConfiguration ([String]$Parameter) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("SELECT [$Parameter] FROM Configuration WHERE Name = '$Global:Configuration'", $SQL) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Command.ExecuteScalar() | |
$SQL.Close() | |
} | |
Function GetStatus ([String]$Field) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("SELECT [$Field] FROM Status", $SQL) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Value = $Command.ExecuteScalar() | |
$SQL.Close() | |
If ($Value -ne [DBNull]::Value) { $Value = [DateTime]$Value } Else { $Value = $Null } | |
Return $Value | |
} | |
Function GetPlayer ([String]$Player) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("SELECT * FROM Players WHERE Name = '$Player'", $SQL) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Command.ExecuteReader() | |
$SQL.Close() | |
} | |
Function GetMotD | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("SELECT * FROM LastMotD", $SQL) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Command.ExecuteReader() | |
$SQL.Close() | |
} | |
Function FormatMotD | |
{ | |
$MotD = GetMotD | |
$Updated = (Duration $MotD['Updated'].ToLocalTime()).Split(' ')[0,1] | |
Return "Message of the Day ($Updated ago by $($MotD['UpdatedBy'])): $($MotD['Text'])" | |
} | |
Function SetStatus ([String]$Field) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("UPDATE Status SET [$Field] = GETUTCDATE()", $SQL) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
[Void]$Command.ExecuteNonQuery() | |
$SQL.Close() | |
} | |
Function SetPlayer ([String]$Name, [System.Data.Common.DbParameter]$Parameter, [Boolean]$FixCase = $False) | |
{ | |
#Add player if they don't already exist in database | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Players_Name = (New-Object System.Data.SqlClient.SqlCommand("SELECT Name FROM Players WHERE Name = '$Name'", $SQL)).ExecuteScalar() | |
If ($Players_Name -eq $Null) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("INSERT INTO Players (Name) VALUES ('$Name')", $SQL) | |
[Void]$Command.ExecuteNonQuery() | |
} | |
ElseIf ( $FixCase -and ($Players_Name -cne $Name) ) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("UPDATE Players SET Name = '$Name' WHERE Name = '$Name'", $SQL) | |
[Void]$Command.ExecuteNonQuery() | |
} | |
$SQL.Close() | |
If (!$Parameter) { Return } | |
$Command = New-Object System.Data.SqlClient.SqlCommand("UPDATE Players SET [$($Parameter.ParameterName)] = @Value WHERE Name = '$Name'", $SQL) | |
$Value = New-Object System.Data.SqlClient.SqlParameter('@Value', $Parameter.DbType) | |
$Value.Direction = [System.Data.ParameterDirection]::Input | |
$Value.Value = $Parameter.Value | |
[Void]$Command.Parameters.Add($Value) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
[Void]$Command.ExecuteNonQuery() | |
$SQL.Close() | |
} | |
Function SetMotD ([String]$DirtyText, [DateTime]$Updated, [String]$UpdatedBy) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("INSERT INTO MotD (Text, Updated, UpdatedBy) SELECT @Text, '$Updated', P.ID FROM Players AS P WHERE P.Name = '$UpdatedBy'", $SQL) | |
$Text = New-Object System.Data.SqlClient.SqlParameter('@Text', [System.Data.DbType]::String) | |
$Text.Direction = [System.Data.ParameterDirection]::Input | |
$Text.Value = $DirtyText | |
[Void]$Command.Parameters.Add($Text) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
[Void]$Command.ExecuteNonQuery() | |
$SQL.Close() | |
} | |
Function Global:MCS.Start | |
{ | |
If (!(SDP.HasExited)) { Write-Host 'Server already started.'; Return } | |
#-- Define process configuration | |
$psiServer = New-Object System.Diagnostics.ProcessStartInfo | |
$psiServer.UseShellExecute = $False | |
$psiServer.RedirectStandardOutput = $True | |
$psiServer.RedirectStandardError = $True | |
$psiServer.RedirectStandardInput = $True | |
$psiServer.FileName = GetConfiguration 'Java' | |
$psiServer.Arguments = (GetConfiguration 'JavaArguments') + ' -jar "' + (GetConfiguration 'MinecraftJAR') + '" ' + (GetConfiguration 'MinecraftArguments') | |
$psiServer.WorkingDirectory = $strScriptPath | |
SDP.Start $psiServer | |
} | |
Function Global:MCS.Stop | |
{ | |
If (SDP.HasExited) { Write-Host 'Server not started.'; Return } | |
If ($Global:blnMCSPrepared -ne $True) { Write-Host 'Server not prepared to take commands yet.'; Return } | |
MCS 'save-all' | |
MCS 'stop' | |
} | |
Function Global:MCS ([String]$strCommand) | |
{ | |
If (SDP.HasExited) { Write-Host 'Server not started.'; Return } | |
If ($Global:blnMCSPrepared -ne $True) { Write-Host 'Server not prepared to take commands yet.'; Return } | |
SDP.WriteLine $strCommand | |
#SDP.WriteLine "#$strCommand" | |
} | |
Function SDP.HasExited | |
{ | |
Return ( ([String]::IsNullOrEmpty($Global:prcProcess.HasExited)) -Or ($Global:prcProcess.HasExited) ) | |
} | |
Function SDP.Start ([System.Diagnostics.ProcessStartInfo]$psiStartInfo) | |
{ | |
$Global:prcProcess = New-Object System.Diagnostics.Process | |
$Global:prcProcess.EnableRaisingEvents = $True | |
$Global:prcProcess.StartInfo = $psiStartInfo | |
Get-EventSubscriber | Where-Object { $_.SourceIdentifier -eq 'Process.OutputData' } | Unregister-Event | |
Get-EventSubscriber | Where-Object { $_.SourceIdentifier -eq 'Process.ErrorData' } | Unregister-Event | |
Get-EventSubscriber | Where-Object { $_.SourceIdentifier -eq 'Process.Exited' } | Unregister-Event | |
Register-ObjectEvent $Global:prcProcess 'OutputDataReceived' -SourceIdentifier 'Process.OutputData' -Action { prcProcess_OutputDataReceived @Args } | Out-Null | |
Register-ObjectEvent $Global:prcProcess 'ErrorDataReceived' -SourceIdentifier 'Process.ErrorData' -Action { prcProcess_ErrorDataReceived @Args } | Out-Null | |
Register-ObjectEvent $Global:prcProcess 'Exited' -SourceIdentifier 'Process.Exited' -Action { prcProcess_Exited @Args } | Out-Null | |
$Global:prcProcess.Start() | Out-Null | |
$Global:prcProcess.BeginOutputReadLine() | |
$Global:prcProcess.BeginErrorReadLine() | |
} | |
Function SDP.WriteLine ([String]$strText) | |
{ | |
$Global:prcProcess.StandardInput.WriteLine($strText) | |
Trap | |
{ | |
Write-Host "Error in SDP.WriteLine" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
Continue | |
} | |
} | |
Function prcProcess_ErrorDataReceived ([System.Object]$sender, $e) | |
{ | |
If ([String]::IsNullOrEmpty($e.Data)) { Return } | |
Write-Host $e.Data | |
If ($e.Data.IndexOf(']') -gt 21) | |
{ | |
If (!$Global:Log) { $Global:Log = New-Object System.Collections.Queue } | |
$Global:Log.Enqueue($e.Data) | |
If ($Global:timProcessLog.Enabled -ne $True) | |
{ | |
If (!($Global:timProcessLog)) | |
{ | |
$Global:timProcessLog = New-Object System.Timers.Timer | |
$Global:timProcessLog.Interval = 100 | |
$Global:timProcessLog.AutoReset = $False | |
} | |
Register-ObjectEvent $Global:timProcessLog 'Elapsed' -SourceIdentifier 'ProcessLog' -Action { timProcessLog_Elapsed @Args } | Out-Null | |
$Global:timProcessLog.Start() | |
} | |
} | |
Trap | |
{ | |
Write-Host "Error Processing Standard Error Stream" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
#Write-Error 'Error Processing Standard Error Stream Test' -ErrorID STDERR1 -TargetObject $_ | |
Continue | |
} | |
} | |
Function prcProcess_OutputDataReceived ([System.Object]$sender, $e) | |
{ | |
If ([String]::IsNullOrEmpty($e.Data)) { Return } | |
Write-Host $e.Data | |
Trap | |
{ | |
Write-Host "Error Processing Standard Output Stream" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
Continue | |
} | |
} | |
Function prcProcess_Exited ([System.Object]$sender, $e) | |
{ | |
$Global:prcProcess.CancelOutputRead() | |
$Global:prcProcess.CancelErrorRead() | |
Unregister-Event 'Process.OutputData' | |
Unregister-Event 'Process.ErrorData' | |
Unregister-Event 'Process.Exited' | |
Remove-Job 'Process.OutputData' | |
Remove-Job 'Process.ErrorData' | |
Remove-Job 'Process.Exited' | |
Write-Host """$(($sender -As [System.Diagnostics.Process]).StartInfo.FileName)"" has exited." | |
If ($Global:blnRestart -eq $True) { MCS.Start; $Global:blnRestart = $False } | |
} | |
Function timProcessLog_Elapsed([System.Object]$sender, [System.Timers.ElapsedEventArgs]$e) | |
{ | |
If ($Global:Log.Count -eq 0) | |
{ | |
If ($Global:timProcessLog.Enabled -eq $True) { $Global:timProcessLog.Stop() } | |
Get-EventSubScriber | Where-Object { $_.SourceIdentifier -eq 'ProcessLog' } | Unregister-Event | |
Remove-Job -Name 'ProcessLog' | |
Return | |
} | |
ProcessLog | |
$Global:timProcessLog.Start() | |
Trap | |
{ | |
Write-Host "Error Processing Log" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
Continue | |
} | |
} | |
Function ProcessLog | |
{ | |
$strLine = $Global:Log.Dequeue() | |
$strLine = StripColorCodes($strLine) | |
$datOccured = $strLine.Substring(0, 19) | |
$strCategory = $strLine.Substring(21, $strLine.IndexOf(']') - 21) | |
$strEntry = $strLine.Substring($strLine.IndexOf(']') + 2) | |
ParseEntry $datOccured $strCategory $strEntry | |
Trap | |
{ | |
Write-Host "Error in ProcessLog" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
Continue | |
} | |
} | |
Function StripColorCodes ([String]$strLine) | |
{ | |
[RegEx]::Replace($strLine, 'º.', '') | |
} | |
Function ParseEntry ([DateTime]$datOccured, [String]$Category, [String]$strEntry) | |
{ | |
If ($Category -ne 'INFO') { Return } | |
#--Game Chat | |
#Example: <EdGruberman> Hello World1! | |
If ($strEntry.StartsWith('<')) | |
{ | |
$Player = $strEntry.Split(('<', '>'))[1] | |
$Text = $strEntry.Substring($strEntry.IndexOf('>') + 2) | |
If ($Global:Players.$Player.AFK -eq $True) | |
{ | |
If (@($Mail.$Player.Message | Where-Object { $_.Deleted -eq $False -And $_.Read -eq $False }).Count -gt 0) { CheckMail $Player $True } | |
} | |
$Global:Players.$Player.AFK = $False | |
If ($Text.StartsWith('=')) { ProcessCommand $datOccured $Player $Text.Substring(1) } | |
Else | |
{ | |
If (($Text.Replace("* $Player ", '').Split(" ").Length - 1) -le 2) { Return } | |
SetPlayer $Player (New-Object System.Data.SqlClient.SqlParameter('RandomComment', $Text)) | |
} | |
} | |
#--Action Chat | |
#Example: * EdGruberman hides | |
ElseIf ($strEntry.StartsWith('*')) | |
{ | |
$Player = $strEntry.Split(' ')[1] | |
If ($Global:Players.$Player.AFK -eq $True) | |
{ | |
If (@($Mail.$Player.Message | Where-Object { $_.Deleted -eq $False -And $_.Read -eq $False }).Count -gt 0) { CheckMail $Player $True } | |
} | |
$Global:Players.$Player.AFK = $False | |
If (($strEntry.Replace("* $Player ", '').Split(" ").Length - 1) -le 2) { Return } | |
SetPlayer $Player (New-Object System.Data.SqlClient.SqlParameter('RandomComment', $strEntry)) | |
} | |
#--Private Command | |
#Example: EdGruberman issued server command: command parameter1 parameter2 | |
#Example: the_Huntress tried command: command something | |
ElseIf ($strEntry.Split(':')[0].EndsWith('command')) | |
{ | |
$Player = $strEntry.Split(' ')[0] | |
$Command = $strEntry.Split(':')[1].Split(' ', 2)[1] | |
ProcessCommand $datOccured $Player $Command $True | |
} | |
#--Private Command (hMod format) | |
#Example: Command used by EdGruberman /command parameter1 parameter2 | |
ElseIf ($strEntry.StartsWith('Command used by ')) | |
{ | |
$Player = $strEntry.Split(' ')[3] | |
$Command = $strEntry.Split('/')[1] | |
ProcessCommand $datOccured $Player $Command $True | |
} | |
#Example: Starting minecraft server version 0.2.2 | |
ElseIf ($strEntry.StartsWith('Starting minecraft server version ')) | |
{ | |
$Global:Version = $strEntry.Split(' ')[-1] | |
} | |
#--Minecraft server prepared | |
#Example: Done! For help, type "help" or "?" | |
ElseIf ($strEntry -like 'Done (*ns)! For help, type "help" or "?"') | |
{ | |
Initialize | |
} | |
#--Minecraft server stopped | |
#Example: Stopping server | |
ElseIf ($strEntry -eq 'Stopping server') | |
{ | |
$Global:blnMCSPrepared = $False | |
$strNow = Get-Date -Date (Get-Date).ToUniversalTime() -Format 'yyyyMMddHHmmss\Z' | |
Copy-Item "$strScriptPath\server.log" "$(GetConfiguration('Logs'))\$strNow.log" | |
Deinitialize | |
} | |
#Example CONSOLE: Forcing save.. | |
ElseIf ($strEntry.EndsWith(': Forcing save..')) | |
{ | |
$Global:blnSaveInProgress = $True | |
} | |
#Example CONSOLE: Save complete. | |
ElseIf ($strEntry.EndsWith(': Save complete.')) | |
{ | |
SetStatus 'LastSave' | |
$Global:blnSaveInProgress = $False | |
MCS 'say Save completed.' | |
} | |
#Example CONSOLE: Disabling level saving.. | |
ElseIf ($strEntry.EndsWith(': Disabling level saving..')) | |
{ | |
If ($Global:TaskInProgress -eq $True) { ProcessTask '' $True } | |
} | |
#--Player Connection | |
#Example: EdGruberman [/127.0.0.1:54160] logged in with entity id 5 | |
ElseIf ($strEntry.Contains(' logged in with entity id ')) | |
{ | |
$Name = $strEntry.Split(' ')[0] | |
$Address = $strEntry.Split(('[', ']'))[1] | |
If ($Global:Players.ContainsKey($Name)) { $Global:Players.Remove($Name) } | |
$Global:Players.Add($Name, @{ Address = $Address; AFK = $False }) | |
SetPlayer $Name $Null $True | |
$Player = GetPlayer($Name) | |
If ($Player['FirstConnection'] -eq [DBNull]::Value) { SetPlayer $Name (New-Object System.Data.SqlClient.SqlParameter('FirstConnection', ($datOccured).ToUniversalTime())) } | |
If ($Player['Connections'] -eq [DBNull]::Value) { $Connections = 1 } Else { $Connections = $Player['Connections'] + 1 } | |
SetPlayer $Name (New-Object System.Data.SqlClient.SqlParameter('Connections', [String]$Connections)) | |
If (!(MemberOf 'Players' $Name)) | |
{ | |
SetPlayer $Name (New-Object System.Data.SqlClient.SqlParameter('LastConnection', ($datOccured).ToUniversalTime())) | |
MCS "say Whitelist Violation; $Name is not in Players group." | |
MCS "kick $Name" | |
Return | |
} | |
$MotD = GetMotD | |
If ($MotD -ne $Null) | |
{ | |
If ($Player['LastConnection'] -eq [DBNull]::Value) { Respond (FormatMotD) $Name $True } | |
Else { | |
$LastTold = New-TimeSpan $Player['LastConnection'] ($datOccured).ToUniversalTime() | |
If ( ($LastTold.TotalMinutes -gt 60) -or ($MoTD['Updated'] -gt $Player['LastConnection']) ) { Respond (FormatMotD) $Name $True } | |
} | |
} | |
SetPlayer $Name (New-Object System.Data.SqlClient.SqlParameter('LastConnection', $datOccured.ToUniversalTime())) | |
If (@($Mail.$Name.Message | Where-Object { $_.Deleted -eq $False -And $_.Read -eq $False }).Count -gt 0) { CheckMail $Name $True } | |
} | |
#--Player Disconnection | |
#Example: EdGruberman lost connection: Quitting | |
ElseIf ($strEntry.Split(':')[0].EndsWith(' lost connection')) | |
{ | |
$Name = $strEntry.Split(' ')[0] | |
$Global:Players.Remove($Name) | |
If (!($strEntry.EndsWith('disconnect.quitting'))) { MCS "say $Name lost connection;$($strEntry.Split(':')[-1])" } | |
SetPlayer $Name (New-Object System.Data.SqlClient.SqlParameter('LastDisconnection', $datOccured.ToUniversalTime())) | |
} | |
#--Player Kicked by Console (No disconnection log entry after) | |
#Example: CONSOLE: Kicking EdGruberman | |
ElseIf ($strEntry.StartsWith('CONSOLE: Kicking ')) | |
{ | |
$Name = $strEntry.Split(' ')[2] | |
$Global:Players.Remove($Name) | |
SetPlayer $Name (New-Object System.Data.SqlClient.SqlParameter('LastDisconnection', $datOccured.ToUniversalTime())) | |
} | |
#--Dropped Connection | |
#Example: Disconnecting /24.17.220.9:1924: Took too long to log in | |
ElseIf ($strEntry.StartsWith('Disconnecting ')) | |
{ | |
$Address = $strEntry.Split((' ', ': '), [System.StringSplitOptions]"None")[1] | |
ForEach ($i In $Global:Players.Keys) { If ($Global:Players.$i.Address -eq $Address) { $Name = $i } } | |
If ( $Name ) | |
{ | |
$Global:Players.Remove($Name) | |
SetPlayer $Name (New-Object System.Data.SqlClient.SqlParameter('LastDisconnection', $datOccured.ToUniversalTime())) | |
} | |
} | |
} | |
Function ProcessCommand ([DateTime]$datOccured, [String]$strRequestor, [String]$strText, [Boolean]$Private = $False) | |
{ | |
$Command = $strText.Split(' ')[0].ToLower() | |
$strParameters = $strText.Split(' ', 2)[1] | |
If ($Command -eq 'players') { $Command = 'who' } | |
#If ($Command -eq 'list') { $Command = 'who' } | |
Switch ($Command) | |
{ | |
#--Everyone | |
'who' | |
{ | |
If (!($strParameters)) | |
{ | |
$strOutput = '' | |
ForEach ($i In ($Global:Players.Keys | Sort-Object)) | |
{ | |
If (![String]::IsNullOrEmpty($strOutput)) { $strOutput += ', ' } | |
$strOutput += $i | |
If ($Global:Players.$i.AFK -eq $True) { $strOutput += '(AFK)' } | |
} | |
If ($Global:Players.Count -ne 1) { $strPlural = 's' } | |
Respond "Who is connected = $strOutput `($($Global:Players.Count) player$strPlural)" $strRequestor $Private | |
Return | |
} | |
#Who <Player>[ groups] | |
#If (!(MemberOf 'Moderators' $strRequestor)) { Return } | |
$Name = $strParameters.Split(' ')[0] | |
$Detail = $strParameters.Split(' ')[1] | |
$Player = GetPlayer($Name) | |
If ($Detail -match '^g[r]?[o]?[u]?[p]?[s]?$') | |
{ | |
Respond "-- $($Player["Name"]) is a member of:" $strRequestor $Private | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Groups = (New-Object System.Data.SqlClient.SqlCommand("SELECT * FROM Members WHERE Players_Name = '$Name' ORDER BY Groups_Name", $SQL)).ExecuteReader() | |
While ( $Groups.Read() ) | |
{ | |
$strAdded = (Duration ($Groups['Added']).ToLocalTime()).Split(' ')[0] | |
Respond "$($Groups['Groups_Name']) group `($strAdded ago by $($Groups['AddedBy']): `"$($Groups['Comments'])`"`)" $strRequestor $Private | |
} | |
$Groups.Close() | |
$SQL.Close() | |
} | |
Else | |
{ | |
If (($Player -ne $Null) -and ($Player['LastConnection'] -ne [DBNull]::Value)) { $strLastConnected = "last connected $((Duration $Player['LastConnection'].ToLocalTime()).Split(' ')[0]) ago" } | |
Else { $strLastConnected = 'has not connected yet' } | |
If ($Player -eq $Null) { $PlayerName = $Name } Else { $PlayerName = $Player["Name"] } | |
Respond "-- $PlayerName $strLastConnected" $strRequestor $Private | |
If (($Player -ne $Null) -and ($Player['FirstConnection'] -ne [DBNull]::Value)) { Respond "$($Player['Connections']) Connections `(First $((Duration $Player['FirstConnection'].ToLocalTime()).Split(' ')[0]) ago`)" $strRequestor $Private } | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Groups = (New-Object System.Data.SqlClient.SqlCommand("SELECT Groups_Name FROM Members WHERE Players_Name = '$Name' ORDER BY Groups_Name", $SQL)).ExecuteReader() | |
While ( $Groups.Read() ) | |
{ | |
If ($MemberOf -ne $Null) { $MemberOf += ', ' } | |
$MemberOf += $Groups['Groups_Name'] | |
} | |
$Groups.Close() | |
$SQL.Close() | |
If ($MemberOf) { Respond "Member of $MemberOf" $strRequestor $Private } | |
If (($Player -ne $Null) -and ($Player['RandomComment'] -ne [DBNull]::Value)) { Respond "Random Comment: `"$($Player['RandomComment'])`"" $strRequestor $Private } | |
If ($Player -ne $Null) { Respond "`(For group detail: /Who $($Player["Name"]) Groups`)" $strRequestor $Private } | |
} | |
} | |
'afk' | |
{ | |
$Global:Players.$strRequestor.AFK = $True | |
ProcessCommand $datOccured $strRequestor 'who' $Private | |
} | |
'status' | |
{ | |
$strLastStarted = (Duration $Global:datLastStarted).Split(' ')[0,1] | |
If ((GetStatus('LastSave')) -ne [DBNull]::Value) { $strLastSave = "finished $((Duration (GetStatus('LastSave')).ToLocalTime()).Split(' ')[0]) ago" } | |
Else { $strLastSave = 'is unknown' } | |
$strNextSave = ([String]::Join(' ', (Duration ($Global:TimerStarts.Save).AddMilliseconds($timAutoSave.Interval)).Split(' ')[0..1])).Replace('-', '') | |
If ((GetStatus('LastBackup')) -ne [DBNull]::Value) { $strLastBackup = "finished $((Duration (GetStatus('LastBackup')).ToLocalTime()).Split(' ')[0]) ago" } | |
Else { $strLastBackup = 'is unknown' } | |
$strNextBackup = ([String]::Join(' ', (Duration ($Global:TimerStarts.Backup).AddMilliseconds($timAutoBackup.Interval)).Split(' ')[0..1])).Replace('-', '') | |
If ((GetConfiguration('AutoImages')) -gt 0) { | |
If ((GetStatus('LastImages')) -ne [DBNull]::Value) { $strLastImages = "finished $((Duration (GetStatus('LastImages')).ToLocalTime()).Split(' ')[0]) ago" } | |
Else { $strLastImages = 'is unknown' } | |
$strNextImages = ([String]::Join(' ', (Duration ($Global:TimerStarts.Images).AddMilliseconds($timAutoImages.Interval)).Split(' ')[0..1])).Replace('-', '') | |
} | |
Respond "Version $Global:Version Started $strLastStarted ago" $strRequestor $Private | |
If ((GetConfiguration('AutoSave')) -gt 0) { Respond "Forced Save $strLastSave `(Next in $strNextSave`)" $strRequestor $Private } | |
If ((GetConfiguration('AutoBackup')) -gt 0) { Respond "Backup $strLastBackup `(Next in $strNextBackup`)" $strRequestor $Private } | |
If ((GetConfiguration('AutoImages')) -gt 0) { Respond "Image Update $strLastImages `(Next in $strNextImages`)" $strRequestor $Private } | |
} | |
'ping' | |
{ | |
$Ping = New-Object System.Net.NetworkInformation.Ping | |
$Reply = $Ping.Send($Global:Players.$strRequestor.Address.Split(('/', ':'))[1]) | |
If ($Reply.Status -ne 'TimedOut') { $Result = "is $($Reply.RoundTripTime)ms `($($Reply.Status)`)" } Else { $Result = 'timed out (Check your firewall)' } | |
Respond "Ping to $strRequestor $Result" $strRequestor $Private | |
} | |
#Mail[ <id>][ d[elete]] | |
'mail' | |
{ | |
#No parameters - Read first unread mail | |
If (!($strParameters)) | |
{ | |
If (@($Mail.$strRequestor.Message | Where-Object { $_.Deleted -eq $False -And $_.Read -eq $False }).Count -gt 0) | |
{ ReadMail $strRequestor -1 $Private } | |
#If (@($Mail.$strRequestor.Message | Where-Object { $_.Deleted -eq $False -And $_.Read -eq $False }).Count -gt 0) | |
CheckMail $strRequestor $Private | |
Return | |
} | |
#Parameter supplied - Read/Delete associated mail | |
$ID = $strParameters.Split(' ')[0] | |
If ($strParameters.Split(' ')[1] -match '^d[e]?[l]?[e]?[t]?[e]?$') | |
{ | |
DeleteMail $strRequestor $ID $Private | |
Return | |
} | |
ReadMail $strRequestor $ID $Private | |
} | |
#SendMail <To> <Message> | |
'sendmail' | |
{ | |
If (!($strParameters)) { $strParameters = '' } | |
If ($strParameters.Split(' ', 2).Count -ne 2) { Respond 'Error: sendmail <To> <Msg> (e.g. =sendmail EdGruberman I have free obsidian for you!)' $strRequestor $Private; Return } | |
SendMail $strRequestor $strParameters.Split(' ')[0] $strParameters.Split(' ', 2)[1] $Private | |
} | |
#Inbox[ <page>] | |
'inbox' | |
{ | |
If ($strParameters) { $Page = $strParameters.Split(' ')[0] } | |
If (!($Page) -Or !(IsNumeric($Page))) { $Page = 1 } | |
ReadMail $strRequestor 0 $Private $Page | |
} | |
#Time[ <Bias>] | |
'time' | |
{ | |
If ($strParameters) | |
{ | |
$strParameters = $strParameters.Split(' ')[0] | |
If (!(IsNumeric $strParameters.Split(':')[0])) { Respond "Invalid time bias. (e.g. =time -8)" $strRequestor $Private } | |
If ($strParameters.Split(':')[1]) | |
{ If (!(IsNumeric $strParameters.Split(':')[1])) { Respond "Invalid time bias. (e.g. =time -8)" $strRequestor $Private } } | |
SetPlayer $strRequestor (New-Object System.Data.SqlClient.SqlParameter('ActiveTimeBias', $strParameters)) | |
} | |
$Now = ToPlayerTime (Get-Date).ToUniversalTime() $strRequestor | |
Respond "Current Time: $(Get-Date -Date $($Now.PlayerTime) -Format 'h:mm:ss tt ddd d') `($($Now.Timezone)`)" $strRequestor $Private | |
} | |
'motd' | |
{ | |
If (!$strParameters) { Respond "$(FormatMotD)" $strRequestor $Private; Return } | |
If (!(MemberOf 'Moderators' $strRequestor)) { Return } | |
SetMotD ($strParameters) $datOccured.ToUniversalTime() $strRequestor | |
Respond "MotD set successfully." $strRequestor $Private | |
} | |
#Kit[ <ID|Name>[ Use]] | |
'kit' | |
{ | |
Kit $strParameters $strRequestor $Private | |
} | |
#Profile[ <key>[ <value>]] | |
'profile' | |
{ | |
If ($strParameters) | |
{ | |
$Key = $strParameters.Split(' ')[0] | |
If ($Key -ne 'Email') { Respond 'Invalid profile item. (e.g. =profile Email [email protected])' $strRequestor $Private; Return } | |
$Value = $strParameters.Split(' ', 2)[1] | |
If ($Value) { SetPlayer $strRequestor (New-Object System.Data.SqlClient.SqlParameter($Key, $Value)) } | |
$Player = GetPlayer($strRequestor) | |
Respond "$Key for $strRequestor is `"$($Player[$Key])`"" $strRequestor $Private | |
} | |
Else | |
{ | |
$Key = 'Email' | |
$Player = GetPlayer($strRequestor) | |
Respond "-- Profile for $strRequestor" $strRequestor $Private | |
Respond "$($Key): $($Player[$Key])" $strRequestor $Private | |
Respond "`(To change: /Profile <Item> <Value>`)" $strRequestor $Private | |
} | |
} | |
#--Moderators | |
#White <MemberName> <Comments...> | |
'white' | |
{ | |
If (!(MemberOf 'Moderators' $strRequestor)) { Return } | |
If (!($strParameters)) { Respond 'Usage: =White <Player> <Comments...>' $strRequestor $Private } | |
$Name = $strParameters.Split(' ')[0] | |
$Comments = $strParameters.Split(' ', 2)[1] | |
If (!$Comments) { Respond 'ERROR: Comments required. (e.g. =White EdGruberman He has no friends.)' $strRequestor $Private } | |
Else { Respond "$(ModifyMembers 'Add' $Name 'Players' $Comments $strRequestor)" $strRequestor $Private } | |
} | |
'size' | |
{ | |
If (!(MemberOf 'Moderators' $strRequestor)) { Return } | |
$colItems = (Get-ChildItem (GetConfiguration('World')) -Recurse | Measure-Object -Property Length -Sum) | |
Respond ('say Current World Size = ' + "{0:N2}" -F ($colItems.Sum / 1MB) + " MB") $strRequestor $Private | |
} | |
'memory' | |
{ | |
If (!(MemberOf 'Moderators' $strRequestor)) { Return } | |
$Global:prcProcess.Refresh() | |
$strMemory = "{0:N0}MB" -F ($Global:prcProcess.WorkingSet64 / 1MB) | |
Respond "Working Set Memory = $strMemory" $strRequestor $Private | |
} | |
'image' | |
{ | |
If (!(MemberOf 'Moderators' $strRequestor)) { Return } | |
If ($strParameters) { $strParameters = $strParameters.Split(' ')[0] } | |
Else { $strParameters = '' } | |
If (!($Global:Images.ContainsKey($strParameters))) | |
{ | |
Respond "Valid images: $($Global:Images.Keys | Sort-Object)" $strRequestor $Private | |
Return | |
} | |
ProcessTask @{ Command = 'Update Images'; Parameters = $strParameters; Requestor = $strRequestor; Private = $Private } | |
} | |
#--Administrators | |
'backup' | |
{ | |
If (!(MemberOf 'Administrators' $strRequestor)) { Return } | |
ProcessTask @{ Command = 'Backup'; Requestor = $strRequestor; Private = $Private } | |
} | |
'save' | |
{ | |
If (!(MemberOf 'Administrators' $strRequestor)) { Return } | |
ProcessTask @{ Command = 'Save'; Requestor = $strRequestor; Private = $Private } | |
} | |
'images' | |
{ | |
If (!(MemberOf 'Administrators' $strRequestor)) { Return } | |
ProcessTask @{ Command = 'Update Images'; Requestor = $strRequestor; Private = $Private } | |
} | |
#Group <Action> <PlayerName> <GroupName> <Comments...> | |
'group' | |
{ | |
If (!(MemberOf 'Administrators' $strRequestor)) { Return } | |
$Action = $strParameters.Split(' ')[0] | |
$PlayerName = $strParameters.Split(' ')[1] | |
$GroupName = $strParameters.Split(' ')[2] | |
$Comments = $strParameters.Split(' ', 4)[3] | |
Respond "$(ModifyMembers $Action $PlayerName $GroupName $Comments $strRequestor)" $strRequestor $Private | |
} | |
'restart' | |
{ | |
If (!(MemberOf 'Administrators' $strRequestor)) { Return } | |
$Global:blnRestart = $True | |
MCS.Stop | |
} | |
} | |
} | |
Function Respond ([String]$Text, [String]$Name, [Boolean]$Private = $False) | |
{ | |
If ($Private) { MCS "tell $Name $Text" } | |
Else { MCS "say $Text" } | |
} | |
Function Kit ([String]$Parameters, [String]$Requestor, [Boolean]$Private = $True) | |
{ | |
#--Available Kits for Requestor | |
If (!$Parameters) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("SELECT * FROM KitsAvailable WHERE Players_Name = '$strRequestor' ORDER BY Kits_ID", $SQL) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$KA = $Command.ExecuteReader() | |
While ( $KA.Read() ) | |
{ | |
$Text = "$($KA['Kits_Name'])" | |
If ($LastKits_Name -eq $KA['Kits_Name']) { $Text = $Text + " `(ID $($KA['ID'])`)" } | |
$Text = $Text + " | " | |
If ($KA['Factor'] -ne [DBNull]::Value) { $Text = $Text + "x$($KA['Factor']), " } | |
If ($KA['Total'] -ne [DBNull]::Value) | |
{ | |
$UsesLeft = $KA['Total'] - $KA['Used'] | |
$Text = $Text + "$UsesLeft left" | |
} | |
Else { $Text = $Text + 'Unlimited' } | |
If ($KA['Reload'] -ne [DBNull]::Value) | |
{ | |
If ($KA['LastUsed'] -ne [DBNull]::Value) | |
{ | |
If ( $KA['LastUsed'].AddSeconds($KA['Reload']) -gt (Get-Date).ToUniversalTime() ) | |
{ | |
$Reloaded = Duration (New-TimeSpan (Get-Date).ToUniversalTime() $KA['LastUsed'].AddSeconds($KA['Reload'])) | |
$Text = $Text + ', reloads in ' + $Reloaded.Split(' ')[0,1] | |
} | |
} | |
Else { $Text = $Text + ', reloaded every ' + (Duration (New-TimeSpan -Seconds $KA['Reload'])) } | |
} | |
Respond $Text $Requestor $Private | |
$LastKits_Name = $KA['Kits_Name'] | |
} | |
$KA.Close() | |
$SQL.Close() | |
If ($LastKits_Name -eq $Null) { Respond 'No kits currently available' $Requestor $Private } | |
Else { Respond '(For details: /Kit <KitName>)' $Requestor $Private } | |
Return | |
} | |
$Kit = $Parameters.Split(' ')[0] | |
If ($Parameters.Split(' ')[1] -eq 'use') { $Use = $True } Else { $Use = $False } | |
#--Retrieve Assignment Details | |
$Command = New-Object System.Data.SqlClient.SqlCommand | |
$Command.Connection = $SQL | |
If (IsNumeric($Kit)) | |
{ $Command.CommandText = "SELECT * FROM KitsAvailable WHERE Players_Name = '$strRequestor' AND ID = $Kit ORDER BY ID" } | |
Else | |
{ | |
$Command.CommandText = "SELECT * FROM KitsAvailable WHERE Players_Name = '$strRequestor' AND Kits_Name = @Kits_Name ORDER BY Kits_ID" | |
$Kits_Name = New-Object System.Data.SqlClient.SqlParameter('@Kits_Name', [System.Data.DbType]::String) | |
$Kits_Name.Direction = [System.Data.ParameterDirection]::Input | |
$Kits_Name.Value = $Kit | |
[Void]$Command.Parameters.Add($Kits_Name) | |
} | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$KA = $Command.ExecuteReader() | |
If (!$KA) { Respond 'Database Error' $strRequestor $Private; Return } | |
If (!$KA.Read()) { Respond 'Invalid Kit' $strRequestor $Private; Return } | |
If ( ($KA['Reload'] -ne [DBNull]::Value) -and ($KA['LastUsed'] -ne [DBNull]::Value) ) | |
{ $Reloaded = New-TimeSpan (Get-Date).ToUniversalTime() $KA['LastUsed'].AddSeconds($KA['Reload']) } | |
If ($KA['Factor'] -ne [DBNull]::Value) { $Factor = $KA['Factor'] } Else { $Factor = 1 } | |
#--Determine Kit Contents | |
$Adapter = New-Object System.Data.SqlClient.SqlDataAdapter("SELECT * FROM KitContents WHERE Kits_ID = $($KA['Kits_ID']) ORDER BY Items_ID", $SQL) | |
$KC = New-Object System.Data.DataTable | |
$Adapter.Fill($KC) | |
$Contents = '' | |
ForEach ($Row In $KC.Rows) | |
{ | |
If ($Contents -ne '') { $Contents = $Contents + ', ' } | |
$Contents = $Contents + $Row['Quantity'] * $Factor + ' ' + $Row['Items_Name'] | |
} | |
If (!$Use) | |
{ | |
#--Show Assignment Details | |
#Donator (ID 1) x10 | |
$Text = "-- $($KA['Kits_Name']) `(ID $($KA['ID'])`)" | |
If ($Factor -ne 1 ) { $Text = $Text + " x$Factor" } | |
Respond $Text $Requestor $Private | |
#Uses = 1 left (2 total - 1 used) | |
$UsesLeft = $KA['Total'] - $KA['Used'] | |
If ($KA['Total'] -ne [DBNull]::Value) { $Text = 'Uses = ' + $UsesLeft + ' left (' + $KA['Total'] + ' total - ' + $KA['Used'] + ' used)' } | |
Else { $Text = 'Uses = Unlimited' } | |
Respond $Text $Requestor $Private | |
#Immediate Reload | Reloaded every 1h 0s (Reloads in 37m 4s) | |
If ($KA['Reload'] -eq [DBNull]::Value) { $Text = 'Immediate Reload' } | |
Else | |
{ | |
$Text = 'Reloaded every ' + (Duration (New-TimeSpan -Seconds $KA['Reload'])) | |
If ( $Reloaded.TotalSeconds -gt 0 ) { $Text = $Text + ' (Reloads in ' + (Duration $Reloaded).Split(' ')[0,1] + ')' } | |
} | |
Respond $Text $Requestor $Private | |
$Contents = 'Contains ' + $Contents | |
} | |
Else | |
{ | |
If ($Reloaded.TotalSeconds -gt 0) { Respond "Kit not reloaded `(Reloads in $((Duration $Reloaded).Split(' ')[0,1])`)" $Requestor $Private; Return } | |
#--Record usage | |
$Command = New-Object System.Data.SqlClient.SqlCommand("INSERT INTO KitUses (Players_ID, KitAssignments_ID, Used) SELECT P.ID, $($KA['ID']), GETUTCDATE() FROM Players AS P WHERE P.Name = '$Requestor'", $SQL) | |
$Affected = $Command.ExecuteNonQuery() | |
If ($Affected -ne 1) { Respond "Database Error" $Requestor $Private; Return } | |
#--Deliver Kit to Requestor | |
ForEach ($Row In $KC.Rows) | |
{ | |
$Total = $Row['Quantity'] * $Factor | |
For ($i = 1; $i -le [Math]::Floor($Total / 64); $i++) { MCS "give $Requestor $($Row['Items_ID']) 64" } | |
If (($Total % 64) -gt 0) { MCS "give $Requestor $($Row['Items_ID']) $($Total % 64)" } | |
} | |
$Contents = 'Delivered ' + $Contents | |
} | |
#Contains 10 Sponge, 20 Cobblestone | |
Respond $Contents $Requestor $Private | |
#Special recognition for your support | |
Respond $KA['Kits_Comments'] $Requestor $Private | |
#EdGruberman - $10 donation on 1/4/2011. Thank you! | |
#Players group - Everyone is so cool you deserve this. | |
If ($KA['Groups_Name'] -ne [DBNull]::Value) { $Text = $KA['Groups_Name'] + ' group' } | |
Else { $Text = $KA['Players_Name'] } | |
$Text = $Text + ' - ' + $KA['KitAssignments_Comments'] | |
Respond $Text $Requestor $Private | |
If (!$Use) { Respond '(To use: /Kit <KitName> Use)' $Requestor $Private } | |
$KA.Close() | |
$SQL.Close() | |
} | |
Function CheckMail([String]$Name, [Boolean]$Private = $False) | |
{ | |
$NewMailCount = @($Mail.$Name.Message | Where-Object { $_.Deleted -eq $False -And $_.Read -eq $False }).Count | |
If ($NewMailCount -eq 0) { $Help = ' (To list: /Inbox)' } Else { $Help = ' (To read: /Mail)' } | |
Respond "$Name has $NewMailCount unread mail.$Help" $Name $Private | |
} | |
Function ReadMail ([String]$Player, [Int]$Index = 0, [Boolean]$Private = $False, [Int]$Page = 1) | |
{ | |
$Messages = @($Mail.$Player.Message | Where-Object { $_.Deleted -eq $False } | Sort-Object 'Sent' -Descending) | |
If ($Messages.Count -eq 0) { Respond "$Player has 0 mail" $Player $Private } | |
If ($Index -ne 0) | |
{ | |
If ($Index -eq -1) | |
{ | |
$Messages = @($Mail.$Player.Message | Where-Object { $_.Deleted -eq $False -And $_.Read -eq $False } | Sort-Object 'Sent' -Descending) | |
$Index = 1 | |
} | |
$Index = $Index - 1 | |
If ($Index -gt $Messages.Count - 1) { Respond "Invalid mail request - $Player has $($Messages.Count) mail" $Player $Private; Return } | |
$Sent = ToPlayerTime $Messages[$Index].Sent $Player | |
If ($Messages[$Index].Read -eq $False) | |
{ | |
$New = '*NEW* ' | |
$Messages[$Index].Read = 'True' | |
$xmlMail.Save($XMLMAILFILE) | |
$Global:Mail = $Global:xmlMail.Mail | |
} | |
$Sent = (Get-Date $Sent.PlayerTime -Format 'h:mmtt ddd MMM dd') + " $($Sent.Timezone)" | |
Respond "[[ $($New)From: $($Messages[$Index].From) on $Sent" $Player $Private | |
Respond "$($Messages[$Index].Body) ]]" $Player $Private | |
Respond "(To respond: /SendMail $($Messages[$Index].From) <Message>)" $Player $Private | |
} | |
Else | |
{ | |
If ($Page -lt 1 -Or $Page -gt ([int]($Messages.Count / 4 + .4))) | |
{ Respond "Invalid inbox request - $Player has $([int]($Messages.Count / 4 + .4)) pages of mail" $Player $Private; Return } | |
For ($i = (($Page - 1) * 4); ($i -lt $Messages.Count) -And ($i -lt ($Page * 4)); $i++) | |
{ | |
If ($Messages[$i].Read -eq $False) { $New = '*NEW* ' } Else { $New = '' } | |
Respond "Mail #$($i + 1) - $($New)From $($Messages[$i].From) $((Duration $Messages[$i].Sent).Split(' ')[0]) ago" $Player $Private | |
} | |
Respond "Page $Page of $([int]($Messages.Count / 4 + .4)) `(For more: /Inbox <Page>`)" $Player $Private | |
} | |
} | |
Function DeleteMail ([String]$Player, [Int]$Index, [Boolean]$Private = $False) | |
{ | |
$Messages = @($Mail.$Player.Message | Where-Object { $_.Deleted -eq $False } | Sort-Object 'Sent' -Descending) | |
If (!(IsNumeric($Index)) -Or ($Index -lt 1) -Or ($Index -gt $Messages.Count)) | |
{ Respond "Invalid delete request - $Player only has $($Messages.Count) mail" $Player $Private; Return } | |
$Index = $Index - 1 | |
$From = $Messages[$Index].From | |
$Sent = ToPlayerTime $Messages[$Index].Sent $Player | |
#$Messages[$Index].SelectSingleNode('..').RemoveChild($Messages[$Index]) | Out-Null | |
$Messages[$Index].Deleted = 'True' | |
$xmlMail.Save($XMLMAILFILE) | |
$Global:Mail = $Global:xmlMail.Mail | |
Respond "Deleted mail $($Index + 1) from $From on $($Sent.PlayerTime) $($Sent.Timezone)" $Player $Private | |
} | |
Function SendMail ([String]$From, [String]$To, [String]$Body, [Boolean]$Private = $False) | |
{ | |
$Inbox = $Mail.$To | |
If (!($Inbox)) | |
{ | |
$Inbox = $xmlMail.CreateElement($To) | |
$xmlMail.SelectSingleNode('Mail').AppendChild($Inbox) | |
$xmlMail.Save($XMLMAILFILE) | |
$Global:Mail = $Global:xmlMail.Mail | |
} | |
$Message = $xmlMail.CreateElement('Message') | |
$Message.SetAttribute('From', $From) | |
$Message.SetAttribute('Sent', (Get-Date (Get-Date).ToUniversalTime() -Format u)) | |
$Message.SetAttribute('Read', 'False') | |
$Message.SetAttribute('Deleted', 'False') | |
$BodyNode = $xmlMail.CreateElement('Body') | |
$BodyNode.InnerText = $Body | |
$Message.AppendChild($BodyNode) | |
$Inbox.AppendChild($Message) | |
$xmlMail.Save($XMLMAILFILE) | |
$Global:Mail = $Global:xmlMail.Mail | |
$Player = GetPlayer($To) | |
If ($Player['LastConnection'] -eq $Null) { $Connected = "`(WARNING: $To has never connected before`)" } | |
If ($Players.$To) { CheckMail $To $True } | |
Respond "Mail sent to $To $Connected" $From $Private | |
} | |
Function ToPlayerTime ([Datetime]$Original, [String]$Name) | |
{ | |
$Player = GetPlayer($Name) | |
If ($Player['ActiveTimeBias'] -ne [DBNull]::Value) | |
{ | |
$dblBiasHours =$Player['ActiveTimeBias'].Split(':')[0] | |
$dblBiasMinutes = $Player['ActiveTimeBias'].Split(':')[1] | |
$strBias = "$dblBiasHours" | |
If ($dblBiasMinutes) { $strBias = $strBias + "`:$dblBiasMinutes" } | |
If (!($strBias.StartsWith('-'))) { $strBias = '+' + $strBias } | |
ElseIf ($dblBiasMinutes) { $dblBiasMinutes = '-' + $dblBiasMinutes } | |
} | |
[Hashtable]$Return = @{} | |
$Return.UTC = $Original.ToUniversalTime() | |
$Return.UTC_ISO8601 = Get-Date $Original.ToUniversalTime() -Format u | |
$Return.PlayerTime = $Original.ToUniversalTime() | |
If ($dblBiasHours) { $Return.PlayerTime = ($Return.PlayerTime).AddHours($dblBiasHours) } | |
If ($dblBiasMinutes) { $Return.PlayerTime = ($Return.PlayerTime).AddMinutes($dblBiasMinutes) } | |
$Return.Timezone = "GMT$strBias" | |
Return $Return | |
} | |
Function MemberOf ([String]$Group, [String]$Player) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("IsMember", $SQL) | |
$Command.CommandType = [System.Data.CommandType]::StoredProcedure | |
$GroupName = New-Object System.Data.SqlClient.SqlParameter('@GroupName', [System.Data.DbType]::String) | |
$GroupName.Direction = [System.Data.ParameterDirection]::Input | |
$GroupName.Value = $Group | |
[Void]$Command.Parameters.Add($GroupName) | |
$PlayerName = New-Object System.Data.SqlClient.SqlParameter('@PlayerName', [System.Data.DbType]::String) | |
$PlayerName.Direction = [System.Data.ParameterDirection]::Input | |
$PlayerName.Value = $Player | |
[Void]$Command.Parameters.Add($PlayerName) | |
$RC = New-Object System.Data.SqlClient.SqlParameter('@RC', [System.Data.DbType]::Int) | |
$RC.Direction = [System.Data.ParameterDirection]::ReturnValue | |
[Void]$Command.Parameters.Add($RC) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Command.ExecuteReader() | |
$SQL.Close() | |
If ($RC.Value -ne 1) { Return $False } | |
Return $True | |
} | |
Function ModifyMembers ([String]$Action, [String]$PlayerName, [String]$GroupName, [String]$Comments, [String]$Requestor) | |
{ | |
#-- Group must exist already before it can be modified | |
$Command = New-Object System.Data.SqlClient.SqlCommand("SELECT 1 FROM Groups WHERE Name = '$GroupName'", $SQL) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Exists = $Command.ExecuteScalar() | |
$SQL.Close() | |
If (!$Exists) { Return "$GroupName group does not exist." } | |
$Member = Memberof $GroupName $PlayerName | |
Switch -regex ($Action.ToLower()) | |
{ | |
'^a[d]?[d]?$' | |
{ | |
If ($Member) { Return "$PlayerName is already a member of $GroupName group." } | |
SetPlayer $PlayerName | |
$Command = New-Object System.Data.SqlClient.SqlCommand(" | |
INSERT INTO PlayersGroups (Players_ID, Groups_ID, Added, AddedBy, Comments) | |
SELECT | |
(SELECT ID FROM Players WHERE Name = @PN) | |
, (SELECT ID FROM Groups WHERE Name = @GN) | |
, GETUTCDATE() | |
, (SELECT ID FROM Players WHERE Name = @R) | |
, @C | |
", $SQL) | |
$PN = New-Object System.Data.SqlClient.SqlParameter('@PN', [System.Data.DbType]::String) | |
$PN.Direction = [System.Data.ParameterDirection]::Input | |
$PN.Value = $PlayerName | |
[Void]$Command.Parameters.Add($PN) | |
$GN = New-Object System.Data.SqlClient.SqlParameter('@GN', [System.Data.DbType]::String) | |
$GN.Direction = [System.Data.ParameterDirection]::Input | |
$GN.Value = $GroupName | |
[Void]$Command.Parameters.Add($GN) | |
$R = New-Object System.Data.SqlClient.SqlParameter('@R', [System.Data.DbType]::String) | |
$R.Direction = [System.Data.ParameterDirection]::Input | |
$R.Value = $Requestor | |
[Void]$Command.Parameters.Add($R) | |
$C = New-Object System.Data.SqlClient.SqlParameter('@C', [System.Data.DbType]::String) | |
$C.Direction = [System.Data.ParameterDirection]::Input | |
$C.Value = $Comments | |
[Void]$Command.Parameters.Add($C) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Affected = $Command.ExecuteNonQuery() | |
$SQL.Close() | |
If ($Affected -eq 1) { Return "$PlayerName added to $GroupName group." } | |
Else { Return "Error adding $PlayerName to $GroupName group." } | |
} | |
'^r[e]?[m]?[o]?[v]?[e]?$' | |
{ | |
If (!$Member) { Return "$PlayerName is not a member of $GroupName group." } | |
$Command = New-Object System.Data.SqlClient.SqlCommand(" | |
DELETE FROM PlayersGroups | |
WHERE | |
Players_ID = (SELECT ID FROM Players WHERE Name = @PN) | |
AND Groups_ID = (SELECT ID FROM Groups WHERE Name = @GN) | |
", $SQL) | |
$PN = New-Object System.Data.SqlClient.SqlParameter('@PN', [System.Data.DbType]::String) | |
$PN.Direction = [System.Data.ParameterDirection]::Input | |
$PN.Value = $PlayerName | |
[Void]$Command.Parameters.Add($PN) | |
$GN = New-Object System.Data.SqlClient.SqlParameter('@GN', [System.Data.DbType]::String) | |
$GN.Direction = [System.Data.ParameterDirection]::Input | |
$GN.Value = $GroupName | |
[Void]$Command.Parameters.Add($GN) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$Affected = $Command.ExecuteNonQuery() | |
$SQL.Close() | |
If ($Affected -eq 1) { Return "$PlayerName removed from $GroupName group." } | |
Else { Return "Error removing $PlayerName from $GroupName group." } | |
} | |
} | |
} | |
Function timAutoSave_Elapsed ([System.Object]$sender, [System.Timers.ElapsedEventArgs]$e) | |
{ | |
If (SDP.HasExited) | |
{ | |
($sender -As [System.Timers.Timer]).Stop() | |
Unregister-Event 'AutoSave' | |
Remove-Job 'AutoSave' | |
Return | |
} | |
$Global:timAutoSave.Interval = (GetConfiguration('AutoSave')) * 60 * 1000 | |
$Global:TimerStarts.Save = Get-Date | |
SetStatus 'LastSaveRequest' | |
ProcessTask 'Save' | |
} | |
Function timAutoBackup_Elapsed ([System.Object]$sender, [System.Timers.ElapsedEventArgs]$e) | |
{ | |
If (SDP.HasExited) | |
{ | |
($sender -As [System.Timers.Timer]).Stop() | |
Unregister-Event 'AutoBackup' | |
Remove-Job 'AutoBackup' | |
Return | |
} | |
$Global:timAutoBackup.Interval = (GetConfiguration('AutoBackup')) * 60 * 1000 | |
$Global:TimerStarts.Backup = Get-Date | |
SetStatus 'LastBackupRequest' | |
ProcessTask 'Backup' | |
} | |
Function timAutoImages_Elapsed ([System.Object]$sender, [System.Timers.ElapsedEventArgs]$e) | |
{ | |
If (SDP.HasExited) | |
{ | |
($sender -As [System.Timers.Timer]).Stop() | |
Unregister-Event 'AutoImages' | |
Remove-Job 'AutoImages' | |
Return | |
} | |
$Global:timAutoImages.Interval = (GetConfiguration('AutoImages')) * 60 * 1000 | |
$Global:TimerStarts.Images = Get-Date | |
SetStatus 'LastImagesRequest' | |
ProcessTask 'Update Images' | |
} | |
Function timAutoPrune_Elapsed ([System.Object]$sender, [System.Timers.ElapsedEventArgs]$e) | |
{ | |
If (SDP.HasExited) | |
{ | |
($sender -As [System.Timers.Timer]).Stop() | |
Unregister-Event 'AutoPrune' | |
Remove-Job 'AutoPrune' | |
Return | |
} | |
$Global:timAutoPrune.Interval = (GetConfiguration('AutoPrune')) * 60 * 1000 | |
$Global:TimerStarts.Prune = Get-Date | |
SetStatus 'LastPruneRequest' | |
ProcessTask 'Prune' | |
} | |
Function ProcessTask ($Task, [Boolean]$blnForceNext = $False) | |
{ | |
#Format task to hashtable if simple string | |
If ($Task) { If ($Task.GetType().Name -eq 'String') { $Task = @{ Command = $Task } } } | |
#Add task to queue if not already in there | |
If ($Task -And ($blnForceNext -eq $False)) | |
{ | |
ForEach ($i In $Global:TaskQueue) | |
{ | |
If (($i.Command -eq $Task.Command) -And ($i.Parameters -eq $Task.Parameters)) { $blnExists = $True; Break } | |
} | |
If ($blnExists -ne $True) | |
{ | |
If (!($Task.Private)) { $Task.Private = $False } | |
$Global:TaskQueue.Enqueue($Task) | |
} | |
} | |
#Ensure retry timer is configured if a task is already in progress | |
If (($Global:TaskInProgress -eq $True) -And ($blnForceNext -eq $False)) | |
{ | |
If ($Global:timTaskRetry.Enabled -ne $True) | |
{ | |
$Global:timTaskRetry = New-Object System.Timers.Timer | |
$Global:timTaskRetry.Interval = 5000 | |
Register-ObjectEvent $timTaskRetry 'Elapsed' -SourceIdentifier TaskRetry -Action { timTaskRetry_Elapsed @Args } | Out-Null | |
$Global:timTaskRetry.Start() | |
} | |
Return | |
} | |
#Exit and cancel retry timer if empty queue | |
If (($Global:TaskQueue.Count -eq 0) -And ($Global:timTaskRetry.Enabled -eq $True)) | |
{ | |
$Global:timTaskRetry.Stop() | |
Unregister-Event -SourceIdentifier 'TaskRetry' | |
Remove-Job -Name 'TaskRetry' | |
$Global:TaskInProgress = $False | |
Return | |
} | |
$Global:TaskInProgress = $True | |
$Task = $Global:TaskQueue.Peek() | |
If ($blnForceNext -eq $True) { $Task.Command = "$($Task.Command.Split('.')[0]).$([Int]($Task.Command.Split('.')[1]) + 1)" } | |
Switch ($Task.Command.ToLower()) | |
{ | |
'save' | |
{ | |
ForceSave | |
$Global:TaskQueue.Dequeue() | Out-Null | |
$Global:TaskInProgress = $False | |
} | |
'backup' | |
{ | |
ForceSave | |
MCS 'save-off' | |
} | |
'backup.1' | |
{ | |
$strNow = Get-Date -Date (Get-Date).ToUniversalTime() -Format 'yyyyMMddHHmmss\Z' | |
$strDestination = "$(GetConfiguration('Backups'))\$strNow.zip" | |
$prcZip = New-Object System.Diagnostics.Process | |
$prcZip.StartInfo.FileName = GetConfiguration('BackupProgram') | |
$prcZip.StartInfo.Arguments = (GetConfiguration('BackupProgramArguments')).Replace('%SOURCE%', (GetConfiguration('World'))).Replace('%DESTINATION%', $strDestination) | |
$prcZip.StartInfo.UseShellExecute = $False | |
$prcZip.StartInfo.WorkingDirectory = $strScriptPath | |
$prcZip.EnableRaisingEvents = $True | |
Register-ObjectEvent $prcZip 'Exited' -SourceIdentifier 'Zip.Exited' -Action { prcZip_Exited @Args } | |
$prcZip.Start() | |
} | |
'backup.2' | |
{ | |
MCS 'save-on' | |
Respond 'This world has just been backed up.' $Task.Requestor $Task.Private | |
SetStatus 'LastBackup' | |
$Global:TaskQueue.Dequeue() | Out-Null | |
$Global:TaskInProgress = $False | |
} | |
'update images' | |
{ | |
$Global:datImagesStarted = Get-Date | |
Respond 'Updating map images...' $Task.Requestor $Task.Private | |
ForceSave | |
MCS 'save-off' | |
} | |
'update images.1' | |
{ | |
If ($Task.Parameters) | |
{ | |
UpdateImages @{ $Task.Parameters = $Global:Images.($Task.Parameters) } | |
} | |
Else | |
{ | |
$strNow = Get-Date -Date ($Global:datImagesStarted).ToUniversalTime() -Format 'yyyyMMddHHmmss\Z' | |
UpdateImages $Global:Images "$(GetConfiguration('Images'))\Archive\$strNow" | |
} | |
} | |
'prune' | |
{ | |
Prune | |
$Global:TaskQueue.Dequeue() | Out-Null | |
$Global:TaskInProgress = $False | |
} | |
Default | |
{ | |
Write-Host "ERROR: Unrecognized task of ""$($Task.Command)""." | |
$Global:TaskQueue.Dequeue() | Out-Null | |
$Global:TaskInProgress = $False | |
} | |
} | |
Trap | |
{ | |
Write-Host "Error in ProcessTask" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
Break #Continue | |
} | |
} | |
Function Prune () | |
{ | |
$PruneBackupsDays = GetConfiguration('PruneBackupsDays') | |
If ($PruneBackupsDays -eq [DBNull]::Value) { $PruneBackupsDays = 0 } | |
If ($PruneBackupsDays -gt 0) | |
{ | |
$Backups = GetConfiguration('Backups') | |
If (Test-Path $Backups) | |
{ | |
$DeleteBackupsOlderThen = (Get-Date).AddDays(-$PruneBackupsDays) | |
Get-ChildItem $Backups *.zip ` | |
| Where-Object { $_.LastWriteTimeUTC -le $DeleteBackupsOlderThen.ToUniversalTime() } ` | |
| Remove-Item -Force | |
} | |
} | |
$PruneImagesDays = GetConfiguration('PruneImagesDays') | |
If ($PruneImagesDays -eq [DBNull]::Value) { $PruneImagesDays = 0 } | |
If ($PruneImagesDays -gt 0) | |
{ | |
$DeleteImagesOlderThen = (Get-Date).AddDays(-$PruneImagesDays) | |
$Archive = (GetConfiguration('Images')) + '\Archive' | |
If (Test-Path $Archive) | |
{ | |
#Remove old folders from Archive | |
Get-ChildItem $Archive ` | |
| Where-Object { ($_.psIsContainer -eq $True) -and ($_.LastWriteTimeUTC -le $DeleteImagesOlderThen.ToUniversalTime()) } ` | |
| Remove-Item -Force -Recurse | |
} | |
$Updates = (GetConfiguration('Images')) + '\Updates' | |
If (Test-Path $Updates) | |
{ | |
#Remove old folders from Updates | |
$Updates = 'D:\Documents\Personal\Games\Minecraft\Inetpub\www\maps\Updates' | |
Get-ChildItem $Updates ` | |
| Where-Object { ($_.psIsContainer -eq $True) -and ($_.LastWriteTimeUTC -le $DeleteImagesOlderThen.ToUniversalTime()) } ` | |
| Remove-Item -Force -Recurse | |
} | |
} | |
Trap | |
{ | |
Write-Host "Error in Prune" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
Continue | |
} | |
} | |
Function ForceSave () | |
{ | |
#--Check global variable as two requests back to back won't update database quick enough | |
If ($Global:LastSave -ne $Null) { | |
If ((New-TimeSpan $Global:LastSave (Get-Date)).TotalMinutes -lt 5) { Return } | |
} | |
#--Check database | |
If ( (New-TimeSpan ((GetStatus('LastSave')).ToLocalTime()) (Get-Date)).TotalMinutes -lt 5 ) { Return } | |
$Global:LastSave = Get-Date | |
MCS 'say Forcing save...' | |
MCS 'save-all' | |
} | |
Function prcZip_Exited ([System.Object]$sender, $e) | |
{ | |
Unregister-Event -SourceIdentifier 'Zip.Exited' | |
Remove-Job -Name 'Zip.Exited' | |
ProcessTask 'backup.2' $True | |
} | |
Function timTaskRetry_Elapsed ([System.Object]$sender, [System.Timers.ElapsedEventArgs]$e) | |
{ | |
ProcessTask | |
} | |
Function UpdateImages ($hshImages, [String]$strOutput) | |
{ | |
If ($hshImages) | |
{ | |
If ($strOutput) { $Global:strImagesOutput = $strOutput } | |
Else | |
{ | |
$strNow = Get-Date -Date ($Global:datImagesStarted).ToUniversalTime() -Format 'yyyyMMddHHmmss\Z' | |
$Global:strImagesOutput = (GetConfiguration('Images')) + '\Updates\' + $strNow | |
} | |
New-Item $Global:strImagesOutput -ItemType 'Directory' | Out-Null | |
$Global:queImages = New-Object System.Collections.Queue | |
ForEach ($i In $hshImages.Keys) | |
{ | |
If (!($hshImages.$i.Parameters.Contains("--show-signs")) -and ($strOutput)) | |
{ | |
$hshImages.$i.Parameters += " --write-json `"C:\Minecraft\Inetpub\www\maps\c10t\$($hshImages.$i.File).json`"" ` | |
+ " --show-signs=* --ttf-path `"c:\windows\fonts\lucon.ttf`"" | |
} | |
$hshImages.$i.Requestor = $Requestor | |
$hshImages.$i.Private = $Private | |
$hshImages.$i.Abbreviation = $i | |
$Global:queImages.Enqueue($hshImages.$i) | |
} | |
$Global:ImageCount = 0 | |
If ($hshImages.Keys.Count -eq 1) { $Global:SingleImage = $Global:Images.$($hshImages.Keys).File } | |
} | |
If ($Global:queImages.Count -eq 0) | |
{ | |
MCS 'save-on' | |
#Record and notify players of completion | |
If ($Global:SingleImage) | |
{ | |
$strUpdate = "Map image $Global:SingleImage" | |
If ($Global:ImageCount -ne 1) { $strUpdate += ' had an error while being' } | |
} | |
Else | |
{ | |
SetStatus 'LastImages' | |
$strUpdate = "$Global:ImageCount Map images" | |
Get-Job | Where-Object { $_.Name -eq 'Google Map Update' } | Remove-Job -Force | |
Start-Job (GetConfiguration('ImagesTilesScript')) -Name 'Google Map Update' | Out-Null | |
} | |
Respond ("$strUpdate updated. `($(Duration $Global:datImagesStarted)`) $(GetConfiguration('HomeURL'))") ` | |
$Global:TaskQueue.Peek().Requestor $Global:TaskQueue.Peek().Private | |
$Global:SingleImage = '' | |
#Finalize task | |
$Global:TaskQueue.Dequeue() | Out-Null | |
$Global:TaskInProgress = $False | |
[System.Net.HttpWebRequest]::Create('http://mc.rjump.com/maps/').BeginGetResponse($Null, $Null) | |
Return | |
} | |
$strFile = $Global:strImagesOutput + '\' + $Global:queImages.Peek().File | |
$strParameters = $Global:queImages.Peek().Parameters | |
$Abbreviation = $Global:queImages.Peek().Abbreviation | |
$Global:queImages.Dequeue() | Out-Null | |
$prcImage = New-Object System.Diagnostics.Process | |
$prcImage.StartInfo.FileName = GetConfiguration('ImagesProgram') | |
$prcImage.StartInfo.Arguments = "-w ""$(GetConfiguration('World'))"" -o ""$strFile"" $strParameters" | |
$prcImage.StartInfo.WorkingDirectory = $strScriptPath | |
$prcImage.StartInfo.UseShellExecute = $False | |
$prcImage.EnableRaisingEvents = $True | |
Register-ObjectEvent $prcImage 'Exited' -SourceIdentifier 'Image.Exited' -Action { prcImage_Exited @Args $Event.MessageData } -MessageData @{ Abbreviation = $Abbreviation; Path = $Global:strImagesOutput } | Out-Null | |
$prcImage.Start() | Out-Null | |
Trap | |
{ | |
Write-Host "Error in Update Images" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
#Write-Error 'Error Processing Standard Error Stream Test' -ErrorID STDERR1 -TargetObject $_ | |
Break #Continue | |
} | |
} | |
Function prcImage_Exited ([System.Diagnostics.Process]$sender, [System.EventArgs]$e, $MessageData) | |
{ | |
Unregister-Event -SourceIdentifier 'Image.Exited' | |
Remove-Job -Name 'Image.Exited' | |
#-- If no errors on exit, then update database with location for image | |
If ($sender.ExitCode -eq 0) | |
{ | |
$Command = New-Object System.Data.SqlClient.SqlCommand("UPDATE Images SET Latest = '$($MessageData.Path)' WHERE Abbreviation = '$($MessageData.Abbreviation)'", $SQL) | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
[Void]$Command.ExecuteNonQuery() | |
$SQL.Close() | |
$Global:ImageCount++ | |
} | |
UpdateImages | |
Trap | |
{ | |
Write-Host "Error in prcImage_Exited" -ForegroundColor Red | |
Write-Host $_ -ForegroundColor Red | |
Write-Host "Ln $($_.InvocationInfo.ScriptLineNumber) Col $($_.InvocationInfo.OffsetInLine): $($_.InvocationInfo.Line)" -ForegroundColor Red | |
Break #Continue | |
} | |
} | |
Function Duration ($In) | |
{ | |
If ($In.GetType().Name -ne 'TimeSpan') { $In = New-TimeSpan $In } | |
$Out = '' | |
If ($In.Days -ne 0) { $Out += [String]$In.Days + 'd ' } | |
If ($In.Hours -ne 0) { $Out += [String]$In.Hours + 'h ' } | |
If ($In.Minutes -ne 0) { $Out += [String]$In.Minutes + 'm ' } | |
Return ($Out + $In.Seconds + 's') | |
} | |
Function IsNumeric ($x) { Return [System.Int32]::TryParse($x, [Ref]0) } | |
Function Test([String]$Command) | |
{ | |
ProcessCommand (Get-Date) 'EdGruberman' $Command $True | |
} | |
$Global:Configuration = 'Workstation' | |
$Global:strScriptPath = Split-Path $MyInvocation.MyCommand.Path | |
$Global:XMLCFGFILE = "$strScriptPath\MCS Configuration.xml" | |
$Global:XMLMAILFILE = "$strScriptPath\MCS Mail.xml" | |
$Global:xmlMail = [XML](Get-Content $XMLMAILFILE) | |
$Global:Mail = $Global:xmlMail.Mail | |
$xmlConfig = [XML](Get-Content $XMLCFGFILE) | |
$Builder = New-Object System.Data.SqlClient.SqlConnectionStringBuilder | |
$Builder['Data Source'] = $xmlConfig.Configuration.Database.Source | |
$Builder['Initial Catalog'] = $xmlConfig.Configuration.Database.Name | |
$Builder['Integrated Security'] = $True | |
$Builder['MultipleActiveResultSets'] = $True | |
$Global:SQL = New-Object System.Data.SqlClient.SqlConnection($Builder.ConnectionString) | |
#-- Get image definitions | |
$ImagesFont = GetConfiguration('ImagesFont') | |
If ($SQL.State -eq 'Closed') { $SQL.Open() } | |
$ImagesSQL = (New-Object System.Data.SqlClient.SqlCommand('SELECT Abbreviation, FileName, Parameters FROM Images', $SQL)).ExecuteReader() | |
$Images = @{} | |
While ( $ImagesSQL.Read() ) | |
{ $Images.($ImagesSQL['Abbreviation']) = @{ File = $ImagesSQL['FileName']; Parameters = $ImagesSQL['Parameters'].Replace('%FONT%', $ImagesFont) } } | |
$ImagesSQL.Close() | |
$SQL.Close() | |
Trap | |
{ | |
Write-Host $_ | |
Continue | |
} | |
MCS.Start |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment