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.
How did you make the call to the world data resource?
Just dug into this plugin, but their lack of straightforward documentation left me a bit confused.
@Anonymous
I’m using the Supplied PHP Library. So its pretty straightforward at least for me.
I know the JSON Api Plugin Author has shuffled his site around a bit but everything is linked from the Github pages.
Depends on which language you are using really.
Everything you need should be on: https://github.com/alecgorge/jsonapi
If you are having a specific issue perhaps I can help>
@Barry Carlyon
I know I’m going about this wrong, but I’m new to this so bear with me if you can, haha. I went through the methods listed in the plugin’s directory, but I couldn’t find a method to call the “getTime()” method that I was hoping to find. I’m sure it must be something I’ve completely overlooked.
@Anonymous
There isn’t a getTime()
I’m putting a call into getWorld and loading the relevant array/object entry from there.
(Fixed my Blog Entry as I wrote /world/ originally… oops)
@Barry Carlyon
And as you replied I found getWorld, lol. I was so confused at why they included a setWorldTime and didn’t include a getTime… Even went so far as to attempt to implement a new method calling bukkit’s actual getTime() method, but to no avail being as I attempted this at 8am without sleeping the night prior.
Yeah my bad for typo-ing in the blog post originally 😀