MySQL: The Magically Perfect Data Storage Method for Performance

Let me walk you through a nightmare scenario that I experienced earlier this week when fixing some bugs on an older project from another developer. The project was fairly simple. It allowed players playing on the network to claim a location where they and their team members could quickly teleport back to at any time but could be destroyed by anyone else. It also included a moderator feature which allowed staff to see the history of a team's home locations, useful when they use it to get to otherwise unreachable areas (homes could be claimed anywhere a player could reach, even places they couldn't actually get to otherwise).

Here is how he had his MySQL database setup:

Team ID [PRIMARY] | Clan Data [TEXT]

Two columns. The first was the ID of the team from the 3rd-party teams plugin, the second was a nightmare of deserialized objects with character separators. Each home object had the following data:

  1. Clan name
  2. Location (x, y, z, and world name)
  3. The player who set it down (the ID of)
  4. The player who destroyed it, if destroyed
  5. The date it was set down (millisecond timestamp)

It was put into a serializable string, resembling something like this:

"5:3:7:world_146727_null_1517941648916"

And added to whatever was in the clan data column. After a few days, you would get something like this:

"5:3:7:world_146727_null_1517941648916|5:3:7:world_146727_null_1517941648916|5:3:7:world_146727_null_1517941648916|5:3:7:world_146727_null_1517941648916|5:3:7:world_146727_null_1517941648916"

Of course, because there was only one column, it meant that everything from the database was loaded into memory on server start. The project was fairly old (about a year and a half old), so there were 6,000 rows in the table, 90% of which were no longer used. On top of all that, the MySQL database wasn't part of the same machine as the server the plugin was running on.

Why would someone do all that? Couldn't they obviously see that it was horribly performance & resource intensive, that a flat-file storage method would have worked much better with the same method?

The truth is, people (new developers especially) see MySQL as somehow extremely quick at delivering data and being very performance friendly. The administrator - or whoever is installing/setting up the plugin - will see that it uses MySQL and automatically assume that it will work much better than using YAML or JSON flat-file. I don't doubt that this developer didn't know MySQL well, and may even have learned it on the spot just because the job description asked for some MySQL experience. 

That being said, here is how I would (and did) set up the MySQL table format:

ID (primary, unique, auto-incrementing) | clan ID | x | y | z | world | date (timestamp) | setter UUID | destroyer UUID (null if active)

The primary difference (which actually called for a rewrite of the entire project) is that each home has a separate row. This made it easy to just grab the active home, or grab just the homes created since a certain date (as was required by the staff history command). I could also very quickly write a statement to remove homes that were inactive and created before a certain date. For example:

DELETE FROM homes WHERE date < 1517941648916 AND destroyer != NULL

With the previous table format, this would have been impossible without downloading all the data in the database. 

(Tutorial) How to create cooldowns with Spigot

Before you start (prerequisites)

You don't need to have any extensive Java experience, but it helps to understand how some of the basic features work. The main point of this tutorial is to go over the method and it's implementation, not how Java features like Singletons work.
 

How we want it to work 

For these examples, we will use the command /cooldown as the feature. It can only be used once every 15 seconds.
 

(Pitfall) Method #1: Using Runnable Timer Tasks

Before we get into the most common and performance friendly cooldown system, I want to cover a commonly suggested method that you should avoid. It's suggested fairly often because of how simple it seems at first.

In this method, your plugin has a Singleton cooldown manager:

public class CooldownManager {

    private HashMap<UUID, Integer> cooldowns = new HashMap<>();

    public static final int DEFAULT_COOLDOWN = 15;

    public void setCooldown(UUID player, Integer time){
        if(time == null)
            cooldowns.remove(player);
        else
            cooldowns.put(player, time);
    }

    public int getCooldown(UUID player){
        return (cooldowns.get(player) == null ? 0 : cooldowns.get(player));
    }

    private CooldownManager(){}

    public static final CooldownManager INSTANCE = new CooldownManager();

}

It contains the basic methods for setting, getting, and removing from a cooldown map. Next we have the Command Executor:

public class CooldownCommand implements CommandExecutor {

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        //Player only command
        if(sender instanceof Player){
            Player p = (Player) sender;
            int timeLeft = CooldownManager.INSTANCE.getCooldown(p.getUniqueId());
            //If the cooldown has expired
            if(timeLeft == 0){
                //Use the feature
                p.sendMessage(ChatColor.GREEN + "Feature used!");
                //Start the countdown task
                CooldownManager.INSTANCE.setCooldown(p.getUniqueId(), CooldownManager.DEFAULT_COOLDOWN);
                new BukkitRunnable() {
                    @Override
                    public void run() {
                        int timeLeft = CooldownManager.INSTANCE.getCooldown(p.getUniqueId());
                        if(timeLeft == 0){
                            CooldownManager.INSTANCE.setCooldown(p.getUniqueId(), null);
                            this.cancel();
                            return;
                        }
                        CooldownManager.INSTANCE.setCooldown(p.getUniqueId(), --timeLeft);
                    }
                }.runTaskTimer(SpaceRaiders.Companion.getPlugin(), 20, 20);

            }else{
                //Hasn't expired yet, shows how many seconds left until it does
                p.sendMessage(ChatColor.RED.toString() + timeLeft + " seconds before you can use this feature again.");
            }
        }else{
            sender.sendMessage("Player-only command");
        }

        return true;
    }

}

 

(Register the command executor)
As you can tell, it seems very simple. The main part of this section is that it decreases the time left before they can use the feature again every second, in the BukkitRunnable task timer. It will work just fine as it is now.

This method, however, has some major issues. For one, you should always avoid using runnables, as async tasks will create a thread for each task. Second, this means if you have several hundred players online, you will have the map updating many, many times a second (assuming the players are using it). For minigames with multiple cooldown features, there can be as many as a hundred tasks running at once, and it can become quite a mess internally.

One of the largest drawbacks, however, is that you can only track seconds with this method (at the smallest). You can't track anything smaller, and if you wanted to you would have to change the time unit to 1/10s of a second or less, and it would need to be updated 10 times more often.
 

Method #2: Using Timestamps

Rather than updating a variable every second or more, you can actually just save the last time a player used a feature, then subtract it from the current time to get how long ago the player used the feature. From there, it's simple to make sure it has been more than x time. It looks something like this:

