Quality-of-life creature companions for Minecraft — without the turns.
Status: 0.8.1 — beta. Core loop (catch → own → summon → work/fight/assist) is feature-complete and server-tested. A few systems are still flagged untested-in-game or have known rough edges — see Known Issues before reporting a bug.
Palmod is a Forge server mod built around one idea: creature-collecting games are fun because of the loop — find something interesting, catch it, raise it, watch it get useful or strong — not because of turn-based battle menus. Palmod keeps the loop and throws out everything else. There's no Pokémon-style combat system, no menus to fight through, and nothing here is Pokémon or Palworld content, assets, or mechanics — it's an original ruleset that happens to call a caught creature a "Pal" because "creature you threw a sphere at" doesn't fit on a tooltip.
Under the hood it's a quality-of-life mod first: your Pals are automated farmhands, combat allies, mobile storage, buffs, and fast travel, layered on top of vanilla and Alex's Mobs creatures with zero turn-based interruption — everything happens in real time, in the open world, while you keep playing normally.
Everything about which mob does what lives in datapack JSON, not code — see Adding & Configuring Pals if you want to add your own creature, rebalance an existing one, or build an addon.
- Minecraft 1.20.1, Forge 47.4.10+
- Alex's Mobs
1.22.9+(required — the Paldex, dictionary pages, and most shipped Pals depend on it) - Citadel
2.6.3+(Alex's Mobs dependency) - Server-authoritative: all Pal logic runs server-side. The client only needs item
textures/models, the egg-tint on filled spheres, and the Paldex book pages — a vanilla or
bare-Forge client can still join and see a functional (if visually plainer) mod, see
allowVanillaClientsbelow.
- Player Guide
- Server configuration
- Adding & Configuring Pals (datapacks)
- Building from source
- Known issues
- Credits
Not every mob is catchable. When a mob spawns, it has a chance (config-controlled, default 40%) to roll "catchable." Catchable mobs show a subtle enchant-glint shimmer — there's no outline-through-walls glow, so you'll need line of sight. Throw a Pal Sphere at an uncatchable mob and the sphere is simply lost — there's no partial credit.
Catch chance is HP-based, and it's deliberately not a coin flip at full health:
catch % = (sphere tier + Leveling enchant level) − max HP + 0.7 × (% health already lost)
In practice: weaken it first. A full-health cow is close to uncatchable with a basic sphere; the same cow at 1 HP is a good bet. Tougher/rarer creatures need a better sphere tier, a Leveling enchant, or both. This is intentional — Palmod rewards fighting or wearing a target down before you commit a sphere, not blind spam-throwing.
You can throw from range, or right-click a mob directly for a guaranteed close-range throw.
| Item | Craft | Notes |
|---|---|---|
| Pal Sphere | 8× Iron Ingot + Redstone (ring around center) | Base tier |
| Mid Pal Sphere | 8× Gold Ingot + Redstone Block | Better catch odds |
| Advanced Pal Sphere | 8× Diamond + Redstone Block | Best catch odds |
All three are enchantable (enchant an empty sphere before you catch with it):
| Enchantment | Effect |
|---|---|
| Leveling | Adds levels directly to the catch-rate formula |
| Infinite | Sphere isn't consumed on a lost/failed throw |
| FastBall | Faster projectile travel speed |
| Following | Sphere homes in on its target (skips uncatchable/hidden mobs) |
| Warp Tether | Recalling the caught Pal later teleports it straight to you |
Craft: 4× Pal Sphere around a vanilla Compass. Right-click-equivalent hold in your hotbar and it points at the nearest catchable mob within 128 blocks (with hysteresis so the needle doesn't twitch between two nearby targets). Shy or ambush-hidden wild Pals are excluded until they reveal themselves. No target in range = the needle spins.
- Throw a filled sphere → summons the Pal into the world, alive, at full state, with a name tag over its head.
- Right-click while it's out → recalls it back into the sphere (snapshots its current state — health, position data, everything).
- The Pal dies → its sphere reverts to an empty sphere automatically. No re-catching a ghost.
- Orphan rule: a released (summoned) Pal despawns if its sphere isn't in your hotbar or offhand — you can't summon a Pal and then wander off without it. Exceptions: Pals bound to a Work Station, deployed Pals (anchor/sentry), and anything you're currently riding.
Right-clicking your own Pal does different things depending on how you click and what it's configured to do:
| Click | Requires | Result |
|---|---|---|
| Sneak + holding an item | fetch enabled |
Sends it to fetch a matching item |
| Sneak, empty hand | mobile_chest_size > 0 |
Opens its storage (a vanilla chest UI) |
| Sneak, empty hand | xp_collector enabled |
Collects its stored XP as bottles |
| Plain click + food it likes | Hunger < 100 | Hand-feeds it |
| Plain click | rideable |
Mounts it (steers by where you look) |
| Plain click | none of the above | Toggles sit/stand |
Every Pal has a Hunger and Mood meter that decays over time (rates are configurable per mob). Actions — chopping, harvesting, casting abilities — cost Hunger too. Effects compound the hungrier a Pal gets:
- < 80 — actively seeks out a stocked Feeder on its own
- < 30 — moves and works at 0.7× speed
- < 5 — stops working entirely, but keeps crawling (0.3×) toward food instead of freezing solid — it can still recover on its own
- Deployed Pals (turrets/waystones) don't decay at all
- Feed it directly by right-clicking with food it likes, or build it a Pal Feeder block (hopper-fed) so it self-serves
Place a Pal Work Station, then throw a station-mode Pal's sphere at it — the sphere is consumed and the Pal spawns bound to that station as a worker (lumberjack, harvester, trader, sorter, or miner, depending on the mob). It'll wander a configurable radius, do its job, and deposit results into the station's output slot (which you can hopper straight into storage). Right-click the station to collect manually. Break the station to get the sphere back; if the worker goes missing for too long, its sphere returns automatically instead of leaving an orphaned mob wandering the world.
Every Pal has one special power (see the ability roster below) that triggers automatically from how you use it — there are no manual ability buttons to press:
- Combat casters throw elemental attacks at your target automatically while summoned and fed.
time_stopPals freeze everything in a radius the instant you summon them — pick your moment and your spot with the throw.warp_beaconPals root themselves in place on a normal summon; recalling them later teleports you to that spot.- Sneak-throwing a sphere with
deploy_modeset (instead of a normal throw) turns that Pal into a stationary anchor or sentry turret instead of a mobile companion. - Aura Pals (heal/storm) passively buff you just by being out and fed nearby.
| Ability | Example Pal | Ability | Example Pal |
|---|---|---|---|
| Bodyguard (retaliate-only) | Grizzly Bear | ZA WARUDO (time stop on summon) | Enderiophage |
| Lumberjack | Gorilla | Warp beacon (teleport on recall) | Spectre |
| Harvester | Leafcutter Ant | Sentry turret | Guster |
| Trader | Crow | Lightning cast | Sunbird |
| Sorter | Raccoon | Fireball cast | Soul Vulture |
| Miner | Rocky Roller | Earth spike cast | Elephant |
| Heal aura | Mungus | Water burst cast | Mantis Shrimp |
| Storm charge (lightning on your hits) | Bald Eagle | Rideable swim mount | Orca |
| Mobile storage | Kangaroo | Swarm / clone | Tasmanian Devil, Capuchin Monkey |
| XP collector | Endergrade | Item magnet (auto-delivers to chest/storage Pal) | Mimicube |
Hand-feeding works on every Pal regardless of its special power.
Craft a Paldex (Book + Pal Sphere) and right-click to open an in-game guide — powered by Alex's Mobs' own dictionary book UI, so it looks and feels native. It covers spheres, catching, enchantments, the compass, care & feeding, stations, powers, and wild types, plus a bestiary page with a Pal Info entry for every shipped creature.
Catchable wild mobs aren't always easy targets. Some fight back based on a difficulty category set in their behavior JSON:
- Brawler — more HP, damage resistance, throws its own combat ability at you
- Skittish — flees the moment it sees or hears you
- Op — has an "unfair" defensive trick: freezes your thrown spheres in mid-air
(
time_stop), dodges + counter-strikes lightning while airborne (storm_dodge), or straight-up teleports away (blink, unless your sphere has Warp Tether) - Predator-locked — can't be hurt at all except by a specific counter-ability from one of your own Pals, or stays invisible/hidden until baited out by a Pal you already own nearby
Config lives at config/palmod-common.toml after first launch:
| Key | Default | Effect |
|---|---|---|
catchableChance |
0.40 |
Chance any naturally-spawning mob rolls catchable (0.0–1.0) |
allowVanillaClients |
true |
Dedicated-server-only. Patches Forge's network handshake so vanilla clients and protocol bots (e.g. mineflayer) can still join even though Alex's Mobs/Citadel would normally reject them. Modded logic still runs server-side; those clients just won't render custom GUIs/animations from other mods. |
Config changes require a server restart to take effect — Forge's config hot-reload does not reliably apply on a dedicated server for this mod.
Palmod deliberately keeps all per-mob balance and behavior out of Java. Adding a new Pal — or reworking an existing one — is a datapack change, no compiling required. This also means a separate datapack/addon can layer on top of Palmod without touching its jar at all.
Drop files under a datapack (or resource pack, for the dictionary pages) at:
data/<your_namespace>/pal_behaviors/<file>.json # required — unlocks the mob as a Pal
data/<your_namespace>/pal_foods/<file>.json # optional — enables hand-feeding
data/<your_namespace>/pal_trades/<file>.json # optional — only for trader-type workers
The filename doesn't matter — the target mob is identified by the "entity" field inside
each JSON (a full entity registry ID, e.g. "minecraft:panda" or "alexsmobs:capuchin_monkey").
Any mob without a pal_behaviors entry simply can't be caught/owned — it stays a plain vanilla
mob and never rolls catchable.
{
"entity": "alexsmobs:gorilla",
"behaviors": {
"follow_owner": { "speed": 1.1, "start_distance": 18.0, "stop_distance": 9.0 }, // or just true/false
"protect_owner": true,
"attack_target": true,
"guard_only": true, "guard_leash": 12.0, // retaliate-only bodyguard behavior
"melee_attack": { "speed": 1.2 }, // or bool
"station_mode": {
"enabled": true, "worker_type": "lumberjack",
"harvest_radius": 10, "wander_radius": 24,
"log_cap": 64, "ore_tag": "forge:ores"
},
"deploy_mode": "anchor", // or "sentry" — sneak-throw activates
"sentry_radius": 16.0,
"warp_beacon": true, // roots on summon; recall warps owner to it
"mobile_chest_size": 27, // storage slots (vanilla chest UI)
"combat_ability": {
"type": "lightning", // lightning | fireball | earth_spike | water_burst
"damage": 6.0, "range": 16.0, "cooldown_ticks": 60, "hunger_cost": 2.0
},
"clone": { "max": 6, "duration_ticks": 200, "cooldown_ticks": 300, "hunger_cost": 4.0 },
"rideable": { "speed": 2.2 }, // or bool
"fetch": { "radius": 16 }, // or bool
"xp_collector": { "radius": 8.0, "max_stored": 1395 },
"magnet": { "radius": 6.0, "slots": 2 }, // hoards one item type, auto-delivers
"greedy_boom": { "boom_at_hunger": 95.0 } // or bool
},
"time_stop": { "duration_ticks": 200, "radius": 24.0, "cooldown_ticks": 1200, "hunger_cost": 40.0 },
"aura": {
"type": "heal", // heal | storm
"radius": 8.0, "interval_ticks": 100, "potency": 0, "hunger_cost": 2.0
},
"stats": { "hunger_decay_per_minute": 3.0, "mood_decay_per_day": 2.0 },
"hunger_costs": { "harvest": 2.0, "chop": 4.0 }, // any action key you reference in code
"wild": {
"category": "brawler", // brawler | skittish | op | predator_locked
"type": "", // op/predator_locked subtype, see below
"counter_ability": "water_burst",
"health_multiplier": 1.5, "resistance": 0, "use_combat_ability": true,
"sight_range": 32.0, "hearing_range": 20.0, "flee_speed": 1.4,
"radius": 24.0, "cooldown_ticks": 600, "hide_range": 16.0, "lure_range": 8.0
}
}Only include the blocks a given Pal actually needs — everything is optional except entity.
station_mode.worker_type picks which job goal a station-bound Pal runs:
worker_type |
Behavior |
|---|---|
harvester |
Harvests a renewable resource in a radius (e.g. leaf-cutting) |
lumberjack |
Chops and replants trees, caps output at log_cap |
trader |
Converts payment items dropped near the station (see trade tables) |
sorter |
Sorts/organizes nearby storage |
miner |
Mines a configurable ore tag (ore_tag) within its radius |
Adding a new job type is a one-file code change: subclass AbstractStationWorkerGoal and
register it with WorkerGoalRegistry.register("your_type", ...) — see
Writing a code addon.
Set under wild.category. Each has its own extra fields (all shown in the reference above):
brawler—health_multiplier,resistance(-1= off,0= Resistance I),use_combat_ability(fires itscombat_abilityblock at attackers, free of hunger cost)skittish—sight_range,hearing_range,flee_speedop— setwild.typeto one of:time_stop— freezes thrown spheres inradius, telegraphed,cooldown_ticksgatestorm_dodge— dodges + strikes the thrower with lightning while airborne; catchable only while groundedblink— teleports away from any incoming sphere unless it has Warp Tether
predator_locked— setwild.typeto one of:damage_immune— untouchable except by an owned Pal whosecombat_ability.typematchescounter_ability(/killand void damage still work)shy_hide— invisible + rooted near players unless a passive owned Pal is withinlure_rangeambush_hide— hidden until any owned Pal wanders withinhide_range, then pounces
Leave wild out entirely for a mob with no special defenses (plain catchable). The six values
above are just the built-ins — wild.type is resolved through WildDefenseRegistry (see
Writing a code addon), so a new type is a registration call away, not
a source edit.
// data/<ns>/pal_foods/<file>.json
{
"entity": "alexsmobs:leafcutter_ant",
"default_hunger_restore": 3.0,
"default_mood_bonus": 0.0,
"foods": [
{ "item": "minecraft:sugar", "hunger_restore": 8.0, "mood_bonus": 3.0 }
]
}A mob with no pal_foods entry can still be summoned/owned, it just can't be hand-fed by item
(only via a Pal Feeder, if it self-feeds as a producer).
// data/<ns>/pal_trades/<file>.json — only relevant for worker_type: "trader"
{
"entity": "alexsmobs:crow",
"payment": "minecraft:emerald",
"results": [
{ "item": "minecraft:diamond", "count": 1, "weight": 3 }
]
}Weights are relative — the trader rolls one results entry per payment item consumed.
Optional, client-only, purely cosmetic. To give a new Pal its own "Pal Info" page in the AM dictionary book:
- Add
assets/alexsmobs/book/animal_dictionary/<page>.json+en_us/<page>.txtas plain resource-pack assets — these merge fine as-is. - If you also want a button linking to it from the bestiary grid or an existing AM page,
that requires overriding an existing AM page JSON, which needs to ship inside a
forced resource pack (same trick Palmod itself uses via
PalmodBookPack) since plain same-path overrides silently lose to Alex's Mobs' own pack.
This system is entirely optional — a Pal works in every other respect without a dictionary page.
Every extension point below is a standalone registration call — add palmod as a compile
dependency in your own mod's build.gradle, call register(...) once (from your mod
constructor or FMLCommonSetupEvent), and you're done. Nothing here requires editing, forking,
or PRing into Palmod itself — that's the whole point of these being registries instead of
switch statements.
New station job (station_mode.worker_type) — subclass AbstractStationWorkerGoal, then:
WorkerGoalRegistry.register("fisher", (mob, stationPos, behavior) ->
new MyFisherGoal(mob, stationPos, behavior.getHarvestRadius(), behavior.getWanderRadius()));New combat ability (combat_ability.type) — one lambda via CombatAbilityRegistry:
CombatAbilityRegistry.register("poison_spit", (level, mob, target, behavior) -> {
target.addEffect(new MobEffectInstance(MobEffects.POISON, 100, 1));
target.hurt(level.damageSources().mobAttack(mob), behavior.getCombatDamage());
});New wild defense (wild.type, for op/predator_locked mobs) — implement whichever
hooks of WildDefenseRegistry.WildDefense you need (all default to a no-op, so a simple dodge
only needs onSphereHit):
WildDefenseRegistry.register("smoke_bomb", new WildDefenseRegistry.WildDefense() {
@Override
public boolean onSphereHit(Mob mob, PalBehavior behavior, PalSphereProjectile sphere, ServerLevel level) {
level.sendParticles(ParticleTypes.LARGE_SMOKE, mob.getX(), mob.getY(), mob.getZ(), 40, 0.5, 0.5, 0.5, 0.05);
mob.addEffect(new MobEffectInstance(MobEffects.INVISIBILITY, 60));
return true; // consumes the sphere — this throw is defended
}
});Reference data/<ns>/pal_behaviors/*.json with "wild": {"category": "op", "type": "smoke_bomb", ...}
and it's live — no Palmod source touched.
New proactive pal power (the "one special power per mob" system — clone, magnet, XP
collector, greedy boom, warp beacon, time-stop-on-summon, and anything you add) — implement
whichever hooks of PalAbilityRegistry.PalAbility you need: onJoin to inject an AI goal,
tick for a passive ~20-tick hook, onSummon to react once right after a fresh summon, or
forcedDeployMode if the power should root the pal into a deploy mode on a plain summon:
PalAbilityRegistry.register(new PalAbilityRegistry.PalAbility() {
@Override
public boolean appliesTo(PalBehavior behavior) {
return behavior.getExtraFieldYouAdded() > 0; // gate on your own behavior field
}
@Override
public void tick(Mob mob, PalBehavior behavior, ServerLevel level) {
// runs every ~20 ticks while this pal is owned and alive
}
});Reacting to a pal's lifecycle — subscribe to the events in com.mx.palmod.api.event on the
Forge event bus like any other Forge event, no registry needed:
| Event | Fires when | Cancelable |
|---|---|---|
PalCaughtEvent |
A wild-catch roll succeeds, before the mob is removed | Yes — canceling treats it as a failed catch |
PalSummonedEvent |
A filled sphere finishes placing a pal in the world | No |
PalRecalledEvent |
A released pal is recalled into its sphere (deliberate or automatic) | No |
PalDiedEvent |
An owned pal dies, right before its sphere reverts to empty | No |
PalDeployedEvent |
A pal roots into a deploy mode (anchor/sentry) on summon | No |
@SubscribeEvent
public static void onCatch(PalCaughtEvent event) {
if (event.getPal().getType() == EntityType.WITHER) {
event.setCanceled(true); // no catching the Wither, thanks
}
}Everything else — the sneak/plain click-priority table, deploy mode (anchor/sentry) selection,
and hunger/mood ticking — is still centralized directly in ForgeEvents rather than a registry;
those are dense, stable UX logic where the regression risk of adding indirection outweighed the
addon payoff. A new mob with a correct pal_behaviors entry still needs zero Java to work
at all — every extension point above is purely additive for mods that want more.
One honest limitation: there's currently no separate published API artifact (see
build.gradle's maven-publish block, which just ships the whole jar) — an
addon still compiles against the full palmod jar and its internal packages, not a slim public
API. The registries above are stable extension points regardless; just don't reach into
unrelated internals and expect them to stay put across versions.
git clone https://github.com/Myddddddd/PalModCore.git
cd PalModCore
.\gradlew.bat buildOutput jar lands in build/libs/palmod-<version>.jar. First build downloads Forge's toolchain
and can take a few minutes. See README.txt for IDE-specific run-config setup
(Eclipse/IntelliJ) inherited from the Forge MDK template.
- Some AM mobs with strong built-in AI (elephant, tasmanian devil) partially fight the mod's hand-feed/target routing — prefer vanilla or simpler-AI mobs when picking a combat-ability carrier.
- Flying mobs are very hard to catch with a thrown sphere (they dodge, and Following doesn't reliably lock on) — the Compass helps you find them, not hit them.
- The wild-catch roll currently fires on every unowned mob join, including bred/egg-hatched mobs, not just natural spawns.
- A few systems are implemented and code-verified but not yet confirmed on a live client: orca riding, fireball/water-burst casts, and all client-only visuals (egg tint, glints, dictionary rendering).
Full list with technical detail lives in CLAUDE.md.
Built on Minecraft Forge for Minecraft 1.20.1. Designed to run alongside Alex's Mobs and Citadel — see CREDITS.txt for full attribution. All rights reserved — see LICENSE.txt.
