Monday, 14 January 2013

Minecraft games

Try using this seed
7014486191554641464
also try firtle and random (in large biome mode.)

OK so some settings to get multiplayer going now.

Set up a server, and then run it. I used this comandline:
java -Xms512M -Xmx1G -jar minecraft_server.jar
exit the server GUI, that will save your world and settings, edit the file
server.properties and change these lines
level-name=MultiplayerWorld

online-mode=false # this disables login authorisation so you can play a lan-game with only 1 account

pvp=false # co-op mode

gamemode=0 # defaults to survival

Then make a new batch file for the clients that want separate names.
@echo off
title Run minecraft as user %USERNAME%
java -Xms512m -Xmx1024m -cp "%APPDATA%\.minecraft\bin\minecraft.jar;%APPDATA%\.minecraft\bin\*" -Djava.library.path="%APPDATA%\.minecraft\bin\natives" net.minecraft.client.Minecraft '"%USERNAME%"'

copy this script to each player PC and save as joingame.bat

Hosting with a listener

I found this helpfull forum-topic got me started and I wrote this script
http://www.techtalkz.com/microsoft-windows-powershell/465931-powershell-tcp-listener.html
Just save the text below into a file with a .ps1 extenstion and run it.
 
function listen-port ($port=25565) {
$endpoint = new-object System.Net.IPEndPoint ([system.net.ipaddress]::any,
$port)
$listener = new-object System.Net.Sockets.TcpListener $endpoint
$listener.start()
$clnt = $listener.AcceptTcpClient() # will block here until connection
$listener.stop()
$clnt.close()
}

(Get-Host).UI.rawUI.windowtitle = "Waiting for incomming connection attempt"
Write-host "Waiting for incoming connection attempt"
listen-port

(Get-Host).UI.rawUI.windowtitle = "Starting server"
Write-host "... detected connection attempt"
cd server
& java -Xms1024m -Xmx1024m -jar minecraft_server.jar nogui

(Get-Host).UI.rawUI.windowtitle = "Done playing"

Right, that's all nice, but your server has no way of exiting again when everyone wants to go home (or to bed) . Along comes netstat and powershell jobs.

Bedtime

It is possible the last op online stops the server, but that requires some thought, planning, and well it's not necessary nor practical. In comes port snooping, the legal local kind.
http://xcud.com/post/5872186891/get-networkstatistics-or-netstat-for-powershell

Once we have deteted that it is bedtime we need to "sendkeys" the word 'stop' to the console window, for a list of console commands see: http://www.minecraftwiki.net/wiki/Commands
for automation purposes we will use save-all, pause about 10 seconds, and then send 'stop'.
The final script looks like this:
# powershell minecraft server wrapper
#
#210 recipes
#27 achievements
#2013-01-20 14:01:23 [INFO] Starting minecraft server version 1.4.7
#2013-01-20 14:01:23 [INFO] Loading properties
#2013-01-20 14:01:23 [INFO] Default game type: SURVIVAL
#2013-01-20 14:01:23 [INFO] Generating keypair
#2013-01-20 14:01:25 [INFO] Starting Minecraft server on *:25565
#2013-01-20 14:01:25 [WARNING] **** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!
#2013-01-20 14:01:25 [WARNING] The server will make no attempt to authenticate usernames. Beware.
#2013-01-20 14:01:25 [WARNING] While this makes the game possible to play without internet access, it also opens up the
#bility for hackers to connect with any username they choose.
#2013-01-20 14:01:25 [WARNING] To change this, set "online-mode" to "true" in the server.properties file.
#2013-01-20 14:01:25 [INFO] Preparing level "MultiplayerWorld"
#2013-01-20 14:01:25 [INFO] Preparing start region for level 0
#2013-01-20 14:01:26 [INFO] Done (0.990s)! For help, type "help" or "?"
#
# references : date format http://msdn.microsoft.com/en-us/library/az4se3k1.aspx
# netstat : http://poshcode.org/2701
# minecraft server commands : http://www.minecraftwiki.net/wiki/Commands
#
$erroractionpreference = "Stop"
Set-Strictmode -version 2