if (current time) - (the time the featured was last used) > (delay) [do feature, update last used time]

For accurate time tracking, we can use a feature in programming known as a timestamp. Timestamps are just like what they sound like - a stamp of the time it was used at. The most accurate type is to use System time milliseconds. Basically, the timestamp is in milliseconds. More technically, how many milliseconds have passed since January 1 1960 (known as epoch). You can use the function System.currentTimeMillis() to get the current timestamp in milliseconds.

We'll use the CooldownManager from earlier, with two changes. int (or Integer) type can't store a variable of that size, millisecond timestamps are stored in Long type variables. Simply replace occurrences of "Integer" or "int" with "Long" in the manager class. Second, instead of returning "0" if the map doesn't contain the cooldown timestamp, we have to use Long.valueOf(0):

return (cooldowns.get(player) == null ? Long.valueOf(0) : cooldowns.get(player));

With this method, our CooldownCommand class should look like this:

Code (Text):

public class CooldownCommand implements CommandExecutor {

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        //Player only command
        if(sender instanceof Player){
            Player p = (Player) sender;
            //Get the amount of milliseconds that have passed since the feature was last used.
            Long timeLeft = System.currentTimeMillis() - CooldownManager.INSTANCE.getCooldown(p.getUniqueId());
            if(TimeUnit.MILLISECONDS.toSeconds(timeLeft) >= CooldownManager.DEFAULT_COOLDOWN){
                p.sendMessage(ChatColor.GREEN + "Featured used!");
                CooldownManager.INSTANCE.setCooldown(p.getUniqueId(), System.currentTimeMillis());
            }else{
                p.sendMessage(ChatColor.RED.toString() + TimeUnit.MILLISECONDS.toSeconds(timeLeft) + " seconds before you can use this feature again.");
            }
        }else{
            sender.sendMessage("Player-only command");
        }

        return true;
    }

}


 

Already much shorter, and the variable is only updated when the feature is actually used!
You'll notice I used a Java util method you may not have seen before - TimeUnit. TimeUnit is extremely helpful, especially if you don't want to convert time units yourself. In the above example, we used TimeUnit.MILLISECONDS to tell TimeUnit the input variable will be in milliseconds, then used toSeconds() to get the output in seconds.

With a bit more math, you can convert to hours, subtract the hours from the initial variable, then convert the remainder to seconds. It does take some playing around with to get it down to perfection. There may be some available libraries or functions by other users that does this for you, however.

Making Time Calculations with Java Timestamps: The best performance-friendly solution to cooldowns

Awhile ago, while trying to become more active in the Spigot community offering help and discussing different methods of accomplishing things, I email subscribed to the Plugin Development section. I now get an email for every post, which occurs atleast once every few minutes. This means I'll probably have to get a new hard drive months before I normally would've, but atleast I can catch posts that are intriguing or spark a train of thought in some way.

For some strange reason, atleast one post a day is someone trying to add a cooldown effect to some tool or ability - basically, a player must wait x seconds before being able to use a feature again. 

People don't seem to be able to use the search feature on the Spigot Forums before posting.

People don't seem to be able to use the search feature on the Spigot Forums before posting.

I can't help myself from responding to them as I see them, so instead I'm making this handy-dandy post with everything you need to know about how to create cooldowns, common pitfalls to avoid, and case examples.

Option #1: Repeating or delayed tasks

This is what I see getting most suggested after using timestamps. Basically, when the player uses the feature for the first time, a variable is set putting a player's UUID and the amount of seconds until they can use that feature again into a map, and a repeating task is started using Bukkit's Scheduler. In that task, the variable is decreased by 1 every second. If the player tries to use the feature, it will get the seconds from the list and if it's more than 0 it'll tell the player it has to wait <x> seconds. 

Why this is an awful method

When using countdowns of any kind, it's always tempting to use repeating tasks. It looks like it makes sense, right? In reality, it's not very performance friendly. First, it's not a good idea to have too many tasks running at a time, as a thread is created for every task. Second, you're changing a variable every second. That doesn't affect performance too much, but there are methods that are much more performance friendly. The main issue, though, is that tasks are just a little weird to deal with anyway. They need to be cancelled when no longer used, and a whole class is needed aswell, with a reference to either the task ID or it's actual object (thought it can also be cancelled from within the task itself). Using tasks should be a last resort, they just aren't a very code-clean method.

Option #2: Timestamps

The only reason you don't see timestamps as a solution to time tracking is that they can be a little difficult to wrap your noggin around the first time you hear about it - it's a little less beginner friendly, but much, much cleaner once you get the concept.

What are timestamps?

Timestamps are very simple by themselves. Simply put, it's the amount of milliseconds that have passed since January 1st, 1970. It's used by all systems. For example, your system clock runs off of that timestamp, and simply translates that into whatever format it requires. You can get the current system timestamp by using System.currentTimeMillis(). As the variable won't fit in an int type variable, it must be stored as a Long.

How it works

When a player uses the feature, their ID and the timestamp at that time is stored in a map inside a manager class. When a player attempts to use the feature again, you can use the equation <currentTimestamp> - <lastFeatureUseTimestamp> to get how many milliseconds have passed since the feature has been last used. From there, you can convert that into whatever time format you want to check it against the required time before the player can use it again.

In order to make time conversions easier, Java has a util class called TimeUnit. To convert milliseconds to seconds, for example, you can use the method TimeUnit.MILLISECONDS.toSeconds(<ms>). 

As you can tell, it is very performance friendly, so much more so than the previous method with repeating tasks. The variable is only set once, and it's even only checked or changed when the player attempts to use the feature. 

Potential issues and how to fix/avoid them

The only issue with this method is that it becomes a memory leak. It's very easy to solve, however, with these two fixes:

  1. On PlayerQuitEvent, remove them from the cooldown manager map
  2. If they use the feature and the cooldown has expired, remove them from the map

You'll notice how much easier it is to handle cooldowns, and with this method you also have the option to display it in whatever format you want.

Google Analytics Integration with Minecraft Networks

Analytics data for a BungeeCord network averaging 15 online active players.

Analytics data for a BungeeCord network averaging 15 online active players.

