Broken "for" loops
#1
Hello,
I was making a plugin that had to run something ten times and came across what seems to be a bug:

Code:
    for i = 1, 10, 1 do
        Player:SendMessage("Pass " .. i)
    end

This should return
Pass 1
Pass 2
Pass 3
Pass 4
Pass 5
Pass 6
Pass 7
Pass 8
Pass 9
Pass 10
in chat.
But instead, i get this error:
'=' expected near 'for'
Reply
Thanks given by:
#2
Could you post the code around the for loop?
Reply
Thanks given by:
#3
(02-19-2021, 06:47 PM)NiLSPACE Wrote: Could you post the code around the for loop?

Warning: this code is a mess. Im planning on making a /fill command and it has to run setBlock for every block inside an area the player provides using a command. For testing, i made the area 10 blocks on the x axis. If that would have worked, I would have run x, increment z by one, x, increment z, and so on until it has to increment y and then loop again.
Here it goes but be warned: It may cause eye cancer because im really bad at lua (this is the second time i made something in lua)

Code:
PLUGIN = nil

function Initialize(Plugin)
    Plugin:SetName("VanillaFill")
    Plugin:SetVersion(1)

    -- Hooks

    PLUGIN = Plugin -- NOTE: only needed if you want OnDisable() to use GetName() or something like that

    -- Command Bindings
    cPluginManager.BindCommand("/setblock", "vanillafill.setblock", setblock, " ~ Changes a block at X Y Z.");
    cPluginManager.BindCommand("/fill", "vanillafill.fill", fill, " ~ Fills an area from X Y Z to X2 Y2 Z2.");

    LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
    return true
end

function OnDisable()
    LOG(PLUGIN:GetName() .. " is shutting down...")
end

-- This segment is a bit of stripped-down code from the WorldEdit Plugin (github.com/cuberite/WorldEdit)

