Page 1 of 1

[OSRS/RS3] Rest system

Posted: Fri Mar 06, 2026 5:37 pm
by runedev
[Release] RS3 Rest System Snippet

Today I’m releasing a small snippet that adds the RS3-style Rest System to your server.
This allows players to sit down and regenerate their run energy faster, similar to the mechanic seen in modern RuneScape.

This was written for the Rune-unique base but can be modified for any other base.

Features
• RS3-style resting animation
• Faster run energy regeneration while resting
• Automatically stops when the player moves or performs another action
• Lightweight snippet – easy to implement into most sources

Preview / Example Code

Code: You must be registered to view this Link


package com.zenyte.game.content;

import com.zenyte.game.packet.in.ClientProtEvent;
import com.zenyte.game.task.WorldTask;
import com.zenyte.game.task.WorldTasksManager;
import com.zenyte.game.world.entity.masks.Animation;
import com.zenyte.game.world.entity.player.LogLevel;
import com.zenyte.game.world.entity.player.Player;
import com.zenyte.game.world.entity.player.container.impl.equipment.EquipmentSlot;

/**
 * Rest system (RS3-style).
 * Author: Rogue#8231
 */
public class RestHandler implements ClientProtEvent {

    // Rest animations
    // Male resting animations
    // Male resting animations
    private static final Animation REST_MALE_1 = new Animation(7186);  // sit / relaxed
    private static final Animation REST_MALE_2 = new Animation(7211);  // laying / resting
    private static final Animation REST_MALE_3 = new Animation(1351);  // sit looking down (idle)
    private static final Animation REST_MALE_4 = new Animation(1352);  // sit thinking / resting

    // Female resting animations
    private static final Animation REST_FEMALE_1 = new Animation(7186);  // sit / relaxed
    private static final Animation REST_FEMALE_2 = new Animation(7211);  // laying / resting
    private static final Animation REST_FEMALE_3 = new Animation(1351);  // sit looking down
    private static final Animation REST_FEMALE_4 = new Animation(1352);  // sit thinking



    // Regen multipliers
    private static final double ENERGY_MULTIPLIER = 3.6; // ~3.6x faster
    private static final int HP_INTERVAL = 6; // every 6 seconds (10x faster)

    /**
     * Starts resting.
     */
    public static void startRest(Player player) {
        if (player.isDead() || player.getHitpoints() <= 0) {
            player.sendMessage("You can't rest right now.");
            return;
        }

        if (!canRest(player)) {
            player.sendMessage("You cannot rest at this moment.");
            return;
        }

        if (isResting(player)) {
            player.sendMessage("You are already resting.");
            return;
        }

        // Reset idle if the entity is a player
        if (player instanceof Player p) {
            IdleHandler.resetIdle(p);//cameron added for the throne idle system
            p.getTemporaryAttributes().put("last_action", System.currentTimeMillis());
        }

        player.getTemporaryAttributes().put("resting", true);
        player.sendMessage("You begin to rest...");

        // Start animation cycle
        cycleAnimations(player);

        // Start regen task using WorldTask
        WorldTasksManager.schedule(new WorldTask() {
            @Override
            public void run() {
                if (!isResting(player)) {
                    stop(); // properly stops this task
                    return;
                }

                // Restore run energy faster
                if (player.getVariables().getRunEnergy() < 100) {
                    int baseRestore = 1 + (player.getSkills().getLevel(16) / 6); // agility effect
                    int restore = (int) Math.ceil(baseRestore * ENERGY_MULTIPLIER);
                    int current = (int) player.getVariables().getRunEnergy();
                    int restored = Math.min(100, current + restore);
                    player.getVariables().setRunEnergy(restored);
                }

                // Restore HP every 6 seconds
                player.setHitpoints(Math.min(player.getMaxHitpoints(),
                        player.getHitpoints() + Math.max(1, player.getMaxHitpoints() / 100)));
            }
        }, 0, 1); // initial delay 0 ticks, repeat every 1 tick
    }

    /**
     * Stops resting.
     */
    public static void stopRest(Player player) {
        if (!isResting(player)) return;

        player.getTemporaryAttributes().remove("resting");
        player.setAnimation(Animation.STOP);
        player.sendMessage("You stop resting.");
    }

    /**
     * Cycles the resting animations.
     */
    private static void cycleAnimations(Player player) {
        WorldTasksManager.schedule(new WorldTask() {
            private int tick = 0;

            @Override
            public void run() {
                if (!isResting(player)) {
                    stop();
                    return;
                }

                if (player.getAppearance().isMale()) {
                    switch (tick % 4) {
                        case 0: player.setAnimation(REST_MALE_1); break;
                        case 1: player.setAnimation(REST_MALE_2); break;
                        case 2: player.setAnimation(REST_MALE_3); break;
                        case 3: player.setAnimation(REST_MALE_4); break;
                    }
                } else {
                    switch (tick % 4) {
                        case 0: player.setAnimation(REST_FEMALE_1); break;
                        case 1: player.setAnimation(REST_FEMALE_2); break;
                        case 2: player.setAnimation(REST_FEMALE_3); break;
                        case 3: player.setAnimation(REST_FEMALE_4); break;
                    }
                }

                tick++;
            }
        }, 0, 20); // cycle every ~12 seconds
    }

    /**
     * Checks if the player is allowed is transformed.
     */

    public static boolean isTransformed(Player player) {
        return player.getAppearance().getNpcId() != -1;
    }

    /**
     * Checks if a player is currently holding a banner.
     */
    public static boolean hasBanner(Player player) {
        // Check weapon slot
        int weaponId = player.getEquipment().getId(EquipmentSlot.WEAPON.getSlot());
        if (weaponId == 20225 || weaponId == 20226) { // banner ids.
            return true;
        }

        return false;
    }


    /**
     * Checks if a player can actually rest.
     */
    private static boolean canRest(Player player) {
        if (player.getToxins().isPoisoned()) {
            return false;
        }
        if (player.isUnderCombat()) {
            return false;
        }
        if (isTransformed(player)) {
            return false;
        }
        if (hasBanner(player)) {
            return false;
        }
        if (player.getArea().isWildernessArea(player)) {
            return false;
        }
        return true;
    }

    /**
     * Checks if a player is currently resting.
     */
    public static boolean isResting(Player player) {
        return (Boolean) player.getTemporaryAttributes().getOrDefault("resting", false);
    }

    @Override
    public void handle(Player player) {
        RestHandler.startRest(player);
    }

    @Override
    public LogLevel level() {
        return LogLevel.INFO;
    }
}

How it Works
When a player activates the rest option, their character will sit down and begin restoring run energy at an increased rate.
The rest state will automatically cancel if the player moves, attacks, or performs another action.

Usage
Simply integrate the snippet into your player or energy handling system and call the rest method when the player activates the rest option.

Notes
This is just a basic snippet and may require small adjustments depending on your source.

Credits
• ROGUE#8231

If you have improvements or questions feel free to reply to the thread.