I recently went through Google's Beginner and Advanced Google Analytics courses, then went on to get a certification for Google Analytics. In the process, I learned the power of Analytics and some of it's API features which I wasn't aware of previously. 

Google Analytics has a few different APIs for different purposes. By default, GA tracking code works as JavaScript that is loaded by the client went visiting a website. When the code is loaded, it sends page hit events (among other data) from the client to GA. That's how the most basic tracking works. However, there are cases where you don't have access to the client, as in the case with video game clients. You do, however, have all the info you need (session time, event hits, etc). Designed especially for such occasions, Google has a fairly simple HTTP API called the Measurement Protocol for GA.

It's extremely simple, and doesn't require any kind of authentication. Send a request to the endpoint with the tracking code and hit type, and it'll get processed by your GA property. 

Because it's so simple, I wondered how it might be useful to integrate with Minecraft Networks. Think about it - players are equivalent to users, pageviews to servers on a network. If you pass a player's UUID as the identifier for GA, you can also track new vs returning players and even bounce rates! That's just the tip of the iceberg, however.

Using the same measurement protocol, you can also record events from a player. One very useful event, for example, is the server vote event. This occurs when a player votes for a server on a server list. Combined with goals, you can then track what percentage of players vote for the server. If you add a label to the event, you can also track which voting sites are the most popular. 

Another useful goal are donations/purchases on your network. You can track the conversion rate - what percentage of active players make a purchase in your store - and which ranks/features are most popular among players. 

One more less obvious feature that several network owners requested was the ability to track player-community engagement. At the most basic level, you can see how many players interact with the community (by the amount of chat messages they send), especially useful if you segment new players only. If you have a high bounce rate (70% or more) and low to none new player engagement it could mean players feel foreign to the community or don't feel welcome.

An obvious question at this point is, how is this useful
As with website Analytics, it's not terribly useful on it's own. However, when paired with changes you make, it's very useful. One of the most common issues with a community not increasing is that the bounce rate is very high - players quit without really playing anything. Many networks get a new user nearly every hour, which means between 20-40 new players join every day. And yet, the average player count doesn't increase (or increases only very gradually). This means there is a very high bounce rate, most servers I play on see about 90% or higher rates. And yet, they work hard to increase the server rank on vote lists and even spend money on advertising. If they managed to decrease the bounce rate to even 50%, they could see an increase in average player count of ~10 players every day - a large increase for Minecraft networks. 

As with websites, people with a very short attention span - according to recent studies, about 8 seconds before we lose interest. That means you have 8 seconds to grab the player's attention with something immediately playable. Most networks have a large, fairly empty hub that looks great design-wise but does not compel the new player to make a decision within 8 seconds. Instead of a large hub, networks can see a decreased bounce rate by immediately jumping the new player into some sort of interactive story or a call to action. 

With Google Analytics, you can make such changes to the new player experience, then track the difference very easily. At an advanced point, you can even use A/B testing to find out which new player experience system works the best

 

I've already created a Google Analytics tracking plugin, and convinced my friend and the owner of a small network called ClownerCraft to install the plugin for testing purposes. It recently went active, and has been working very well. I also discussed using this plugin for larger networks (~80+ average players) with a developer friend, and he was so attracted by the idea he went beyond installing the test plugin on the network he works for to getting feedback from other network owners. I hope to increase the potential for this integration plugin, and in the near future it may see use on many upcoming networks.

You can check out the source code for the BungeeCord network plugin in it's current state on my GitHub account.

Programming Minigames

Every minigame I make are very similar internally.

Each minigame has a Game class, which has a game loop and methods such as addPlayer(), removePlayer(), startGame(), etc. Minigames normally have the following:

Game loop: This is called every second. It's used to track things like the countdown, or even checking if the game still has enough players to keep playing.

Add or Remove player methods: These are used when you want to add or kick a player from the game. When you add the player, it saves the player's inventory, location, exp, hunger, and health to be restored once the game has ended. It then clears his inventory, then adds any items needed (armor, weapons, etc). It then uses the sendMessage method to notify users ingame that a player has joined. This method is normally called when the player sends the join command, or when they interact with a join sign.

Send Message: This one is simple. In fact, it's only 3 lines. It takes a String as an argument, and sends a message with a specially colored tag with the name of the game to all players along with the String argument.

End and Start game: These methods control when the game starts or ends. The Game Status is an enum, typically GameStatus.WAITING or GameStatus.INGAME. These are used with listeners. For example, if I don't want a player to be able to move unless the game has already started, I could just cancel his movements if the game he is in has a status of WAITING. The Start Game method sends a chat message to all players, and sometimes executes a bit of code when deciding teams or giving special items depending on the team. A good example of this is when I made my Infection minigame. Two out of all the players are selected to be infected when the game starts. It's also then that they are given items depending on whether they are infected or not. The end game method is used when the game has ended (not enough players, or all players eliminated, etc) or when the server is stopped. This one gives back the player data saved during the AddPlayer method and resets the countdown timer and GameStatus.

As well as the Game class, I also have the GameManager. This contains some useful functions, such as getGame(ID). When a new Game instance is created, it is registered with the GameManager. When registered, it goes into a list of games. This list is accessed by the Main class, which then calls a doSecond() method in every Game instance. The GameManager also has functions for getting whether a player is in a Game, and even getting the Game a player is in.

Launching a Minecraft MiniGame Server

For a while now, I've been working on setting up a server for someone and making coding minigame plugins. The server was finally opened yesterday, and I'm satisfied with the work I did.

The server has one main minigame, Infection. This is a simple game where there are two teams; the infected, zombies, and the humans. The infected have to try infecting the humans, putting the humans on the zombie side. The humans have ranged guns, with no melee, whereas zombies merely are super powerful but on melee. This creates an interesting combination, where the humans have to shoot the infected before they can get near enough the infect.

The humans can use three guns; a shotgun, which is really bad accuracy (only usable at less then 5 blocks range) and a high recharge time (meaning you only get one shot) but can kill zombies in one hit, a sniper rifle which can kill zombies immediately if you get a headshot, and a machine gun which fires tons of arrows at once with no recharge, but low accuracy/power.

