Lua value not changing? - lua

I use very simple Lua scripting in an online game called ROBLOX. My problem is that values in my scripts aren't changing! Example:
num = 0
while true do
num = num + 1
print(num)
wait(1)
end
That should count up starting on 0, but the number won't change. Could this be from the ROBLOX website? I can't figure out what else it might be.

What happens with
local num = 0
while true do
num = num + 1
print(num)
wait(1)
end
?
Maybe some other part of the system is changing the global num.

I just put your code in the Lua demo and it works fine if you remove the wait() function call. I'm assuming you defined this function somewhere?

There is nothing wrong with the code. You must be running it wrong. Also, wait is a function defined in the Roblox API. It is legit.

There is no error in your code. If you are using ROBLOX, then I'm not sure how you're running it wrong as it is a fairly simple interface. I'll try it in ROBLOX and see if it errors for me.
To the people who were wondering about wait(): it's a ROBLOX-specific global function, that pauses the current task the amount of seconds in the parentheses.

Try this:
local num = 0
while true do
num = num + 1
print(num)
print(type(num))
wait(1)
end

Related

attempt to yield across metamethod/C-call boundary AND cannot resume non-suspended coroutine in ROBLOX STUDIO when using wait (00.1)

This is my code
-- Script by supermarioclub231 as known as marioroblox102, and special thanks to jacko for some scripts things
-- idk
-- Player
local plr = game.Players:CreateLocalPlayer(0)
game:GetService("Visit")
game:GetService("RunService"):run()
plr:LoadCharacter()
-- have to do this so that the same numbers arent generated every time
math.random(); math.random(); math.random()
digits = 4 -- the amount of times to add digits to the end of the player name
prefix = "NoName "
suffix = "" -- wouldnt wanna type anything here, the digits will be added here!
for i=1, digits do
suffix = suffix .. math.random(1,9)
i = i + 1;
end
plr.Name = prefix .. suffix
-- shopium brings to you...
shirt = Instance.new("Shirt", plr)
pants = Instance.new("Pants", plr)
shirt.ShirtTemplate = "rbxasset://shirts/jared.png"
pants.PantsTemplate = "rbxasset://pants/jeans.png"
while true do
wait (0.001)
if plr.Character.Humanoid.Health <= 0 then
wait(5)
plr:LoadCharacter(true)
elseif plr.Character.Parent == nil then
wait(5)
plr:LoadCharacter(true)
end
end
everytime i run it, i get this
the line 39 is wait(000.1),
why its not working?
its supossed to do something forever
like a loop
but it gives me a error
First of all you don't have to you use math.random() three times at the start so it doesn't generate the same script everytime as thats not how it works it will generate a random number between the range you specify every time and the number may be the same every once in a while but thats why its called math.random() but I'm also working on fixing the rest of you script just wanted to tell you that. Also just use the ROBLOX Health Changed Event and the link to the wiki of that event is here.

CFrame Bullet Will Not Fire

Recently, I have been experimenting in the Roblox version of Lua in the studio. I tried to hook up a moving projectile to a GUI button. Here is the code:
local cannonp1 = workspace.CannonP1
local loopingvar = 0
script.Parent.MouseButton1Click:Connect(fire)
function fire()
repeat until loopingvar == 100
workspace.ProjectileP1.CFrame = workspace.ProjectileP1.CFrame * CFrame.new(1, 0, 0)
loopingvar = loopingvar + 1
wait(0.1)
end
end
I am very new to Roblox Studio, so all I can say is that When I press the button, not a single thing happens to my projectile. And the projectile is anchored, if you were wondering. I know that good questions should be elaborate, but there is no other information that i can find that would effect the movement of the projectile other than my extremely poor scripting. I have also checked on the Roblox developer forums, but most of the posts about CFrame there are outdated and do not work in the new version of Roblox Studio. I have checked about every website possible, but to no avail. Any advice would be amazing.
You're not using repeat until correctly. The first line is supposed to be repeat and the last line is supposed to be until loopingvar == 100. There's not supposed to be an end at all. Currently, there's a syntax error in your code due to the extra end, and even without that, you'd have an infinite loop, since it's basically repeat --[[do nothing]] until loopingvar == 100.
However, you can do even one step better than this, by using a numeric for loop. Instead of the above changes, get rid of local loopingvar = 0 and loopingvar = loopingvar + 1, and replace repeat until loopingvar == 100 with for loopingvar = 0,100 do.

Simulate parallelism in Lua