function MyTrace([string]$traceMsg) {
    try {
        test-path $global:MyTraceLogFile | out-null
    } catch
    {
        $global:MyTraceLogFile = "$pwd\TraceLogFile.log"
        if (!(test-path $global:MyTraceLogFile))
        {
            "Init trace file" | out-File $global:MyTraceLogFile -encoding utf8 -force
        }
        MyTrace "======================================================================"
        MyTrace "Starting trace"
    }
    $traceMsg = @($traceMsg.split("`n") | ?{-not ([string]::isnullorempty($_.trim()))} ) -join "`n"

    "$(Get-Date -format 'T') $traceMsg" | out-File $global:MyTraceLogFile -append -encoding utf8
}

$consoleHost = (get-host).ui.rawui
$title = "Minecraft LAN Server"
$consoleHost.windowtitle = $title
$consoleHost.foregroundcolor = 'white'

$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$executable = 'java.exe'
$svrProcname = $executable.split('.')[0]
if ((@(get-process $svrProcname -ea 0).count) -gt 0) {throw "error $executable already running"}
MyTrace "======================================================================"
MyTrace "Starting minecraft server date: (get-date -format 'D')"

write-host "Searching path for $executable..." -nonewline
MyTrace "Searching for app $svrProcname in path"
($env:path).split(';')|%{join-path $_ $executable}|%{if (test-path $_) {$executablePath = $_}}
write-host "$executablePath"
MyTrace "Found app $svrProcname in path $executablePath OK"

cd server
$pinfo.FileName = $executablePath
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.RedirectStandardInput = $true
$pinfo.UseShellExecute = $false
$pinfo.WorkingDirectory = $pwd
$pinfo.Arguments = "-Xms1024m -Xmx1024m -jar minecraft_server.jar nogui"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo

#invoke-expression "& `"$executablePath`" $($pinfo.Arguments)"
#exit

cd ..
MyTrace "Start app $executablePath with arguments $($pinfo.Arguments)"
$p.Start() | Out-Null
write-host "CMD: Started process, id = $($p.id)"
MyTrace "Started id = $($p.id)"


function ReadMineData($p)
{
    $msg ="";
    if ($p.HasExited)
    {
        while (!($p.StandardOutput.endofstream)){$msg += [char]($p.StandardOutput.Read()) }
        while (!($p.StandardError.endofstream)){$msg += [char]($p.StandardError.Read()) }
    } else
    {
        while (-1 -ne $p.StandardOutput.Peek()){$msg += [char]($p.StandardOutput.Read()) }
        while (-1 -ne $p.StandardError.Peek()){$msg += [char]($p.StandardError.Read()) }
    }
    write-host "DATA: $msg " -foregroundcolor yellow
    if (-not [string]::IsNullOrEmpty($msg.Trim())) {
        MyTrace "READ: $msg"
    }
    $msg
}

function SendCommand($p, [string]$command, [string]$response)
{
    write-host "WRITE: '$command'" -foregroundcolor yellow
    MyTrace "WRITE: $command"
    $p.StandardInput.WriteLine($command)
    $found = $false
    $tries = 5
    while ((!$found) -and ($tries -gt 0))
    {
        start-sleep -m 1000
    if (!($p.StandardError.endofstream)) {write-host ([char]($p.StandardError.Read())) -foregroundcolor cyan}
        $msg = [string](ReadMineData $p)
        $found = @($msg.split("`n") | ?{$_ -like "*$response*"}).count -gt 0
        $tries--;
    }
    if ($found) {
        write-Host "WRITE: '$command' OK "-foregroundcolor green
        MyTrace "WROTE: $command OK"
    } else {
        write-Host "WROTE: '$command' FAILED "-foregroundcolor red
        MyTrace "WROTE: $command FAILED"
    }
}

