So, I tend to now and again do random bits and pieces to MineCraft Servers.
Of late I have been working with ZimDoorCraft, took the existing relatively static site, and flipped it over to a Mini PHP Powered Content Management System, that I wrote and roll out to smaller sites.
Couple of MySQL powered bits to make updates easier (Staff list and the like).
In time more complex and interesting things will be added (it was for a while running a Login with Mojang/MineCraft account, but that means you type your MineCraft login into the site…), how that works is a subject for another post. As is what ever I build next 😀
The MineCraft server in this case is running a derivative of Bukkit, which means it supports plugins, so we are using the JSON Api plugin, and making a call to the getWorld() data resource.
Which passes back information about the world in a nice handy format.
Heres an example
[world] => stdClass Object
(
[remainingWeatherTicks] => 14670
[hasStorm] =>
[time] => 4964
[environment] => normal
[isThundering] =>
[name] => world
[fullTime] => 2903932964
)
If your running Vanilla you can grab the same information just by decoding the level.dat file in the World Directory, however opening a file currently being written to, is not often a good idea, and the level.dat is written to a lot.
Like a lot of games, Minecraft uses ticks, in this case operating at 20 ticks per second, and running to 24000 ticks per Minecraft day, which means a Minecraft day is about 20mins.
Just to be interesting 0 ticks is Sunrise, rather than midnight. And midnight itself is 18000 ticks.
Also contained in the data packet is a count down to when the weather changes, in this case there are 7500 (ish) ticks to go.
Which works out as
14670 / 20 to get Real Seconds = 733.5 Seconds, and then its arbitrary to flip this to a human readable time. We have about 12 minutes, or half a MineCraft day, until the weather changes.
Reading out a more recent packet
[world] => stdClass Object
(
[remainingWeatherTicks] => 7339
[hasStorm] => 1
[time] => 3827
[environment] => normal
[isThundering] =>
[name] => world
[fullTime] => 3902379827
)
Looks like there is a storm on…. But its only Rain no Thunder and Lighting. With 6 mins to go.
On a side note!, watch out for FullTime, as its likely to run away, on a long running server, to something a 32 bit system might not be able to handle! Refer to my Post on Facebook and the Order ID on some thoughts about dealing with that.
Using Tick to Seconds math, means that it is also possible to display the current server time and weather on the website.
I’m using a bit of CSS, and the MineCraft time piece (craftable in game) to show the current time visually. In this case I’ve taken the 16×16 PNG’s and expanded them (by hand) to 32×32, finally converting the time from ticks to the relevant chunk of 360 degrees, offsetting as needed to account for the fact that Sunrise is 0 instead of Midnight.
I do this by adding 6000 ticks and from there treating the ticks complete as a percentage and scaling to meet 360 degrees. Some of the code involved needs a little tweaking and tidying to improve efficiency, but the angle is being calculated by a CRON Job powered script and stored with the full World JSON packet, in an extended object and cached in a file on the file system ready to be read by the web server when a request comes in. So it’s not a top priority to clean up yet.
I was finding that after taking into account the addition 6000 ticks to offset for Sunrise, the whole Sun Moon picture was upside down. So I just added 180 degrees, and corrected it when the angle was greater that 360. Since why bother rotating thru a whole 360 degrees?
$time = $world->time;// grab from data packet from JSON Api Call
$time += 6000;// add 600 for sunrise
// work out the scale factor 360 degrees / ticks in a Minecraft day
$scale = 360 / 24000;
$angle = $scale * $time;// calculate the <span class="hiddenGrammarError" pre=""><span class="hiddenGrammarError" pre=""><span class="hiddenGrammarError" pre="">angle
$angle</span></span></span> = number_format($angle, 0);// clean up
// correct
$angle = $angle + 180;// the image is upside down :-(
if ($angle >= 360) {// clean up again
$angle -= 360;
}
The rotation component was quite difficult to initially decide how to do, PHP wasn’t quite cutting it so switched to a CSS Transform.
HTML wise it consists of a pair of divs, a pair of images, and a chunk of CSS.
<div class="worldtime"><div class="inner"></div></div>
WorldTime being the one behind contains the Sun Moon Picture as a background image.
And Inner contains the Watch overlay also as a background image.
Apply the CSS transformation to rotate the Sun Moon Picture is just a little nasty, because in rotating the Sun Moon picture it also rotated the overlay (inner).
I decided to apply rotation to the overlay, in the reverse direction (so just sticking a negative sign in front).
Works quite well, but if you can think of a better way to spit out this with the rotation please comment below.
Heres my current Style Code
<style type="text/css">
.worldtime .inner {
width: 32px;
height: 32px;
background: url('large_watch.png') left top no-repeat;
/* CSS3 then proprietary code */
rotation: -336deg;
-webkit-transform: rotate(-336deg);
-moz-transform: rotate(-336deg);
filter: progid: DXImageTransform.Microsoft.BasicImage(-rotation=4);
}
.worldtime {
float: left;
width: 32px;
height: 32px;
margin: 0 10px;
background: url('large_inner.png') left top no-repeat;
/* CSS3 then proprietary code */
rotation: 336deg;
-webkit-transform: rotate(336deg);
-moz-transform: rotate(336deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=4);
}
</style>
The whole WorldTime Div is then wrapped in another Div and jQuery used to once per minute go and fetch the updated time, weather and CSS rotation.
At first I did try using the PHP function to rotate the image, but the quality drop off when rotating by an angle not divisible by 90 was shocking.
So ended up resorting to CSS, which does work a hell of a lot better.
This only covers how to do this using the JSON API, in a future post I’ll talk about decoding level.dat and other Minecraft Files.