Skip to content

The C++ you need

Lesson 2.1

You don’t have to be a C++ expert to write a good mod. Most mods use a friendly part of the language: functions, variables, if and loops, std::string, a class or two, and lambdas. This lesson lists what to learn and where to learn it.

Learn the language on W3Schools

W3Schools has a free C++ tutorial with short pages and an editor in the browser. Read these pages in this order, and do the little exercises at the end of each one. The first group is enough for your first mod; the second one is what the wrapper uses all the time.

The basics (a few evenings):

  1. Get started and Syntax
  2. Output and Comments
  3. Variables and Constants
  4. Data types and The auto keyword
  5. Operators and Booleans
  6. If … else and Switch
  7. While loop, For loop and The foreach loop
  8. Strings, Concatenation and Numbers and strings
  9. Arrays and Structures
  10. Functions, Parameters and Default parameters

For mods (the parts the wrapper uses a lot):

  1. References and Pass by reference: what the & in cl_ev_player& e means
  2. Scope and Namespaces: everything in the wrapper lives in clight::
  3. Lambdas: every event handler in this course is one
  4. Classes and objects, Class methods and Constructors
  5. Inheritance and Virtual functions: your mod is a class that overrides a few functions
  6. Pointers and Enums
  7. Vectors and Maps
  8. Memory management and new and delete

Later, when you need them: Templates (to read the wrapper’s clight::on<...>), Math, Random numbers, Files, Debugging and the string reference.

The minimum, in one list

Before you write a mod, you should be able to read and write code like this without looking things up:

  • declare variables with int, float, double, bool, auto and std::string,
  • write if, else, for (also for (auto& x : list)) and while,
  • write a function that takes parameters, some by reference, and returns a value,
  • join strings with + and turn numbers into text with std::to_string,
  • write a class that inherits from another and overrides a virtual function,
  • write a lambda, [](int x) { return x * 2; }, and know what goes inside the [],
  • know what static does to a variable.

The lambda and the class are the important ones for mods. Your mod is a class, the game calls your lambdas when something happens, and the lambdas keep state in variables that outlive them.

Types you will see everywhere

The API uses the fixed-width types: int32_t is a 32-bit whole number, uint32_t the same without a sign, int64_t a 64-bit one. They work exactly like int, but their size is the same everywhere. size_t is used for lengths.

std::string_view is a string you only look at: a pointer and a length, without a copy. The wrapper takes std::string_view for every id and message, so you can pass "minecraft:stone", a std::string or a std::string_view, whatever you have. It gives text back as std::string, which you own.

You don’t need to include these yourself; clight.hpp does it for you.

C++ you won’t need

Some things from W3Schools don’t apply in a mod, so don’t worry about them:

  • User input (std::cin): a mod gets its input from the game, not from a terminal.
  • main: a mod has no main function. A macro, CLIGHT_MOD, creates your mod class when the game loads it.
  • Exceptions (try, throw, catch): mods are built with exceptions turned off. throw is a compile error, and errors come back as values instead (see Errors and Expected).
  • Threads: the game calls your code; you never start threads yourself.
  • Most files: a mod may only read its own folder and write its own data/ folder. Memory in the sandbox explains it.

Try it

Without a computer: what does this print, and why?

#include <iostream>
#include <functional>

int main() {
    int count = 0;
    std::function<void()> by_value = [count]() mutable { count = count + 1; };
    std::function<void()> by_ref = [&count]() { count = count + 10; };

    by_value();
    by_value();
    by_ref();
    std::cout << count << "\n";
    return 0;
}
Show a solution

It prints 10. [count] copies count into the lambda when it is created, so by_value only changes its own copy (mutable allows that). [&count] captures a reference, so by_ref changes the real variable.

This matters a lot in mods. The game calls your lambdas long after the function that created them has returned, so a lambda must never capture a local variable by reference: by then the variable is gone. Capture by value, or keep the state in a variable that lives as long as the mod. If this was new, read Lambdas on W3Schools.

Recap: learn the basics, references, lambdas, classes and inheritance on W3Schools first; a mod is a class whose lambdas the game calls, it uses std::string_view and std::string for text, and it has no main, no exceptions and no threads.