-- Returns the block type (and block meta) from a string. This can be something like "1", "1:0", "stone" and "stone:0".
-- If a string with a percentage sign is given it will take the second half of the string (With "40%1:0" it uses only "1:0")
function GetBlockTypeMeta(a_BlockString)
    g_DefaultMetas = {
    [E_BLOCK_CHEST]              = 2,
    [E_BLOCK_ENDER_CHEST]        = 2,
    [E_BLOCK_FURNACE]            = 2,
    [E_BLOCK_LADDER]             = 2,
    [E_BLOCK_LIT_FURNACE]        = 2,
    [E_BLOCK_NETHER_PORTAL]      = 1,
    [E_BLOCK_TORCH]              = 1,
    [E_BLOCK_TRAPPED_CHEST]      = 2,
    [E_BLOCK_REDSTONE_TORCH_ON]  = 1,
    [E_BLOCK_REDSTONE_TORCH_OFF] = 1,
    [E_BLOCK_WALLSIGN]           = 2,
    [E_BLOCK_WALL_BANNER]        = 2
}

    if (a_BlockString:find("%%")) then
        local ItemInfo = StringSplit(a_BlockString, "%")
        if (#ItemInfo ~= 2) then
            return false
        end

        a_BlockString = ItemInfo[2]
    end

    local BlockID = tonumber(a_BlockString)

    -- Check if it was a normal number
    if (BlockID) then
        return BlockID, g_DefaultMetas[BlockID] or 0, true
    end

    -- Check for block meta
    local HasMeta = string.find(a_BlockString, ":")

    -- Check if it was a name.
    local Item = cItem()
    if (not StringToItem(a_BlockString, Item)) then
        return false
    else
        if (HasMeta or (Item.m_ItemDamage ~= 0)) then
            return Item.m_ItemType, Item.m_ItemDamage
        else
            return Item.m_ItemType, g_DefaultMetas[Item.m_ItemType] or 0, true
        end
    end
end


function setblock(Split, Player)
    if (#Split ~= 5) then
        -- There was more or less than four arguments (excluding the "/" bit)
        -- Send the proper usage to the player and exit
        Player:SendMessage("Usage: /setblock X Y Z [blocktype]")
        return true
    end

    outVector3 = Vector3i(tonumber(Split[2]), tonumber(Split[3]), tonumber(Split[4]))
    Player:SendMessage("Setting block " .. Split[2] .. " "  .. Split[3] .. " " .. Split[4] .. " to type " .. Split[5])
    local type, meta = GetBlockTypeMeta(Split[5])
    Player:GetWorld():SetBlock(outVector3, type, meta)

    return true
end

function fill(Split, Player)
    if (#Split ~= 8) then
        -- There was more or less than seven arguments (excluding the "/" bit)
        -- Send the proper usage to the player and exit
        Player:SendMessage("Usage: /fill X1 Y1 Z1 X2 Y2 Z2 [blocktype]")
        return true
    end
    offsetx = tonumber("0")
    x1 = tonumber(Split[2])
    y1 = tonumber(Split[3])
    z1 = tonumber(Split[4])
    x2 = tonumber(Split[5])
    y2 = tonumber(Split[6])
    z2 = tonumber(Split[7])
    countx = tonumber("0")
    county = tonumber("0")
    countz = tonumber("0")
    posx = tonumber("0")
    posy = tonumber("0")
    posz = tonumber("0")

-- Calculate the numbers for the couter:

    offsetx = offsetx(x1, x2, offsetx)
    countx = tonumber(offsetx(x1, x2, offsetx).replace("-", ""))
    countx

-- Doesnt work because of broken if statement???   

    for i=10,0,-1
    do
--      Placeholder. Will put filling function in here later
        Player:SendMessage("offsetX=" .. offsetx)
    end
   
   
--    for i=countx+county+countz,0,-1
--    do
   
--    end

--    setblockforplugins(Player, posx, posy, posz, Split[8])


    outVector3 = Vector3i(tonumber(Split[2]), tonumber(Split[3]), tonumber(Split[4]))
    Player:SendMessage("Setting block " .. Split[2] .. " "  .. Split[3] .. " " .. Split[4] .. " to type " .. Split[5])
    local type, meta = GetBlockTypeMeta(Split[5])
    Player:GetWorld():SetBlock(outVector3, type, meta)

    return true
end


function setblockforplugins(Player, Split)
    outVector3 = Vector3i(tonumber(Split[2]), tonumber(Split[3]), tonumber(Split[4]))
    Player:SendMessage("Setting block " .. Split[2] .. " "  .. Split[3] .. " " .. Split[4] .. " to type " .. Split[5])
    local type, meta = GetBlockTypeMeta(Split[5])
    Player:GetWorld():SetBlock(outVector3, type, meta)
    return true
end

-- Will use this later to find the vertical offset and size:

function countY(y1, y2)
    if tonumber(y1) < tonumber(y2) then
    for i=y1,y2,-1
    do
       -- put function here
    end
    else
    for i=y1,y2,-1
    do
       -- put function here
    end           
    end
    return y1, y2
end

-- Make offset and size and find out which values are negative.

function offsetX(x1, x2, xoffset)
    if tonumber(x1) < 0 then
        if tonumber(x2) < 0 then
        if tonumber(x1) < tonumber(x2) then
        for i=x1,x2,1
        do
                    xoffset = xoffset - 1
        end
        else
        for i=x1,x2,-1
        do
                    xoffset = xoffset + 1
        end
        end
    else
        if tonumber(x1) < tonumber(x2) then
        for i=tonumber(x1.replace("-", "")),x2,1
        do
                    xoffset = xoffset + 1
        end
        else
        if tonumber(x1) < tonumber(x2) then
        for i=x1,tonumber(x2.replace("-", "")),1
        do
                    xoffset = xoffset + 1
        end
        end
        end
    end
    if tonumber(x1) > 0 then
        if tonumber(x2) < 0 then
        if tonumber(x1) < tonumber(x2) then
        for i=x1,tonumber(x2.replace("-", "")),1
        do
                    xoffset = xoffset + 1
        end
        else
        for i=tonumber(x1.replace("-", "")),x2,1
        do
                    xoffset = xoffset + 1
        end
        end
    else
        if tonumber(x1) < tonumber(x2) then
        for i=x2,x1,1
        do
                    xoffset = xoffset + 1
        end
        else
        for i=x1,x2,1
        do
                    xoffset = xoffset + 1
        end
        end
        end
    end
    return xoffset
end
Reply
Thanks given by:
#4
If there is a more elegant way to fill an area from a plugin, please tell me. Would make my life way easyer here.
Reply
Thanks given by:
#5
The reason why the for loop doesn't work is because the statement above it is incorrect. You just have 'countx' which isn't a valid statement. Once you remove that or comment it out the for loop should work.
Reply
Thanks given by:
#6
(02-19-2021, 07:32 PM)mueller_minki Wrote: If there is a more elegant way to fill an area from a plugin, please tell me. Would make my life way easyer here.

What is the fill command supposed to do? Is it just take two sets of coordinates and fill it with the specified block?
Reply
Thanks given by:
#7
(02-19-2021, 07:32 PM)NiLSPACE Wrote: The reason why the for loop doesn't work is because the statement above it  is incorrect. You just have 'countx' which isn't a valid statement. Once you remove that or comment it out the for loop should work.

Ok, changed my code:

Code:
PLUGIN = nil

function Initialize(Plugin)
    Plugin:SetName("VanillaFill")
    Plugin:SetVersion(1)

    -- Hooks

    PLUGIN = Plugin -- NOTE: only needed if you want OnDisable() to use GetName() or something like that

    -- Command Bindings
    cPluginManager.BindCommand("/setblock", "vanillafill.setblock", setblock, " ~ Changes a block at X Y Z.");
    cPluginManager.BindCommand("/fill", "vanillafill.fill", fill, " ~ Fills an area from X Y Z to X2 Y2 Z2.");

    LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
    return true
end

function OnDisable()
    LOG(PLUGIN:GetName() .. " is shutting down...")
end

-- This segment is a bit of stripped-down code from the WorldEdit Plugin (github.com/cuberite/WorldEdit)

-- Returns the block type (and block meta) from a string. This can be something like "1", "1:0", "stone" and "stone:0".
-- If a string with a percentage sign is given it will take the second half of the string (With "40%1:0" it uses only "1:0")
function GetBlockTypeMeta(a_BlockString)
    g_DefaultMetas = {
    [E_BLOCK_CHEST]              = 2,
    [E_BLOCK_ENDER_CHEST]        = 2,
    [E_BLOCK_FURNACE]            = 2,
    [E_BLOCK_LADDER]             = 2,
    [E_BLOCK_LIT_FURNACE]        = 2,
    [E_BLOCK_NETHER_PORTAL]      = 1,
    [E_BLOCK_TORCH]              = 1,
    [E_BLOCK_TRAPPED_CHEST]      = 2,
    [E_BLOCK_REDSTONE_TORCH_ON]  = 1,
    [E_BLOCK_REDSTONE_TORCH_OFF] = 1,
    [E_BLOCK_WALLSIGN]           = 2,
    [E_BLOCK_WALL_BANNER]        = 2
}

    if (a_BlockString:find("%%")) then
        local ItemInfo = StringSplit(a_BlockString, "%")
        if (#ItemInfo ~= 2) then
            return false
        end

        a_BlockString = ItemInfo[2]
    end

    local BlockID = tonumber(a_BlockString)

    -- Check if it was a normal number
    if (BlockID) then
        return BlockID, g_DefaultMetas[BlockID] or 0, true
    end

    -- Check for block meta
    local HasMeta = string.find(a_BlockString, ":")

    -- Check if it was a name.
    local Item = cItem()
    if (not StringToItem(a_BlockString, Item)) then
        return false
    else
        if (HasMeta or (Item.m_ItemDamage ~= 0)) then
            return Item.m_ItemType, Item.m_ItemDamage
        else
            return Item.m_ItemType, g_DefaultMetas[Item.m_ItemType] or 0, true
        end
    end
end


function setblock(Split, Player)
    if (#Split ~= 5) then
        -- There was more or less than four arguments (excluding the "/" bit)
        -- Send the proper usage to the player and exit
        Player:SendMessage("Usage: /setblock X Y Z [blocktype]")
        return true
    end

    outVector3 = Vector3i(tonumber(Split[2]), tonumber(Split[3]), tonumber(Split[4]))
    Player:SendMessage("Setting block " .. Split[2] .. " "  .. Split[3] .. " " .. Split[4] .. " to type " .. Split[5])
    local type, meta = GetBlockTypeMeta(Split[5])
    Player:GetWorld():SetBlock(outVector3, type, meta)

    return true
end

function fill(Split, Player)
    if (#Split ~= 8) then
        -- There was more or less than seven arguments (excluding the "/" bit)
        -- Send the proper usage to the player and exit
        Player:SendMessage("Usage: /fill X1 Y1 Z1 X2 Y2 Z2 [blocktype]")
        return true
    end
    offsetx = tonumber("0")
    x1 = tonumber(Split[2])
    y1 = tonumber(Split[3])
    z1 = tonumber(Split[4])
    x2 = tonumber(Split[5])
    y2 = tonumber(Split[6])
    z2 = tonumber(Split[7])
    countx = tonumber("0")
    county = tonumber("0")
    countz = tonumber("0")
    posx = tonumber("0")
    posy = tonumber("0")
    posz = tonumber("0")

-- Calculate the numbers for the couter:

    offsetx = offsetx(x1, x2, offsetx)
    countx = tonumber(offsetx(x1, x2, offsetx).replace("-", ""))

-- Doesnt work because of broken if statement???   

    for i=10,0,-1
    do
--      Placeholder. Will put filling function in here later
        Player:SendMessage("offsetX=" .. offsetx)
    end
   
   
--    for i=countx+county+countz,0,-1
--    do
   
--    end

--    setblockforplugins(Player, posx, posy, posz, Split[8])


    outVector3 = Vector3i(tonumber(Split[2]), tonumber(Split[3]), tonumber(Split[4]))
    Player:SendMessage("Setting block " .. Split[2] .. " "  .. Split[3] .. " " .. Split[4] .. " to type " .. Split[5])
    local type, meta = GetBlockTypeMeta(Split[5])
    Player:GetWorld():SetBlock(outVector3, type, meta)

    return true
end


function setblockforplugins(Player, Split)
    outVector3 = Vector3i(tonumber(Split[2]), tonumber(Split[3]), tonumber(Split[4]))
    Player:SendMessage("Setting block " .. Split[2] .. " "  .. Split[3] .. " " .. Split[4] .. " to type " .. Split[5])
    local type, meta = GetBlockTypeMeta(Split[5])
    Player:GetWorld():SetBlock(outVector3, type, meta)
    return true
end

-- Will use this later to find the vertical offset and size:

function countY(y1, y2)
    if tonumber(y1) < tonumber(y2) then
    for i=y1,y2,-1
    do
       -- put function here
    end
    else
    for i=y1,y2,-1
    do
       -- put function here
    end           
    end
    return y1, y2
end

-- Make offset and size and find out which values are negative.

function offsetX(x1, x2, xoffset)
    if tonumber(x1) < 0 then
        if tonumber(x2) < 0 then
        if tonumber(x1) < tonumber(x2) then
        for i=x1,x2,1
        do
                    xoffset = xoffset - 1
        end
        else
        for i=x1,x2,-1
        do
                    xoffset = xoffset + 1
        end
        end
    else
        if tonumber(x1) < tonumber(x2) then
        for i=tonumber(x1.replace("-", "")),x2,1
        do
                    xoffset = xoffset + 1
        end
        else
        if tonumber(x1) < tonumber(x2) then
        for i=x1,tonumber(x2.replace("-", "")),1
        do
                    xoffset = xoffset + 1
        end
        end
        end
    end
    if tonumber(x1) > 0 then
        if tonumber(x2) < 0 then
        if tonumber(x1) < tonumber(x2) then
        for i=x1,tonumber(x2.replace("-", "")),1
        do
                    xoffset = xoffset + 1
        end
        else
        for i=tonumber(x1.replace("-", "")),x2,1
        do
                    xoffset = xoffset + 1
        end
        end
    else
        if tonumber(x1) < tonumber(x2) then
        for i=x2,x1,1
        do
                    xoffset = xoffset + 1
        end
        else
        for i=x1,x2,1
        do
                    xoffset = xoffset + 1
        end
        end
        end
    end
    return xoffset
end
end

Now it at least loads. But I get this error now:
[10:41:40] LUA: Plugins/VanillaFill/main.lua:115: attempt to call global 'offsetx' (a number value)
[10:41:40] Stack trace:
[10:41:40]  Plugins/VanillaFill/main.lua(115): (no name)
[10:41:40] Stack trace end
[10:41:40] Error in <attached> calling function <callback>()
Reply
Thanks given by:
#8
That's because you're trying to use the variable 'offsetx' as a function. You probably want to use your 'offsetX' function with a capital X.
Reply
Thanks given by:
#9
(02-19-2021, 07:45 PM)NiLSPACE Wrote: That's because you're trying to use the variable 'offsetx' as a function. You probably want to use your 'offsetX' function with a capital X.

You were right. It was a simple typo. Thank you so much.
Reply
Thanks given by:




Users browsing this thread: 1 Guest(s)