I am trying to use lua to prototype some parallel algorithm. With this I mean to write code in pure Lua, perform tests on it, debug it, etc. Then, when I am confident that it works, I can translate it to a true multithread library, or even to another language (e.g. OpenCL kenel). Obviously I am not concerned in any way with the performance of the prototype code.
I thought to use a coroutine that yield at each line, with some boilerplate to randomly select the next "Thread" to run. For example:
local function parallel_simulation(...)
local function_list = {...}
local coroutine_list = {}
local thread_number = #function_list
for i = 1, thread_number do
coroutine_list[i] = coroutine.create(function_list[i])
end
while 0 < thread_number do
local current = math.random(1, thread_number)
local worker = coroutine_list[current]
coroutine.resume(worker)
if 'dead' == coroutine.status(worker) then
thread_number = thread_number - 1
table.remove(coroutine_list, current)
end
end
end
----------------------------------------------------------
-- Usage example
local Y = coroutine.yield
local max = 3
local counter = 0
local retry = 99
local function increment()
Y() local c = counter
Y() while max > c do
Y() c = counter
Y() c = c + 1
Y() counter = c
Y() end
end
for i=1,retry do
counter = 0
parallel_simulation(increment, increment)
if max ~= counter then
print('Test SUCCESS ! A non-thread-safe algorithm was identified .', i, counter)
return
end
end
error('Test FAIL ! The non-thread-safe algorithm was not identified .')
This is just an idea, any solution involving pure Lua is welcome! What makes me very uncomfortable with this solution, are all that Y(). Is there any way to avoid them? (debug.sethook does not allow to yield...)
EDIT 1 - More meaningful example was provided
EDIT 2 - Hopefully, I clearified what I am trying to accomplish
A simple alternative to putting Y() in front of each line is to use gsub and load:
Y = coroutine.yield
max = 3
counter = 0
code = [[
function increment()
local c = counter
while max > c do
c = counter
c = c + 1
counter = c
end
end]]
code = code:gsub("\n ", "\n Y() ") -- replace two spaces in find/replace with whatever tab character(s) you use
assert(load(code))()
local retry = 99
-- rest of code here
(Use load or loadstring depending on your Lua version)
Note that the variable declarations Y/max/counter must be global or else the loaded function will not have access to them. Similarly, the function in code must be global or else increment will not exist outside the loaded code.
Such a solution assumes that all instructions on each line are atomic/thread-safe, of course.
An improvement I would recommend making to parallel_simulation is to add some way of changing how the next thread is chosen. ex, perhaps the error will only be revealed if one of the threads is early on in execution and another one is almost done - though this state could theoretically be reached through sufficient random trials, having an argument that allows you to adjust which threads are more likely to be chosen next (ex using weights) should make it much more likely.

A unique environment per script in Lua 5.3

