aboutsummaryrefslogtreecommitdiff
path: root/builtin/profiler
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/profiler')
0 files changed, 0 insertions, 0 deletions
/a> 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
-- Detect optional mods.
local armor_path = minetest.get_modpath("3d_armor")

-- global runtime storage for data and references
-- contains .motors loaded from mod storage
-- runtime variables and api functions
elevator = {
	SPEED		= minetest.settings:get("elevator_speed") or 10,	-- Initial speed of a box.
	ACCEL		= minetest.settings:get("elevator_accel") or 0.1,	-- Acceleration of a box.
	VISUAL_INCREASE = 1.75,
	VERSION		= 8,	-- Elevator interface/database version.
	PTIMEOUT	= minetest.settings:get("elevator_time") or 120,	-- Maximum time a box can go without players nearby.
	SLOW_DIST = 16,
	SLOW_SPEED = 1.75,
	boxes		= {}, -- Elevator boxes in action.
	lastboxes	= {}, -- Player near box timeout.
	riding		= {}, -- Players riding boxes.
	formspecs	= {}, -- Player formspecs.
}

local MP = minetest.get_modpath(minetest.get_current_modname())
dofile(MP .. "/helpers.lua")
dofile(MP .. "/storage.lua")
dofile(MP .. "/crafts.lua")
dofile(MP .. "/components.lua")
dofile(MP .. "/hooks.lua")
dofile(MP .. "/formspecs.lua")

local phash = elevator.phash
local punhash = elevator.punhash
local get_node = elevator.get_node

-- Cause <sender> to ride <motorhash> beginning at <pos> and targetting <target>.
elevator.create_box = function(motorhash, pos, target, sender)
    -- First create the box.
    local obj = minetest.add_entity(pos, "elevator:box")
    obj:setpos(pos)
    -- Attach the player.
    sender:setpos(pos)
    sender:set_attach(obj, "", {x=0, y=9, z=0}, {x=0, y=0, z=0})
    sender:set_eye_offset({x=0, y=-9, z=0},{x=0, y=-9, z=0})
    sender:set_properties({visual_size = {x=elevator.VISUAL_INCREASE, y=elevator.VISUAL_INCREASE}})
    if armor_path then
        armor:update_player_visuals(sender)
    end
    -- Set the box properties.
    obj:get_luaentity().motor = motorhash
    obj:get_luaentity().uid = math.floor(math.random() * 1000000)
    obj:get_luaentity().attached = sender:get_player_name()
    obj:get_luaentity().start = pos
    obj:get_luaentity().target = target
    obj:get_luaentity().halfway = {x=pos.x, y=(pos.y+target.y)/2, z=pos.z}
    obj:get_luaentity().vmult = (target.y < pos.y) and -1 or 1
    -- FIX for "overshooting"
    local delta_y = math.abs(pos.y-target.y)
	 
    local speed = elevator.SPEED
    if (delta_y<elevator.SLOW_DIST) then
       speed = elevator.SLOW_SPEED

    end

    -- Set the speed.
    obj:setvelocity({x=0, y=speed*obj:get_luaentity().vmult, z=0})
    obj:setacceleration({x=0, y=elevator.ACCEL*obj:get_luaentity().vmult, z=0})
    -- Set the tables.
    elevator.boxes[motorhash] = obj
    elevator.riding[sender:get_player_name()] = {
        motor = motorhash,
        pos = pos,
        target = target,
        box = obj,
    }
    return obj
end

-- Starting from <pos>, locate a motor hash.
elevator.locate_motor = function(pos)
    local p = vector.new(pos)
    while true do
        local node = get_node(p)
        if node.name == "elevator:elevator_on" or node.name == "elevator:elevator_off" then
            p.y = p.y + 2
        elseif node.name == "elevator:shaft" then
            p.y = p.y + 1
        elseif node.name == "elevator:motor" then
            return phash(p)
        else
            return nil
        end
    end
end

