« Posts under Code

MineCraft Math

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 :-D

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

  1. [world] => stdClass Object
  2.         (
  3.             [remainingWeatherTicks] => 14670
  4.             [hasStorm] =>
  5.             [time] => 4964
  6.             [environment] => normal
  7.             [isThundering] =>
  8.             [name] => world
  9.             [fullTime] => 2903932964
  10.         )

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

  1. [world] => stdClass Object
  2.         (
  3.             [remainingWeatherTicks] => 7339
  4.             [hasStorm] => 1
  5.             [time] => 3827
  6.             [environment] => normal
  7.             [isThundering] =>
  8.             [name] => world
  9.             [fullTime] => 3902379827
  10.         )

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?

  1. <?php
  2.  
  3. $time = $world->time;// grab from data packet from JSON Api Call
  4. $time += 6000;// add 600 for sunrise
  5.  
  6. // work out the scale factor 360 degrees / ticks in a Minecraft day
  7. $scale = 360 / 24000;
  8. $angle = $scale * $time;// calculate the angle
  9. $angle = number_format($angle, 0);// clean up
  10. // correct
  11. $angle = $angle + 180;// the image is upside down :-(
  12. if ($angle >= 360) {// clean up again
  13.         $angle -= 360;
  14. }

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.

  1. <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

  1. <style type="text/css">
  2.         .worldtime .inner {
  3.                 width: 32px;
  4.                 height: 32px;
  5.                 background: url(‘large_watch.png’) left top no-repeat;
  6.             /* CSS3 then proprietary code */
  7.             rotation: -336deg;
  8.             -webkit-transform: rotate(-336deg);
  9.             -moz-transform: rotate(-336deg);
  10.             filter: progid: DXImageTransform.Microsoft.BasicImage(-rotation=4);
  11.         }
  12.         .worldtime {
  13.                 float: left;
  14.                 width: 32px;
  15.                 height: 32px;
  16.                 margin: 0 10px;
  17.                 background: url(‘large_inner.png’) left top no-repeat;
  18.             /* CSS3 then proprietary code */
  19.             rotation: 336deg;
  20.             -webkit-transform: rotate(336deg);
  21.             -moz-transform: rotate(336deg);
  22.             filter: progid: DXImageTransform.Microsoft.BasicImage(rotation=4);
  23.         }
  24.         </style>

Space added between the progid: and the DX to stop a smilie face :D

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.

Facebook Credits, the Order ID, and dealing with large integers in 32 bit PHP

So, currently at work I’ve been rewriting all our Payment Gateways for Your Members. Making them more better Class based an abstracting out the common functions to a base class, to save memory footprint and code etc.

And came across a problem when rewriting the Facebook Credits handler.

The order ID that gets passed around, as well as the Application ID is too long for a 32 Bit PHP installation to handle when treating it as an Integer.

So a number like “239724439419867″ was ending up as “1.7592246582797E+14″ when stored/processed, or converted to a string.
Now the obvious way to process this is to convert it to a string another way, which is somewhat difficult since before you even start it is in a format that you can’t handle.

The saving grace here is the fact that data is passed to you as a JSON packet (aside from the fact the Order ID is in the $_POST variable and thus a string, so I could of used it from there).

This led to me to look at the JSON packet, which starts as a string but when decoded the large integers are still a larger integer than can be processed (whether you json_decode to a Array or to an Object, the problem persists). So I thought about how to process the raw JSON packet and make sure the order ID, and other large integers are treated as strings.

If you look at a Raw JSON packet you can easily spot whats a string, integer, object or array.

Take this example Facebook Credits JSON Packet, (wrapped for readability):

