ibu

profen

lua

Information

    Libraries/Engines Included

    lua 5.1 | package | coroutine | string | table | math | bit32 | jit | ffi | utf8

    Scripts Folder

    (sot directory)/ibuprofen/scripts

    Tutorial Series
    #1 | Automatic Ammo Refill

Global

    vec2

    fields: x (int), y (int)

                                            
    local my_vec2 = vec2.new(100, 500) --creates a new vec2 object
    print(my_vec2) --prints x: 100, y: 500
    print(my_vec2.x) --prints 100
    print(my_vec2.y) --prints 500
                                            
                                        
    vec3

    fields: x (int), y (int), z (int)

                                            
    local my_vec3 = vec3.new(400, 200, 740) -- creates a new vec3 object
    local my_other_vec3 = vec3.new(100, 300, 520)
    
    print(my_vec3) -- prints x: 400, y: 200, z: 740
    print(my_vec3.x) -- prints 400
    print(my_vec3.y) -- prints 200
    print(my_vec3.z) -- prints 740
                                                
    --[[
        functions:
        length: returns the euclidean length of your vec3
        length_2d: returns the length of x and y in your vec3
        length_2d_sqr: returns the squared length of x and y in your vec3
        length_sqr: returns the squared length of your vec3
        dist_to: returns the euclidean distance between your vec3 and the other vec3
        dist_to_sqr: returns the squared distance of your vec3 and the other vec3
        normalize: normalizes your vec3
    ]]
                                                
    print(my_vec3:length()) -- prints 864.638671875
    print(my_vec3:length_2d()) -- prints 447.2135925293
    print(my_vec3:length_2d_sqr()) -- prints 200000
    print(my_vec3:length_sqr()) -- prints 747600
    print(my_vec3:dist_to(my_other_vec3)) -- prints 385.22720336914
    print(my_vec3:dist_to_sqr(my_other_vec3)) -- prints 148400
                                                
    my_vec3:normalize() --normalizes your vec3
    print(my_vec3) -- prints x: 400, y: 160, z: 0
                                            
                                        
    img

    fields: texture (uint64_t), width (int), height (int)

                                            
    local cat_img = render.load_image("C:\\Users\\jake\\Downloads\\cat.jpg")
    print(cat_img) --prints texture: {texture addr}, width {width}, height {height}
    print(cat_img.width) --prints 100
    print(cat_img.height) --prints 500
                                            
                                        
    u_object

    fields: vtable (uint64_t*), flags (uint32_t), name (f_name), internal_index (uint32_t), outer (u_object*)

                                            
    local local_character_obj = memory.cast_to_object(engine.get_local_character())
    local athena_player_character_class = engine.find_class("Athena.AthenaPlayerCharacter")
                                                
    --[[
        functions:
        get_name: returns the name of the object
        get_full_name: returns the full name of the object
        is_a: returns true if the object is a or apart of a class
        get_address: returns the address of the object
    ]]
                                                                                            
    print(local_character_obj:get_name()) --prints BP_PlayerPirate_C
    print(local_character_obj:get_full_name()) --prints BP_PlayerPirate_C SOT_World_layout_Starlight.SOT_World_layout_Starlight.PersistentLevel.BP_PlayerPirate_C_2
    print(local_character_obj:is_a(athena_player_character_class)) --prints true, as the local character is from the athena player character class
                                            
                                        
    f_name

    fields: comparison_idx (int32_t), number (int32_t)

                                            
    local some_fname = engine.find_fname("AthenaFaction")
    
    print(some_fname) --prints comparison index: 212490, number: 0
    print(some_fname.comparison_idx) --prints 212490
    print(some_fname.number) --prints 0
    
    --[[
        functions:
        get_name: returns the string of the fname
    ]]
    
    print(some_fname:get_name()) --prints AthenaFaction
                                            
                                        
    u_class (inherits u_object)

    fields: none

                                            
    local ship_class = engine.find_class("Athena.Ship")
    
    print(ship_class:get_name()) --prints Ship
    print(ship_class:get_full_name()) --prints Class Athena.Ship
                                            
                                        
    u_function (inherits u_object)

    fields: function_flags (int32_t), func (void*)

                                            
    local jump_fn = engine.find_function("Engine.Character.Jump")
    
    print(jump_fn:get_name()) --prints Jump
    print(jump_fn:get_full_name()) --prints Function Engine.Character.Jump
                                            
                                        
    a_actor (inherits u_object)

    fields: none

                                            
    --[[
        functions:
        get_actor_location: returns a vec3 of the current actors pos
    ]]
                                            
                                        

