evolve
Магазин/Общие библиотеки

lane_geom

A lane as a polyline: the point on it nearest to a creep, the heading there, and a walk of N units along it.

hunnyc0 скриптов используют
ПоддержкаИсходник открыт
Подключить в скрипт
pack.json
"requires": { "lane_geom": "^1.0" }
твой lua
local lane_geom = require("lib/lane_geom")

Игрокам ставить ничего не нужно: скрипт приносит библиотеку сам, любую версию в пределах диапазона. Правку можно проверить до публикации в dev-сессии, в scripts/lib/lane_geom/.

API
lane_geom.project(wps: table[], pos: table): number, number#

arc length along the lane of the point nearest to pos, and its distance from the lane.

Параметры
wps table[] waypoints in index order
pos table a point with GetX/GetY or x/y
Возвращает
number
number
lane_geom.heading(wps: table[], pos: table, dir: integer, span?: number): number|nil, number|nil#

unit heading of the lane at pos, going the way dir says (+1 = rising waypoint index,

Параметры
wps table[]
pos table
dir integer
span number default 150
Возвращает
number|nil
number|nil

-1 = falling). taken over span units either side of the point, so a corner turns the arrow over span rather than flipping it at the waypoint. nil for a lane of one point.

lane_geom.walk(wps: table[], pos: table, dist: number, dir: integer): number, number#

where a creep that stands at pos is after walking dist along the lane: projected on

Параметры
wps table[]
pos table
dist number
dir integer +1 rising waypoint index, -1 falling
Возвращает
number
number

the lane first, then along it, corners included. stops at the lane's end.

lane_geom.walk_point(wps: table[], pos: table, dist: number, dir: integer): table#

walk as a Vector (z of the start point kept), for callers that keep Vectors.

Параметры
wps table[]
pos table
dist number
dir integer
Возвращает
table
lane_geom.angle(wps: table[], pos: table, dir: integer, span?: number): number|nil#

heading as an angle in world axes, radians (atan2(dy, dx)); nil as heading.

Параметры
wps table[]
pos table
dir integer
span number default 150
Возвращает
number|nil
Описание

lib/lane_geom

