Introduction: How to Create a Minigame Using Javascript on a SpigotMC Server
In this tutorial we will show you how to create a minigame for Minecraft using the Scriptcraft plugin on the SpigotMC server.
But first let's take a step back. There are various versions of Minecraft that work on different devices and operating systems. Our tutorial is aimed at all those who own a PC. During the tutorial we will refer to the installation of the server under Windows, but the operations we do (except the installation) are the same for the other operating systems (Mac and Linux). The knowledge of javascript (the language used by browsers) is also required in order to write the code; in the tutorial we will show some interesting links on which you can become acquainted with the syntax and the use of the language.
One last note: the SpigotMC server we are using for this tutorial allows you to play Minecraft version 1.12.2. However, the information in the tutorial can be valid for all servers running Minecraft from version 1.10.x to 1.12.x and later.
Let's start.
What is a Minecraft server
When we launch the Minecraft game the program activates two sections of the game:
- a client that displays the interface and the window on the world
- and a server that manages the structure of the world and the interactions that the player can have with it.
When we play Single Player the program activates both sections. When we play Multiplayer instead, the program activates only the client side and listens to search for a server to interface with, on the local network or online.
Indeed, SpigotMC is a program which activates only the server part of Minecraft and, in addition, allows you to use plugins (programs written in Java) to expand the gaming experience.
For this purpose, SpigotMC maps all the properties and functions of Minecraft and makes them available to developers in a predefined format called Bukkit.
Among the plugins developed for SpigotMC there is one - called Scriptcraft - which allows access to these methods directly from script in javascript code (and not java): this language is certainly easier to use and better known for its use on the Internet.
Step 1: How to Install SpigotMC
The SpigotMC server home page is located at the address https://www.spigotmc.org/. Here you can find all the information and news about the program.
Requirements
To install the SpigotMC server, you need to have the Java8 programming language installed on your computer. On Windows and Mac you can check this prerequisite following the instructions on the Java site at this address https://www.java.com/it/download/help/version_manu.... While you can download the Java installer from this address http://java.com/.
Downloading and creating the installation file
First create two directories: a "SpigotDownload" (where we'll download the BuildTools.jar file to create the SpigotMC .jar file) and a "Spigot" (where we'll install the server). Go to https://hub.spigotmc.org/jenkins/job/BuildTools/,... ,download the latest version of the BuildTools.jar file and save it in the "SpigotDownload" folder.
Now create a command file under the "SpigotDownload" directory (in the case of Windows you have to create a new text file with the extension .bat) that you will name "start". Open the file you just created for editing and write the following command:
java -jar BuildTools.jar --rev X.X.X
replace the word X.X.X with the version of Minecraft for which you want to create the server, then save the file.
Execute the command file you just created (in the case of Windows, just double click on the file).
NOTE: In case the procedure does not work, I suggest you follow the instructions given at the following addresses:
A command window will open at this point. This may take several minutes. When the window closes in the "SpigotDownload" directory you should find the spigot-XXX.jar file (where XXX is the name of the Minecraft version), copy the file in the "Spigot" folder and delete the "SpigotDownload" folder because at this point you don't need it anymore.
Server installation
Create a command file under the "Spigot" directory (in the case of Windows you have to create a new text file with the extension .bat) and name it "start". Open the file you just created for editing and write the following command:
java -jar spigot-X.X.X.jar
then save the file. Execute the command file you just created (in the case of Windows, just double click on the file). A command window will be opened and closed after a few moments. At this point in the "Spigot" folder some files should have appeared, in particular the "eula.txt" file should be present. Open this file in edit and replace the following:
eula=false
with
eula=true
then save the "eula.txt" file and restart the "start" command file. The command window will appear again but this time it should remain open without closing again. When the ">" prompt appears, your SpigotMC server is online. To access the server, open Minecraft, enter in multiplayer mode and add a new server with the address 127.0.0.1 (represents the IP address of the local machine). Save and access the newly created server: congratulations, this is your server.
Server configuration
Now, if you want to become the administrator of the newly created server, enter the following command in the command window opened by the server:
op Name-Account-Minecraft
where Name-Account-Minecraft is the name of your account on Minecraft, press the return key and you can execute on Minecraft the commands such as:
/gamemode 1
to switch to creative mode. We will not go further on the Minecraft commands or on the configurations of the "server.properties" file: on the internet you can find all the documentation you need. However we bring you some tips:
- usually the server creates a rather buggy world. Our advice is to generate the world in single player and then bring it back under the server. To do this, simply delete the "world" folder from the server and copy the one created in Single Player mode;
- to access the server from the outside it is also necessary to configure the "server-ip =" parameter in the "server.properties" file, reporting the static IP of the online machine (if you have a static IP) or otherwise the generated IP from programs like "LogMei Hamaci" or "EvolveHQ",
- you can improve server performance by assigning additional RAM over the default 512 Mb. To do this just change the line in the "start" command file as follows:
java -Xms1G -Xmx1G -jar spigot-X.X.X.jar
where 1G is the size (expressed in Gigabyte) of the memory allocated to the server (in this case 1 Gigabyte).
Step 2: How to Install Scriptcraft
The Scriptcraft home page is located at the address https://scriptcraftjs.org/. Here you can find all the information and tutorials related to the plugin.
Plugin download and installation
The SpigotMC server we previously installed meets all the requirements for installing the plugin. Let's go to this address https: //scriptcraftjs.org/download/latest/scriptcr ... and download the latest version of the plugin. Move to the "Spigot" directory we created previously and copy the file you just downloaded to the "plugins" directory. Turn off the SpigotMC server by closing the command window and restart it by launching the "start" command file. At the end of the server restart we can verify that both in the "Spigot" directory and in the "plugins" sub-directory two new folders called "scriptcraft" have been created. To find out the list of created files and their purpose, refer to the site's documentation. What we are interested in is the "scriptcraft" directory that is located under the "Spigot" folder. In it we find two sub folders
- "data" in which we find a series of ".json" files
- and "plugins" where we find some ".js" files.
Our advice is to save any configuration json objects in the "data" directory, while under the "plugins" folder we recommend creating the subdirectory of the minigame in which to insert js files containing the game code.
To verify that the installation of the plugin has been successful connect with Minecraft to the server and type in the command line
/js echo(2 + 2)
if the result is 4, the plugin works correctly.
Step 3: We Write the Code
Useful documents
Before starting to write the code, our advice is to always keep the following reference pages open:
- https://hub.spigotmc.org/javadocs/bukkit/index.htm... here you will find all the constants and functions of Minecraft mapped by the SpigotMC server,
- https://github.com/walterhiggins/ScriptCraft/blob/... here you can find a guide to using Scriptcraft,
- https://github.com/walterhiggins/ScriptCraft/blob/... here you can find a list of Scriptcraft reference functions,
- https://minecraft-ids.grahamedgecombe.com/ finally here you can find a list of the materials present in minecraft.
Let's begin
First we create a new "myMinegame" folder in the "plugins" directory under the "scriptcraft" directory. We enter this directory and create a new "myMinigame.js" file. Open the file in edit mode and write the following lines of code:
var utils = require('utils');
var funTest = function () { echo("FIRST TEST"); }
exports.Test = funTest;
then save the changes.
The first line:
var utils = require('utils');
allows you to include in the code the functionalities of the "utils" module of Scriptcraft (for more details, refer to the documentation pages of the plugin.) We then define a function and then associate the function to exports.Test: now the function now can be invoked from the Minecraft command console with the name "Test".
Open the server with the command file and once it started, launch Minecraft and connect to the server as we saw earlier. Open the command console in Minecraft and type "/ js Test ()" followed by return key: the program should print "FIRST TEST" on the console.
Search for bugs
Here are some techniques to look for errors in the code we are going to create.
Reopen the file "myMinigame.js" and replace the code:
exports.Test = funTest;
with the code
exports.Test = funTestNone;
and save the file.
To reload the changes just made in the Scriptcraft plugin we must type in the following command "/js refresh ()" in the Minecraft command line and press enter. Write again the command "/js Test ()" and press enter. At this point the program should return an error. Looking at the error on the Minecraft console we can verify which error is to correct it.
However, there is another type of error. Reopen the "myMinigame.js" file, delete all the content and write the following code:
var utils = require('utils');<br><br>var funTest = function () { echo("FIRST TEST"); ] exports.Test = funTest;
In this case we inserted a javascript syntax error in the code. In line 3 we replaced the brace with a square bracket. When the command "/js refresh ()" is repeated in the Minecraft console, it is always a good idea to check the "SpigontMC" server command window. In fact, we find a reference to syntax errors that is not reported in the Minecraft console.
Another system to find the bugs or to track the progress of the code, is to insert within the code a series of "echo" functions to display the value of the variables during operation.
Experience
The advice at this point is to do a bit of testing, documentation in hand, to see what you can do. Once you have got a little confidence with the Minecraft programming in javascript, go to the next chapter where we will begin to see pieces of code useful for your mission.
Step 4: How to Develop a Minigame
The steps for development
Here are the steps to develop a minigame:
1) first of all it is important to define the idea behind the minigame:
- what is the purpose of the minigame,
- what are the mechanics of victory,
- what are the interactions between the players,
- what are the interactions between the players and any hostile mobs,
- what are the interactions between the players and the environment.
these are just some of the questions to ask in order to define the initial idea;
2) do not try to develop the minigame in its entirety but try to break it down into the functionalities that compose it. Analyze each feature in search of all the components that will be implemented;
3) before writing the code, define the necessary data for each function and map them with objects and / or arrays; in this way, if you need to modify parameters, you'll be able to do it more easily in just one place;
4) even when you implement the code, do not do it all at once but make a piece of code at a time and test it. To test it, map the functionality you want to test with an external function so that you can launch it manually;
5) pay attention to the contexts and use of "this"; if you do not understand the concept of closing in javascript always use global variables.
A practical example.
1) we want to create a minigame called "Open Pit" : the purpose of this game is to earn points to the player recovering iron, gold and diamonds in a set time, avoiding the assault of mobs:
- the purpose of the game is therefore to accumulate more minerals,
- each mineral will have a different score; who makes more points wins,
- we prefer to avoid games where PvP is possible, therefore players will have to find other systems to hinder the other competitors
- players will have to deal with different waves of enemies: the deeper they go, the stronger the enemies will be,
- players will be able to destroy blocks within the game square. Let us remember we'll have to prevent that ability in the rest of the map.
2) let's analyze now what are the functionalities that we have to implement to realize the minigame:
- at the start the game will have to generate the mine in a random way,
- then we will have to teleport the players to a starting area, assigning them the necessary objects: some armor, a pickaxe, a sword, a shield (all of these must be indestructible) and torches. The player's inventory will then be emptied completely at the end of the game,
- the game will allow the player to destroy and place blocks only within the mine play area,
- every minute the game will generate hostile mobs based on the number of players and the depth they have reached.
We will now focus only on creating the map. We build the map on 6 levels, each of which consists of 3 layers of randomly arranged minerals and 3 layers of air . The 3 layers of air allow us to position the mobs for each level, while the three layers of minerals will make it more difficult for players to hide from mobs. We would therefore need:
- a feature for creating random numbers;
- one that cancels all layers of the level;
- and finally one that builds the three layers of minerals according to a series of percentages.
3) So the useful data we need to register, to implement the features listed above, are the following:
- the location of the mine in the game world: to get it, we take the angle with x and z minor and with y (height) greater,
- the size of the mine,
- and a list of the percentages of the various materials needed to build the layers.
Write the following code in the "myMinigame.js" file:
// here we use a command from the scriptcraft utils library
var utils = require('utils');
// define a global variable for Bukkit reference
var gobjBukkit = null;
if (__plugin.bukkit) { gobjBukkit = org.bukkit; }
var gobjMine = { location: utils.locationFromJSON({ x: 140, y: 110, z: 184 }), width: 20, height: 3, large: 20, layers: [ { materials: [ { type: gobjBukkit.Material.STONE, data: 3, density: 10 }, { type: gobjBukkit.Material.STONE, data: 5, density: 10 }, { type: gobjBukkit.Material.COAL_ORE, data: 0, density: 20 }, { type: gobjBukkit.Material.STONE, data: 0, density: 60 } ] }, { materials: [ { type: gobjBukkit.Material.STONE, data: 1, density: 10 }, { type: gobjBukkit.Material.STONE, data: 3, density: 10 }, { type: gobjBukkit.Material.STONE, data: 5, density: 20 }, { type: gobjBukkit.Material.IRON_ORE, data: 0, density: 60 } ] }, { materials: [ { type: gobjBukkit.Material.STONE, data: 3, density: 10 }, { type: gobjBukkit.Material.STONE, data: 1, density: 10 }, { type: gobjBukkit.Material.STONE, data: 5, density: 20 }, { type: gobjBukkit.Material.GOLD_ORE, data: 0, density: 60 } ] } ] };
Here you can see that we used the "utils" library of Scriptcraft, to convert a json with the coordinates in a Location object used by Minecraft (see Scriptcraft documentation for this), and we defined a global variable "gobjBukkit" to access more easily to the costants and methods mapped in Bukkit. In the global variable "gobjMine" instead we report the position, the dimensions and the mapping of the layers of the mine (currently only 3). It is useless to add others at this stage because we still have to make the functionality for the creation of the various layers of mine. For each layer we define the materials that compose it by reporting:
- the values that define the material ("type" and "data")
- and an integer value ("density") that defines the probability of distribution of the material.
4) We begin to create the functionality for creating the layers of the mine. We proceed by steps: first we create a function that returns a random value included in a range, in order to randomly generate the layers. We declare the function as global as it will be useful in several situations:
// function for the calculation of a random value
function GetRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
To test the function, add this line of code
exports.TestRandom = GetRandomInt;
so you can run it from the command line in Minecraft as follows:
/js TestRandom(1, 100)
We run the function several times to verify that it works correctly, then we delete the line of code that exports it.
5) Now write the function that places the blocks of the layer:
// function for creating layers
// x, y, z angle with x and z minimum and y maximum // the construction of the state starts from the top down // materials [ { type: TYPE, data: INT, density: INT } ]
function CreateLayer(x, y, z, w, h, l, materials) {
// we recover the reference the world var world = server.getWorlds()[0]; var block = null; var value = null; var material = null; // loop on large for(var zz = z; zz < (z + l); zz++) { // loop on height for (var yy = y; yy > (y - h); yy--) { // loop on width for (var xx = x; xx < (x + w); xx++) { // we calculate a value between 1 and 100 value = GetRandomInt(1, 100); // cycling on the materials to see which one to use material = null; for (var mm = 0; mm < materials.length; mm++) { if (value <= materials[mm].density) { // we recover the material material = materials[mm]; // we reduce the number of blocks on the material break; } else { value -= materials[mm].density; } } if (material != null) { // we place the block block = world.getBlockAt(utils.locationFromJSON({x: xx, y: yy, z: zz})); block.setType(material.type, false); block.setData(material.data); } } } } } exports.TestCreateLayer = function() { var y = gobjMine.location.y; for (var ii = 0; ii < gobjMine.layers.length; ii++) { CreateLayer(gobjMine.location.x, y, gobjMine.location.z, gobjMine.width, gobjMine.height, gobjMine.large, gobjMine.layers[ii].materials); y -= 6; } };
From the command line in Minecraft, run the following instruction
/js TestCreateLayer()
and verify that it works.
Now you can continue on your own. In the next chapter, however, we will provide you with some pieces of code that will be useful for your minigame.
Good luck.
Step 5: Useful Pieces of Code
Here are some pieces of code that may be useful to you.
to place an entity
var entity = server.getWorlds()[0].spawnEntity(location, gobjBukkit.entity.EntityType.SKELETON);
to assign an object to an entity
entity.getEquipment().setHelmet(new gobjBukkit.inventory.ItemStack(gobjBukkit.Material.CHAINMAIL_HELMET));<br>entity.getEquipment().setHelmetDropChance(0.5); // value between 0 to 1
to launch a Minecraft command that is not referred to any user
<p>// to empty a parallelepiped of space</p><p>server.dispatchCommand(server.getConsoleSender(), "fill " + location.x + " " + location.y + " " + location.z + " " + w + " " + h + " " + z + " minecraft:air");</p>
to check which entities are present in a parallelepiped and among these recognize any players
<p>var varrEntities = server.getWorlds()[0].getNearbyEntities(location, w, h, l);</p><p>for (var jj = 0; jj < varrEntities.length; jj++) {</p><p> // we verify if the entity is valid, alive and active</p><p> if ((varrEntities[jj] instanceof gobjBukkit.entity.LivingEntity) && (varrEntities[jj].isValid()) && (!varrEntities[jj].isDead())) { // we check if the entity is a player if (varrEntities[jj] instanceof gobjBukkit.entity.Player) { } } }</p>
to prevent the player from breaking blocks
<p>var events = require("events");</p><p>function OnBlockBreak(event) { var vobjPlayer = event.getPlayer(); var vobjBlock = event.getBlock();</p><p> // here we set a condition based on the type of block or the position of the player</p><p> event.setCancelled(true); }</p><p>events.blockBreak(OnBlockBreak);</p>
to prevent the player from placing blocks
<p>var events = require("events");</p><p>function OnBlockPlace(event) { var vobjPlayer = event.getPlayer();</p><p> var vobjBlock = event.getBlock();</p><p> // here we set a condition based on the type of block or the position of the player event.setCancelled(true); }</p><p>events.blockPlace(OnBlockPlace);</p>
to check if the user pressed a certain wooden button
<p>var events = require("events");</p><p>function OnPlayerInteract(event) { var vobjPlayer = event.getPlayer();</p><p> var vobjAction = event.getAction(); if (event.hasBlock() && (event.getAction() == gobjBukkit.event.block.Action.RIGHT_CLICK_BLOCK)) { var vobjBlock = event.getClickedBlock(); if (vobjBlock.getType() == gobjBukkit.Material.WOOD_BUTTON) {</p><p> // here we carry out an action } } };</p><p>events.playerInteract(OnPlayerInteract);</p>
to kill an entity
<p>entity.damage(1000);</p>
to teleport an entity
<p>entity.teleport(location);</p>
Have fun!