Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minecraft Legends Documentation Overhaul Step 1 #16

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
66 changes: 37 additions & 29 deletions BSharpReferenceSheet.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# B# Reference Sheet
## Core B#

## Core `B#`

### Listeners

Expand Down Expand Up @@ -30,7 +31,7 @@ SNIPPET_EntitySpawned("es_snippet_to_execute", (entity, payload) => {
```

- `"es_snippet_to_execute"` : First parameter is the snippet name. Listeners with the same `snippet` value will trigger this snippet.
- It is possible to have multiple listeners point to a single snippet, but not the other way around (when a snippet is defined its name must be unique).
- It is possible to have multiple listeners point to a single snippet, but not the other way around (when a snippet is defined its name must be unique).
- `(entity, ...)` : Each snippet will be provided a set number of arguments to operate on. See the documentation for more details on each snippet type.
- `(..., payload)` : The last argument for any snippet is always the payload.

Expand All @@ -57,15 +58,15 @@ declare function SNIPPET_GameLoadBootstrap(snippetName: string, callback: GameLo
declare type GameLoadBootstrapCallback = (isSaveLoaded: boolean) => void

/**
* Similiar to Bootstrap. The name of the snippet should match the rule that is being reacted to.
* Similar to Bootstrap. The name of the snippet should match the rule that is being reacted to.
* Passes along the value of the rule as a parameter.
* No listener required. All rule initialized snippets will fire at the beginning of a new game.
*/
declare function SNIPPET_RuleInitialized(snippetName: string, callback: RuleInitializedCallback): void
declare type RuleInitializedCallback = (ruleValue: VariantData) => void

/**
* Similiar to Bootstrap. The name of the snippet should match the game mode this is being reacted to.
* Similar to Bootstrap. The name of the snippet should match the game mode this is being reacted to.
* No listener required. All rule initialized snippets will fire at the beginning of a new game.
*/
declare function SNIPPET_InheritsFromGameMode(snippetName: string, callback: RuleInitializedCallback): void
Expand All @@ -75,13 +76,13 @@ declare type RuleInitializedCallback = () => void
In general, this is when you would use this specific bootstrap:

- `SNIPPET_Bootstrap` when you need shared “core” functionality between all game modes. **In general this shouldn’t be used**.
- `SNIPPET_InheritsFromGameMode` when you need behaviour specific to a game mode. **This should be your default go to.**
- `SNIPPET_RuleInitialized` when you want to enable modular behaviour defined by game-rules, the idea being it is functional across multiple game modes.
- `SNIPPET_InheritsFromGameMode` when you need behavior specific to a game mode. **This should be your default go to.**
- `SNIPPET_RuleInitialized` when you want to enable modular behavior defined by game-rules, the idea being it is functional across multiple game modes.
- `SNIPPET_GameLoadBootstrap` used in special circumstances when you need to do something on game reload (from a save file). The intended use for this is for DLC islands, when we need to add content after a world has already been generated.

### Callbacks

Another class of special snippets that don’t use a listener. Instead some B# functions (OUTPUTS) when executed can specify a callback as the last parameter, which will execute the associated snippet when relevant.
Another class of special snippets that don’t use a listener. Instead some`B#`functions (OUTPUTS) when executed can specify a callback as the last parameter, which will execute the associated snippet when relevant.

There are 2 callbacks, taken from the documentation itself:

Expand Down Expand Up @@ -113,15 +114,15 @@ Payloads are supported for all listeners and snippets. It allows you to past con

- Listeners can pass **one of each** payload type via `payloadString`, `payloadInt`, `payloadFloat`, `payloadEntities`
- Snippets can receive the payload **as the last argument of the snippet** via `payload.string`, `payload.int`, `payload.float`, `payload.entities`
- You can also use `payload.ownerVillageId` which will be defined if the listener defined `ownerVillageId`. (This is the preferred way of getting the village in a snippet when possible)
- You can also use `payload.ownerVillageId` which will be defined if the listener defined `ownerVillageId`. (This is the preferred way of getting the village in a snippet when possible)

### Villages & Suspension

A core concept in Minecraft Legends (not just B#) are villages. You can think of villages as a “Location” - an area in the game world which can house entities such as buildings, mobs, or even invisible things (like music emitters, trigger volumes, etc.).
A core concept in Minecraft Legends (not just B#) are villages. You can think of villages as a “Location” - an area in the game world which can house entities such as buildings, mobs, or even invisible things (like music emitters, trigger volumes, etc.).

Suspension is the act of saving out an entity and having it enter a state of stasis due to our massive open world which makes keeping everything loaded infeasible. Special care has been made sure to ensure B# only ever works with fully loaded active entities (so all the information on the entity will be on as you expect).
Suspension is the act of saving out an entity and having it enter a state of stasis due to our massive open world which makes keeping everything loaded infeasible. Special care has been made sure to ensure`B#`only ever works with fully loaded active entities (so all the information on the entity will be on as you expect).

Villages are crucial to B# as they can guarantee what entities are queryable and useable at the time of your snippet execution. **When a listener that belongs to a village executes it is guaranteed that all entities belonging to the same village will also be loaded**.
Villages are crucial to`B#`as they can guarantee what entities are queryable and useable at the time of your snippet execution. **When a listener that belongs to a village executes it is guaranteed that all entities belonging to the same village will also be loaded**.

- For example: querying the number of structures in a village when a village owned listener executes is safe.

Expand All @@ -135,13 +136,13 @@ The mechanism that drives this group un/suspension is called Atomic Village Susp

An Entity Group (EG) is how we represent an entity or entities in B#. It is a special data type, don't ask about it.

Note some functions require an entity group of one and only one (referred to as "**entity**" in the documentation).
Note some functions require an entity group of one and only one (referred to as "**entity**" in the documentation).

Conversely, some functions require a group of entities (referred to as “**entities**” in the documentation) which includes a group of 0 entities or more.

### Queries

Queries are how we read game state - without mutating it - such as getting the count in an entity group.
Queries are how we read game state - without mutating it - such as getting the count in an entity group.

All queries are prefixed with `QUERY_`

Expand All @@ -159,37 +160,43 @@ All filters are prefixed with `FILTER_`

### Operations

Operations are how combine entity groups into another group. For example doing the union of two groups (combine with no duplicates). If you consider an EG as a set of entities, there is an operation function for each mathematical set operation.
Operations are how combine entity groups into another group. For example doing the union of two groups (combine with no duplicates). If you consider an EG as a set of entities, there is an operation function for each mathematical set operation.

All operations are prefixed with `OPER_`

### Global Variables

B# is largely stateless, we listen to events and respond to them "right away". However, if you do need to store some information you can use our global variable storage via commands such as `OUTPUT_SetGlobalVariable(key, intergerValue)` allowing you to store integer values to retrieve at a later time.
B# is largely stateless, we listen to events and respond to them "right away". However, if you do need to store some information you can use our global variable storage via commands such as `OUTPUT_SetGlobalVariable(key, integerValue)` allowing you to store integer values to retrieve at a later time.

Please **DO NOT** store variables like this `var thing = 123` at the global scope. Values like this still be lost to the void when the player exits and reloads.

# **Advanced topics**
## **Advanced topics**

These topics dive a little deeper into the nuance of our game, how we author scripts, as well as functions specific to game-modes like campaign.

### Configuration objects / files

Located at the top of scripts generally, are configuration objects which only contain “data” (and no logic). This presents an easy way to tune the functionality of a script as all the tunable values are grouped in one location.

**Notes**

You may notice special config objects existing in separate files entirely by themselves, with *another* script utilizing the config elsewhere. For example imagine `const gameConfig = {}` moved to a `a_moba_config.js` file. This is generally done for two reasons
**Notes**:
You may notice special config objects existing in separate files entirely by themselves, with *another* script utilizing the config elsewhere.
For example imagine `const gameConfig = {}` moved to a `a_new_game_mode_config.js` file. This is generally done for two reasons

- It allows our teams to completely override the config (including removing it) for separate game-modes, useful for DLC (note there are other approaches to this too).
- Separates massive config files to shorten scripts, this is especially useful if multiple configs exists (eg. `a_config_horde_attack.js`, `a_config_horde_defend.js`) which makes tracking changes much easier.
- This allows developers to completely override the config (including removing it!) for separate game-modes, such as user-created `Lost Legends` and `Myths`!
- Separates massive config files to shorten scripts, this is especially useful if multiple configs exists (e.g. `a_config_horde_attack.js`, `a_config_horde_defend.js`) which makes tracking changes much easier.
- Modularity is always nice to have!

### Naming Conventions

When a constant or function at the global scope is prefixed with `_` it means this **constant/function is only used within this file.** For example `_SpawnAttackingUnits = () => { // return stuff }` .This provides an easy way to know if changing a function’s behaviour could affect other scripts.
When a constant or function at the global scope is prefixed with `_` it means this constant/function is **only** used within this file.

To be clear this is purely used for semantics - all scripts are loaded at the global level meaning you *can* reference other file’s constants (but you shouldn’t!). If you get a ‘x declared already’ error this is most likely why!
Take, for example:
`_SpawnAttackingUnits = () => { // return stuff }`

This provides an easy way to *know* if changing a function’s behavior could affect other scripts.

Mojang note on semantics:
To be clear this is purely used for semantics - all scripts are loaded at the global level meaning you *can* reference other file’s constants (but you shouldn’t!). If you get a ‘x declared already’ error this is most likely why!
When `_` is used in a function though, it means the **function argument is not used**. For example `SNIPPET_EntitySpawned(..., (_spawnedEntity))` - if you don’t actually need to operate on the spawned entity in anyway.

### File Naming Conventions & Load Order
Expand All @@ -198,9 +205,9 @@ The file *path* (that includes the folder name!) determines the load order, sort

### Helper functions

Helper functions (local to a file or global to all) are ways to execute common functionality repeatedly. If you notice yourself duplicating scripts or doing something very similar make a helper function or reach out to fellow scripters for assistance!
Helper functions (local to a file or global to all) are ways to execute common functionality repeatedly. If you notice yourself duplicating scripts or doing something very similar make a helper function or reach out to fellow developers for assistance!

In B# land we define functions like so:
In the wonderful and mythical world of `B# land` we define functions like so:

```jsx
// or MyLocalFunction if you wanted it to be global!
Expand All @@ -211,16 +218,18 @@ const _myLocalFunction = (argument1, argument2) => {
```

If you have used Javascript before then you may be more familiar with this syntax:

```function _myLocalFunction(argument1, argument2) => { }```

We don’t do this because you can redefine and *stomp* an existing function - which leads to really hard to catch bugs!

### Special “Libraries”

B# has some special libraries fully* defined in script, utilizing all of Core B# to do neat things.
`B#` has some special libraries fully*(some things do rely on the C++ backend) defined in script, utilizing all of `B#` to do neat things.

For example

- `DECK_` : Used to drawn and set B# decks (this is a special case and is not *fully* scripted)
- `DECK_` : Used to drawn and set`B#`decks (this is a special case and is not *fully* scripted)
- [DEPRECATED] `RALLYMAN_` : Used to group and dispatch units.
- `aaaa_ai_helpers.js` : Supersedes above, and unfortunately doesn’t have a prefix. Used to interface with base AI.

Expand All @@ -238,7 +247,6 @@ Due to the massive open world nature of Minecraft Legends, we’ve had to introd

Avoid the standard library's `Math.random()` as it is not deterministic between instances of the game. Stick to `QUERY_RandomNumber` and `QUERY_RandomNumberGroup`.

The `Number` returned by `QUERY_RandomNumber` and `QUERY_RandomNumberGroup` is an integer and can immediately be used as an array index.
The `Number` returned by `QUERY_RandomNumber` and `QUERY_RandomNumberGroup` is an integer and can immediately be used as an array index.

Consider using `QUERY_RandomNumberGroup` for consistent randomness that you do not want to be affected by other areas of the game (eg: the player affecting the state of the game world).

25 changes: 16 additions & 9 deletions BarrierBlocks.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Barrier Blocks in Minecraft Legends

In most cases barrier blocks are invisible blocks used to block player and mob collision. We have a few barrier blocks that are very specific and used in a handful of specialized cases.

## Blocks

Each barrier block used in game are listed below with examples of how and where to use them:

### block_barrier_soft
Expand All @@ -10,45 +12,50 @@ Player and Mob collision, no damage receiver.

Can be used for blocking the player and mobs from entering the structure.

![](images/barrier_blocks/image01.png)
![block_barrier_soft](images/barrier_blocks/image01.png)

### block_barrier_solid

Player and Mob collision, has damage receiver.

Can be used for blocking the player and mobs from passing through the deco block, but also if hit with the player sword it would plink off the block.

![](images/barrier_blocks/image02.png)
![block_barrier_solid](images/barrier_blocks/image02.png)

### block_barrier_path

Player and Mob collision, no damage receiver, ignored by pathfinding.

Not currently used for anything.

### block_barrier_door

Player and Mob collision, has damage receiver, ignored by pathfinding.

Gate closed and Piglin Gate closed structure entites both use this block to prevent entities entering through the gate.
Gate closed and Piglin Gate closed structure entities both use this block to prevent entities entering through the gate.

![](images/barrier_blocks/image03.png)
![block_barrier_door](images/barrier_blocks/image03.png)

### block_barrier_boss

Player is able to walk through. Stops boss mobs from entering lava in boss fights. (Only used in base gen boss areas)

Used in the defend horde boss battle. The block is generated above all lava areas so the boss cannot fall in.

![](images/barrier_blocks/image04.png)
![block_barrier_boss](images/barrier_blocks/image04.png)

### block_village_solid_air

Player is able to pass through. Stops mobs from leaving village houses through windows. (Only used in village houses)

Used in the medium village house. The blocks are placed in the areas we don't want the mobs traveling. Forcing them to use the door but still allowing the player to pass through. 

![](images/barrier_blocks/image05.png)
Used in the medium village house. The blocks are placed in the areas we don't want the mobs traveling. Forcing them to use the door but still allowing the player to pass through.

![block_village_solid_air](images/barrier_blocks/image05.png)

### block_barrier_soft_denether

Player and Mob collision, no damage receiver. Block is denetherable and gatherable. (Only used in denetherable/gatherable structures)

Used in the obstacle horde mushroom trees. This act the same as the `block_barrier_soft` but when the tree is denethered the barrier blocks will also disappear.

![](images/barrier_blocks/image06.png)
![block_barrier_soft_denether](images/barrier_blocks/image06.png)
Loading