A lane as a polyline: the point on it nearest to a creep, the heading there, and a walk of N units along it. The four uTEA copies of walk_along_waypoints (awareness, naga, natureprophet, clockwerk) took the nearest waypoint and went straight to the next one, which cuts a corner and points the wrong way near it; awareness lane_dir did the same for the minimap arrow (#191). On the top and bot lanes of LANE_WAYPOINTS that was a heading off by more than 20 degrees on 11-14% of the lane, 61 at worst, and a fog walk of 1500 u that ended up to 250 u off the lane.

local LG = require("lib/lane_geom")

local dx, dy = LG.heading(wps, pos, -1)        -- unit heading, falling waypoint index
local x, y   = LG.walk(wps, pos, 1500, -1)     -- after 1500 u on the lane
local v      = LG.walk_point(wps, pos, 1500, -1)   -- the same as a Vector, z of pos kept
local s, off = LG.project(wps, pos)            -- arc length from waypoint 1, distance off the lane

wps is a list of points (Vector or {x=, y=}) in lane order. dir is +1 for rising index, -1 for falling. heading is taken over 150 u either side of the point (span), so it turns through a corner instead of flipping at the waypoint. Test: tools\lua\lua.exe scripts\lib\lane_geom\selftest.lua from the repo root.

Исходник

Код версии 1.0.0, как его получает клиент. Байткод в сборке собран из этих файлов.

init.lua145 строк
--- the lane as a polyline: where a point stands on it, which way it runs there, and how far a
--- creep walks along it. one copy of what awareness, naga, natureprophet and clockwerk each
--- carried as "nearest waypoint, then straight to the next", which cuts every corner.
---@class lane_geom
local M = {}

local sqrt, atan2 = math.sqrt, math.atan2 or function(y, x) return math.atan(y, x) end

local function xy(p)
    if p.GetX then return p:GetX(), p:GetY() end
    return p.x, p.y
end

-- every waypoint as plain numbers, once per list: the callers hand over the same table each frame
local cache = setmetatable({}, { __mode = "k" })
local function flat(wps)
    local f = cache[wps]
    if f then return f end
    f = { n = #wps, x = {}, y = {}, s = {} }
    local acc = 0
    for i = 1, #wps do
        f.x[i], f.y[i] = xy(wps[i])
        if i > 1 then
            local dx, dy = f.x[i] - f.x[i - 1], f.y[i] - f.y[i - 1]
            acc = acc + sqrt(dx * dx + dy * dy)
        end
        f.s[i] = acc
    end
    f.len = acc
    cache[wps] = f
    return f
end

-- arc length (from waypoint 1) of the point on the polyline closest to (px, py), and how far off
local function project(f, px, py)
    local best_s, best_d2 = 0, math.huge
    for i = 1, f.n - 1 do
        local ax, ay = f.x[i], f.y[i]
        local vx, vy = f.x[i + 1] - ax, f.y[i + 1] - ay
        local l2 = vx * vx + vy * vy
        local t = 0
        if l2 > 0 then
            t = ((px - ax) * vx + (py - ay) * vy) / l2
            if t < 0 then t = 0 elseif t > 1 then t = 1 end
        end
        local qx, qy = ax + vx * t, ay + vy * t
        local d2 = (px - qx) ^ 2 + (py - qy) ^ 2
        if d2 < best_d2 then best_d2, best_s = d2, f.s[i] + t * sqrt(l2) end
    end
    return best_s, sqrt(best_d2)
end

-- the point at arc length s (clamped to the ends)
local function at(f, s)
    if s <= 0 then return f.x[1], f.y[1] end
    if s >= f.len then return f.x[f.n], f.y[f.n] end
    for i = 1, f.n - 1 do
        if s <= f.s[i + 1] then
            local l = f.s[i + 1] - f.s[i]
            local t = l > 0 and (s - f.s[i]) / l or 0
            return f.x[i] + (f.x[i + 1] - f.x[i]) * t, f.y[i] + (f.y[i + 1] - f.y[i]) * t
        end
    end
    return f.x[f.n], f.y[f.n]
end

--- arc length along the lane of the point nearest to `pos`, and its distance from the lane.
---@param wps table[] waypoints in index order
---@param pos table a point with GetX/GetY or x/y
---@return number s
---@return number off
function M.project(wps, pos)
    if not wps or #wps < 2 or not pos then return 0, math.huge end
    local px, py = xy(pos)
    return project(flat(wps), px, py)
end

--- unit heading of the lane at `pos`, going the way `dir` says (+1 = rising waypoint index,
--- -1 = falling). taken over `span` units either side of the point, so a corner turns the
--- arrow over `span` rather than flipping it at the waypoint. nil for a lane of one point.
---@param wps table[]
---@param pos table
---@param dir integer
---@param span? number default 150
---@return number|nil dx
---@return number|nil dy
function M.heading(wps, pos, dir, span)
    if not wps or #wps < 2 or not pos then return nil end
    local f = flat(wps)
    local px, py = xy(pos)
    local s = project(f, px, py)
    span = span or 150
    local ax, ay = at(f, s - span)
    local bx, by = at(f, s + span)
    local dx, dy = bx - ax, by - ay
    local len = sqrt(dx * dx + dy * dy)
    if len < 1 then return nil end
    if dir < 0 then dx, dy = -dx, -dy end
    return dx / len, dy / len
end

--- where a creep that stands at `pos` is after walking `dist` along the lane: projected on
--- the lane first, then along it, corners included. stops at the lane's end.
---@param wps table[]
---@param pos table
---@param dist number
---@param dir integer +1 rising waypoint index, -1 falling
---@return number x
---@return number y
function M.walk(wps, pos, dist, dir)
    local px, py = xy(pos)
    if not wps or #wps < 2 then return px, py end
    local f = flat(wps)
    local s = project(f, px, py)
    return at(f, s + (dir < 0 and -dist or dist))
end

--- `walk` as a Vector (z of the start point kept), for callers that keep Vectors.
---@param wps table[]
---@param pos table
---@param dist number
---@param dir integer
---@return table
function M.walk_point(wps, pos, dist, dir)
    local x, y = M.walk(wps, pos, dist, dir)
    local z = pos.GetZ and pos:GetZ() or pos.z or 0
    local V = rawget(_G, "Vector")
    if V then return V(x, y, z) end
    return { x = x, y = y, z = z }
end

--- heading as an angle in world axes, radians (atan2(dy, dx)); nil as `heading`.
---@param wps table[]
---@param pos table
---@param dir integer
---@param span? number default 150
---@return number|nil
function M.angle(wps, pos, dir, span)
    local dx, dy = M.heading(wps, pos, dir, span)
    if not dx then return nil end
    return atan2(dy, dx)
end

return M
pack.json2 строк
{ "kind": "lib", "version": "1.0.0" }
Изменения

Заметок к версиям нет.

Используют

Пока ни один опубликованный скрипт её не требует.

Ещё у этого автора

Ещё у этого автора

ground

от hunnyc

Ground height and high-ground level at any point of the dota map.

pack.json
"requires": { "ground": "^1.0" }
твой lua
local ground = require("lib/ground")
0 скриптов используютОпубликованных версий пока нет

Beta Tester Config

от hunnyc
Входит в доступ

Beta 0.10.54 preset: combo on F, last hit on B, every other bind moved off dota's own keys, hp cards and minimap marks on.

configcombolast hit
Оценок пока нет0 установок
v1.0.0 · Обновлён 2026-10-17✓ 0.10.70

fog_seen

от hunnyc

Where each enemy hero is while nobody sees him: the tick he left vision, his last cast in the fog, a teleport's landing, a position another script worked out, plus the enemy smokes.

pack.json
"requires": { "fog_seen": "^1.0" }
твой lua
local fog_seen = require("lib/fog_seen")
0 скриптов используютv1.0.1