25,000,000 blocks

Using the Bukkit Scheduler In ScriptCraft

In this post we’ll use the Bukkit Scheduler to decrease the likelihood of our Minecraft client being dropped while performing computationally intensive tasks in our ScriptCraft code–tasks like building gigantic structures. As an added bonus we also get to watch our huge structures being built (rather than just poofing into existence as they currently do). Poof!

MCMap Live Shot For Perspective (the jagged tops are an artifact of the rendering software).

MCMap Live Shot For Perspective (the jagged tops are an artifact of the rendering software).

From what I can gather ScriptCraft currently performs all of its work in the main server thread. The main thread also takes care of a number of important tasks including the networking logic which manages the connection to your Minecraft client. Now, running on the main thread isn’t a problem in itself, it only becomes a problem once you start doing some heavy lifting like rendering a 500 x 100 x 500 rectangular prism (at least for my little server):

25,000,000 blocks (most clipped beyond the horizon)

25,000,000 blocks (most clipped beyond the horizon)

If your ScriptCraft code is gobbling up too much time you’ll end up seeing this screen:

Dirty Screen

Dirty Screen

I see it frequently.

One way to decrease your chances of seeing the old dirt screen is to punt off your ScriptCraft tasks off into another thread thereby giving the main server thread a little breathing room. Here’s an example of using the schedule to draw a large rectangular prism:

As you can see it is only a few extra lines of code and doesn’t add too much complexity. We get a reference to the scheduler and call the scheduleAsyncDelayedTask method supplying a reference to the ScriptCraft plugin and the task we wish to run.

Now a async delayed task isn’t the only type we can use in our ScriptCraft–in fact sometimes we shouldn’t use it. All in all Bukkit allows us to schedule four different types of tasks:

  1. Synchronous Delayed – Schedules a one-time task to run in the main thread with an optional delay.
  2. Synchronous Repeating – Schedules a repeating task to run in the main thread on a specified period with an optional delay.
  3. Asynchronous Delayed – Schedules a one-time task to run in a separate thread managed by the scheduler with an optional delay.
  4. Asynchronous Repeating – Schedules a repeating task to run in a separate thread managed by the scheduler with an optional delay.

 

In our example above I scheduled an async delayed task and you can too as long as your task is thread safe and doesn’t utilize the Bukkit API (so far all I have done with just ScriptCraft and JavaScript has been fine). If you need to use the Bukkit API inside your task, then you will have to use a synchronous task or just run your ScriptCraft code like you always have. You can also find out more about the Bukkit Scheduler in the Doxygen docs.

Finally, remember this is no silver bullet! If your doing too much work and your server can’t keep up nothing will save you from being dropped.

Advertisements

ScriptCrafting A Quest In Minecraft

Below I will use the Bukkit API to implement a simple quest, including a quest-giving NPC, objective, and reward.

Spawn Quest Giving NPC

First we need to spawn the NPC who will offer the quest to players as well as give out the rewards. Creating an NPC with Bukkit looks like this:

The above will create a Villager NPC, which isn’t ideal because every time we right-click him he will show us his inventory, but it will work for this tutorial.

Track Quest Progress

So now that we have an NPC, we need to give it a memory so it can track each player’s respective quest progress. To save each player’s current quest progress we save the index of their state in a array where each key is the player’s ID (similar to what we did in the Wolfbot post).

Let’s also create a method which initializes another hash that maps quest state to a blurb of text we want the NPC to spit out when interacted with by a player:

As you can see from the code our quest involves a gang of skeletons who are running amok nearby. The quest is for the player to simply kill 10 and then return for their reward. Of course we are still missing the logic that will cause the Villager to spit out the text and drop the rewards if the quest objective is met:

Watch For Quest Completion

There are only two bits of code left to round out our quest logic. We need a command for the player to accept the quest and also a listener to watch for skeleton deaths–specifically deaths that were at the hands of our questing player:

The full code list can be found at the end of this post. Drop that code in your js-plugin directory and you can start questing:

  1. /jsp spawn_npc
  2. Right-click to move through the quest prompts.
  3. /jsp accept
  4. Go hunt down and slay 10 skeletons.
  5. Return to the NPC and claim your XP reward!
Skeleton Menace

Skeleton Menace

Next Steps

There are a number of improvements you can add to this ScriptCraft plugin; however, if you really want to put time into creating quests I would recommend checking out the Citizens plugin which is much more powerful and lets you script NPC interactions with YAML. There is also a helpful repository with script examples.

Here is our little quest plugin in its entirety: