Jump to content
View in the app

A better way to browse. Learn more.

OSBot :: 2007 OSRS Botting

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

[OPEN SOURCE] Death Recorder

Featured Replies

Ever been testing a script for a long time and you come back to the

bot dead and you're wondering how the hell did it die?
------------------------------------------

Open Source Death Recorder to the rescue!

Using a rolling cache of jpgs and ffmpeg to record the last 10 seconds leading up to when the bot dies for debugging/testing scripts while you're not watching.

This is still under development/testing so I'm releasing it essentially as a concept for now and welcome to anyone who wants to use/build onto this project.

(REQUIRES ffmpeg installed and in system PATH for video conversion)

Still building/testing this thing and adding some more error handling so I might update this thread in the very near future.

 

Source:

Spoiler
import org.osbot.rs07.script.Script;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.LinkedList;
import java.util.Queue;
import javax.imageio.ImageIO;

public class DeathRecorder {
    
    private static final int MAX_FRAMES = 300; // 10 seconds @ 30 FPS
    private static final int CAPTURE_INTERVAL = 33; // ~30 FPS
    private static final int IMAGE_SCALE = 2; // Reduce image size for performance
    
    private final Script script;
    private final Rectangle captureArea;
    private final Queue<File> frameQueue = new LinkedList<>();
    private volatile boolean recording = false;
    private Thread captureThread;
    private Robot robot;

    public DeathRecorder(Script script) throws AWTException {
        this.script = script;
        this.robot = new Robot();
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        this.captureArea = new Rectangle(0, 0, 
            screenSize.width/IMAGE_SCALE, 
            screenSize.height/IMAGE_SCALE);
    }

    public void startRecording() {
        if (recording) return;
        
        recording = true;
        captureThread = new Thread(this::captureLoop);
        captureThread.start();
        script.log("Death recording started");
    }

    private void captureLoop() {
        try {
            File tempDir = new File(System.getProperty("java.io.tmpdir"), "osbot_records");
            tempDir.mkdirs();

            while (recording) {
                BufferedImage screen = robot.createScreenCapture(captureArea);
                BufferedImage scaled = scaleImage(screen);
                File frameFile = saveTempFrame(scaled, tempDir);
                
                synchronized(frameQueue) {
                    if (frameQueue.size() >= MAX_FRAMES) {
                        File oldFrame = frameQueue.poll();
                        if (oldFrame != null) oldFrame.delete();
                    }
                    frameQueue.add(frameFile);
                }
                
                Thread.sleep(CAPTURE_INTERVAL);
            }
        } catch (Exception e) {
            script.log("Recording error: " + e.getMessage());
        }
    }

    private BufferedImage scaleImage(BufferedImage original) {
        int width = original.getWidth() / IMAGE_SCALE;
        int height = original.getHeight() / IMAGE_SCALE;
        BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        scaled.getGraphics().drawImage(original, 0, 0, width, height, null);
        return scaled;
    }

    private File saveTempFrame(BufferedImage image, File dir) throws Exception {
        File tempFile = File.createTempFile("frame_", ".jpg", dir);
        ImageIO.write(image, "jpg", tempFile);
        return tempFile;
    }

    public void saveLastMoments() {
        recording = false;
        try {
            if (captureThread != null) {
                captureThread.join();
            }
            
            File output = new File(System.getProperty("user.home"), 
                "Death_" + System.currentTimeMillis() + ".avi");
            
            // Convert frames to video using built-in Java features
            createVideoFromFrames(output);
            
            cleanupTempFiles();
            script.log("Saved death recording to: " + output.getAbsolutePath());
            
        } catch (Exception e) {
            script.log("Failed to save recording: " + e.getMessage());
        }
    }

    private void createVideoFromFrames(File output) throws Exception {
        // Simple AVI creation using JPG frames sequence
        // Note: This creates a playable but large AVI file
        File tempDir = new File(System.getProperty("java.io.tmpdir"), "osbot_records");
        ProcessBuilder pb = new ProcessBuilder(
            "ffmpeg",
            "-framerate", "30",
            "-i", tempDir.getAbsolutePath() + "/frame_%08d.jpg",
            "-c:v", "mjpeg",
            "-q:v", "3",
            output.getAbsolutePath()
        );
        
        pb.redirectErrorStream(true);
        Process process = pb.start();
        process.waitFor();
    }

    private void cleanupTempFiles() {
        File tempDir = new File(System.getProperty("java.io.tmpdir"), "osbot_records");
        for (File file : tempDir.listFiles()) {
            if (file.getName().startsWith("frame_")) {
                file.delete();
            }
        }
    }
}

Something like this to integrate it into your scripts and trigger recording on death:
 

Spoiler
public class MyBot extends Script {
    private DeathRecorder deathRecorder;
    private long lastCheck;

    @Override
    public void onStart() {
        try {
            deathRecorder = new DeathRecorder(this);
            deathRecorder.startRecording();
        } catch (AWTException e) {
            log("Failed to initialize death recorder: " + e);
        }
    }

    @Override
    public int onLoop() throws InterruptedException {
        if (System.currentTimeMillis() - lastCheck > 1000) {
            if (isDead()) {
                deathRecorder.saveLastMoments();
                // Handle death logic
            }
            lastCheck = System.currentTimeMillis();
        }
        return random(200, 300);
    }

    private boolean isDead() {
               getSkills().getDynamic(Skill.HITPOINTS) <= 0;
    }

    @Override
    public void onExit() {
        if (deathRecorder != null) {
            deathRecorder.saveLastMoments();
        }
    }
}

 

  • Author
15 hours ago, Czar said:

Amazing keep up the good work, these types of snippets/utilities are super valuable around here

More coming in the very near future!

  • 3 weeks later...

I’ve definitely had times when I came back to a dead bot, and it’s a nightmare trying to figure out what went wrong. The idea of having a last-10-seconds recording sounds perfect for debugging.

  • Author
10 hours ago, BloodyNoah said:

I’ve definitely had times when I came back to a dead bot, and it’s a nightmare trying to figure out what went wrong. The idea of having a last-10-seconds recording sounds perfect for debugging.

It is actually really useful, let me know if you decide to work with the snippets, I ended up tweaking it further I might post what I ended up with later today

  • 2 weeks later...
  • Author
4 hours ago, Wacky Jacky said:

Totally gonna use it; when i start making combat scripts 🫢

Definitely a good idea, also for minigames were death is a possibility, good for long test runs

Create an account or sign in to comment

Recently Browsing 0

  • No registered users viewing this page.

Account

Navigation

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.