Skip to content
This repository has been archived by the owner on Jul 15, 2024. It is now read-only.

Commit

Permalink
Basic Problem Solving
Browse files Browse the repository at this point in the history
  • Loading branch information
IMB11 committed Dec 10, 2023
1 parent ede7b9b commit 8c10f13
Show file tree
Hide file tree
Showing 20 changed files with 247 additions and 57 deletions.
4 changes: 3 additions & 1 deletion .vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ export default defineConfig({
{ text: 'Launching the Game', link: '/getting-started/launching-the-game' },
{ text: 'Launching Servers', link: '/getting-started/launching-servers' },
{ text: 'Access Wideners', link: '/getting-started/access-wideners' },
{ text: 'Mixins', link: '/getting-started/mixins' }
{ text: 'Mixins', link: '/getting-started/mixins' },
{ text: 'Basic Problem Solving', link: '/getting-started/basic-problem-solving' },
{ text: 'Using The IDE Effectively', link: '/getting-started/using-the-ide' }
]
}
],
Expand Down
2 changes: 1 addition & 1 deletion blocks/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ Since the example block does not have a complex blockstate, only one entry is re
}
```

Blockstates are really complex, which is why they are addressed in an upcoming page: [Block States](./_assets/blockstates)
Blockstates are really complex, which is why they are addressed in an upcoming page: [Block States](/blocks/blockstates)

Restarting the game, or reloading via <kbd>F3</kbd> + <kbd>T</kbd> to apply changes - you should be able to see the block texture in the inventory and physically in the world:

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
228 changes: 228 additions & 0 deletions getting-started/basic-problem-solving.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
---
title: Basic Problem Solving
description: Learn how to solve simple issues and mistakes on your own.
order: 6
---

# Basic Problem Solving

Issues, mistakes and bugs can happen even to the best programmer. You can develop a basic set of steps to potentially identify and resolve those issues without the help of others. Problems solved on your own can teach you many things and also feel rewarding. However, if you are stuck without being able to fix the problems by yourself, there is no shame in asking others for help.

This page focuses mostly on functionality which is provided by IntelliJ (and many other IDEs) such as Logging and how to use the Debugger.

## Console and LOGGER

The most basic but also fastest tool to identify problems is the console. Values can be printed there at "run-time" which can inform the developer about the current state of the code and makes it easy to analyze changes and potential mistakes.

In the `ModInitializer` implementing entry point class of the mod, a `LOGGER` is used by default, to print the desired output to the console.

```java
public class MyMod implements ModInitializer {
public static final String MOD_ID = "mod_id";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);

@Override
public void onInitialize() {
// ...
}
}
```

Whenever you need to know a value for something at a specific point in the code, use this `LOGGER` by passing the `String` value to its `info(...)` method.

```java
public class TestItem extends Item {

public TestItem(Settings settings) {
super(settings);
}

@Override
public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) {
// Values are used in a String to provide more information
TestMod.LOGGER.info("Is Client World: " + user.getWorld().isClient()
+ " | Health: " + entity.getHealth() + " / " + entity.getMaxHealth()
+ " | The item was used with the " + hand.name()
);

return ActionResult.SUCCESS;
}
}
```

When, in this case, the `TestItem` is used on an Entity it will provide the values at this current state of the mod in the console of the currently used instance. If your `Run` window for the console is missing, you can open a new one in the toolbar at the top (`View > Tool Windows > Run`), if you are working with IntelliJ.

![LOGGER output](./_assets/basic_problem_solving_01.png)

### Keeping the console clean

Keep in mind that this will also be printed if the mod is used in any other environment. This is completely optional, but I like to create a custom `LOGGER` method and use that, instead of the `LOGGER` itself to prevent printing data, which is only needed in a development environment.

```java
public class MyMod implements ModInitializer {
public static final String MOD_ID = "mod_id";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);

@Override
public void onInitialize() {
// ...
}

