I'm trying to write a lua script to assist in modifying a game, and it keeps breaking on one particular line of one of my assistant libraries.
odfWriter.lua:
require 'loopsetup'
require 'ioWriter'
local open = {}
odfWriter = class{
writer = false
}
odfWriter[open] = false
function odfWriter:open(name)
if not self[open] then
self.writer = ioWriter()
self.writer:open(name)
self[open] = true
else
error("tried to open an already open writer")
end
end
function odfWriter:write(args)
self.writer:write(args.Key .. " = ") --<-- error is here, when trying to access args
if args.Type == "seqstrings" then
for k,v in pairs(args.Value) do
self.writer:write("\"" .. v .. "\" ")
end
elseif args.Type == "string" then
self.writer:write("\"" .. args.Value .. "\"")
elseif args.Type == "seqnumbers" then
for k,v in pairs(args.Value) do
self.writer:write(tostring(v) .. " ")
end
elseif args.Type == "number" then
self.writer:write(tostring(args.Value))
elseif args.Type == "boolean" then
if args.Value == true then
self.writer:write("1")
elseif args.Value == false then
self.writer:write("0")
end
end
self.writer:write("\n")
end
function odfWriter:close()
if self[open] then
self.writer:close()
self.writer = false
self[open] = false
else
error("tried to close an already closed writer")
end
end
loopSetup.lua
-----------------------------------------------------------------------
-- file : loopsetup.lua
-- description : provides global access to all of the (known) members
-- of the loop.simple code (for easier access)
-----------------------------------------------------------------------
require 'loop.simple'
class = loop.simple.class
classof = loop.simple.classof
initclass = loop.simple.initclass
instanceof = loop.simple.instanceof
isclass = loop.simple.isclass
memberof = loop.simple.memberof
members = loop.simple.members
new = loop.simple.new
rawnew = loop.simple.rawnew
subclassof = loop.simple.subclassof
superclass = loop.simple.superclass
ioWriter.lua:
local loaded = require('loopsetup')
assert(loaded, 'loopsetup not loaded')
local open = {}
ioWriter = class{
stream = false
}
ioWriter[open] = false
function ioWriter:open(name)
if not self[open] then
self.stream = io.open(name, "w")
self[open] = true
else
error("attempted to open an already open writer")
end
end
function ioWriter:write(str)
self.stream:write(str)
end
function ioWriter:writeLine(str)
self.stream:write(str .. '\n')
end
function ioWriter:close(self)
if self[open] then
self.stream:flush()
self.stream:close()
self.stream = false
self[open] = false
else
error("attempted to close an already closed writer")
end
end
test code:
require 'loopsetup'
require 'odfWriter'
local odf = odfWriter()
odf:open('test.odf')
local line1Data = {
Type = "seqstrings",
Key = "engineTargetHardpoints",
Value = {"hp01", "hp02", "hp03"}
}
odf:write(line1data)
odf:close()
Why do i have this error when i am clearly passing in a valid table to odfwriter.write?
At least in your test code, you have a typo:
line1data ~= line1Data
You also have a typo in ioWriter.lua in the close method:
function ioWriter:close(self)
should be
function ioWriter:close()
You haven't explicitly checked that everything implementing odf:open() succeeded. My concern is that it looks like the whole flow control in of odf:open() seems to assume that everything succeeded. Is it possible that it didn't, and as a result that at the line indicated the error is caused by attempting to index self.writer containing nil?
It could be nil as opposed to false if odfWriter:open() didn't successfully execute the constructor self.writer = ioWriter() for example. I'm not a regular user of loop, so I might be barking up the wrong tree, but...
If that were happening, it would be easy to get a message that is confused about which index was at fault.
Perhaps dropping calls to assert() in a few choice spots would be productive.
Related
I tried to fix some Garry's Mod addon and this is what happens. I tried to fix it for long time, but I'm not the best in Lua coding :/ . What is wrong with this code? I get this error:
[ERROR] addons/garrys_bombs_5_base_528449144/lua/entities/gb5_shockwave_sound_lowsh.lua:80: bad argument #1 to 'SetPhysicsAttacker' (Entity expected, got nil)
1. SetPhysicsAttacker - [C]:-1
2. unknown - addons/garrys_bombs_5_base_528449144/lua/entities/gb5_shockwave_sound_lowsh.lua:80
And the code is pretty long. I have every file working fine, but this file is not working
AddCSLuaFile()
DEFINE_BASECLASS( "base_anim" )
if (SERVER) then
util.AddNetworkString( "gb5_net_sound_lowsh" )
end
ENT.Spawnable = false
ENT.AdminSpawnable = false
ENT.PrintName = ""
ENT.Author = ""
ENT.Contact = ""
ENT.GBOWNER = nil
ENT.MAX_RANGE = 0
ENT.SHOCKWAVE_INCREMENT = 0
ENT.DELAY = 0
ENT.SOUND = ""
net.Receive( "gb5_net_sound_lowsh", function( len, pl )
local sound = net.ReadString()
LocalPlayer():EmitSound(sound)
end );
function ENT:Initialize()
if (SERVER) then
self.FILTER = {}
self:SetModel("models/props_junk/watermelon01_chunk02c.mdl")
self:SetSolid( SOLID_NONE )
self:SetMoveType( MOVETYPE_NONE )
self:SetUseType( ONOFF_USE )
self.Bursts = 0
self.CURRENTRANGE = 0
self.GBOWNER = self:GetVar("GBOWNER")
self.SOUND = self:GetVar("SOUND")
end
end
function ENT:Think()
if (SERVER) then
if not self:IsValid() then return end
local pos = self:GetPos()
self.CURRENTRANGE = self.CURRENTRANGE+(self.SHOCKWAVE_INCREMENT*10)
if(GetConVar("gb5_realistic_sound"):GetInt() >= 1) then
for k, v in pairs(ents.FindInSphere(pos,self.CURRENTRANGE)) do
if v:IsPlayer() then
if not (table.HasValue(self.FILTER,v)) then
net.Start("gb5_net_sound_lowsh")
net.WriteString(self.SOUND)
net.Send(v)
v:SetNWString("sound", self.SOUND)
if self:GetVar("Shocktime") == nil then
self.shocktime = 1
else
self.shocktime = self:GetVar("Shocktime")
end
if GetConVar("gb5_sound_shake"):GetInt()== 1 then
util.ScreenShake( v:GetPos(), 5555, 555, self.shocktime, 500 )
end
table.insert(self.FILTER, v)
end
end
end
else
if self:GetVar("Shocktime") == nil then
self.shocktime = 1
else
self.shocktime = self:GetVar("Shocktime")
end
local ent = ents.Create("gb5_shockwave_sound_instant")
ent:SetPos( pos )
ent:Spawn()
ent:Activate()
ent:SetPhysicsAttacker(ply)
ent:SetVar("GBOWNER", self.GBOWNER)
ent:SetVar("MAX_RANGE",50000)
ent:SetVar("DELAY",0.01)
ent:SetVar("Shocktime",self.shocktime)
ent:SetVar("SOUND", self:GetVar("SOUND"))
self:Remove()
end
self.Bursts = self.Bursts + 1
if (self.CURRENTRANGE >= self.MAX_RANGE) then
self:Remove()
end
self:NextThink(CurTime() + (self.DELAY*10))
return true
end
end
function ENT:OnRemove()
if SERVER then
if self.FILTER==nil then return end
for k, v in pairs(self.FILTER) do
if not v:IsValid() then return end
v:SetNWBool("waiting", true)
end
end
end
function ENT:Draw()
return false
end
Is there a chance someone fix this for me? Or even just telling me what's wrong? I would be pleased. If needed I can send all files. Well... It's not my addon but I'm trying to fix an existing one. Someone tried to fix it too but he didn't (actually he broke it even more).
What the error means
Inside your ENT:Think() function, you are calling ent:SetPhysicsAttacker(ply)
ply is not defined anywhere inside that function, so is nil (Entity expected, got nil)
How to fix this
If no player is responsible for the damage caused by this entity, delete the line ent:SetPhysicsAttacker(ply).
Otherwise, assign an Owner to the entity at the point of creation, using SetOwner.
This would then allow you to use self:GetOwner() inside your Think hook
Example
hook.Add("PlayerSay", "SpawnEntity", function(ply, text)
if string.lower(text) == "!spawnentity" then
-- Create your entity
local myEntity = ents.Create("gb5_shockwave_sound_lowsh")
myEntity:SetPos(ply:GetPos())
myEntity:SetAngles(ply:GetAngles())
myEntity:Spawn()
-- Sets the owner to the player that typed the command
myEntity:SetOwner(ply)
return ""
end
end)
-- Inside your entity code
function ENT:Think()
print("My owner is: " .. tostring(self:GetOwner()))
-- ...
ent:SetPhysicsAttacker(self:GetOwner())
end
I am having this error, can't find the error.
local choice_revive = {function(player,choice)
local user_id = vRP.getUserId(player)
if user_id ~= nil then
vRPclient.getNearestPlayer(player,{10},function(nplayer)
local nuser_id = vRP.getUserId(nplayer)
if nuser_id ~= nil then
vRPclient.isInComa(nplayer,{}, function(in_coma)
if in_coma then
if vRP.tryGetInventoryItem(user_id,"medkit",1,true) else
vRP.tryGetInventoryItem(user_id,"smartwatch",1,true)
io.write("Smartwatch: Tilkalder Ambulance")
then
vRPclient.playAnim(player,{false,revive_seq,false}) -- anim
SetTimeout(15000, function()
vRPclient.varyHealth(nplayer,{50}) -- heal 50
end)
end
else
vRPclient.notify(player,{lang.emergency.menu.revive.not_in_coma()})
end
end)
else
vRPclient.notify(player,{lang.common.no_player_near()})
end
end)
end
end,lang.emergency.menu.revive.description()}
I have tried to make, and look for error, but without luck.
- If anyone can fix it, tell me please.
if statement, functions and for statement must be ended with end.
this code must be like that
--Settings--
local Tunnel = module("vrp", "lib/Tunnel")
local Proxy = module("vrp", "lib/Proxy")
vRP = Proxy.getInterface("vRP")
vRPclient = Tunnel.getInterface("vRP","vRP_smartwatch")
if in_coma then
vRP.tryGetInventoryItem(user_id,"smartwatch",1,true)
io.write("Smartwatch: Tilkalder Ambulance")
end
function vRP.sendServiceAlert(sender, emergency,x,y,z, msg)
local service = services[service_name]
local answered = false
if service then
local players = {}
for k,v in pairs(vRP.rusers) do
local player = vRP.getUserSource(tonumber(k))
-- check user
if vRP.hasPermission(k,service.alert_permission) and player ~= nil then
table.insert(players,player)
end
end
end
end
I have the following code snippet
function initializeWorld()
_G.require = function(name)
if package.loaded[name] == nil then
local result, err = external.MyAPIEndpoint:LUAInclude(name .. '.lua')
if err == nil then
if result ~= nil then
package.loaded[name] = result
else
package.loaded[name] = true
end
return package.loaded[name]
else
local errTxt = err .. "\r\n" .. debug.traceback()
error(errTxt, 1)
end
else
return package.loaded[name]
end
end
helloWorld = require ("helloWorld")
print(helloWorld.welcome())
end
function initializeUniverse()
_G.require = function(name)
if package.loaded[name] == nil then
local result, err = external.MyAPIEndpoint:LUAInclude(name .. '.lua')
if err == nil then
if result ~= nil then
package.loaded[name] = result
else
package.loaded[name] = true
end
return package.loaded[name]
else
local errTxt = err .. "\r\n" .. debug.traceback()
error(errTxt, 1)
end
else
return package.loaded[name]
end
end
helloUniverse = require ("helloUniverse")
print(helloUniverse.welcome())
end
As you can see that the global requires is used in two different places. once in initializeWorld and the other in initializeUniverse
Can I make ammendments to the code such that it is loaded only once ?
Thanks
You probably shouldn't overwrite the global require function. If you want to run third-party- or user-code you can just sandbox it, and otherwise you can simply use a different name like my_require() or load_awesome_stuff()
I will assume that you don't know which of the two functions initializeWorld() and initializeUniverse() is called first, though this solution works either way.
Simply define the function under some name, whichever you like most, but if possible avoiding the global require, at some point where you can be sure that it runs before either of those two initialize functions. Then you can just use it in both of them. If you want it to be called require, you could just define it locally in the fucntion body like local require = my_require; require "some_stuff"
I need to check if a member exists in a table that isn't at the next level, but along a path of members.
foo = {}
if foo.bar.joe then
print(foo.bar.joe)
end
this will cast an attempt to index field 'bar' (a nil value) because bar isn't defined.
My usual solution is to test the chain, piece-by-piece.
foo = {}
if foo.bar and foo.bar.joe then
print(foo.bar.joe)
end
but this can be very tedious when there are many nested tables. Are there a better way to do this test than piece-by-piece?
I don't understand what you try to mean by "along a path of members". From the example, I assume you are trying to find a value in a "subtable"?
local function search(master, target) --target is a string
for k,v in next, master do
if type(v)=="table" and v[target] then return true end
end
end
A simple example. If you use such a function, you can pass the foo table and the joe string to see if foo.*.joe exists. Hope this helps.
debug.setmetatable(nil, {__index = {}})
foo = {}
print(foo.bar.baz.quux)
print(({}).prd.krt.skrz.drn.zprv.zhlt.hrst.zrn) -- sorry ))
To search for an element that is at any level of a table, I would use a method such as this one:
function exists(tab, element)
local v
for _, v in pairs(tab) do
if v == element then
return true
elseif type(v) == "table" then
return exists(v, element)
end
end
return false
end
testTable = {{"Carrot", {"Mushroom", "Lettuce"}, "Mayonnaise"}, "Cinnamon"}
print(exists(testTable, "Mushroom")) -- true
print(exists(testTable, "Apple")) -- false
print(exists(testTable, "Cinnamon")) -- true
I think you're looking for something along these lines:
local function get(Obj, Field, ...)
if Obj == nil or Field == nil then
return Obj
else
return get(Obj[Field], ...)
end
end
local foo = {x = {y = 7}}
assert(get() == nil)
assert(get(foo) == foo)
assert(get(foo, "x") == foo.x)
assert(get(foo, "x", "y") == 7)
assert(get(foo, "x", "z") == nil)
assert(get(foo, "bar", "joe") == nil)
assert(get(foo, "x", "y") or 41 == 7)
assert(get(foo, "bar", "joe") or 41 == 41)
local Path = {foo, "x", "y"}
assert(get(table.unpack(Path)) == 7)
get simply traverses the given path until a nil is encountered. Seems to do the job. Feel free to think up a better name than "get" though.
As usual, exercise care when combining with or.
I'm impressed by Egor's clever answer, but in general I think we ought to not rely on such hacks.
See also
The 'Safe Table Navigation' patch for Lua 5.2 : http://lua-users.org/wiki/LuaPowerPatches
Lengthy discussion on this matter : http://lua-users.org/lists/lua-l/2010-08/threads.html#00519
Related technique : http://lua-users.org/wiki/AutomagicTables
I suspect something relevant has been implemented in MetaLua, but I can't find at the moment.
If I understood your problem correctly, here's one possibility:
function isField(s)
local t
for key in s:gmatch('[^.]+') do
if t == nil then
if _ENV[ key ] == nil then return false end
t = _ENV[ key ]
else
if t[ key ] == nil then return false end
t = t[ key ]
end
--print(key) --for DEBUGGING
end
return true
end
-- To test
t = {}
t.a = {}
t.a.b = {}
t.a.b.c = 'Found me'
if isField('t.a.b.c') then print(t.a.b.c) else print 'NOT FOUND' end
if isField('t.a.b.c.d') then print(t.a.b.c.d) else print 'NOT FOUND' end
UPDATE: As per cauterite's suggestion, here's a version that also works with locals but has to take two arguments :(
function isField(t,s)
if t == nil then return false end
local t = t
for key in s:gmatch('[^.]+') do
if t[ key ] == nil then return false end
t = t[ key ]
end
return true
end
-- To test
local
t = {}
t.a = {}
t.a.b = {}
t.a.b.c = 'Found me'
if isField(t,'a.b.c') then print(t.a.b.c) else print 'NOT FOUND' end
if isField(t,'a.b.c.d') then print(t.a.b.c.d) else print 'NOT FOUND' end
foo = {}
foo.boo = {}
foo.boo.jeo = {}
foo.boo.joe is foo['boo']['joe'] and so
i make next function
function exist(t)
local words = {}
local command
for i,v in string.gmatch(t, '%w+') do words[#words+1] = i end
command = string.format('a = %s', words[1])
loadstring(command)()
if a == nil then return false end
for count=2, #words do
a = a[words[count]]
if a == nil then return false end
end
a = nil
return true
end
foo = {}
foo.boo = {}
foo.boo.joe = {}
print(exist('foo.boo.joe.b.a'))
using loadstring to make temp variable. my lua ver is 5.1
remove loadstring at 5.2 5.3, instead using load
So I thought of having this for so long, I just don't know where to start. I am new to this language and I keep learning, but kind of hard for me. But I have built my very own custom character which took 2 weeks for me. Anyway, For my question. An example is if I have a button and I click it, a model will be clone and I can drag that model and put it anywhere nearby. What possible method I can use to achieve this?
First things first, I suggest for any future questions, you head over to https://scriptinghelpers.org/
now, on to your question, for cloning the model, you should use mouse.Target.Parent:Clone() or the GetTopParent(mouse.Target) function in my function library (which you can get here; http://www.roblox.com/item.aspx?id=244244638)
then deposit the model into workspace and MakeJoints()
the next step is to move the model, this can be tricky, but the simplest method is model:MoveTo(mouse.Hit.p) on mouse.Moved (but that's a little buggy)
Another method for movement would be to use the Handles class, but I'm not really familiar with it, so you'd have to figure that one out on your own.
To make the first method less buggy, I'd suggest something along the lines of
model:MoveTo(mouse.Hit.p.X, mouse.Target.Position.Y + (model:GetExtentsSize().Y / 2), mouse.Hit.p.Z)
but you'd have to set up the mouse to ignore the model, which I can't really help with.
A really good place to start is to search the free models in Studio Toolbox for a 'Dragger Tool' or 'Model Dragger Tool' and then use the script inside to get started creating your own. I have learned to create my own custom draggers by doing this and it is way easier than you may think at first. Once you find a good dragger tool to borrow code from, if you need to enhance it, you can find the dragger api in the Roblox Wiki to help you further customize it to your specific needs.
http://wiki.roblox.com/index.php?title=API:Class/Dragger
EDIT: So here's the first dragger script that showed when I searched. It will drag models and parts but you will have to edit it to meet your requirements using the dragger api. Create a Tool in player.BackPack then create a LocalScript inside the Tool then copy and paste the code below into the LocalScript, and that will get you started.
local Tool = script.Parent
enabled = true
local origTexture = Tool.TextureId
game:GetService("ContentProvider"):Preload("rbxasset://icons/freemove_sel.png")
local selectionBox
local currentSelection
local currentSelectionColors = {}
local selectionLasso
local inGui = false
local inPalette = false
local lockTime = 0
function canSelectObject(part)
return part and not (part.Locked) and (part.Position - script.Parent.Parent.Head.Position).Magnitude < 60
end
function findModel(part)
while part ~= nil do
if part.className == "Model" then
return part
end
part = part.Parent
end
return nil
end
function startDrag(mousePart, hitPoint, collection)
dragger = Instance.new("Dragger")
pcall(function() dragger:MouseDown(mousePart, hitPoint, collection) end)
end
function collectBaseParts(object, collection)
if object:IsA("BasePart") then
collection[#collection+1] = object
end
for index,child in pairs(object:GetChildren()) do
collectBaseParts(child, collection)
end
end
function onMouseDown(mouse)
mouse.Icon ="rbxasset://textures\\GrabRotateCursor.png"
local part = mouse.Target
if canSelectObject(part) then
local hitPoint = mouse.Hit:toObjectSpace(part.CFrame).p
if trySelection(part) then
local instances = {}
collectBaseParts(currentSelection, instances)
startDrag(part, hitPoint, instances)
return
end
end
--Clear the selection if we weren't able to lock succesfullu
onMouseUp(mouse)
end
function onMouseUp(mouse)
mouse.Icon ="rbxasset://textures\\GrabCursor.png"
if dragger ~= nil then
pcall(function() dragger:MouseUp() end)
dragger = nil
end
end
function trySelection(part)
if canSelectObject(part) then
selectionLasso.Part = part
local model = findModel(part)
if model then
return setSelection(model)
else
return setSelection(part)
end
else
clearSelection()
return false
end
end
function onKeyDown(key)
if dragger ~= nil then
if key == 'R' or key == 'r' then
dragger:AxisRotate(Enum.Axis.Y)
elseif key == 'T' or key == 't' then
dragger:AxisRotate(Enum.Axis.Z)
end
end
end
local alreadyMoving
function onMouseMove(mouse)
if alreadyMoving then
return
end
alreadyMoving = true
if dragger ~= nil then
--Maintain the lock
if time() - lockTime > 3 then
Instance.Lock(currentSelection)
lockTime = time()
end
--Then drag
pcall(function() dragger:MouseMove(mouse.UnitRay) end)
else
trySelection(mouse.Target)
end
alreadyMoving = false
end
function saveSelectionColor(instance)
if instance:IsA("BasePart") then
currentSelectionColors[instance] = instance.BrickColor
if instance.BrickColor == BrickColor.Blue() then
instance.BrickColor = BrickColor.new("Deep blue")
else
instance.BrickColor = BrickColor.Blue()
end
end
local children = instance:GetChildren()
if children then
for pos, child in pairs(children) do
saveSelectionColor(child)
end
end
end
function setSelection(partOrModel)
if partOrModel ~= currentSelection then
clearSelection()
if Instance.Lock(partOrModel) then
lockTime = time()
currentSelection = partOrModel
saveSelectionColor(currentSelection)
selectionBox.Adornee = currentSelection
return true
end
else
if currentSelection ~= nil then
if time() - lockTime > 2 then
--Maintain the lock
if not(Instance.Lock(currentSelection)) then
--we lost the lock
clearSelection()
return false
else
lockTime = time()
return true
end
else
return true
end
end
end
return false
end
function clearSelection()
if currentSelection ~= nil then
for part, color in pairs(currentSelectionColors) do
part.BrickColor = color
end
selectionBox.Adornee = nil
Instance.Unlock(currentSelection)
end
currentSelectionColors = {}
currentSelection = nil
selectionLasso.Part = nil
selectionBox.Adornee = nil
end
function onEquippedLocal(mouse)
Tool.TextureId = "rbxasset://icons/freemove_sel.png"
local character = script.Parent.Parent
local player = game.Players:GetPlayerFromCharacter(character)
inGui = false
inPalette = false
mouse.Icon ="rbxasset://textures\\GrabCursor.png"
mouse.Button1Down:connect(function() onMouseDown(mouse) end)
mouse.Button1Up:connect(function() onMouseUp(mouse) end)
mouse.Move:connect(function() onMouseMove(mouse) end)
mouse.KeyDown:connect(function(string) onKeyDown(string) end)
selectionBox = Instance.new("SelectionBox")
selectionBox.Name = "Model Delete Selection"
selectionBox.Color = BrickColor.Blue()
selectionBox.Adornee = nil
selectionBox.Parent = player.PlayerGui
selectionLasso = Instance.new("SelectionPartLasso")
selectionLasso.Name = "Model Drag Lasso"
selectionLasso.Humanoid = character.Humanoid
selectionLasso.archivable = false
selectionLasso.Visible = true
selectionLasso.Parent = game.workspace
selectionLasso.Color = BrickColor.Blue()
alreadyMoving = false
end
function onUnequippedLocal()
Tool.TextureId = origTexture
clearSelection()
selectionBox:Remove()
selectionLasso:Remove()
end
Tool.Equipped:connect(onEquippedLocal)
Tool.Unequipped:connect(onUnequippedLocal)