Client

    user_name

    returns: string

    print(client.user_name)
    get_screen_size

    returns: vec2

    local screen_size = client.get_screen_size()
    time_since_epoch

    args: (optional) return ms (bool) | returns: int

    local time_ms = client.time_since_epoch(true)
    get_fps

    returns: int

    local fps = client.get_fps()
    is_key_held

    args: virtual key (int) | returns: bool

    local x_held = client.is_key_held(0x58)
    is_key_toggled

    args: virtual key (int) | returns: bool

    local l_toggled = client.is_key_toggled(0x4c)
    screen_log

    args: text (string)

    client.screen_log("hello world")

Engine

    get_game_world

    returns: uint64_t

    local gworld = engine.get_game_world()
    get_local_character

    returns: uint64_t

    local local_character = engine.get_local_character()
    get_local_controller

    returns: uint64_t

    local local_controller = engine.get_local_controller()
    find_class

    args: class name (string) | returns: u_class

    local ship_class = engine.find_class("Athena.Ship")
    find_function

    args: function name (string) | returns: u_function

    local jump_fn = engine.find_function("Engine.Character.Jump")
    find_offset

    args: class name (string), member name (string) | returns: uint32_t

    local storm_list_offset = engine.find_offset("StormService", "StormList")
    find_fname

    args: name (string) returns: f_name

    local some_fname = engine.find_fname("AthenaFaction")
    is_valid_fname_index

    args: fname index (int32_t) | returns: bool

    local is_valid = engine.is_valid_fname_index(some_fname.comparison_idx)
    fname_index_to_string

    args: fname index (int32_t) | returns: string

    local fname_str = engine.fname_index_to_string(some_fname.comparison_idx)
    get_actors

    args: actor class (u_class) | returns: table

    local ships = engine.get_actors(ship_class)

Memory

    find_pattern

    args: ida-style pattern (string)| returns: uint64_t

    local recieve_draw_hud_addr = memory.find_pattern("53 56 57 48 81 EC ? ? ? ? 48 8B ? ? ? ? ? 48 33 ? 48 89 ? ? ? 48 8B ? ? 48 8B")
    cast_to_object

    args: address (uin64_t) | returns: u_object

    local u_world_obj = memory.cast_to_object(engine.get_game_world())

Render

    load_image

    args: path (string) | returns: img

    local cat_img = render.load_image("C:\\Users\\jake\\Downloads\\cat.jpg")
    world_to_screen

    args: world pos (vec3) | returns: vec2

    local screen_pos = render.world_to_screen(world_pos)
    get_text_size

    args: font (int, 0 = small; 1 = medium; 2 = large), text (string) | returns: vec2

    local text_sz = render.get_text_size(0, "hello world")
    text

    args: font (int, 0 = small; 1 = medium; 2 = large), position (vec2), color (color), text (string) | optional args: outline (bool), centered (bool), dropshadow (bool)

    render.text(0, vec2.new(100, 135), color.new(255, 255, 255, 255), "some text", true, true)
    rect

    args: position (vec2), size (vec2), color (color) | optional args: rounding (int), thickness (int)

    render.rect(vec2.new(100, 150), vec2.new(100, 50), color.new(255, 255, 0, 255))
    rect_filled

    args: position (vec2), size (vec2), color (color) | optional args: rounding (int)

    render.rect_filled(vec2.new(100, 150), vec2.new(100, 50), color.new(255, 255, 0, 255), 5)
    rect_gradient

    args: position (vec2), size (vec2), left color (color), right color (color) | optional args: vertical gradient (bool)

    render.rect_gradient(vec2.new(100, 270), vec2.new(100, 50), color.new(255, 0, 255, 255), color.new(0, 255, 255, 255))
    circle

    args: position (vec2), radius (int), color (color) | optional args: segments (int), thickness (int)

    render.circle(vec2.new(150, 360), 30, color.new(0, 255, 0, 255))
    circle_filled

    args: position (vec2), radius (int), color (color) | optional args: segments (int)

    render.circle_filled(vec2.new(150, 430), 30, color.new(255, 0, 0, 255))
    triangle

    args: pos1 (vec2), pos2 (vec2), pos3 (vec2), color (color) | optional args: thickness (int)

    render.triangle(vec2.new(150, 550), vec2.new(100, 470), vec2.new(200, 470), color.new(255, 255, 255, 255), 2)
    triangle_filled

    args: pos1 (vec2), pos2 (vec2), pos3 (vec2), color (color)

    render.triangle_filled(vec2.new(150, 650), vec2.new(100, 570), vec2.new(200, 570), color.new(0, 255, 255, 255))
    polygon

    args: points (vec2 array), color (color) | optional args: thickness (int)

    render.polygon({vec2.new(100, 670), vec2.new(150, 670), vec2.new(200, 720), vec2.new(100, 720), vec2.new(100, 670)}, color.new(255, 255, 255, 255), 2)
    polygon_filled

    args: points (vec2 array), color (color)

    render.polygon_filled({vec2.new(100, 770), vec2.new(150, 770), vec2.new(200, 820), vec2.new(100, 820), vec2.new(100, 770)}, color.new(255, 165, 0, 255))
    line

    args: start (vec2), end (vec2), color (color) | optional args: thickness (int)

    render.line(vec2.new(100, 500), vec2.new(200, 500), color.new(255, 255, 255, 255), 3)
    arc

    args: pos (vec2), min angle (int), max angle (int), radius (int), color (color) | optional args: thickness (int)

    render.arc(vec2.new(150, 500), 60, 180, 30, color.new(255, 255, 255, 255), 2)
    image

    args: image (image obj), position (vec2) | optional args: center (bool)

    render.image(cat_img, vec2.new(50, 500))

