Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9a3ed83
Add example boss, ore, and incursion content
Jamesp1989SL Jan 20, 2026
515f085
Merge pull request #4 from DrFair/master
Jamesp1989SL Jan 20, 2026
8b2fe81
Add ExampleAI and ExampleAILeaf for mob behavior
Jamesp1989SL Jan 20, 2026
3eca28d
Refactor item structure and add Example Bar item
Jamesp1989SL Jan 21, 2026
e4e729d
Add example sound and play packet for boss mob
Jamesp1989SL Jan 21, 2026
978f2a7
Refactor item/object IDs and add ExampleStoneItem
Jamesp1989SL Jan 22, 2026
17d29f0
Play sound for AI leaf on both teleport and failure
Jamesp1989SL Jan 22, 2026
4439c77
Add landscaping recipes and update item textures
Jamesp1989SL Jan 22, 2026
785c7d2
Add example loot table and preset, update incursion level
Jamesp1989SL Jan 23, 2026
7512ef3
Refactor ExamplePreset and add utility classes
Jamesp1989SL Jan 23, 2026
bab2f9e
Add example wall, door, and window objects
Jamesp1989SL Jan 24, 2026
6406686
Refactor mod initialization into loader classes
Jamesp1989SL Jan 27, 2026
ebde9ad
Add example armor set, categories, and refactor items
Jamesp1989SL Jan 29, 2026
c304209
Refactor and update mod category structure and objects
Jamesp1989SL Feb 1, 2026
28cd55e
Add example tree, sapling, log, and chair objects
Jamesp1989SL Feb 2, 2026
f6844b9
Add examplesapling loot and update assets
Jamesp1989SL Feb 2, 2026
b044a04
Add detailed comments to example preset classes
Jamesp1989SL Feb 2, 2026
6498fca
Add pre-antialias textures Gradle task
Jamesp1989SL Feb 2, 2026
daa3b92
Add example grass biome, tile, object & seed
Jamesp1989SL Feb 3, 2026
7f2bb19
Add example level event, object, and loader
Jamesp1989SL Feb 4, 2026
e326567
Add summon weapon, mob, and level-event object
Jamesp1989SL Feb 5, 2026
b9f6025
Add arrow ammo, bow, projectile & arrow buff
Jamesp1989SL Feb 6, 2026
d01ff2b
Add settler jobs, settings, objects, and packets
Jamesp1989SL Feb 11, 2026
709ebf8
Rename JobFinder stream patch
Jamesp1989SL Feb 11, 2026
b857df3
Add boss summon item, journal, traps, and biome
Jamesp1989SL Feb 15, 2026
fc6eaef
Add example trinket item and buff
Jamesp1989SL Feb 15, 2026
17bb4bd
Log settings; add boss private loot rotation, add trinket to loot tab…
Jamesp1989SL Feb 16, 2026
7d748e2
Refactor example mod IDs, tools, and job logic
Jamesp1989SL Feb 17, 2026
8d3ccbe
Use examplewall (ID 1436) in preset
Jamesp1989SL Feb 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ task createModInfoFile(type: JavaExec) {
// Makes compiling also create mod info file
classes.dependsOn("createModInfoFile")

task preAntialiasTextures(type: JavaExec) {
group "necesse"
description "Runs pre-antialiasing on all textures in the resources folder"

classpath = files(gameDirectory + "/Necesse.jar")

main "PreAntialiasTextures"
args "-folders", "${sourceSets.main.resources.srcDirs.stream().map {file -> file.path}.toArray().join(";")}"
}

task runClient(type: JavaExec) {
group "necesse"
description "Run client with current mod"
Expand Down
132 changes: 41 additions & 91 deletions src/main/java/examplemod/ExampleMod.java
Original file line number Diff line number Diff line change
@@ -1,126 +1,76 @@
package examplemod;

import examplemod.examples.*;
import examplemod.examples.items.ExampleFoodItem;
import examplemod.examples.items.ExampleHuntIncursionMaterialItem;
import examplemod.examples.items.ExampleMaterialItem;
import examplemod.examples.items.ExamplePotionItem;
import necesse.engine.commands.CommandsManager;
import examplemod.Loaders.*;
import examplemod.examples.maps.biomes.ExampleBiome;
import necesse.engine.modLoader.annotations.ModEntry;
import necesse.engine.registries.*;
import necesse.gfx.gameTexture.GameTexture;
import necesse.inventory.recipe.Ingredient;
import necesse.inventory.recipe.Recipe;
import necesse.inventory.recipe.Recipes;
import necesse.engine.sound.SoundSettings;
import necesse.engine.sound.gameSound.GameSound;
import necesse.level.maps.biomes.Biome;

@ModEntry
public class ExampleMod {
// Global access point for mod settings
public static ExampleModSettings settings;

// We define our static registered objects here, so they can be referenced elsewhere
public static ExampleBiome EXAMPLE_BIOME;
public static GameSound EXAMPLESOUND;
public static SoundSettings EXAMPLESOUNDSETTINGS;

// Load settings for the example mod from the external file defined in ExampleModSettings
public ExampleModSettings initSettings() {
settings = new ExampleModSettings();
return settings;
}

public void init() {
System.out.println("Hello world from my example mod!");
settings.logLoadedSettings(); // log the loaded settings for debug

// Register a simple biome that will not appear in natural world gen.
EXAMPLE_BIOME = BiomeRegistry.registerBiome("exampleincursion", new ExampleBiome(), false);

// Register the incursion biome with tier requirement 1.
IncursionBiomeRegistry.registerBiome("exampleincursion", new ExampleIncursionBiome(), 1);

// Register the level class used for the incursion.
LevelRegistry.registerLevel("exampleincursionlevel", ExampleIncursionLevel.class);
// Register categories first: Used by Items/Objects to appear correctly in Creative/crafting trees
ExampleModCategories.load();

// Register our tiles
TileRegistry.registerTile("exampletile", new ExampleTile(), 1, true);
// Register packets early: Anything networked (mobs, settlers, job UIs, events) can safely reference packet IDs
ExampleModPackets.load();

// Register our objects
ObjectRegistry.registerObject("exampleobject", new ExampleObject(), 2, true);
// Core content building blocks first: Tiles/Objects/Items are referenced by biomes, incursions, mobs, projectiles, buffs, etc.
ExampleModTiles.load();
ExampleModObjects.load();
ExampleModItems.load();

// Register our items
ItemRegistry.registerItem("exampleitem", new ExampleMaterialItem(), 10, true);
ItemRegistry.registerItem("examplehuntincursionitem", new ExampleHuntIncursionMaterialItem(), 50, true);
ItemRegistry.registerItem("examplesword", new ExampleSwordItem(), 20, true);
ItemRegistry.registerItem("examplestaff", new ExampleProjectileWeapon(), 30, true);
ItemRegistry.registerItem("examplepotionitem", new ExamplePotionItem(), 10, true);
ItemRegistry.registerItem("examplefooditem", new ExampleFoodItem(),15, true);
// Combat + entity registries next: Projectiles and buffs often reference items/mobs, and mobs can reference buffs/projectiles.
ExampleModProjectiles.load();
ExampleModBuffs.load();
ExampleModMobs.load();

// Register our mob
MobRegistry.registerMob("examplemob", ExampleMob.class, true);
// Settlement systems after mobs/items exist: Settlers are mobs; jobs can reference settlers, items, and packets/UI.
ExampleModSettlers.load();
ExampleModJobs.load();

// Register our projectile
ProjectileRegistry.registerProjectile("exampleprojectile", ExampleProjectile.class, "exampleprojectile", "exampleprojectile_shadow");
// World generation last-ish: Biomes/incursions can safely reference all registered tiles/objects/mobs/items now.
ExampleModBiomes.load();
ExampleModIncursions.load();

// Register our buff
BuffRegistry.registerBuff("examplebuff", new ExampleBuff());
// Events after everything is registered: Lets event listeners safely reference IDs and content without ordering surprises.
ExampleModEvents.load();

// Register our packet
PacketRegistry.registerPacket(ExamplePacket.class);
// Journal last: JournalEntry.addMobEntries() resolves MobRegistry immediately at registration time.
ExampleModJournal.load();
}

public void initResources() {
// Sometimes your textures will have a black or other outline unintended under rotation or scaling
// This is caused by alpha blending between transparent pixels and the edge
// To fix this, run the preAntialiasTextures gradle task
// It will process your textures and save them again with a fixed alpha edge color

ExampleMob.texture = GameTexture.fromFile("mobs/examplemob");
ExampleModResources.load();
}

public void postInit() {
// Add recipes
// Example item recipe, crafted in inventory for 2 iron bars
Recipes.registerModRecipe(new Recipe(
"exampleitem",
1,
RecipeTechRegistry.NONE,
new Ingredient[]{
new Ingredient("ironbar", 2)
}
).showAfter("woodboat")); // Show recipe after wood boat recipe

// Example sword recipe, crafted in iron anvil using 4 example items and 5 copper bars
Recipes.registerModRecipe(new Recipe(
"examplesword",
1,
RecipeTechRegistry.IRON_ANVIL,
new Ingredient[]{
new Ingredient("exampleitem", 4),
new Ingredient("copperbar", 5)
}
));

// Example staff recipe, crafted in workstation using 4 example items and 10 gold bars
Recipes.registerModRecipe(new Recipe(
"examplestaff",
1,
RecipeTechRegistry.WORKSTATION,
new Ingredient[]{
new Ingredient("exampleitem", 4),
new Ingredient("goldbar", 10)
}
).showAfter("exampleitem")); // Show the recipe after example item recipe

// Example food item recipe
Recipes.registerModRecipe(new Recipe(
"examplefooditem",
1,
RecipeTechRegistry.COOKING_POT,
new Ingredient[]{
new Ingredient("bread", 1),
new Ingredient("strawberry", 2),
new Ingredient("sugar", 1)
}
));
// load our recipes from the ExampleRecipes class so we can keep this class easy to read
ExampleModRecipes.registerRecipes();


// Add our example mob to default cave mobs.
// Spawn tables use a ticket/weight system. In general, common mobs have about 100 tickets.
Biome.defaultCaveMobs
.add(100, "examplemob");

// Register our server chat command
CommandsManager.registerServerCommand(new ExampleChatCommand());
}

}
37 changes: 37 additions & 0 deletions src/main/java/examplemod/ExampleModSettings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package examplemod;

import necesse.engine.GameLog;
import necesse.engine.modLoader.ModSettings;
import necesse.engine.save.LoadData;
import necesse.engine.save.SaveData;

public class ExampleModSettings extends ModSettings {
// Your config values
public boolean exampleBoolean = true;
public int exampleInt = 1;
public String exampleString = "Hello! from the config file ";

@Override
public void addSaveData(SaveData data) {
// This is what gets written to cfg/mods/<modid>.cfg under SETTINGS { ... }
data.addBoolean("exampleBoolean", exampleBoolean);
data.addInt("exampleInt", exampleInt);
data.addSafeString("exampleString", exampleString);
}

@Override
public void applyLoadData(LoadData data) {
// This is what gets read back from cfg/mods/<modid>.cfg
exampleBoolean = data.getBoolean("exampleBoolean", exampleBoolean);
exampleInt = data.getInt("exampleInt", exampleInt);
exampleString = data.getSafeString("exampleString", exampleString, false);
}

public void logLoadedSettings() {

GameLog.out.println("[ExampleMod] Settings loaded:");
GameLog.out.println(" exampleBoolean = " + exampleBoolean);
GameLog.out.println(" exampleInt = " + exampleInt);
GameLog.out.println(" exampleString = \"" + exampleString + "\"");
}
}
15 changes: 15 additions & 0 deletions src/main/java/examplemod/Loaders/ExampleModBiomes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package examplemod.Loaders;

import examplemod.ExampleMod;
import examplemod.examples.maps.biomes.ExampleBiome;
import necesse.engine.registries.BiomeRegistry;

public class ExampleModBiomes {
public static void load() {
// Register a simple biome that will not appear in natural world gen.
ExampleMod.EXAMPLE_BIOME = BiomeRegistry.registerBiome("examplebiome", new ExampleBiome(), false);
}
}



21 changes: 21 additions & 0 deletions src/main/java/examplemod/Loaders/ExampleModBuffs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package examplemod.Loaders;

import examplemod.examples.buffs.*;
import necesse.engine.registries.BuffRegistry;
import necesse.entity.mobs.buffs.staticBuffs.Buff;

public class ExampleModBuffs {
public static void load(){
// Register our buff
BuffRegistry.registerBuff("examplebuff", new ExampleBuff());

// Register our Armor Set Bonus
BuffRegistry.registerBuff("examplearmorsetbonusbuff", new ExampleArmorSetBuff());

// Register our Arrow Buff
BuffRegistry.registerBuff("examplearrowbuff", new ExampleArrowBuff());

// Register our Trinket Buff
BuffRegistry.registerBuff("exampletrinketbuff",new ExampleTrinketBuff());
}
}
118 changes: 118 additions & 0 deletions src/main/java/examplemod/Loaders/ExampleModCategories.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package examplemod.Loaders;

import necesse.engine.localization.message.LocalMessage;
import necesse.inventory.item.ItemCategory;

public final class ExampleModCategories {
private ExampleModCategories() {}

/*
* IMPORTANT (Creative Menu requirement)
* ------------------------------------
* The Creative menu tabs currently only browse a small set of hard-coded ROOT categories but this will be changed in the future.
*
* Placeables tab roots: tiles / objects / wiring
* Items tab roots: equipment / consumable / materials / misc
* Mobs tab roots: mobs
*
* So: your itemCategoryTree MUST start with one of those roots, otherwise the item/object
* will not appear in Creative even though it is registered.
*/

// VANILLA PLACABLE
// ===== ROOT =====
public static final String ROOT_TILES = "tiles";
public static final String ROOT_OBJECTS = "objects";
public static final String ROOT_WIRING = "wiring";

// ===== VANILLA: TILES children =====
public static final String TILES_FLOORS = "floors";
public static final String TILES_LIQUIDS = "liquids";
public static final String TILES_TERRAIN = "terrain";

// ===== VANILLA: OBJECTS children =====
public static final String OBJECTS_SEEDS = "seeds";
public static final String OBJECTS_CRAFTINGSTATIONS = "craftingstations";
public static final String OBJECTS_LIGHTING = "lighting";
public static final String OBJECTS_FURNITURE = "furniture";
public static final String OBJECTS_DECORATIONS = "decorations";
public static final String OBJECTS_WALLSANDDOORS = "wallsanddoors";
public static final String OBJECTS_FENCESANDGATES = "fencesandgates";
public static final String OBJECTS_COLUMNS = "columns";
public static final String OBJECTS_TRAPS = "traps";
public static final String OBJECTS_LANDSCAPING = "landscaping";
public static final String OBJECTS_MISC = "misc";

// ===== VANILLA: FURNITURE children =====
public static final String FURNITURE_MISC = "misc";
public static final String FURNITURE_OAK = "oak";
public static final String FURNITURE_SPRUCE = "spruce";
public static final String FURNITURE_PINE = "pine";
public static final String FURNITURE_MAPLE = "maple";
public static final String FURNITURE_BIRCH = "birch";
public static final String FURNITURE_WILLOW = "willow";
public static final String FURNITURE_DUNGEON = "dungeon";
public static final String FURNITURE_BONE = "bone";
public static final String FURNITURE_DRYAD = "dryad";
public static final String FURNITURE_BAMBOO = "bamboo";
public static final String FURNITURE_DEADWOOD = "deadwood";

// ===== VANILLA: DECORATIONS children =====
public static final String DECORATIONS_PAINTINGS = "paintings";
public static final String DECORATIONS_CARPETS = "carpets";
public static final String DECORATIONS_POTS = "pots";
public static final String DECORATIONS_BANNERS = "banners";

// ===== VANILLA: LANDSCAPING children =====
public static final String LANDSCAPING_FORESTROCKSANDORES = "forestrocksandores";
public static final String LANDSCAPING_SNOWROCKSANDORES = "snowrocksandores";
public static final String LANDSCAPING_PLAINSROCKSANDORES = "plainsrocksandores";
public static final String LANDSCAPING_SWAMPROCKSANDORES = "swamprocksandores";
public static final String LANDSCAPING_DESERTROCKSANDORES = "desertrocksandores";
public static final String LANDSCAPING_INCURSIONROCKSANDORES = "incursionrocksandores";
public static final String LANDSCAPING_CRYSTALS = "crystals";
public static final String LANDSCAPING_TABLEDECORATIONS = "tabledecorations";
public static final String LANDSCAPING_PLANTS = "plants";
public static final String LANDSCAPING_MASONRY = "masonry";
public static final String LANDSCAPING_MISC = "misc";

// ===== VANILLA: WIRING children =====
public static final String WIRING_LOGICGATES = "logicgates";


// YOUR MOD ROOT CATEGORY
public static final String MOD = "examplemod";
// YOUR MOD SUB CATEGORY
public static final String MOD_OBJECTS = "objects";

public static final String EXAMPLEWOOD = "examplewood";

public static void load() {

// ITEM CATEGORIES (not Creative-visible right now, but valid categories)
ItemCategory.createCategory("Z-EXAMPLEMOD",
new LocalMessage("itemcategory", "examplemodrootcat"),
MOD);

ItemCategory.createCategory("Z-EXAMPLEMOD-OBJECTS",
new LocalMessage("itemcategory", "examplemodobjectsubcat"),
MOD, MOD_OBJECTS);

ItemCategory.createCategory("Z-EXAMPLEMOD-OBJECTS-FURNATURE",
new LocalMessage("itemcategory", "examplemodfurnaturesubcat"),
MOD, MOD_OBJECTS,EXAMPLEWOOD);

// CRAFTING CATEGORIES
ItemCategory.craftingManager.createCategory("Z-EXAMPLEMOD",
new LocalMessage("itemcategory", "examplemodrootcat"),
MOD);

ItemCategory.craftingManager.createCategory("Z-EXAMPLEMOD-OBJECTS",
new LocalMessage("itemcategory", "examplemodobjectsubcat"),
MOD,MOD_OBJECTS);

ItemCategory.craftingManager.createCategory("Z-EXAMPLEMOD-OBJECTS-FURNATURE",
new LocalMessage("itemcategory", "examplemodfurnaturesubcat"),
MOD,MOD_OBJECTS,EXAMPLEWOOD);
}
}
13 changes: 13 additions & 0 deletions src/main/java/examplemod/Loaders/ExampleModCommands.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package examplemod.Loaders;

import examplemod.examples.ExampleChatCommand;
import necesse.engine.commands.CommandsManager;

public class ExampleModCommands {
public static void load(){

// Register our server chat command
CommandsManager.registerServerCommand(new ExampleChatCommand());

}
}
Loading