Gakuran Open Source AutoFarm
Key Required

Gakuran Open Source AutoFarm

(学乱) GakuranDirectMemoryAccessDirectMemoryAccess 3.1K views 6.8K executesUpdated Sep 3, 2026
5.0/ 5(2 votes)
20100% Positive
Lua Script•514 lines (15328 chars)
--// Made by @DirectMemoryAccess
local Players           = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace         = game:GetService("Workspace")
local TweenService      = game:GetService("TweenService")
local RunService        = game:GetService("RunService")

local Settings = {
    Farming = {
        Enabled      = true,
        AutoStart    = true,
        RefreshRate  = 0.3,
        TweenSpeed   = 14,
        MaxDistance  = 1.2,
        MaxDuration  = 3.5,
        MinDuration  = 0.6,
        FollowOffset = 4,
        PhotoRange   = 10,
        MaxAttempts  = 60,
    }
}

local S = Settings.Farming

--// tasks
local AREA_TASKS = {
    { canonical = "Rooftop",                   aliases = { "rooftop", "roof" } },
    { canonical = "Courtyard",                 aliases = { "courtyard", "court yard" } },
    { canonical = "Cafeteria",                 aliases = { "cafeteria", "cafe", "lunch room", "lunchroom" } },
    { canonical = "Basketball Court",          aliases = { "basketball court", "basketball", "bball court" } },
    { canonical = "Dojo Room",                 aliases = { "dojo room", "dojo" } },
    { canonical = "Music Room",                aliases = { "music room", "music" } },
    { canonical = "Parking Lot",               aliases = { "parking lot", "parking", "car park" } },
    { canonical = "Nishikata High Entrance",   aliases = { "nishikata high entrance", "school entrance", "entrance", "nishikata entrance", "high entrance", "school front", "front entrance" } },
    { canonical = "Infirmary",                 aliases = { "infirmary", "nurse office", "nurse's office", "medical room" } },
    { canonical = "Study Room",                aliases = { "study room", "study", "library" } },
    { canonical = "Lounge",                    aliases = { "lounge" } },
    { canonical = "GAKUMART",                  aliases = { "gakumart", "mart", "store", "shop" } },
    { canonical = "Nishikata District",        aliases = { "nishikata district", "district", "nishikata" } },
}

local LocalPlayer = Players.LocalPlayer
local Character, HRP, Humanoid

local phoneScreenPush = nil
local photoJobSubmit  = nil

local State = {
    farming    = false,
    processing = false,
    following  = false,
    tweening   = false,
    lastTask   = "",
    taskCount  = 0,
}

local followConnection = nil
local currentTween     = nil

--// handler
local function bindCharacter(char)
    Character = char
    HRP       = char:WaitForChild("HumanoidRootPart")
    Humanoid  = char:WaitForChild("Humanoid")

    if followConnection then
        followConnection:Disconnect()
        followConnection = nil
        State.following  = false
    end
    if currentTween then
        currentTween:Cancel()
        currentTween   = nil
        State.tweening = false
    end
    for _, p in ipairs(char:GetDescendants()) do
        if p:IsA("BasePart") then p.CanCollide = true end
    end
end

local Util = {}

function Util.findRemotes()
    local remotes = ReplicatedStorage:FindFirstChild("Remotes")
    if not remotes then return false end
    phoneScreenPush = remotes:FindFirstChild("PhoneScreenPush")
    photoJobSubmit  = remotes:FindFirstChild("PhotoJobSubmit")
    return phoneScreenPush ~= nil and photoJobSubmit ~= nil
end

function Util.startPhotoJob()
    if not photoJobSubmit then return end
    pcall(photoJobSubmit.InvokeServer, photoJobSubmit, "Start")
    task.wait(0.5)
end

function Util.setCollision(enabled)
    if not Character then return end
    for _, p in ipairs(Character:GetDescendants()) do
        if p:IsA("BasePart") then p.CanCollide = enabled end
    end
end

function Util.cancelActiveTween()
    if currentTween then
        currentTween:Cancel()
        currentTween = nil
    end
    State.tweening = false
end

