feat(lib): update examples
This commit is contained in:
parent
492fecc32c
commit
944f595841
@ -3,9 +3,11 @@ Username = "ErrorNoWatcher"
|
||||
Owners = { "ErrorNoInternet" }
|
||||
|
||||
for _, module in ipairs({
|
||||
"automation",
|
||||
"enum",
|
||||
"events",
|
||||
"inventory",
|
||||
"lib",
|
||||
"movement",
|
||||
"utils",
|
||||
}) do
|
||||
@ -13,3 +15,5 @@ for _, module in ipairs({
|
||||
package.loaded[module] = nil
|
||||
require(module)
|
||||
end
|
||||
|
||||
update_listeners()
|
||||
|
132
lib/automation.lua
Normal file
132
lib/automation.lua
Normal file
@ -0,0 +1,132 @@
|
||||
FishingBobber = nil
|
||||
FishingTicks = 0
|
||||
FishLastCaught = 0
|
||||
LastEaten = 0
|
||||
|
||||
function auto_fish()
|
||||
stop_auto_fish()
|
||||
FishingTicks = 0
|
||||
|
||||
function hold_fishing_rod()
|
||||
if client.held_item.kind == "minecraft:fishing_rod" or hold_items({ "minecraft:fishing_rod" }) then
|
||||
return true
|
||||
end
|
||||
warn("no fishing rod found!")
|
||||
end
|
||||
|
||||
if not hold_fishing_rod() then
|
||||
return
|
||||
end
|
||||
|
||||
add_listener("add_entity", function(entity)
|
||||
if entity.kind == "minecraft:fishing_bobber" and entity.data == client.id then
|
||||
FishingBobber = entity
|
||||
end
|
||||
end, "auto-fish_watch-bobber")
|
||||
|
||||
add_listener("remove_entities", function(entity_ids)
|
||||
if table.contains(entity_ids, FishingBobber.id) then
|
||||
if os.time() - LastEaten < 3 then
|
||||
sleep(3000)
|
||||
end
|
||||
hold_fishing_rod()
|
||||
client:use_item()
|
||||
end
|
||||
end, "auto-fish_watch-bobber")
|
||||
|
||||
add_listener("level_particles", function(particle)
|
||||
if particle.kind == 30 and particle.count == 6 then
|
||||
local current_bobber = client:find_entities(function(e)
|
||||
return e.id == FishingBobber.id
|
||||
end)[1]
|
||||
if distance(current_bobber.position, particle.position) <= 0.75 then
|
||||
FishLastCaught = os.time()
|
||||
client:use_item()
|
||||
end
|
||||
end
|
||||
end, "auto-fish")
|
||||
|
||||
add_listener("tick", function()
|
||||
FishingTicks = FishingTicks + 1
|
||||
if FishingTicks % 600 ~= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if os.time() - FishLastCaught >= 60 then
|
||||
hold_fishing_rod()
|
||||
client:use_item()
|
||||
end
|
||||
end, "auto-fish_watchdog")
|
||||
|
||||
client:use_item()
|
||||
end
|
||||
|
||||
function stop_auto_fish()
|
||||
remove_listeners("add_entity", "auto-fish_watch-bobber")
|
||||
remove_listeners("remove_entities", "auto-fish_watch-bobber")
|
||||
remove_listeners("level_particles", "auto-fish")
|
||||
remove_listeners("tick", "auto-fish_watchdog")
|
||||
|
||||
if FishingBobber and client:find_entities(function(e)
|
||||
return e.id == FishingBobber.id
|
||||
end)[1] then
|
||||
FishingBobber = nil
|
||||
client:use_item()
|
||||
end
|
||||
end
|
||||
|
||||
function attack_entities(target_kind, minimum)
|
||||
if not minimum then
|
||||
minimum = 0
|
||||
end
|
||||
|
||||
function hold_sword()
|
||||
if client.held_item.kind == "minecraft:iron_sword" or hold_items({ "minecraft:iron_sword" }) then
|
||||
return true
|
||||
end
|
||||
warn("no sword found!")
|
||||
end
|
||||
|
||||
while true do
|
||||
local self_pos = client.position
|
||||
local entities = client:find_entities(function(e)
|
||||
return e.kind == target_kind and distance(e.position, self_pos) < 5
|
||||
end)
|
||||
|
||||
if #entities > minimum then
|
||||
local e = entities[1]
|
||||
local pos = e.position
|
||||
pos.y = pos.y + 1.5
|
||||
|
||||
hold_sword()
|
||||
client:look_at(pos)
|
||||
client:attack(e.id)
|
||||
while client.has_attack_cooldown do
|
||||
sleep(100)
|
||||
end
|
||||
else
|
||||
sleep(1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function check_food(hunger)
|
||||
if hunger.food >= 20 then
|
||||
return
|
||||
end
|
||||
|
||||
local current_time = os.time()
|
||||
if current_time - LastEaten >= 3 then
|
||||
LastEaten = current_time
|
||||
|
||||
while not hold_items({
|
||||
"minecraft:golden_carrot",
|
||||
"minecraft:cooked_beef",
|
||||
"minecraft:bread",
|
||||
}) do
|
||||
sleep(1000)
|
||||
LastEaten = current_time
|
||||
end
|
||||
client:use_item()
|
||||
end
|
||||
end
|
11
lib/enum.lua
11
lib/enum.lua
@ -32,3 +32,14 @@ QUICK_CRAFT_START = 0
|
||||
QUICK_CRAFT_ADD = 1
|
||||
QUICK_CRAFT_END = 2
|
||||
PICKUP_ALL = 11
|
||||
|
||||
POSE_NAMES = {
|
||||
"standing",
|
||||
"flying",
|
||||
"sleeping",
|
||||
"swimming",
|
||||
"attacking",
|
||||
"sneaking",
|
||||
"jumping",
|
||||
"dying",
|
||||
}
|
||||
|
108
lib/events.lua
108
lib/events.lua
@ -1,30 +1,90 @@
|
||||
local center = { x = 0, z = 0 }
|
||||
local radius = 100
|
||||
Center = { x = 0, y = 64, z = 0 }
|
||||
Radius = 100
|
||||
Whitelist = Owners
|
||||
Ticks = -1
|
||||
|
||||
function log_player_positions()
|
||||
local entities = client:find_entities(function(e)
|
||||
return e.kind == "minecraft:player"
|
||||
and e.position.x > center.x - radius + 1
|
||||
and e.position.x < center.x + radius
|
||||
and e.position.z > center.z - radius
|
||||
and e.position.z < center.z + radius
|
||||
function check_radius()
|
||||
Ticks = Ticks + 1
|
||||
if Ticks % 20 ~= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local self_id = client.id
|
||||
local players = client:find_players(function(p)
|
||||
return self_id ~= p.id
|
||||
and p.position.x > Center.x - Radius + 1
|
||||
and p.position.x < Center.x + Radius
|
||||
and p.position.z > Center.z - Radius
|
||||
and p.position.z < Center.z + Radius
|
||||
end)
|
||||
for _, e in ipairs(entities) do
|
||||
client:chat(string.format("%s (%s) at %.1f %.1f %.1f", e.kind, e.id, e.position.x, e.position.y, e.position.z))
|
||||
|
||||
local tab_list = client.tab_list
|
||||
for _, player in ipairs(players) do
|
||||
local target
|
||||
for _, tab_player in ipairs(tab_list) do
|
||||
if tab_player.uuid == player.uuid and not table.contains(Whitelist, tab_player.name) then
|
||||
target = tab_player
|
||||
break
|
||||
end
|
||||
end
|
||||
if not target then
|
||||
goto continue
|
||||
end
|
||||
|
||||
client:chat(
|
||||
string.format(
|
||||
"%s is %s %d blocks away at %.2f %.2f %.2f facing %.2f %.2f",
|
||||
target.name,
|
||||
POSE_NAMES[player.pose + 1],
|
||||
distance(Center, player.position),
|
||||
player.position.x,
|
||||
player.position.y,
|
||||
player.position.z,
|
||||
player.direction.x,
|
||||
player.direction.y
|
||||
)
|
||||
)
|
||||
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
add_listener("init", function()
|
||||
info("client initialized, setting information...")
|
||||
client:set_client_information({ view_distance = 16 })
|
||||
end)
|
||||
function update_listeners()
|
||||
for type, listeners in pairs(get_listeners()) do
|
||||
for id, _ in pairs(listeners) do
|
||||
remove_listeners(type, id)
|
||||
end
|
||||
end
|
||||
|
||||
add_listener("login", function()
|
||||
info("player successfully logged in!")
|
||||
end)
|
||||
|
||||
add_listener("death", function()
|
||||
warn(string.format("player died at %.1f %.1f %.1f!", client.position.x, client.position.y, client.position.z))
|
||||
end, "warn_player_died")
|
||||
|
||||
add_listener("tick", log_player_positions)
|
||||
for type, listeners in pairs({
|
||||
login = {
|
||||
message = function()
|
||||
info("bot successfully logged in!")
|
||||
end,
|
||||
eat = function()
|
||||
sleep(5000)
|
||||
check_food(client.hunger)
|
||||
end,
|
||||
},
|
||||
death = {
|
||||
warn_bot_died = function()
|
||||
warn(
|
||||
string.format(
|
||||
"bot died at %.2f %.2f %.2f facing %.2f %.2f!",
|
||||
client.position.x,
|
||||
client.position.y,
|
||||
client.position.z,
|
||||
client.direction.x,
|
||||
client.direction.y
|
||||
)
|
||||
)
|
||||
end,
|
||||
},
|
||||
set_health = { auto_eat = check_food },
|
||||
tick = { log_player_positions = check_radius },
|
||||
}) do
|
||||
for id, callback in pairs(listeners) do
|
||||
add_listener(type, callback, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,10 +1,42 @@
|
||||
function hold_items_in_hotbar(target_kinds, inventory)
|
||||
if not inventory then
|
||||
inventory = client:open_inventory()
|
||||
end
|
||||
for index, item in ipairs(inventory.contents) do
|
||||
if index >= 37 and index <= 45 and table.contains(target_kinds, item.kind) then
|
||||
inventory = nil
|
||||
sleep(500)
|
||||
client:set_held_slot(index - 37)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function hold_items(target_kinds)
|
||||
local inventory = client:open_inventory()
|
||||
if hold_items_in_hotbar(target_kinds, inventory) then
|
||||
return true
|
||||
end
|
||||
for index, item in ipairs(inventory.contents) do
|
||||
if table.contains(target_kinds, item.kind) then
|
||||
inventory:click({ source_slot = index - 1, target_slot = client.held_slot }, SWAP)
|
||||
sleep(100)
|
||||
inventory = nil
|
||||
sleep(500)
|
||||
return true
|
||||
end
|
||||
end
|
||||
inventory = nil
|
||||
sleep(500)
|
||||
return false
|
||||
end
|
||||
|
||||
function steal(item_name)
|
||||
for _, chest_pos in ipairs(client:find_blocks(client.position, get_block_states({ "chest" }))) do
|
||||
client:chat(dump(chest_pos))
|
||||
|
||||
client:go_to({ position = chest_pos, radius = 3 }, { type = RADIUS_GOAL })
|
||||
while client.pathfinder.is_calculating or client.pathfinder.is_executing do
|
||||
sleep(50)
|
||||
sleep(500)
|
||||
end
|
||||
client:look_at(chest_pos)
|
||||
|
||||
@ -23,6 +55,23 @@ function steal(item_name)
|
||||
end
|
||||
end
|
||||
|
||||
function dump_inventory(hide_empty)
|
||||
local inventory = client:open_inventory()
|
||||
for index, item in ipairs(inventory.contents) do
|
||||
if hide_empty and item.count == 0 then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local item_damage = ""
|
||||
if item.damage then
|
||||
item_damage = item.damage
|
||||
end
|
||||
info(string.format("%-2d = %2dx %-32s %s", index - 1, item.count, item.kind, item_damage))
|
||||
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
function drop_all_hotbar()
|
||||
local inventory = client:open_inventory()
|
||||
for i = 0, 9 do
|
||||
|
72
lib/lib.lua
Normal file
72
lib/lib.lua
Normal file
@ -0,0 +1,72 @@
|
||||
function clock_gettime(clock)
|
||||
local status, module = pcall(require, "posix")
|
||||
posix = status and module or nil
|
||||
|
||||
if posix then
|
||||
local s, ns = posix.clock_gettime(clock)
|
||||
return s + ns / (10 ^ (math.floor(math.log10(ns)) + 1))
|
||||
else
|
||||
warn("failed to load posix module! falling back to os.time()")
|
||||
return os.time()
|
||||
end
|
||||
end
|
||||
|
||||
function distance(p1, p2)
|
||||
return math.sqrt((p2.x - p1.x) ^ 2 + (p2.y - p1.y) ^ 2 + (p2.z - p1.z) ^ 2)
|
||||
end
|
||||
|
||||
function table.shallow_copy(t)
|
||||
local t2 = {}
|
||||
for k, v in pairs(t) do
|
||||
t2[k] = v
|
||||
end
|
||||
return t2
|
||||
end
|
||||
|
||||
function table.map(t, f)
|
||||
local t2 = {}
|
||||
for k, v in pairs(t) do
|
||||
t2[k] = f(v)
|
||||
end
|
||||
return t2
|
||||
end
|
||||
|
||||
function table.contains(t, target)
|
||||
for _, v in pairs(t) do
|
||||
if v == target then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function dump(object)
|
||||
if type(object) == "table" then
|
||||
local string = "{ "
|
||||
local parts = {}
|
||||
for key, value in pairs(object) do
|
||||
table.insert(parts, key .. " = " .. dump(value))
|
||||
end
|
||||
string = string .. table.concat(parts, ", ")
|
||||
return string .. " " .. "}"
|
||||
else
|
||||
return tostring(object)
|
||||
end
|
||||
end
|
||||
|
||||
function dumpp(object, level)
|
||||
if not level then
|
||||
level = 0
|
||||
end
|
||||
if type(object) == "table" then
|
||||
local string = "{\n" .. string.rep(" ", level + 1)
|
||||
local parts = {}
|
||||
for key, value in pairs(object) do
|
||||
table.insert(parts, key .. " = " .. dumpp(value, level + 1))
|
||||
end
|
||||
string = string .. table.concat(parts, ",\n" .. string.rep(" ", level + 1))
|
||||
return string .. "\n" .. string.rep(" ", level) .. "}"
|
||||
else
|
||||
return tostring(object)
|
||||
end
|
||||
end
|
@ -3,16 +3,9 @@ function look_at_player(name)
|
||||
if player then
|
||||
player.position.y = player.position.y + 1
|
||||
client:look_at(player.position)
|
||||
else
|
||||
client:chat(string.format("/w %s player not found!", sender))
|
||||
end
|
||||
end
|
||||
|
||||
function go_to_player(name, opts)
|
||||
local player = get_player(name)
|
||||
if player then
|
||||
client:go_to(player.position, opts)
|
||||
else
|
||||
client:chat(string.format("/w %s player not found!", sender))
|
||||
end
|
||||
function go_to_player(name, go_to_opts)
|
||||
client:go_to(get_player(name).position, go_to_opts)
|
||||
end
|
||||
|
174
lib/utils.lua
174
lib/utils.lua
@ -1,3 +1,177 @@
|
||||
SpeedTracking = {}
|
||||
TpsTracking = {}
|
||||
|
||||
function entity_speed(uuid, seconds)
|
||||
if not seconds then
|
||||
seconds = 1
|
||||
end
|
||||
|
||||
local callback = function()
|
||||
local old_entity = SpeedTracking[uuid]
|
||||
local new_entity = client:find_entities(function(e)
|
||||
return e.uuid == uuid
|
||||
end)[1]
|
||||
|
||||
if not new_entity then
|
||||
remove_listeners("tick", "speed-tracking_" .. uuid)
|
||||
SpeedTracking[uuid] = -1
|
||||
return
|
||||
end
|
||||
|
||||
if old_entity then
|
||||
old_entity._distance = old_entity._distance + distance(old_entity.position, new_entity.position)
|
||||
old_entity.position = new_entity.position
|
||||
|
||||
if old_entity._ticks < seconds * 20 then
|
||||
old_entity._ticks = old_entity._ticks + 1
|
||||
else
|
||||
remove_listeners("tick", "speed-tracking_" .. uuid)
|
||||
SpeedTracking[uuid] = old_entity._distance / seconds
|
||||
end
|
||||
else
|
||||
new_entity._ticks = 1
|
||||
new_entity._distance = 0
|
||||
SpeedTracking[uuid] = new_entity
|
||||
end
|
||||
end
|
||||
add_listener("tick", callback, "speed-tracking_" .. uuid)
|
||||
|
||||
repeat
|
||||
sleep(seconds * 1000 / 10)
|
||||
until type(SpeedTracking[uuid]) == "number"
|
||||
|
||||
local speed = SpeedTracking[uuid]
|
||||
SpeedTracking[uuid] = nil
|
||||
return speed
|
||||
end
|
||||
|
||||
function tps(seconds)
|
||||
if not seconds then
|
||||
seconds = 1
|
||||
end
|
||||
|
||||
add_listener("tick", function()
|
||||
if not TpsTracking.ticks then
|
||||
TpsTracking.ticks = 0
|
||||
TpsTracking.start = clock_gettime(0)
|
||||
else
|
||||
TpsTracking.ticks = TpsTracking.ticks + 1
|
||||
if TpsTracking.ticks >= seconds * 20 then
|
||||
TpsTracking.stop = clock_gettime(0)
|
||||
remove_listeners("tick", "tps_tracking")
|
||||
end
|
||||
end
|
||||
end, "tps_tracking")
|
||||
|
||||
sleep(seconds * 1000)
|
||||
repeat
|
||||
sleep(20)
|
||||
until TpsTracking.stop
|
||||
|
||||
local tps = seconds * 20 / (TpsTracking.stop - TpsTracking.start)
|
||||
TpsTracking = {}
|
||||
return tps
|
||||
end
|
||||
|
||||
function nether_travel(pos, go_to_opts)
|
||||
info(string.format("going to %.2f %.2f %.2f through nether", pos.x, pos.y, pos.z))
|
||||
|
||||
local portal_block_states = get_block_states({ "nether_portal" })
|
||||
local nether_pos = table.shallow_copy(pos)
|
||||
nether_pos.x = nether_pos.x / 8
|
||||
nether_pos.z = nether_pos.z / 8
|
||||
|
||||
if client.dimension == "minecraft:overworld" then
|
||||
info("currently in overworld, finding nearest portal")
|
||||
local portals = client:find_blocks(client.position, portal_block_states)
|
||||
|
||||
info(string.format("going to %.2f %.2f %.2f through nether", portals[1].x, portals[1].y, portals[1].z))
|
||||
client:go_to(portals[1], go_to_opts)
|
||||
while client.dimension ~= "minecraft:the_nether" do
|
||||
sleep(1000)
|
||||
end
|
||||
sleep(3000)
|
||||
end
|
||||
|
||||
info(string.format("currently in nether, going to %.2f %.2f", nether_pos.x, nether_pos.z))
|
||||
client:go_to(nether_pos, { type = XZ_GOAL })
|
||||
while client.pathfinder.is_calculating or client.pathfinder.is_executing do
|
||||
sleep(1000)
|
||||
end
|
||||
|
||||
info("arrived, looking for nearest portal")
|
||||
local portals_nether = client:find_blocks(client.position, portal_block_states)
|
||||
if not next(portals_nether) then
|
||||
warn("failed to find portals in the nether")
|
||||
return
|
||||
end
|
||||
|
||||
local found_portal = false
|
||||
for _, portal in ipairs(portals_nether) do
|
||||
if (client.position.y > 127) == (portal.y > 127) then
|
||||
found_portal = true
|
||||
|
||||
info(string.format("found valid portal, going to %.2f %.2f %.2f", portal.x, portal.y, portal.z))
|
||||
client:go_to(portal)
|
||||
while client.dimension ~= "minecraft:overworld" do
|
||||
sleep(1000)
|
||||
end
|
||||
sleep(3000)
|
||||
end
|
||||
|
||||
if found_portal then
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found_portal then
|
||||
warn("failed to find valid portals in the nether")
|
||||
return
|
||||
end
|
||||
|
||||
info(string.format("back in overworld, going to %.2f %.2f %.2f", pos.x, pos.y, pos.z))
|
||||
client:go_to(pos, go_to_opts)
|
||||
end
|
||||
|
||||
function interact_bed()
|
||||
local bed = client:find_blocks(
|
||||
client.position,
|
||||
get_block_states({
|
||||
"brown_bed",
|
||||
"white_bed",
|
||||
"yellow_bed",
|
||||
})
|
||||
)[1]
|
||||
if not bed then
|
||||
return
|
||||
end
|
||||
|
||||
client:go_to(bed, { type = REACH_BLOCK_POS_GOAL, options = { without_mining = true } })
|
||||
while client.pathfinder.is_calculating or client.pathfinder.is_executing do
|
||||
sleep(500)
|
||||
end
|
||||
|
||||
client:look_at(bed)
|
||||
client:block_interact(bed)
|
||||
end
|
||||
|
||||
function closest_entity(target_kind)
|
||||
local self_pos = client.position
|
||||
local entities = client:find_entities(function(e)
|
||||
return e.kind == target_kind
|
||||
end)
|
||||
|
||||
local closest_entity = entities[1]
|
||||
local closest_distance = distance(closest_entity.position, self_pos)
|
||||
for _, entity in ipairs(entities) do
|
||||
local dist = distance(entity.position, self_pos)
|
||||
if dist <= closest_distance then
|
||||
closest_entity = entity
|
||||
closest_distance = dist
|
||||
end
|
||||
end
|
||||
return closest_entity
|
||||
end
|
||||
|
||||
function get_player(name)
|
||||
local target_uuid = nil
|
||||
for _, player in ipairs(client.tab_list) do
|
||||
|
Loading…
x
Reference in New Issue
Block a user