# slighly modded version of Get-NetworkStatistics by Shay Levy (it barfs if $erroractionpref=stop and/or strict mode is set)
# from http://poshcode.org/2701
function Get-NetworkStatistics
{
    [OutputType('System.Management.Automation.PSObject')]
    [CmdletBinding(DefaultParameterSetName='name')]
   
    param(
        [Parameter(Position=0,ValueFromPipeline=$true,ParameterSetName='port')]
        [System.Int32]$Port='*',
       
        [Parameter(Position=0,ValueFromPipeline=$true,ParameterSetName='name')]
        [System.String]$ProcessName='*',
       
        [Parameter(Position=0,ValueFromPipeline=$true,ParameterSetName='address')]
        [System.String]$Address='*',       
       
        [Parameter()]
        [ValidateSet('*','tcp','udp')]
        [System.String]$Protocol='*',

        [Parameter()]
        [ValidateSet('*','Closed','CloseWait','Closing','DeleteTcb','Established','FinWait1','FinWait2','LastAck','Listen','SynReceived','SynSent','TimeWait','Unknown')]
        [System.String]$State='*'
       
    )
   
    begin
    {
        $properties = 'Protocol','LocalAddress','LocalPort'
            $properties += 'RemoteAddress','RemotePort','State','ProcessName','PID'
    }
   
    process
    {
        netstat -ano | Select-String -Pattern '\s+(TCP|UDP)' | ForEach-Object {

            $item = $_.line.split(' ',[System.StringSplitOptions]::RemoveEmptyEntries)

            if($item[1] -notmatch '^\[::')
            {  
                $pref = $erroractionPreference
                $erroractionPreference = "silentlycontinue"
                $localAddress=""
                $localPort = 65535
                $remoteAddress=""
                $remotePort = 65535
                $status = "UNK"
                if (($la = $item[1] -as [ipaddress]).AddressFamily -eq 'InterNetworkV6')
                {
                   $localAddress = $la.IPAddressToString
                   $localPort = $item[1].split('\]:')[-1]
                }
                else
                {
                    $localAddress = $item[1].split(':')[0]
                    $localPort = $item[1].split(':')[-1]
                }

                if (($ra = $item[2] -as [ipaddress]).AddressFamily -eq 'InterNetworkV6')
                {
                   $remoteAddress = $ra.IPAddressToString
                   $remotePort = $item[2].split('\]:')[-1]
                }
                else
                {
                   $remoteAddress = $item[2].split(':')[0]
                   $remotePort = $item[2].split(':')[-1]
                }
                $erroractionPreference = $pref
                $procId = $item[-1]
                $procName = (Get-Process -Id $item[-1] -ErrorAction SilentlyContinue).Name
                $proto = $item[0]
                $status = if($item[0] -eq 'tcp') {$item[3]} else {$null}               
               
               
                $pso = New-Object -TypeName PSObject -Property @{
                    PID = $procId
                    ProcessName = $procName
                    Protocol = $proto
                    LocalAddress = $localAddress
                    LocalPort = $localPort
                    RemoteAddress =$remoteAddress
                    RemotePort = $remotePort
                    State = $status
                } | Select-Object -Property $properties                               

                if (0 -gt $verbosePreference) {
                    $pso | fl
                }
                if($PSCmdlet.ParameterSetName -eq 'port')
                {
                    if($pso.RemotePort -like $Port -or $pso.LocalPort -like $Port)
                    {
                        if($pso.Protocol -like $Protocol -and $pso.State -like $State)
                        {
                            $pso
                        }
                    }
                }

                if($PSCmdlet.ParameterSetName -eq 'address')
                {
                    if($pso.RemoteAddress -like $Address -or $pso.LocalAddress -like $Address)
                    {
                        if($pso.Protocol -like $Protocol -and $pso.State -like $State)
                        {
                            $pso
                        }
                    }
                }
               
                if($PSCmdlet.ParameterSetName -eq 'name')
                {       
                    if($pso.ProcessName -like $ProcessName)
                    {
                        if($pso.Protocol -like $Protocol -and $pso.State -like $State)
                        {
                               $pso
                        }
                    }
                }
            }
        }
    }
}