public static void devLogger(String loggerInput) {
// prevent usage if the Instance is not run in a development environment
if (!FabricLoader.getInstance().isDevelopmentEnvironment()) return;

// customize that message however you want...
TestMod.LOGGER.info("DEV - [" + loggerInput + "]");
}
}
```

Otherwise clean up the `LOGGER` usage as much as you can, to prevent causing a headache for Modpack developers and curious users.

### Locating the issues

The Logger prints the `MOD-ID` in front of the line. The Search function <kbd>CTRL / CMD + F</kbd> can be used to highlight it, making it easier to spot the problem. Missing assets, such as the Purple & Black placeholder when a texture is missing, also print their errors in the console and mention their missing files. You can also use the Search function here and look for the asset name in question.

<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/Minecraft_missing_texture_block.svg/1024px-Minecraft_missing_texture_block.svg.png" width="150" height="150" style="margin-left: auto; margin-right: auto;" />

![missing assets](./_assets/basic_problem_solving_02.png)

## Debugging

### Breakpoint

A more "sophisticated" way of debugging is the usage of Breakpoints in an IDE. As their name suggests, they are used to halt the executed code at specific locations and make it possible to inspect and modify the state of the software with a variety of tools.

When working with Breakpoints, the Instance needs to be executed using the `Debug` option instead of the `Run` option.

![Debugging](./_assets/basic_problem_solving_03.png)

Let's use a custom Item as an example again. The Item is supposed to increase its efficiency level, whenever it has been used. But whenever this happens all the remaining enchantments get removed. How can this issue be resolved?

```java
// problematic example code:

public class TestItem extends Item {

public TestItem(Settings settings) {
super(settings);
}

@Override
public ActionResult useOnBlock(ItemUsageContext context) {
ItemStack itemStack = context.getStack();
World world = context.getWorld();
BlockPos pos = context.getBlockPos();

if (world.isClient()) return super.useOnBlock(context);

int levelOfEfficiency = EnchantmentHelper.getLevel(Enchantments.EFFICIENCY, itemStack);

itemStack.removeSubNbt("Enchantments");
itemStack.addEnchantment(Enchantments.EFFICIENCY, levelOfEfficiency + 1);

if (levelOfEfficiency > 10) {
world.createExplosion(context.getPlayer(), pos.getX(), pos.getY(), pos.getZ(), 2, true, World.ExplosionSourceType.MOB);
}

return ActionResult.SUCCESS;
}
}
```

Place a Breakpoint by clicking right next to the line number. You can place more than one at once if needed.

![basic breakpoint](./_assets/basic_problem_solving_04.png)

Then let the instance execute this part of the code. In this case, the custom Item needs to be used on a Block. The Instance should freeze and in IntelliJ a yellow arrow right next to the Breakpoint appears. This indicates at which point the Debugger is currently. In the `Debug` window the controls can be used to move the current execution point using the blue arrow icons. This way the code can be processed step by step.

![move execution point](./_assets/basic_problem_solving_05.png)

<Subtitle>The "Step over" function is the most common one so try to get used to its Keybind <kbd>(F8)</kbd></Subtitle>

If you are done with the current inspection you can press the `Resume Program` button at the left side of the `Debug` window. This will un-freeze the Minecraft instance and further testing can be done.

Currently, loaded values and objects are listed on the right side of this window, while a complete Stacktrace is on the left side. You can also hover, with the Mouse Cursor, over the values in the code. If they are in scope and are still loaded a window will show their specific values too.

![loaded values](./_assets/basic_problem_solving_06.png)

<Subtitle>Not loaded Integer vs. loaded Integer</Subtitle>

If we inspect the `ItemStack` object we can see that the enchantments are stored as NBT values. The `removeSubNbt()` method removes all SubNbt values with the "Enchantments" key.

![itemstack](./_assets/basic_problem_solving_07.png)

To avoid that, only the specific enchantment needs to be removed. This can be done using the `EnchantmentHelper` in combination with filtering a `Stream`.

```java
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
ItemStack itemStack = context.getStack();
World world = context.getWorld();
BlockPos pos = context.getBlockPos();