{“order_id”:239724439419867,”buyer”:197803678,”app”:148748711865470,
“receiver”:197803678,”amount”:5,”update_time”:1320075413,
“time_placed”:1320075408,”data”:”",”items”:[{"item_id":"","title":"Post",
"description":"A New Purchasable Post",
"image_url":"","product_url":"",
"price":5,"data":""}],”status”:”“}
  • order_id is an integer as it has no ” around it
  • status is a string as its surrounded by “
  • Items is an array as its surrounded by [, in this case containing a single object, entries/items are comma separated.

So after thinking about this I decided the best way to sort this out was to convert the integers in the raw JSON packet to strings before decoding.

In pseudo code.

Lop off the { and } from the start and end
Explode around ,
array walk each item
split on :
check if there are no " in the second bit
if none wrap in "
glue back together

Something alone the lines of:

  1. function largeint($rawjson) {
  2.   $rawjson = substr($rawjson, 1, -1);
  3.   $rawjson = explode(',' , $rawjson);
  4.   array_walk($rawjson, 'strfun');
  5.   $rawjson = implode(',', $rawjson);
  6.   $rawjson = '{', . $rawjson . '}';
  7.   $json = json_decode($rawjson);
  8.   return $json;
  9. }
  10.  
  11. function strfun(&$entry, $key) {
  12.   $data = explode(':', $entry);
  13.   if (FALSE === strpos($data[1], '"')) {
  14.     $data[1] = '"' . $data[1] . '"';
  15.     $entry = implode(':', $data);
  16.   }
  17. }

I'm not sure in terms of memory footprint if its cheaper to do a substr of $data[1] and check if its a ” or not.
I suppose it could test the string length of the detected integer to see if its invalid/unable to process, but then you would be performing a string function on an integer and again the problem would arise.

But as a block of code is does the job, its obviously not ideal for all situations, since in this case I want the integer as a string, I’m not using it for math, but if I did, we probably need to do some bizarre unpack-ing or something.

Any opinions or improvements give us a comment below :-D

My Leeds Hack 2 Project

Thought I would write a blog post about what I built in 24 hours for Leeds Hack 2 last weekend. I kinda got distracted last week and not had the time to write this post.

You can look at all the projects that people finished over on the Leeds Hack Website.

So what did I write

I decided to write something that I had been pondering about for a while. It’s called Spotify Roulette and revolves around the idea of crowd sourcing a new artist or area of music to listen to.

Originally it started off with me posting on Twitter quite a while back asking for something new to listen to, to which @Stanton responded with Hybrid. (I can’t find the original tweet on twitter but it’s here on Spotwitfy) Which are actually quite nice to listen to and I have a nice Spotify playlist to listen to.

I was wondering if there was a way to automate this.

So thru the combination of the Twitter and Spotify Meta Data API’s, means I can post out to Twitter, await a response, parse out the Artist and then pop open Spotify with a random track by that Artist and if the requester wants a playlist can be generated, and thru a limitation in Spotify, drag and dropped into Spotify to listen further to the Artist.

In short

In short its pretty straight forward.
Just a handful of calls to a couple of different API end points to get an Artist ID from the name, then their albums and the tracks on these albums. Chuck in a little GeoIP to hopefully check the tracks are available in the requesters’ region.
Grab the first track, pop open Spotify and grab another 10 tracks to make a playlist.

Finally I used Nerf Guns to help demo! Russian Roulette stylee.

Responses

People on Twitter can either response with text, an artist which we parse out the @user and the hashtag word. Then look that up on Spotify.
Or a response can be either an HTTP open Spotify link or a Spotify protocol link. Either to the artist page, track or album.
if it’s the Artist, I can parse out the artist ID and look for albums and tracks.
Currently not playlist urls, but that’s easy to implement.

Technology

So we used,

  • Twitter API, using @Abraham Twitter oAuth Library
  • Spotify Meta Data API
  • MaxMind GeoIP
  • jQuery and jQuery UI
  • Rick Astley
  • Nerf Guns

Give it a Go

Give it a go and offer me some feedback.
Watch out for Rick Astley tho. He likes to crop up every now and again….

It’s still a little rough round the edges in terms of theme/layout.

Spotify Roulette (http://spotifyroulette.com/)

Future

Hopefully if people like it and use it I can expand further.

Perhaps use Facebook to share playlists, or another way to crowd source a new artist. And if Spotify release a HTTP API for generating and saving playlists then incorporate that too.

WordPress and the Admin Bar

So WordPress 3.1 introduced the new admin bar. Essentially its another way to navigate around your WordPress Blog’s inner workings, the bar itself can be enabled and disabled both inside and outside the admin system, for I like to have it enabled on both the admin and non admin sides of WordPress.

The WordPress.com Stats Plugin makes quite good use, on the non admin side, by showing a graph of site visits over the last 48hours:

This led me to think about how to put my own links on, so I turned to adding the navigation from YourMembers to the admin bar (but in this case on Both Sides, admin and non admin).

Won’t show you a admin side one as it looks exactly the same :-P

Actually writing the code to make the YourMembers navigation be added to the nav bar, is actually relatively simple, since the admin bar itself has been written rather nicely in its own class.

Opening up the admin-bar.php file in wp-includes is a bit messy, but looking at the first function (_wp_admin_bar_init) shows the class function add_menus() and further down add_menu, so off I went to find them…. A quick grep later finds that is class-wp-admin-bar.php and from there just a matter of reading what add_menu wants….

  1. <?php
  2.  
  3.         function add_menu( $args = array() ) {
  4.                 $defaults = array(
  5.                         ‘title’ => false,
  6.                         ‘href’ => false,
  7.                         ‘parent’ => false, // false for a root menu, pass the ID value for a submenu of that menu.
  8.                         ‘id’ => false, // defaults to a sanitized title value.
  9.                         ‘meta’ => false // array of any of the following options: array( ‘html’ => ”, ‘class’ => ”, ‘onclick’ => ”, target => ”, title => ” );
  10.                 );

I went thru and checked to see where the other “normal admin” links were being added, the function add_menus in the same class file shows that. The key thing to be aware of is the use of priority on those do_actions (line 182 thru 194) in order to order the links, so needing/wanting the YourMembers links to be at the end I went for a sensible priority of 90 since the last normal admin was set to 80.

Then it was just a matter of setting up my own add_action on the same hook (‘admin_bar_menu’) and then globalising the pre existing class method and adding my menus to it.

Since it is a drop down menu, needed to add the top menu as a parent and then adding the child nodes.

Its quite a clever class since the class function of add_menu can handle both parents and childs at the same time with little fuss, as long as you pass it the right ID variables.

Heres a copy of my function:

  1. <?php
  2.  
  3. function ym_admin_bar() {
  4.         global $wp_admin_bar;
  5.  
  6.         if (ym_admin_user_has_access(TRUE)) {
  7.                 $wp_admin_bar->add_menu(
  8.                         array(
  9.                                 ‘id’            => ‘yourmembers_adb’,
  10.                                 ‘title’         => ‘Your Members’,
  11.                                 ‘href’          => YM_ADMIN_INDEX_URL
  12.                         )
  13.                 );
  14.                 global $ym_nav;
  15.                 foreach ($ym_nav as $page => $subpages) {
  16.                         if (is_array($subpages)) {
  17.                                 $first = array_shift($subpages);
  18.                         } else {
  19.                                 $first = ;
  20.                         }
  21.                         $id = ‘ym_adb_’ . strtolower($first);
  22.                         $url = strtolower($first);
  23.                         if (substr($first, 0, 5) == ‘other’) {
  24.                                 $url = ‘ym-other&action=’ . substr($first, 6);
  25.                         }
  26.                         $wp_admin_bar->add_menu(
  27.                                 array(
  28.                                         ‘parent’        => ‘yourmembers_adb’,
  29.                                         ‘id’            => $id,
  30.                                         ‘title’         => $page,
  31.                                         ‘href’          => YM_ADMIN_INDEX_URL . ‘&ym_page=’ . $url
  32.                                 )
  33.                         );
  34.                 }
  35.         }
  36.         return;
  37. }
  38. add_action(‘admin_bar_menu’, ‘ym_admin_bar’, 90);
  39. ?>

There are a couple of funky bits in there due to the method we currently generate the nav items.
The essential bit to consider is the array passed to $wp_admin_bar->add_menu at the start (the parent element note, no parent key) and the $wp_admin_bar->add_menu at the end, specifying a child element.

The function ym_admin_user_has_access just checks to see if the user is of the correct level or not.

You might want to throw in a switch on is_admin() to return different navigational items depending on if you are in the admin or not.

I’m sure there is a lot more you can do with the class function but when I installed WordPress 3.1 and saw the admin bar and WordPress.com Site stats this was the first thing I thought of and implemented, tho why its taken me this long to blog about it I don’t know…..

Travels of a Commercial WordPress Plugin Developer 1

My job at the moment is updating and coding YourMembers, which is a commercial plugin for WordPress.

Recently I’ve been working on a method to Auto Upgrade the plugin, since commercial plugins cannot go on Extend, and there is no commercial equivalent. Extend being the WordPress plugin repository.

Commercial plugins get no nice little “Plugin needs updating Circle” on the plugins tab, or a nice little message on the plugins page, let alone access to the auto updater!

Which leaves us (commercial plugin devs) to write our own version checkers and hook in accordingly.

So now I have a nice little PHP class which will detect whether it can fwrite/rename and if not if it can FTP instead, much the same as the WordPress updater does.

Now this is all well and good, but I needed a method to download and unzip the new plugin file. Grabbing the file is easy, either file_get_contents (heaven forbid), or curl (yay for curl), and write the file (being a zip) to the web servers temporary directory and process from there.

Now the problem here is how to unzip. A Brief look at how WordPress does it seems to show it has three different methods of unzipping. So dump that.

Didn’t feel the need to use PHP’s ZipArchive class, since I don’t need to edit the zip, just extract its contents.

Off to php.net I go and I find some nice handy functions, and quite surprised to find that the zip_read function can handily recurs into directories within the zip file to return their paths/names. Mildly annoying at the time as I had gone and written a recur loop to go inside directories…. and got thrown a error, nice headdesk moment!

So basically the Zip functions, the basic ones of PHP, are actually quite nice, handy and useful!

Heres my code snippet:

  1. <?php
  2. class someclass() {
  3.         private function unpack() {
  4.                 $from = $this->tmp_write;
  5.                 $to = $this->tmp_out;
  6.                 @mkdir($to);
  7.                
  8.                 $zip = zip_open($from);
  9.                 if (is_resource($zip)) {
  10.                         $this->readzip($zip);
  11.                         zip_close($zip);
  12.                 } else {
  13.                         // failed to open
  14.                         $this->error = 1;
  15.                 }
  16.         }
  17.        
  18.         private function readzip($zip) {
  19.                 $from = $this->tmp_write;
  20.                 $to = $this->tmp_out;
  21.                
  22.                 echo ‘</pre><textarea style="width: 100%; height: 100px;">’;
  23.                
  24.                 while (FALSE !== ($file = zip_read($zip))) {
  25.                         $name = zip_entry_name($file);
  26.                         echo $name . "\n";
  27.                         if (!strpos($name, ‘.’)) {
  28.                                 // is dir
  29.                                 @mkdir($to . ‘/’ . $name);
  30.                         } else {
  31.                                 // it recurs into directorys on its own!
  32.                                 $item = zip_entry_open($zip, $file);
  33.                                 $size = zip_entry_filesize($file);
  34.                                
  35.                                 $read = zip_entry_read($file, $size);
  36.                                 $fp = fopen($to . ‘/’ . $name, ‘w’);
  37.                                 fwrite($fp, $read);
  38.                                 fclose($fp);
  39.                         }
  40.                 }
  41.                
  42.                 echo ‘</textarea><pre>’;
  43.         }
  44. }
  45. ?>

I just installed this code snippet plugin, which I might need to change its background colours…..

Any suggestions for code snippet plugins greatly appreciated!