Infection is probably the largest plugin I've worked on, but not the first minigame. The first minigame plugin is called Banana Tag. In real life, Banana Tag is a game where all players can tag each other. Once tagged, the player has to crouch down, meaning he/she cannot move. To become untagged, the player who tagged them must be tagged or they can try tagging someone who gets near them. I used the basic mechanics and put them into a Minecraft minigame. To tag a player, you need to hit them twice. Once tagged, they sit down on the ground and cannot get up. The winner is the player who has tagged every player.

Beam Interactive with Minecraft

Beam.pro is a fairly new streaming service, similar to Twitch.tv. It allows people to stream their gameplay for viewers to watch realtime, and interact with via chat. Beam was released with less delay between the client and viewers, as well as a thing called Interactive mode.

Interactive mode allowed the streamer to setup a control panel of buttons and joysticks, as well as track viewers mouse movement on the streaming screen. Then, they could allow the viewers to interact with the streamer via the buttons. The most common use is in Minecraft. One button might teleport the player to a random position close to where they were, while another might give him a random item, useless or rare.

In order to limit the amount of times these buttons could be used, Beam also introduced their own kind of currency, or points. These points could be used on the buttons, while earned overtime by watching streams or streaming themselves.

Currently, though, Beam Interactive is in beta. This is because in order to use it, you need programming knowledge to connect to Beam's API and receive data about the buttons. Then, in order to interact with Minecraft, you need to use plugins or mods to then change the Minecraft world. Beam did release an interactive app for Minecraft, but only with set controls and commands.

I decided to make a Beam Interactive Minecraft mod. It would allow you to set Minecraft commands to each button. Now, one command doesn't seem like it can do a lot. However, with the /setblock command, you could easily trigger tons of command blocks, making the possibilities endless.

After getting lots of help from Beam's developer channel, I was able to make a simple mod. It got the IDs of all the buttons, meaning you just needed to set what they did in a text box. Then, you could load and save the control layout, with up to 3 save slots. That part was my favorite, and my first time implementing a save/load mechanic in any program.

The mod isn't available for download just yet, but it should be soon in the next few days. You can check out my Planet Minecraft member page to see when I release it.

Minecraft Modding: Storing custom NBT data

So for a secret idea for a mod, I was learning how to store data on a player. The best way to do this that I know of would be to use NBT data, which is saved on the world per player. NBT data can include many things about the player, like health, potion effects, hunger, strength, etc. It is more commonly used in entities, for things like velocity, age, speed (for horses). You can often see this when you use the /summon command for mobs with custom data.

I was having lots of trouble, starting with getting the NBT data of a player upon joining a worldserver (single or multiplayer). If the player didn't have my custom data stored on him/her, it would create the data with a default value. This is almost only used when a new player joins the worldserver. However, the function that I was using (player.getNBTTagCompound()) was giving me a bit of trouble. Every time I tried using the hasKey() function (to test whether the player has a certain bit of data), it crashed. I led this down to the fact that the getNBTTagCompound function was actually returning null. To see why, I looked at the vanilla function for this.

Guess what? The function had a single line of code. "return null;". WHAT?!? Why on EARTH would you have a function return null, unless you purposely wanted it to crash the game. It might have been there because the Mojangsta working on updating that found too many dependencies on that function and lazily didn't fix the errors by updating the code; he simply made the function return null. And, as it turns out, that didn't cause any problems. Until now, when it was extremely misleading.

Anyway, I found a function called readFromNBT() which accepted an NBT tag. I assumed from how other people used this function that it would basically input the NBT tag I put into the function with all the data values of the player. This would mean creating an empty NBT variable, then using readFromNBT to input it with data.

As it turned out, I was half right. There was another function, writeToNBT() (again, taking an NBT tag variable) which I assumed would apply the NBT tag to the player. Like I said before, I was half right. Every time I joined the world, it set me to 0,0,0 coordinate position. It really confused me. Then, suddenly, I facepalmed. Of course, duh. I got the functions mixed up. The writeToNBT() function would write the player's data to a variable, while readFromNBT() would take the data of the variable and write it to the player.

I haven't yet gotten a chance to try it out, but I'm looking forward to it tomorrow.

Scarab's Missing Furniture Mod

So about a week ago, I decided to get back into modding with 1.8. This time, I followed the tutorials on YouTube by MrCrayfish, and it was pretty simple. He didn't get into too much detail, but I'd already had some experience with 1.6 and 1.7 modding already.

That night, I had the idea for a furniture mod. Not just any furniture mod, and not one that copied mods like MrCrayfish's and other people's famous mods. Instead, I would add the small things that they missed, as a sort of addon to the other mods. In 3 days, I got 2,000 downloads and 5,000 views, as well as lots of comments.

The mod started when I was building a Minecraft house. It was a lakeside house, and I was just building the back patio over the water, when I realized there wasn't anything to put on it furniture wise. It needed a deck chair, which wasn't in MrCrayfish's furniture mod. Solution? I created my own. Then, I added a monitor, and an espresso machine. Nice little decoration blocks for around the house. It started with about six blocks, which were just plain models with no function. I released it on the Minecraft Forum, but got no response and only a few downloads. Then, I put it up on Planet Minecraft. Checked back about an hour later, and I had more then a hundred downloads. I immediately realized that I had better update it with more function and features, while it was still popular.

I added coffee, function to the espresso machine, video on the monitor, a ceiling light, a 3D printer, and lots more. Every day since I've released it, I've managed to release an update.

Probably my two favorite parts about the mod is the 3D Printer function, and the recently added update notifier. The 3D Printer function is simple. Just right click the 3D Printer with printer filament, and you get a random player's head. It chooses the head from a list, randomly. This list is actually stored online in a Dropbox folder, and is downloaded every time the game is started. I also added an option for people to donate, and get their username to the list of players that it can choose from.

The update notifier is equally simple. In another text file on Dropbox, there are four lines of text. The latest version number, the latest update name, the latest changelog link, and the direct download for the latest update. When you open a world, it will check if the version in the online file is later then the mod's own version. If it is, it sends a chat message notifying the player of a new update. It includes links to the changelog and download, so usersdon't have to go find the mod page again.

You can view this mod by clicking here.

Pi Wars Podcast Episode With The Raspberry Pi Guy

For basically the first time, I got to talk with someone on my podcast, Kids Who Code.