Callbacks

    add

    args: event (string), function (func)

    callbacks.add("render", my_function)
    remove

    args: event (string)

    callbacks.remove("render")

Events

    render

    called every frame

                                            
    callbacks.add("render", function()
        render.rect(vec2.new(100, 150), vec2.new(100, 50), color.new(255, 255, 0, 255))
    end)
                                            
                                        

Examples

    oxygen indicator

    example on how you can read the games memory

                                                                               
    
    local offsets = {
        drowning_component = engine.find_offset("AthenaPlayerCharacter", "DrowningComponent"), --https://sot.dumps.host/?class=AAthenaPlayerCharacter&member=DrowningComponent
        oxygen_level = engine.find_offset("DrowningComponent", "OxygenLevel") --https://sot.dumps.host/?class=UDrowningComponent&member=OxygenLevel
    }
                                        
    --little wrapper i made
    local mem = {
        read = function(ctype, addr, offset)
            return ffi.cast(ctype, ffi.cast("uint64_t", addr) + offset)[0]
        end,
                                        
        write = function(ctype, addr, offset, value)
            ffi.cast(ctype, ffi.cast("uint64_t", addr) + offset)[0] = value
        end,
                                        
        valid_ptr = function(ptr)
            return ptr ~= nil and ptr ~= 0
        end
    }
                                        
    local function oxygen_indicator()
        local local_character = engine.get_local_character()
        if not mem.valid_ptr(local_character) then --make sure to check all of your addresses so you dont crash
            return
        end
                                        
        local drowning_component = mem.read("void***", local_character, offsets.drowning_component)
        if not mem.valid_ptr(drowning_component) then
            return
        end
                                        
        local oxygen_level = mem.read("float*", drowning_component, offsets.oxygen_level)
                                        
        if oxygen_level < 1 then
            local screen = client.get_screen_size()
                                                
            render.circle_filled(vec2.new(screen.x / 2, 150), 27, color.new(0, 0, 0, 100), 0)
            render.arc(vec2.new(screen.x / 2, 150), 0, 360 * oxygen_level, 27, color.new(0, 100, 255, 255), 3)
            render.text(1, vec2.new(screen.x / 2, 155), color.new(255, 255, 255, 255), "O2: " .. string.format("%.f%%", (oxygen_level * 100)), false, true, true)
        end
    end
                                        
    callbacks.add("render", oxygen_indicator)
                                        
                                    
    shark esp

    example on how you can make esp

                                                                  
    local shark_class = engine.find_class("Athena.SharkPawn")
    
    local function shark_esp()
        local sharks = engine.get_actors(shark_class)
    
        for i = 1, #sharks do
            local shark = sharks[i]
    
            if shark then
                local location = shark:get_actor_location()
                local screen = render.world_to_screen(location)
    
                if(screen.x ~= 0 and screen.y ~= 0) then
                    render.text(0, screen, color.new(0, 100, 255, 255), "shark", true, true)
                end
            end
        end
    end
    
    callbacks.add("render", shark_esp)
                                        
                                    
    bhop

    example on how you call internal functions

                                        
    local process_event_t = ffi.typeof("void(__fastcall*)(uint64_t*, uint64_t*, void*)")                          
    local function process_event(object, func, params)
        local process_event_fn = ffi.cast(process_event_t, ffi.cast("void***", object)[0][55])
        process_event_fn(ffi.cast("uint64_t*", object), ffi.cast("uint64_t*", func), params)
    end
                                        
    local fns = {
        can_jump = engine.find_function("Engine.Character.CanJump"),
        jump = engine.find_function("Engine.Character.Jump")
    }
                                        
    ffi.cdef([[
        typedef struct
        {
            bool return_value;
        } can_jump_params;
    ]])
                                        
    local function bhop()
        local local_char = engine.get_local_character()
        if not local_char or local_char == 0 then
            return
        end
                                        
        local params = ffi.cast("can_jump_params*", ffi.new("can_jump_params"))
        process_event(local_char, fns.can_jump:get_address(), params)
                                           
        if(params[0].return_value and client.is_key_held(0x20)) then
            process_event(local_char, fns.jump:get_address(), nil)
        end
    end
                                        
    callbacks.add("render", bhop)