I would like to be able to have a chunk of Lua code (a "script") that could be shared among enemy types in a game but where each instance of a script gets a unique execution environment. To illustrate my problem, this is my first attempt at what a script might look like:
time_since_last_shoot = 0
tick = function(entity_id, dt)
time_since_last_shoot = time_since_last_shoot + dt
if time_since_last_shoot > 10 then
enemy = find_closest_enemy(entity_id)
shoot(entity_id, enemy)
time_since_last_shoot = 0
end
end
But that fails since I'd be sharing the global time_since_last_shoot variable among all my enemies. So then I tried this:
spawn = function(entity)
entity.time_since_last_shoot = 0;
end
tick = function(entity, dt)
entity.time_since_last_shoot = entity.time_since_last_shoot + dt
if entity.time_since_last_shoot > 10 then
enemy = find_closest_enemy(entity)
shoot(entity, enemy)
entity.time_since_last_shoot = 0
end
end
And then for each entity I create a unique table and then pass that as the first argument when I call the spawn and tick functions. And then somehow map that table back to an id at runtime. Which could work, but I have a couple concerns.
First, it's error prone. A script could still accidentally create global state that could lead to difficult to debug problems later in the same script or even others.
And second, since the update and tick functions are themselves global, I'll still run into issues when I go to create a second type of enemy which tries to use the same interface. I suppose I could solve that with some kind of naming convention but surely there's a better way to handle that.
I did find this question which seems to be asking the same thing, but the accepted answer is light on specifics and refers to a lua_setfenv function that isn't present in Lua 5.3. It seems that it was replaced by _ENV, unfortunately I'm not familiar enough with Lua to fully understand and/or translate the concept.
[edit] A third attempt based on the suggestion of #hugomg:
-- baddie.lua
baddie.spawn = function(self)
self.time_since_last_shoot = 0
end
baddie.tick = function(self, dt)
entity.time_since_last_shoot = entity.time_since_last_shoot + dt
if entity.time_since_last_shoot > 10 then
enemy = find_closest_enemy(entity)
shoot(entity, enemy)
entity.time_since_last_shoot = 0
end
end
And in C++ (using sol2):
// In game startup
sol::state lua;
sol::table global_entities = lua.create_named_table("global_entities");
// For each type of entity
sol::table baddie_prototype = lua.create_named_table("baddie_prototype");
lua.script_file("baddie.lua")
std::function<void(table, float)> tick = baddie_prototype.get<sol::function>("tick");
// When spawning a new instance of the enemy type
sol::table baddie_instance = all_entities.create("baddie_instance");
baddie_instance["entity_handle"] = new_unique_handle();
// During update
tick(baddie_instance, 0.1f);`
This works how I expected and I like the interface but I'm not sure if it follows the path of least surprise for someone who might be more familiar with Lua than I. Namely, my use of the implicit self parameter and my distinction between prototype/instance. Do I have the right idea or have I done something weird?
For your first issue (accidentally creating globals), you can rely on a linter like luacheck or a module that prevents you from creating globals like strict.lua from Penlight.
And then, why not just make things local? I mean both time_since_last_shoot and tick. This leverages closures, one of the most useful features of Lua. If you want different tick functions, each with its own variables, you can do something like this:
local function new_tick()
local time_since_last_shoot = 0
return function(entity_id, dt)
time_since_last_shoot = time_since_last_shoot + dt
if time_since_last_shoot > 10 then
local enemy = find_closest_enemy(entity_id)
shoot(entity_id, enemy)
time_since_last_shoot = 0
end
end
end
local tick_1 = new_tick()
local tick_2 = new_tick()
Of course, you could also use the environment for this, but here I think local variables and closure are a better solution to the problem.
The way _ENV works in 5.3 is that global variable are "syntactic" sugar for reading fields from the _ENV variable. For example, a program that does
local x = 10
y = 20
print(x + y)
is equivalent to
local x = 10
_ENV.y = 20
_ENV.print(x + _ENV.y)
By default, _ENV is a "global table" that works like you would expect global variables to behave. However, if you create a local variable (or function argument) named _ENV then in that variable's scope any unbound variables will point to this new environment instead of point to the usual global scope. For example, the following program prints 10:
local _ENV = {
x = 10,
print=print
}
-- the following line is equivalent to
-- _ENV.print(_ENV.x)
print(x)
In your program, one way to use this technique would be to add an extra parameter to your functions for the environment:
tick = function(_ENV, entity, dt)
-- ...
end
then, any global variables inside the function will actually just be accessing fields in the _ENV parameter instead of actually being global.
That said, I'm not sure _ENV is the best tool to solve your problem. For your first problem, of accidentally creating globals, a simpler solution would be to use a linter to warn you if you assign to an undeclared global variable. As for the second problem, you could just put the update and tick functions in a table instead of having them be global.

Lua - Couple Questions

Im a amatuer at coding. So, mind me if i face palmed some things.
Anyways, im making a alpha phase for a OS im making right? I'm making my installer. Two questions. Can i get a code off of pastebin then have my lua script download it? Two. I put the "print" part of the code in cmd. I get "Illegal characters". I dont know what went wrong. Here's my code.
--Variables
Yes = True
No = False
--Loading Screen
print ("1")
sleep(0.5)
print("2")
sleep(0.5)
print("Dowloading OS")
sleep(2)
print("Done!")
sleep(0.2)
print("Would you like to open the OS?")
end
I see a few issues with your code.
First of all, True and False are both meaningless names - which, unless you have assigned something to them earlier, are both equal to nil. Therefore, your Yes and No variables are both set to nil as well. This isn't because true and false don't exist in lua - they're just in lowercase: true and false. Creating Yes and No variables is redundant and hard to read - just use true and false directly.
Second of all, if you're using standard lua downloaded from their website, sleep is not a valid function (although it is in the Roblox version of Lua, or so I've heard). Like uppercase True and False, sleep is nil by default, so calling it won't work. Depending on what you're running this on, you'll want to use either os.execute("sleep " .. number_of_seconds) if you're on a mac, or os.execute("timeout /t " .. number_of_seconds) if you're on a PC. You might want to wrap these up into a function
function my_sleep_mac(number_of_seconds)
os.execute("sleep " .. number_of_seconds)
end
function my_sleep_PC(number_of_seconds)
os.execute("timeout /t " .. number_of_seconds)
end
As for the specific error you're experiencing, I think it's due to your end statement as the end of your program. end in lua doesn't do exactly what you think it does - it doesn't specify the end of the program. Lua can figure out where the program ends just by looking to see if there's any text left in the file. What it can't figure out without you saying it is where various sub-blocks of code end, IE the branches of if statements, functions, etc. For example, suppose you write the code
print("checking x...")
if x == 2 then
print("x is 2")
print("Isn't it awesome that x is 2?")
print("x was checked")
lua has no way of knowing whether or not that last statement, printing the x was checked, is supposed to only happen if x is 2 or always. Consequently, you need to explicitly say when various sections of code end, for which you use end. For a file, though, it's unnecessary and actually causes an error. Here's the if statement with an end introduced
print("checking x...")
if x == 2 then
print("x is 2")
print("isn't it awesome that x is 2?")
end
print("x was checked")
although lua doesn't care, it's a very good idea to indent these sections of code so that you can tell at a glance where it starts and ends:
print("checking x...")
if x == 2 then
print("x is 2")
print("isn't it awesome that x is 2?")
end
print("x was checked")
with regards to your "pastebin" problem, you're going to have to be more specific.
You can implement sleep in OS-independent (but CPU-intensive) way:
local function sleep(seconds)
local t0 = os.clock()
repeat
until os.clock() - t0 >= seconds
end

Resources