--// tween functions
function Util.smoothTween(targetPos)
    if not HRP then return end
    Util.cancelActiveTween()

    local origin = HRP.Position
    local dist   = (targetPos - origin).Magnitude

    if dist < S.MaxDistance then
        HRP.CFrame = CFrame.new(targetPos)
        Util.setCollision(true)
        return
    end

    Util.setCollision(false)
    State.tweening = true

    local duration = math.clamp(dist / S.TweenSpeed, S.MinDuration, S.MaxDuration)
    local midPos   = origin:Lerp(targetPos, 0.55)

    local phase1 = TweenService:Create(
        HRP,
        TweenInfo.new(duration * 0.55, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
        { CFrame = CFrame.new(midPos) }
    )
    local phase2 = TweenService:Create(
        HRP,
        TweenInfo.new(duration * 0.45, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out),
        { CFrame = CFrame.new(targetPos) }
    )

    currentTween = phase1
    phase1:Play()
    phase1.Completed:Wait()

    if not State.farming then
        Util.cancelActiveTween()
        Util.setCollision(true)
        return
    end

    currentTween = phase2
    phase2:Play()
    phase2.Completed:Wait()
    currentTween = nil

    Util.setCollision(true)
    State.tweening = false
    task.wait(0.08)
end

function Util.fastFollowTween(targetPos)
    if not HRP or State.tweening then return end
    State.tweening = true
    Util.setCollision(false)

    local dist = (targetPos - HRP.Position).Magnitude
    local dur  = math.clamp(dist / (S.TweenSpeed * 1.6), 0.25, 1.4)

    if currentTween then currentTween:Cancel() end
    currentTween = TweenService:Create(
        HRP,
        TweenInfo.new(dur, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out),
        { CFrame = CFrame.new(targetPos) }
    )
    currentTween:Play()
    currentTween.Completed:Wait()
    currentTween   = nil
    State.tweening = false
end

--// photo functions
function Util.takePhoto(targetPos)
    if not phoneScreenPush or not photoJobSubmit or not HRP then return end

    local buf = buffer.create(7)
    buffer.writeu8(buf, 0, 1)
    buffer.writeu8(buf, 1, 4)
    buffer.writeu8(buf, 2, 0)
    buffer.writeu8(buf, 3, 1)
    buffer.writeu8(buf, 4, 1)
    buffer.writeu8(buf, 5, 42)
    buffer.writeu8(buf, 6, 24)

    pcall(phoneScreenPush.FireServer, phoneScreenPush, buf)
    task.wait(0.15)

    local lookAt = targetPos or (HRP.Position + HRP.CFrame.LookVector * 10)
    pcall(photoJobSubmit.InvokeServer, photoJobSubmit, "Submit", CFrame.new(HRP.Position, lookAt))
    task.wait(0.15)
end

--// find functions
function Util.findPlayer(name)
    local low = name:lower()
    for _, p in ipairs(Players:GetPlayers()) do
        if p ~= LocalPlayer then
            if p.Name:lower():find(low, 1, true) or p.DisplayName:lower():find(low, 1, true) then
                if p.Character and p.Character:FindFirstChild("HumanoidRootPart") then
                    return p
                end
            end
        end
    end
    return nil
end

local function fuzzyScore(haystack, needle)
    local score = 0
    for word in needle:gmatch("%S+") do
        if #word > 2 and haystack:find(word, 1, true) then
            score = score + 1
        end
    end
    return score
end

function Util.normalizeTaskText(raw)
    return raw
        :gsub("^get a photo of ", "")
        :gsub("^a photo of ", "")
        :gsub("^photo of ", "")
        :gsub("^the ", "")
        :lower()
        :match("^%s*(.-)%s*$")
end

function Util.resolveCanonical(normalized)
    for _, entry in ipairs(AREA_TASKS) do
        for _, alias in ipairs(entry.aliases) do
            if normalized == alias then
                return entry.canonical
            end
        end
    end

    for _, entry in ipairs(AREA_TASKS) do
        for _, alias in ipairs(entry.aliases) do
            if normalized:find(alias, 1, true) or alias:find(normalized, 1, true) then
                return entry.canonical
            end
        end
    end

    local bestScore    = 0
    local bestCanonical = nil
    for _, entry in ipairs(AREA_TASKS) do
        for _, alias in ipairs(entry.aliases) do
            local s = fuzzyScore(alias, normalized) + fuzzyScore(normalized, alias)
            if s > bestScore then
                bestScore     = s
                bestCanonical = entry.canonical
            end
        end
    end
    if bestScore > 0 then return bestCanonical end

    return nil
end

function Util.findLocation(raw)
    local normalized = Util.normalizeTaskText(raw)
    local canonical  = Util.resolveCanonical(normalized)

    local searchTerms = {}
    if canonical then
        table.insert(searchTerms, canonical:lower())
    end
    table.insert(searchTerms, normalized)

    for word in normalized:gmatch("%S+") do
        if #word > 3 then
            table.insert(searchTerms, word)
        end
    end

    local bestPart  = nil
    local bestScore = 0

    for _, obj in ipairs(Workspace:GetDescendants()) do
        if obj:IsA("BasePart") then
            local objName = obj.Name:lower()

            for _, term in ipairs(searchTerms) do
                if objName:find(term, 1, true) then
                    local s = fuzzyScore(objName, term) + 1
                    if s > bestScore then
                        bestScore = s
                        bestPart  = obj
                    end
                end
            end

            local lm = obj:FindFirstChild("PhotoJobLandmark")
            if lm and lm.Value then
                local lmVal = lm.Value:lower()
                for _, term in ipairs(searchTerms) do
                    if lmVal:find(term, 1, true) then
                        local s = fuzzyScore(lmVal, term) + 2
                        if s > bestScore then
                            bestScore = s
                            bestPart  = obj
                        end
                    end
                end
            end
        end
    end

    return bestPart and bestPart.Position or nil
end

--// gui functions
function Util.getTaskText()
    local gui = LocalPlayer:FindFirstChild("PlayerGui")
    if not gui then return nil end
    local jobGui = gui:FindFirstChild("PhotoJobGui")
    if not jobGui then return nil end
    local card = jobGui:FindFirstChild("Card")
    if not card then return nil end
    local label = card:FindFirstChild("Task")
    if not label or not label:IsA("TextLabel") then return nil end
    return label.Text
end

local function isKnownArea(text)
    local low = text:lower()
    for _, entry in ipairs(AREA_TASKS) do
        for _, alias in ipairs(entry.aliases) do
            if low:find(alias, 1, true) then return true end
        end
    end
    return false
end

--// task handlers
local function handlePlayerTask(playerName)
    local targetPlayer = Util.findPlayer(playerName)
    if not targetPlayer then return end

    State.following = true

    followConnection = RunService.Heartbeat:Connect(function()
        if not State.following or not targetPlayer or not targetPlayer.Character then
            State.following = false
            return
        end

        local tRoot = targetPlayer.Character:FindFirstChild("HumanoidRootPart")
        if not tRoot or not HRP then return end

        local goal = tRoot.Position + Vector3.new(S.FollowOffset, 0, S.FollowOffset)
        if (goal - HRP.Position).Magnitude > 3 then
            Util.fastFollowTween(goal)
        end

        if HRP then
            HRP.CFrame = CFrame.new(HRP.Position, tRoot.Position)
        end
    end)

    local attempts   = 0
    local photoTaken = false

    while attempts < S.MaxAttempts and State.farming and State.following do
        if not targetPlayer or not targetPlayer.Character then
            targetPlayer = Util.findPlayer(playerName)
            if not targetPlayer then break end
        end

        local tRoot = targetPlayer.Character:FindFirstChild("HumanoidRootPart")
        if tRoot and HRP then
            if (tRoot.Position - HRP.Position).Magnitude < S.PhotoRange then
                Util.cancelActiveTween()
                Util.setCollision(true)
                Util.takePhoto(tRoot.Position)
                photoTaken = true
                break
            end
        end

        task.wait(0.3)
        attempts += 1
    end

    State.following = false
    if followConnection then
        followConnection:Disconnect()
        followConnection = nil
    end

    Util.setCollision(true)
    State.tweening = false

    if not photoTaken and targetPlayer and targetPlayer.Character then
        local tRoot = targetPlayer.Character:FindFirstChild("HumanoidRootPart")
        if tRoot then
            Util.smoothTween(tRoot.Position + Vector3.new(S.FollowOffset, 0, S.FollowOffset))
            task.wait(0.2)
            Util.takePhoto(tRoot.Position)
        end
    end
end

local function handleLocationTask(taskText)
    local pos = Util.findLocation(taskText)
    if not pos then return end
    Util.smoothTween(pos)
    task.wait(0.2)
    Util.takePhoto(pos)
end

--// process task
local function processTask()
    if State.processing or not State.farming then return end

    local taskText = Util.getTaskText()
    if not taskText or taskText == "" or taskText == "Waiting for assignment..." then return end
    if taskText == State.lastTask then return end

    State.lastTask   = taskText
    State.processing = true
    State.taskCount += 1

    local low           = taskText:lower()
    local hasPhotoOf    = low:find("get a photo of ") ~= nil
    local hasThe        = low:find(" the ") ~= nil or low:find("^the ") ~= nil
    local knownArea     = isKnownArea(taskText)
    local hasPlayer     = low:find("player") ~= nil

    local isPlayerTask  = hasPlayer or (hasPhotoOf and not hasThe and not knownArea)

    if isPlayerTask then
        local playerName = taskText
            :gsub("^get a photo of ", "")
            :gsub("^a photo of ", "")
            :gsub("^photo of ", "")
        handlePlayerTask(playerName)
    else
        handleLocationTask(taskText)
    end

    Util.setCollision(true)
    State.tweening = false
    task.wait(0.5)

    State.processing = false
    State.lastTask   = ""
end

--// farm loop
local function farmLoop()
    while State.farming do
        if not State.processing then processTask() end
        task.wait(S.RefreshRate)
    end
end

--// setup
local initChar = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
bindCharacter(initChar)
LocalPlayer.CharacterAdded:Connect(bindCharacter)

--// main
task.spawn(function()
    local tries = 0
    while not Util.findRemotes() and tries < 10 do
        task.wait(1)
        tries += 1
    end
    Util.startPhotoJob()
    if S.AutoStart then
        State.farming = true
        task.spawn(farmLoop)
    end
end)

--// global functions
_G.StopFarming = function()
    State.farming    = false
    State.following  = false
    State.tweening   = false
    State.processing = false
    if followConnection then followConnection:Disconnect(); followConnection = nil end
    if currentTween then currentTween:Cancel(); currentTween = nil end
    Util.setCollision(true)
end

_G.StartFarming = function()
    if State.farming then return end
    State.farming    = true
    State.processing = false
    State.following  = false
    State.tweening   = false
    State.lastTask   = ""
    State.taskCount  = 0
    Util.setCollision(true)
    task.spawn(farmLoop)
end

_G.GetStatus = function()
    return State
end

Features & Information

Gakuran Auto Photo Job What it does: Auto-farms photo jobs - reads tasks finds players/locations moves to them takes photos All automatic Why open source: So you can see how the fuck it works and make your own Study the tweening text parsing remote handling and movement logic Use it break it fix it improve it do whatever you want.

Community Comments (5)

holy ai aint no way bros using the global table in the big 26😭

Replying to @funjimmywantstodie
DirectMemoryAccessDirectMemoryAccessSep 5, 2026(edited)

@funjimmywantstodie kid saw _G and had a meltdown Go learn actual Lua before talking to me skid Can't afford Pottasium so he's on Xeno with the Israeli spyware skidded a free UI lib ChatGPT wrote his whole script AI generated his thumbnail and named his free skid hub 'Uranium' like it's radioactive Your whole hub is AI generated but you calling my script AI ironic! I can just hit your Cloudflare Worker endpoint get the raw script and deobfuscate it whatever free obfuscator you used in minutes Nothing original in it skid

Replying to @DirectMemoryAccess
sorrosorroSep 9, 2026

@DirectMemoryAccess im crying why’d you have to fry him 😭

gabrielchablauugabrielchablauuSep 5, 2026

😐😐

delores083gdelores083gSep 8, 2026

I made one but can't upload it....

More Scripts for (学乱) Gakuran