start-sleep -s 1
write-host "$(ReadMineData $p)"


SendCommand $p "gamerule keepInventory true" "Game rule has been updated"
write-host "CMD: $(get-date -format 'T') sent rule"
#start-sleep -s 1

$playersConnected = $false
$connectCounter = 0
while ($connectCounter -lt 5) { # !$playersConnected) {
    write-host "CMD: waiting for players... ($svrProcname)" -foregroundcolor cyan
    MyTrace "WAITING FOR PLAYERS: connectcounter = $connectCounter"

    $netStats = Get-NetworkStatistics
    write-host "CMD: allstats = $($netStats.count)"
    $javaNetStats = @($netStats | ?{($_.localport -eq 25565) -or ($_.processname -eq $svrProcname)})
    write-host "CMD: javastats = $($javanetStats.count)"
    $playersConnected = @($netStats | ?{($_.processname -eq $svrProcname) -and ($_.State -eq 'ESTABLISHED')}).count -gt 0
    if (!$playersConnected) {
        $connectCounter=0
    } else {
        $connectCounter++;
        write-host "CMD: Countup $connectCounter"
    }
    $debug = $javaNetStats | fl | out-string | %{@($_.split("`n") | ?{-not ([string]::isnullorempty($_.trim()))} ) -join "`n" }
    $debug | write-host
    if ($verbosepreference -gt 0) {
        $debug | %{ MyTrace "netstat : $_"}
    }
    start-sleep -s 5
}
MyTrace "AT LEAST 1 PLAYER HAS BEEN DETECTED : on (get-date -format 'D')"

write-host "CMD: $(get-date -format 'T') idle"
start-sleep -s 1
write-host "$(ReadMineData $p)"
MyTrace "IDLE:"

$disconnectCounter = 10
while ($disconnectCounter -gt 0) {
    write-host "CMD: waiting for players to go home..." -foregroundcolor cyan
    MyTrace "WAITING FOR SHUTDOWN: disconnectCounter = $disconnectCounter"
    Start-Sleep -s 10
    $netStats = Get-NetworkStatistics
    write-host "CMD: allstats = $($netStats.count)"
    $javaNetStats = @($netStats | ?{($_.localport -eq 25565) -or ($_.processname -eq $svrProcname)})
    write-host "CMD: javastats = $($javanetStats.count)"
    $playersConnected = @($netStats | ?{($_.processname -eq $svrProcname) -and ($_.State -eq 'ESTABLISHED')}).count -gt 0
    $numEstablished = @($netStats | ?{($_.processname -eq $svrProcname) -and ($_.State -eq 'ESTABLISHED')}).count
    write-host "CMD: PLAYER CONNECTIONS = $numEstablished"
    MyTrace "PLAYER CONNECTIONS = $numEstablished"
   
    if (!$playersConnected) {
        write-host "CMD: Countdown! $disconnectCounter"
        $disconnectCounter--
    } else {
        $disconnectCounter = 10
    }
    write-host "$(ReadMineData $p)"
    $debug = $javaNetStats | fl | out-string | %{@($_.split("`n") | ?{-not ([string]::isnullorempty($_.trim()))} ) -join "`n" }
    $debug | write-host
    if ($verbosepreference -gt 0) {
        $debug | %{ MyTrace "netstat : $_"}
    }
}
$javaNetStats | fl
SendCommand $p "save-all" "Saved the world"
start-sleep -s 1
write-host "$(ReadMineData $p)"

SendCommand $p "stop" "Stopping server"
$msg = "$(ReadMineData $p)"
write-host $msg

MyTrace "SHUTDOWN: $svrProcname processes count $(@(get-process $svrProcname -ea 0).count)"

Script as a service

http://blog.start-transcript.com/2012/01/22/running-powershell-scripts-as-a-service-events-prologue/

No comments:

Post a Comment