elevator.build_motor = function(hash)
    local need_saving = false
    local motor = elevator.motors[hash]
    -- Just ignore motors that don't exist.
    if not motor then
        return
    end
    local p = punhash(hash)
    local node = get_node(p)
    -- And ignore motors that aren't motors.
    if node.name ~= "elevator:motor" then
        return
    end
    p.y = p.y - 1
    motor.elevators = {}
    motor.pnames = {}
    motor.labels = {}
    -- Run down through the shaft, storing information about elevators.
    while true do
        local node = get_node(p)
        if node.name == "elevator:shaft" then
            p.y = p.y - 1
        else
            p.y = p.y - 1
            local node = get_node(p)
            if node.name == "elevator:elevator_on" or node.name == "elevator:elevator_off" then
                table.insert(motor.elevators, phash(p))
                table.insert(motor.pnames, tostring(p.y))
                table.insert(motor.labels, "")
                p.y = p.y - 1
                need_saving = true
            else
                break
            end
        end
    end
    -- Set the elevators fully.
    for i,m in ipairs(motor.elevators) do
        local pos = punhash(m)
        local meta = minetest.get_meta(pos)
        meta:set_int("version", elevator.VERSION)
        if meta:get_string("motor") ~= hash then
            elevator.build_motor(meta:get_string("motor"))
        end
        motor.labels[i] = meta:get_string("label")
        meta:set_string("motor", hash)
        if motor.labels[i] ~= meta:get_string("infotext") then
            meta:set_string("infotext", motor.labels[i])
        end
    end
    if need_saving then
        elevator.save_elevator()
    end
end

elevator.unbuild = function(pos, add)
    local need_saving = false
    local p = table.copy(pos)
    p.y = p.y - 1
    -- Loop down through the network, set any elevators below this to the off position.
    while true do
        local node = get_node(p)
        if node.name == "elevator:shaft" then
            p.y = p.y - 1
        else
            p.y = p.y - 1
            local node = get_node(p)
            if node.name == "elevator:elevator_on" or node.name == "elevator:elevator_off" then
                local meta = minetest.get_meta(p)
                meta:set_string("motor", "")
                p.y = p.y - 1
            else
                break
            end
        end
    end
    -- After a short delay, build the motor and handle box removal.
    minetest.after(0.01, function(p2, add)
        if not p2 or not add then
            return
        end
        p2.y = p2.y + add
        local motorhash = elevator.locate_motor(p2)
        elevator.build_motor(motorhash)
        -- If there's a box below this point, break it.
        if elevator.boxes[motorhash] and elevator.boxes[motorhash]:getpos() and p2.y >= elevator.boxes[motorhash]:getpos().y then
            elevator.boxes[motorhash] = nil
        end
        -- If the box does not exist, just clear it.
        if elevator.boxes[motorhash] and not elevator.boxes[motorhash]:getpos() then
            elevator.boxes[motorhash] = nil
        end
    end, table.copy(pos), add)
end

-- Ensure an elevator is up to the latest version.
local function upgrade_elevator(pos, meta)
    if meta:get_int("version") ~= elevator.VERSION then
        minetest.log("action", "[elevator] Updating elevator with old version at "..minetest.pos_to_string(pos))
        minetest.after(0, function(pos) elevator.build_motor(elevator.locate_motor(pos)) end, pos)
        meta:set_int("version", elevator.VERSION)
        meta:set_string("formspec", "")
        meta:set_string("infotext", meta:get_string("label"))
    end
end

-- Convert off to on when applicable.
local offabm = function(pos, node)
    local meta = minetest.get_meta(pos)
    upgrade_elevator(pos, meta)
    if not elevator.boxes[meta:get_string("motor")] and elevator.motors[meta:get_string("motor")] then
        node.name = "elevator:elevator_on"
        minetest.swap_node(pos, node)
    end
end

minetest.register_abm({
    nodenames = {"elevator:elevator_off"},
    interval = 1,
    chance = 1,
    action = offabm,
    label = "Elevator (Off)",
})

-- Convert on to off when applicable.
minetest.register_abm({
    nodenames = {"elevator:elevator_on"},
    interval = 1,
    chance = 1,
    action = function(pos, node)
        local meta = minetest.get_meta(pos)
        upgrade_elevator(pos, meta)
        if elevator.boxes[meta:get_string("motor")] or not elevator.motors[meta:get_string("motor")] then
            node.name = "elevator:elevator_off"
            minetest.swap_node(pos, node)
        end
    end,
    label = "Elevator (On)",
})

