Developer notes

How to Create a New Level

The specific files for each level are located in the folder server/src/main/resources/static/levels/<level-id>. The files are placed in the static folder of the server so that the server can serve them, but within the level folders, we also find files that are used only by the CLI, such as the Dockerfile used to generate the container images.

game.json

Each level must define a configuration file in JSON format, structured as in the following example:

{
  "name": "n00b",
  "image": "linux-bomb-n00b",
  "description": {
    "en": "n00b: for beginners",
    "it": "n00b: per principianti"
  },
  "time": 600,
  "steps": 4,
  "error_penality": -1,
  "max_errors": 5
}
  • image is the name of the Docker image to be loaded for the level (without the specific language tag);
  • time is the time available in seconds;
  • steps is the total number of steps;
  • error_penality is the number of points deducted in case of incorrect commands (exit status different from 0);
  • max_errors is the maximum number of tolerated errors before the bomb explodes.

Dockerfile

The folder server/src/main/resources/static/levels/base contains the Dockerfile for the base image required to create the game levels. The base image requires a LANG argument (e.g., en_US.UTF-8) that is used to define the language to be installed and configured in the container. The images specify the language using tags (e.g., linux-bomb-base:en).

Each level therefore has a Dockerfile for each language. Each Dockerfile must inherit from the base image specific to the chosen language.

When creating a Dockerfile, it is important to place the level resources according to the conventions used by the game:

  • The material that needs to be edited by the user should be placed in /opt/linux-bomb/bomb; the entrypoint of the base image copies the contents of this folder into the volume /bomb at the startup of the container;
  • The container must start with the user player (already created in the base image);
  • Any additions to the .bashrc should be made by creating a file at /opt/linux-bomb/.bashrc.

checker.py

Each level must provide a Python script named checker.py. This script is called by the main checker.

The script receives 3 arguments as input:

  • bomb_folder: the path where the /bomb folder is mounted on the host machine;
  • step: the current step number in the game;
  • lang: the language chosen by the user to play.

The output of the script must always consist of 2 numbers: the calculated step and the assigned score.

Examples:

  • If the input step is 1 and the output is 1 0, it means that the command executed by the user did not produce any changes;
  • If the input step is 1 and the output is 2 100, it means that the user has moved to the next step and earned 100 points;
  • If the output is -1 -1000, it means that the user has caused the bomb to explode and has lost 1000 points.

bomb.js

The file bomb.js defines a WebComponent whose associated tag must be linux-bomb.

The component must expose the following methods:

  • setTimer(): receives a parameter that corresponds to the remaining time already formatted as “mm:ss”; it is used to display the remaining time within the UI;
  • setStep(): receives a numeric parameter corresponding to the step to be displayed;

The following code constitutes a valid skeleton for a new component:

class LinuxBomb extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <!-- TODO: insert HTML and CSS of the component here -->
    `;
  }

  setTimer(time) {
    // TODO
  }

  setStep(step) {
    // TODO
  }

  /** Notifies to the parent that the rendering of the component is concluded */
  connectedCallback() {
    this.dispatchEvent(new CustomEvent('bomb-rendered', { bubbles: true, composed: true }));
  }
}

Notes: import of new fonts doesn’t work inside the WebComponent. The page provides 2 fonts that can be used to display custom text inside the levels: E1234 (used for the clocks) and Xolonium.