And of course, the first person I talked was the well-known Raspberry Pi Guy. It went very well. We talked about Pi Wars, an event in Cambridge, UK where Raspberry Pi powered robots compete in (non destructive) challenges. He talked about some of the challenges, like the proximity detector challenge where your robot has to get as close to a wall as possible without actually touching it. He attended the event (he didn't participate though) and told me about some of the robots that he had seen and what they did. It sounded quite interesting. You can listen to it here:

Top 3D Printing Problems (Check For Them Before Starting a Print Job)

When 3D printing, it is NOT going to be easy. It's not as simple as loading the 3D model, slicing the 3D model, and printing the sliced model. There are many things you have to look for before starting a 3D print, such as ambient and bed temperatures, or Z Calibration. Here are a list of the top <some amount here> problems!

  • Heat bed is too cold: When the heat bed is cold (or at least not hot) 3D prints tend to warp. Warping occurs when the bottom of the print cools faster then the top, and expands. A hot heat bed keeps the print on it warm on the bottom, where it would typically get cold from the ambient temperature of the environment.
  • Heat bed is not level: This is a rare problem, and shouldn't normally occur. However, sometimes you may notice that the nozzle is printing too high above the bed and at other places it is scraping the bed. This usually means that the bed is bent in such a way that on end of it is bent upwards while the other end is bent downwards.
  • Ambient room temperature is low: When the room temperature is too low, it will cool the heat bed. Heat beds are usually very weak anyway, and won't stand up to a cold room.
  • Not enough adhesion: When your prints are coming off of the bed during printing, it probably indicates that you do not have enough adhesion for the print to stick to the (heat) bed. When adding adhesion, you will need to use some sort of tape (so as not to dirty up the actual metal bed).
  • Z Calibration is wrong: You will notice this when either the nozzle is scraping into the bed or it is too high above it and the plastic is not touching the bed enough. You have to calibrate it every few weeks, to get perfect prints. Usually, you have to get this correct within 0.05 of a millimeter.
  • Bigger 3D Prints Are Warping: This is common, and mostly happens because the middle of the heat bed is where the heater is, and is a lot hotter then the outer edges of the heat bed. Also, it has a lot more space that can be hit by a cold draft.
  • Under or Over Extrusion: You will notice this when the 3D prints have bits of plastic sticking up above the current print layer, or plastic wrapping around the nozzle. This means it is printing too much plastic at a time. For under extrusion, you will see very thin wallsthat aren't even very solid.

Pragmatically Programming

Programming and life are two very different things, right? When you do programming, it's either yes it works or no it doesn't. If it doesn't, you go and fix it. You program something, and there is always one way to do it.

As it turns out, this is not actually the case. Programming and life are actually very similar. When you do programming, there might be two ways to do something. And, when having a team of programmers, it is even more important that you code things CORRECTLY. Sometimes, you might get the end result you wished for, but your code is incredibly messy that anyone trying to edit it would be completely lost in it all, and even you yourself might find it difficult to fix problems. One good example of correct programming is going by the DRY principle. DRY stands for Don't Repeat Yourself. While this may seem like a hard principle to get wrong, you may be finding yourself copy-and-pasting code or writing similar methods. The opposite of DRY code is WET code, which stands for We Enjoy Typing. Don't write WET code. Whenever possible, write methods and use variables.

For example, when writing a Minecraft plugin, you would probably want the text "[CoolPlugin]" (or whatever the name of your plugin is) before each message it sends to the server, like "[CoolPlugin] ScarabCoder left the game". You could make it do something like:

server.sendMessage("[CoolPlugin] Player left the game")

However, you will find you are repeating yourself if you write this way. For every server message you want to send, you will be writing "[CoolPlugin] ". Sure, it might do what you want, but it'd be really, really messy. Imagine the horror you would have to go through when you wanted to change your plugin name from "CoolPlugin" to "AwesomePlugin". Search-and-replace? You would probably still miss something, or probably replace the wrong text. Instead, use the obvious answer; variables. That way, if you wanted to change the plugin name, you could just make a global variable (a variable that is accessible from any part of the program. Languages like Java use this) that would equal to "[CoolPlugin]":

pName = "[CoolPlugin] "
server.sendMessage(pName + "Player left the server")
server.sendMessage(pName + "Player joined the server")

See how much simpler that is? But wait, you are still repeating yourself! You are writing "pName + " before each server message. It's time to create a method. Methods allow you to do things like "sendServerMessage(message)". You can accept inputs, and it is really easy. Not only that, but you could also do something like "logAlert(message)" or "logError(message)", which would send a server message in different colors (red for error, orange for alert, etc). Example:

method logError(message){
  server.sendMessage(color.red + pName + message)
}
logError("server crashed!")

Woooaah! You just cut down the amount of characters you are using by a ton, and made it so much easier to configure your plugin. If, for example, you ever wanted to add another prefix to your errors, you can add that simply in the method.

 

This also means you shouldn't be writing "hacky" code anymore. Hacky code is code that you are using shortcuts or code that might be a bit sketchy and may break with newer versions. You shouldn't be writing this kind of code, and make sure you keep it far away. The temptation to take small shortcuts like this without even checking for another way gets strong, believe me.

Buycraft

Many servers actually run off of player donations, and some people are even able to live off the extra money that doesn't go into to the server! But how does this process work?

You may have seen shop pages for servers. If you haven't they typically look like this (EcoCityCraft's Shop). If that seems familiar, it should. In fact, almost every server webstore will look similar to this, this, or this (HiveMC, ClownerCraft, and The Chunk store pages). They are all powered using a service called BuyCraft. BuyCraft allows you to setup a webstore, and then send custom commands to the server when you buy a rank. For example, I could create a "package" (or virtual product) that, when bought, would send multiple server commands to set a player's rank, give him ingame money, and broadcast to the server.

It has many, many features, and extremely customizable. Not only can you edit the default CSS of multiple themes, but you can even edit the HTML too! This means that you can have a completely custom store that makes easy updates every time you add a package. Another cool feature is that you can have subscription packages which can charge the buyer after a custom time, and can send commands each time. This could work for temporary ranks that you would have to pay a monthly subscription to, and, when the subscription expires, would demote the player back to the previous rank.

Buycraft is free, though with many limitations unless you upgrade to a different plan. For example, the free plan only allows one payment gateway (the method through which you receive payments) and five packages. The next plan costs ~$6 a month, and allows you to have unlimited packages, categories, and gateways, but only allows you to earn $2500 or less per month. The final plan has many more features for huge servers, and costs ~$30 a month.