-- Remove the player from self, and teleport them to pos if specified.
local function detach(self, pos)
    local player = minetest.get_player_by_name(self.attached)
    local attached = player:get_attach()
    if not attached or attached:get_luaentity().uid ~= self.uid then
        return
    end
    player:set_detach()
    player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
    player:set_properties({visual_size = {x=1, y=1}})
    if armor_path then
        armor:update_player_visuals(player)
    end
    if pos then
        player:setpos(pos)
	minetest.after(0.1, function(pl, p)
		pl:setpos(p)
	end, player, pos)
    end
    elevator.riding[self.attached] = nil
end

local box_entity = {
    physical = false,
    collisionbox = {0,0,0,0,0,0},
    visual = "wielditem",
    visual_size = {x=1, y=1},
    textures = {"elevator:elevator_box"},

    attached = "",
    motor = false,
    target = false,

    start = false,
    lastpos = false,
    halfway = false,
    vmult = 0,

    on_activate = function(self, staticdata)
        -- Don't want the box being destroyed by anything except the elevator system.
        self.object:set_armor_groups({immortal=1})
    end,

    on_step = function(self, dtime)
        local pos = self.object:getpos()
        -- First, check if this box needs removed.
        -- If the motor has a box and it isn't this box.
        if elevator.boxes[self.motor] and elevator.boxes[self.motor] ~= self.object then
            minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to duplication.")
            self.object:remove()
            return
        end
        -- If our attached player can't be found.
        if not minetest.get_player_by_name(self.attached) then
            minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to lack of attachee logged in.")
            self.object:remove()
            elevator.boxes[self.motor] = nil
            return
        end
        -- If our attached player is no longer with us.
        if not minetest.get_player_by_name(self.attached):get_attach() or minetest.get_player_by_name(self.attached):get_attach():get_luaentity().uid ~= self.uid then
            minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to lack of attachee.")
            self.object:remove()
            elevator.boxes[self.motor] = nil
            return
        end
        -- If our motor's box is nil, we should self-destruct.
        if not elevator.boxes[self.motor] then
            minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to nil entry in boxes.")
            detach(self)
            self.object:remove()
            elevator.boxes[self.motor] = nil
            return
        end

        minetest.get_player_by_name(self.attached):setpos(pos)
        -- Ensure lastpos is set to something.
        self.lastpos = self.lastpos or pos

        -- Loop through all travelled nodes.
        for y=self.lastpos.y,pos.y,((self.lastpos.y > pos.y) and -0.3 or 0.3) do
            local p = vector.round({x=pos.x, y=y, z=pos.z})
            local node = get_node(p)
            if node.name == "elevator:shaft" then
                -- Nothing, just continue on our way.
            elseif node.name == "elevator:elevator_on" or node.name == "elevator:elevator_off" then
                -- If this is our target, detach the player here, destroy this box, and update the target elevator without waiting for the abm.
                if vector.distance(p, self.target) < 1 then
                    minetest.log("action", "[elevator] "..minetest.pos_to_string(p).." broke due to arrival.")
                    detach(self, vector.add(self.target, {x=0, y=-0.4, z=0}))
                    self.object:remove()
                    elevator.boxes[self.motor] = nil
                    offabm(self.target, node)
                    return
                end
            else
                -- Check if we're in the top part of an elevator, if so it's fine.
                local below = vector.add(p, {x=0,y=-1,z=0})
                local belownode = get_node(below)
                if belownode.name ~= "elevator:elevator_on" and belownode.name ~= "elevator:elevator_off" then
                    -- If we aren't, then break the box.
                    minetest.log("action", "[elevator] "..minetest.pos_to_string(p).." broke on "..node.name)
                    elevator.boxes[self.motor] = nil
                    detach(self, p)
                    self.object:remove()
                    return
                end
            end
        end
        self.lastpos = pos
    end,
}

minetest.register_entity("elevator:box", box_entity)