if (world.isClient()) return super.useOnBlock(context);

int levelOfEfficiency = EnchantmentHelper.getLevel(Enchantments.EFFICIENCY, itemStack);


// Get a list of the itemStack's enchantments
var enchantments = EnchantmentHelper.fromNbt(itemStack.getOrCreateNbt().getList("Enchantments", NbtElement.COMPOUND_TYPE));
var filteredEnchantments = enchantments.entrySet().stream()
// Keep only enchantments which aren't EFFICIENCY
.filter(entry -> !(entry.getKey().equals(Enchantments.EFFICIENCY)))
// collect the entries of the stream for the final itemStack's enchantments Map
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

// put the changed enchantments Map (without the efficiency) back on the itemStack
EnchantmentHelper.set(filteredEnchantments, itemStack);

// add the efficiency enchantment back with the new level
itemStack.addEnchantment(Enchantments.EFFICIENCY, levelOfEfficiency + 1);

if (levelOfEfficiency > 10) {
world.createExplosion(context.getPlayer(), pos.getX(), pos.getY(), pos.getZ(),
2, true, World.ExplosionSourceType.MOB);
}

return ActionResult.SUCCESS;
}
```

### Breakpoints with conditions

Sometimes it is necessary to only halt the code when certain conditions are met. Create a basic Breakpoint and right-click it to open the Breakpoint's settings. In there, you can use boolean statements for the condition.

![Breakpoint with conditions](./_assets/basic_problem_solving_08.png)

### Reloading an active Instance

It is possible to make limited changes to the code, while a Minecraft instance is running. Method bodies can be rewritten at run-time using the `Debug` option instead of the `Run` option. This way, the Minecraft instance doesn't need to be restarted again. This makes e.g. testing Screen element alignment and other feature balancing faster.

![Debugging](./_assets/basic_problem_solving_03.png)

When the instance is running and changes to the code have been made, use `Build Project` to reload the changes. This process is also known as "Hotswap". If the changes were applied to the current instance, a green notification will be shown.

![build project](./_assets/basic_problem_solving_09.png)

![hotswap](./_assets/basic_problem_solving_10.png)

<Subtitle>Correct Hotswap vs. failed Hotswap</Subtitle>

Other changes can be reloaded in-game.

- changes to the `assets/` folder -> press `[F3 + T]`
- changes to the `data/` folder -> use the `/reload` command

## Logs and crash report files

The console of a previously executed instance helps with finding the issues. They are exported into the log files, located in the Minecraft instance's `logs` directory. The newest log is usually called `latest.log`. Users can send this file, for further inspection, to the mod developer or host the file content on code-hosting websites.

In the development environment you can find the logs in the project's `run > logs` folder and the crash reports in the `run > crash-reports` folder.

## Still couldn't solve the problem?

Join the community and ask for help!

- [Official Fabric Wiki](https://fabricmc.net/wiki/start) and their [Discord server](https://discord.com/invite/v6v4pMv)
34 changes: 9 additions & 25 deletions getting-started/using-the-ide.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Using the IDE to the fullest
description: Useful information to handle and traverse your Project using the IDE.
order: 7
---

# Using the IDE to the fullest
Expand All @@ -17,27 +18,16 @@ Refer to the `File > Setings > Keymap` Settings or search for the functionality

### Manually

IntelliJ has many different ways of traversing projects. If you have generated sources using the...

```
./gradleW genSources
```

...command in the terminal
or used the `Tasks > fabric > genSources` Gradle Task in the Gradle Window, you can manually go through the source files of Minecraft in the
IntelliJ has many different ways of traversing projects. If you have generated sources using the `./gradlew genSources` command in the terminal or used the `Tasks > fabric > genSources` Gradle Task in the Gradle Window, you can manually go through the source files of Minecraft in the
Project Window's External Libraries.

![Gradle Task](./_assets/traversing_01.png)

<Subtitle>Generate Sources using the Gradle Task</Subtitle>

The Minecraft Source code can be found if you look for `net.minecraft`, but also other sources of projects, libraries and dependencies, which are imported using the `build.gradle` file
are located in there. This method is often used when browsing for assets, tags and other files.

![External Library](./_assets/traversing_02.png)

<Subtitle>To search in the Project Window, just focus it and start typing</Subtitle>

### Search

Pressing `Shift` twice opens up a Search window. In there you can search for your project's files and classes. When Activating the checkbox `include non-project items`
Expand Down Expand Up @@ -69,15 +59,11 @@ Creating `Mnemonic Bookmarks` enables you to quickly switch back to those bookma

![set Bookmark](./_assets/traversing_05.png)

<Subtitle>Right-click on a line number to set a Bookmark</Subtitle>

It is possible to create multiple Bookmark lists at the same time if you need to separate or order them, in the `Bookmarks` window.
[`Breakpoints`](basic-problem-solving#breakpoint) will also be displayed in there.

![Bookmark window](./_assets/traversing_06.png)

<Subtitle>Get an overview over all Bookmarks using the `Bookmarks` window</Subtitle>

## Analyzing classes

### Structure of a class
Expand Down Expand Up @@ -157,8 +143,6 @@ and the `Comment with Block Comment` entries, and set their Key binds to your pr

![Keymap settings](./_assets/comments_01.png)

<Subtitle>Open IntelliJ Settings (`File > Setings > Keymap`)</Subtitle>

Now you can highlight the necessary code and use the shortcuts, to comment the section out.

```java
Expand Down Expand Up @@ -197,10 +181,10 @@ if you are not actively working on them. To create a custom block which can be c

