Jump to content

[OPEN SOURCE] Death Recorder


dubai

Recommended Posts

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();
        }
    }
}

 

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...