I setup a quick webstore, partly for the idea of Mine Monthly Events that I had, and partly to test some of the Buycraft features. Currently, the packages actually do send commands to the server, but the server itself is a local one (you can't join it). You can visit it here.

Mine Monthly Events Idea

I haven't been using my server subscription with CubedHost, and I had to cancel it. However, I recently had the idea of doing events similar to the StarWars event on May 4th. I had quite a lot of people signing up for it (nearly forty people), and it was lots of fun. I enjoyed doing it, and would do it more if I could get the money to pay for the server. And, due to the fairly large amount of players on the server and probably because there would be lots of explosions and mods, I would have to get a server with a large amount of memory to keep down the lag. For the Star Wars event I used 6GBs of RAM, and it cost $40 a month. There was no lag at all on the server, so I could probably have done with 4GBs.

I had an idea that would both let me hosts events, and take care of the cost for paying for the server. I could host two events every month (or, if I couldn't get enough people, just once a month) and only allow people to play every other time. If they wanted to play every time, they could buy a "ticket" for just $2 USD and use that. That way, probably at least half of the cost of the server would be payed for. If I could set up a subscription service, I could be hosting the server for free (of course, I would still have to set up the events, but I enjoy that).

There are also many events I could host, all of them would probably be about some famous (family friendly) movie, such as Lord of the Rings or Star Wars. I could repeat certain themes but at different places, and maybe even follow some of the battles in these movies.

PiPad - A Raspberry Pi Tablet

Recently, the Raspberry Pi company released the long awaited Raspberry Pi Official 7" touchscreen. Almost as soon as I saw it, I knew I wanted it. I already had the Adafruit Powerboost 500, and I immediately had the idea of creating a Raspberry Pi tablet.

I have a 3D Printer, so I was able to find a nice 3D model on Thingiverse and quickly printed all of the pieces. When putting them together, I had to use ABS glue to glue some of the pieces together, and then used several screws to put together the rest. It isn't perfect, but it is solid enough. I used the Adafruit Powerboost 500 and a battery, and also a short micro USB cord.

I haven't done anything software wise yet, but I definitely plan to. Probably I'll be using Kivy, because it is perfect for touchscreens (though PyGame would probably be easier to code). Several of the Python games that came with the Pi work with the touchscreen (the memory puzzle and slide puzzle), and my 4-year-old sister loves to play both. It can also play Youtube videos at a nice ~45fps, so it would do well as a media player. I'm looking in to some sort of Youtube downloader so that I can watch videos wirelessly.

Here is a video I took (sorry for bad quality, was using a phone at the time :D):

Learning To Program, Some Problems that People Have

Recently, I have seen different problems that people have had when starting to learn programming. 

It isn't that programming is very difficult, it is just that people assume too much. The main problem that kids have when learning to program, is that they do it expecting to make a simple game within a few days. Unfortunately, though, it's not about programming visually. They don't fully realize the fact that 'programming' is to write code similar to mathematics in a simple text editor, and not dragging and dropping objects onto a 2D or 3D plane. I found this problem when looking through a few Youtube (yes, I know, usually a bad idea) comments on indie game development or showcase videos. 

The way they see it, it is really easy. For example, this person implemented a variety of different attacks in a few hours. It may sound easy, but you have to really know all of these things. You can't expect half of the code (collisions, health, movement, etc) to be already written for you, so that all you have to code are the attacks and armor. My point is, you CANNOT start your programming with complicated 3D Java and Unity stuff. You have to start with things like Python, and get used to programming and it's methods. I've seen tons of people disappointed because they realize that they have to do a lot of things before they can create their game. It takes time, dedication, and work. 

Some people have the idea that creating game-making programs that are more like what kids would expect would help; however, I don't think that is what you need to do. This is why I dislike Scratch. Scratch is a popular animation and game maker, with things like logic. While there is no code written, you can drag and drop things like if/else statements, create variable, and so on. However, I find this a bit misleading. It is NOT programming, and one should not try teaching using a game or animation environment.

Most of these things I found out when trying to teach my (then) 8-year-old brother to program. I got him started with Learn To Program by Chris Pine, on how to start programming for beginners with Ruby. It was the same book I learned from, and even where I had gotten interested into programming in the first place. The book was not originally for me, it had been for my oldest brother. However, he was not very interested in it after a while, and eventually gave up. I picked it up, and started reading it. It was very interesting to me, especially creating text interactive games with input and if/else conditions. This was before I even played video games (three years ago, though, there was still Minecraft and other popular games), so I didn't have any big idea of what to make. 

When I gave it to my brother, he got about as far as printing text and if/else conditions before he had a problem. In a way, I expected it to happen. He was used to seeing me make Minecraft mods, walk around in a self-coded environment, and do many things with Minecraft Pi. I don't really know what he expected coding to be like, and there was no way I would have him get started with Java. He asked me when he could start doing things like what I was doing. Stuff like making games, and modding Minecraft. I tried to explain to him that it required lots of learning and work and memorization and practice to get as far as I was in programming (3 years of programming in total). 

For some people, programming can be interesting and fun. For others, it is a chore, like learning Algebra. You have to program not for the end result, but because you like doing it. If, for example, I only programmed to make a 3D game, I would lose interest fast. Doing all that 'work' of learning Java and it's methods wouldn't be worth it. However, I don't do it for the finished game. I do it because I like doing it, because it is fun for me. This doesn't mean that I'd lose interest in programming if I had to do it for work and the end result was the most important thing. In my mind, programming is what I like best, not the end result.

EcoCityCraft Minecraft Server

Recently I was looking for a Minecraft server to play on, and I wanted to play on a some fair, economic city server. Going through a few, I found some problems. The first had really bad staff (improper spelling and grammar is usually the first sign, not doing anything about people not following the rules is another), another was endless city that was really hard to play on unless you donated. This pretty much needs you need to travel hundreds of thousands of blocks to get to the end of the city (little or no warps), then travel much farther to find some wood or a material you could sell or use. Then, if you wanted to sell it (in order to buy a plot), you needed to find a person willing to buy. Most of the people one the server didn't bother with newcomers, so it was really difficult to get started. Finally, however, a few server listings down, I found a server called EcoCityCraft. I joined, went through a short tutorial (tutorials are a good sign that the server will cater to newcomers), then got started.

First of all, they had multiple worlds. One was the city world, and another was the 'wild' world. They set it up nicely, where the wild world got reset monthly. Griefing was frowned upon, but allowed, in this world (to prevent people from settling and getting mad when the world reset). PvP was disabled in all worlds except the Nether and PvP world.  I got lucky and when I joined, the wild world had been reset only a week before. Surprisingly, however, there was very little marks of people being there (aside from tons of marks of mining), so it wasn't hard to get wood. It was also awesome that you could use a command "/wild" that would teleport you to a random place in the world, meaning that there weren't any resources around spawn, you wouldn't have to waste hunger and travel far. 

The way the server is setup, you can rankup. The first beginning rank is Builder, then you can rankup to Resident when you earn enough money and read the rules and tutorials. After that, you can rankup to Mayor, which allows you to make a town/city, meaning you could rent/sell out plots or houses (called pre-builts) to players. Then, you could become a President, which meant that you could own two cities/towns. 

The players on the server were all very nice, and welcoming to newcomers. Right away, I was able to get a free apartment (usually fairly expensive, or at least not free) that was only available to newcomers and permission to use that city's farm. The reason farming is a great way to earn cash is because you can sell the produce to the server (instead of a player). This meant that one 'career' (or method of farming) would always sustain you at the same rate. That is opposed to selling to players. If you were trying to sell carrots, for instance, people wouldn't always want to buy from you. They also may as well make their own farms instead of repeatedly buying from you. However, when selling to the server (using a command), it would always give you the same amount per item. Then, you could really have a stable method of farming, and this also gives a stable economy to the rest of the server (prices for plots, for example, wouldn't sell depending on how much much money the average player has). 

The best method of farming (farming gave the most money, wood sold for very little and mining wasn't always dependable) was to farm cocoa beans, as they sold for a fair amount and were quick and easy to do with the proper tool. After about 15 minutes of farming cocoa beans in the town I lived in, I earned $1,000 Eco Dollars (the currency on the server). This was enough to buy a small 10x10 plot of land in the same town my apartment was in (prices change per town, but 1k for 10x10 was regular) right next to my apartment. However, I found out that once you buy a plot, you lose the apartment (probably because newcomers wouldn't be needing the apartment anymore if they have another place to stay. This was a rule for the specific town, however). I built a small business building (that I have only used as a small storage for now), complete with four stories and cyan-light blue glass windows. However, I did forget that the town had a max building limit (15 blocks) and mine went over it (17 blocks high), so I just had to lower it a bit. After some more more farming, I saw in chat (where people advertise houses, plots, jobs, etc) that someone was selling a lakeside house, and that it was the last one left in a row. I saw the house (donaters can use /tpa for teleportation), and immediately wanted to buy ,it. It cost $5,000 ED, and I only had $2k ED.  I was able to buy it for $2k, then pay back the $3k when I earned it (the amount people trust each other is nice, though if I hadn't paid it back the house would have been taken away. 

The last great feature about this server was the donation balance. There were tons of things you could donate for (including fly and teleportation), but while those seemed like big cheating things, it did not impede gameplay at all or even make it worse for non-donors. Most donators, in fact, helped other people who wanted to use the features (like helping teleport to each other). So though the donation rewards seemed huge, they did not seem to impede on gameplay much.

The Many Different 3D Printing Settings

To 3D print a model file, it must first be sliced. This process is where a model will get all of it's settings.

3D printing a 3D model isn't as easy as drag-and-drop. First of all, a 3D model file usually only contains mesh data (and sometimes textures). Where would you change the speed, quality, size, etc? For a 3D printer to print a model, the model must be converted into a different file that is a list of commands telling where the printer should go, at what speed, etc. The kind of programming that a printer understands is called gCode. 

When I slice a file, I use a program called Cura. You can most 3D model file types (like obj and stl), and then export to a gCode file. Of course, you should not consider the gCode file as a 3D model, or Cura as a model converter. When you import a model, you can choose many different settings. Some of them have to be specific to the filament or printer you are using, like the diameter of the plastic and the flow of how fast it goes into the extruder. Others, however, can be decided upon depending on the print itself (things like quality or whether or not to add supports). This allows you to get the right ratio of speed to quality, and sometimes you can print a high quality print in a short amount of times by choosing the right settings. 

The first setting in the list is the layer height. During the printing process, models are printed by laying one layer on top of another.  The layer height decides how many layers to fit into a space. The more layers, the higher quality, since the lines that you usually see on prints wouldn't be there. However, it takes longer since there are more layers to print. If you do less, then there would be visible lines on the print, though it does go faster since there are less layers to print. To little layers, however, and it won't bond with the layer underneath it. 

The next setting is shell thickness. This is how thick (or strong) the layer on the outside will be. The reason this is a setting is because sometimes you would want to print hollow models but don't want a weak shell, or even semi-hollow models. Usually, though, you wouldn't change this. Another setting is the bottom and top thickness. When printing with 50% infill, it creates a grid pattern on the inside without fully filling inside. The bottom and top thickness is how many layers to print before it starts the grid pattern and how many before the surface of the print is done. The fill density settings is next. The less you fill it, the more hollow it will be. When it becomes hollow, it creates a sort of honeycomb grid pattern inside. Less infill will drastically speed up the print, but make it feel cheaper due to light weight. The more infill, the longer the print will take. However, it is worth it for that strong plastic feel. This is where you could change the speed to a high amount, and fill the inside completely. 

The next setting is speed. This setting will change the time it takes to print the most. The value of this setting will most likely be specific to the piece you are doing. The higher speed, the lower quality, and it may be that the print could fail if this setting is too high. A lower speed helps the print hold together, and make it much stronger during and after printing. Sometimes, for large prints without delicate parts, I will make the speed very high. Usually, however, (especially for overnight prints), I will make the speed lower. Usually when quality matters or time doesn't. The next two settings are the nozzle and bed temperature. These are specific to the plastic you are using, and once you can find a nice temperature (or use the default) you usually wouldn't change it again.

A really nice option is an option to add supports. Due to the way printer do their printing (layer on top of layer), overhangs do not print well (if at all. Floating pieces don't print).  However, when you add the supports option, it adds a weak and easy to remove support underneath overhangs and floating pieces. This wastes a tiny (very tiny) bit of plastic, though the main problem is that it takes longer to print. However, for overhangs, it is necessary. Probably one of the big satisfying things of life is digging into a print with pliers and removing the supports. The collapse when pressed, making them come off in chunks. Normally, though, you wouldn't use supports.

Another option is the platform adhesion option. You would use this when dealing with warping and/or prints not sticking to the bed. The raft adhesion option prints a raft (hence the name) underneath the model, meaning that it warps instead of the print. It also means more of the print is touching the bed. Like the supports, it comes off of the print fairly easily. The next option is the brim option. It is similar to the raft, except instead of adding itself under the model it wraps around the model, sort of like a skirt. It prevents warping better, but not so much with adhesion problems. Both options take a lot longer to print, so it is better to get a heated bed or use a better adhesion solution (like ABS slurry).

There are some other more specific options, like the speed at which parts of the model print at, but almost all of the others have values specific to the printer.

OctoPrint

Usually, to control your 3D printer and start prints, people use their computers or an SD card. However, they both have their limitations

The problem with 3D printing with a computer is that the computer has to stay connected to the printer. This means you can't really move the computer, and there are tons of situations in which you wouldn't want to be working next to a 3D printer. One of them is the slightly toxic smell of ABS plastic or Acetone. 

The problem with 3D printing from an SD card (you can plug an SD card into the printer, that has a file that the printer can print with) is that you have very little control over the printer. You can't view the temperature, the progress, you can't (properly) cancel prints or pause them. In fact, if your print does fail, the only way to stop the printer is by unplugging it. This is never advised, and usually means you have to power cycle the printer to get it to work again. 

Obviously, the majority of the people who own 3D printer don't use the above two options. But what do they use, then? The answer is a simple, $35 programmable board. Namely, the Raspberry Pi. There is a program that you can install on the Raspberry Pi called OctoPi (the project name is OctoPrint, but the version for Raspberry Pi is called OctoPi). All you need is a power cord for the Pi, an Ethernet or WiFi dongle, and another cord for connecting the Pi to the 3D printer. You can also get a camera module to view your current print (live!) and record timelapses.

What does it do? Well, it creates a whole online UI from which you can control your 3D printer. Normally, you can only access the UI when connected to the same network as the Pi, but you can set up a port forwarding system, allowing you to control and view your 3D printer from anywhere in the world, as long as you have internet connection. In some cases, for example, you would want to print a 70-hour object (things like helmets and exoskeleton pieces, mostly). You could have the 3D printer running while you go on a small trip to your grandparent's house, but if you used a computer and the print didn't go correctly, you could come home to a big mess. However, with OctoPi, you could view your prints (even on the road) and make sure everything is going correctly. The only thing that is missing that would make things really automated is a way to remove prints without actually being there.

There are many other things you can do with OctoPi, too. For one, you could upload your "slicing" (things like the speed and temperature of the printer) settings to OctoPi, and then it would turn your 3D model files into 3D printer files. This way, if you used a different computer, you wouldn't have to worry about copying all your settings over. OctoPi also has a gCode viewer, meaning you can view what the print will look like by viewing each layer individually. It also syncs with the printer progress, so you can see what it is supposed to be printing. Not only that, but it has a plugin system. There are currently about 20 different plugins you can get (things like model viewers), but the plugin API is very new so there could be many more coming. 

It also has a login system, so you don't have to worry about showing other people your 3D printer UI page. They can view the status of prints, view the print going live, even download timelapses, but they cannot control the printer or it's settings. This means that if you have a fairly large following, you can let other people see your 3D printer working! Also, with the plugin API, you could code a plugin that automatically shares timelapses to your social media. The timelapse feature on OctoPi is very nice, and timelapse settings are very configurable. Currently, I have my settings so that every time it goes up a layer it takes a picture. The effect is that the print seems to "grow" upwards. When you think about it, it used to just be a picture on a computer, and it has now grown into a real life object. Here is an example of a timelapse:

Installing the new Ubis 13 Hotend

Printrbot recently released a new hot end for their 3D printers, and can print with a lot more detail.

The hotend is the nozzle of the printer, the part that contains the extruder and the part that melts the plastic. Some nozzles are more detailed, some of them can handle more heat. This nozzle is way more precise, and even cheaper to make too! I ordered the new Ubis 13 hotend from Printrbot about a week after it came out. Looking at the instructions online, it seemed only mildly difficult to put together.

Normally, I would have my older brother put it together (he put together the heat bed). That is because every time I have ever tried installing or soldering any kind of hardware, something gets fried. However, it looked like there was little risk of things going wrong. After all, I only had to plug four things in; what could possibly go wrong? At first, nothing did go wrong. This hotend requires a fan to function correctly (if not, it jams), so I had a little extra work to do. I plugged both cords of the fan into the Printrboard (the PCB in the printer). Then, I removed the hotend I used previously (when I got a good look at it, it seemed really beat up and dirty). I screwed in the new hotend easily, then after a little bit of trouble I connected the hotend cords to the new hotend.

Finally, the moment of truth. However, it was not to be. I wasn't able to connect to the printer (it was spotty before anyway) using OctoPi, or any other computer. Then, I tried reflashing the firmware of the Printrboard (the software built into the printer), but even then I wasn't able to connect to it (which is supposedly impossible if it was functioning). I tried printing from an SD card (in case the micro USB input on the printer was broken), but that didn't do anything either. I thought that maybe my horrible luck when it came to putting things together had come back, and I had fried my 3D printer. 

Finally, I disconnected the fan and hotend cords from the printer that I had installed, and suddenly I was able to connect to the printer again. It crashed immediately, though, saying there was no extruder. I plugged the hotend back in, and the printer was functional. I was able to do everything like heating up the bed, extruder, moving the head, etc. However, it would melt the hotend if I tried using it without the fan, so my problems still weren't solved. 

After connecting the fan again, I was able to connect to it again but the fan wasn't functioning. Whenever the printer is on, the fan is supposed to turn on. I have a feeling that either the fan was broken before I got it, or I broke it when trying to connect it. Strangely, though, no one else had my problem.