![Keymap settings](./_assets/comments_02.png)

<Subtitle>Region comment block collapsing</Subtitle>

<Callout type="warning">This feature may not be supported in other editors and IDEs.
If you notice that you are using too many of them, consider refactoring your code to make it more readable!</Callout>
::: warning
This feature may not be supported in other editors and IDEs.
If you notice that you are using too many of them, consider refactoring your code to make it more readable!
:::

### TODO and FIXME notes

Expand All @@ -217,7 +201,9 @@ which uses those type of comments.

![Commit with TODO](./_assets/comments_05.png)

<Callout type="warning">This feature may not be supported in other editors and IDEs.</Callout>
::: warning
This feature may not be supported in other editors and IDEs.
:::

### Javadocs

Expand All @@ -228,8 +214,6 @@ When hovering over method or class names, which have JavaDoc comments added to t

![JavaDoc](./_assets/comments_06.png)

<Subtitle>Example JavaDocs information</Subtitle>

To get started, simply write `/**` above the method or class definition and press enter. IntelliJ will automatically generate lines for the return value
and the parameters but you can change them however you want. There are many custom functionalities available and you can also use HTML if needed.

Expand Down
7 changes: 1 addition & 6 deletions items/armor.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
---
title: Armor
description: Learn how to create your own armor sets.
prev:
text: "Tools and Weapons"
link: "/items/tools"
next:
text: "Item Groups"
link: "/items/item-groups"
order: 3
---

# Armor
Expand Down
7 changes: 1 addition & 6 deletions items/food.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
---
title: Food
description: Learn how to add a FoodComponent to an item to make it edible, and configure it.
prev:
text: "Creating Your First Item"
link: "/items/index"
next:
text: "Tools and Weapons"
link: "/items/tools"
order: 1
---

# Food Items
Expand Down
4 changes: 1 addition & 3 deletions items/index.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
---
title: Creating Your First Item
description: Learn how to register a simple item and how to texture, model and name it.
next:
text: "Food Items"
link: "/items/food"
order: 0
---

# Creating Your First Item
Expand Down
4 changes: 1 addition & 3 deletions items/interactivity.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
---
title: Item Interactivity
description: Learn how to create an item that uses built-in vanilla events.
prev:
text: "Custom Item Groups"
link: "/items/item-groups"
order: 5
---

# Interactivity
Expand Down
Loading

0 comments on commit 8c10f13

Please sign in to comment.