Lua atempt to call a nil method - lua

I'm having trouble understanding why this code results in an error. Shouldnt the line t.__index = self make sure the table t looks up the init function in Vector?
Vector = {}
Vector.init = function(self,x,y)
self.x = x
self.y = y
end
mt = {}
mt.__call = function(self,...)
local t = {}
t.__index = self
setmetatable(t,self)
t:init(...)
return t
end
setmetatable(Vector,mt)
Vector.__add = function(self,other)
return Vector(self.x+other.x,self.y+other.y)
end
local t = Vector(5,5)
local l = Vector(5,5)
local v = l + t
print(v.x,v.y)
Im also terrible with lua code. I usually use someone else's class library as i cant write my own. Just seems confusing to me.
Ive revised my code as follows.
Vector = {}
Vector.__index = Vector
Vector.mt = {}
Vector.init = function(self,x,y)
self.x = x
self.y = y
end
setmetatable(Vector,Vector.mt)
Vector.mt.__call = function(self,...)
local t = {}
setmetatable(t,self)
t:init(...)
return t
end
Vector.__add = function(self,other)
return Vector(self.x+other.x,self.y+other.y)
end
local t = Vector(5,5)
local l = Vector(5,5)
local v = l + t
print(v.x,v.y)
Works as intended
I came up with this as a general class system
Class = {}
Class.mt = {}
setmetatable(Class,Class.mt)
Class.mt.__call = function(self,name)
local class = {}
class.name = name
class.__index = class
class.mt = {}
class.mt.__call = function(self,...)
local t = {}
setmetatable(t,self)
t.init(t,...)
return t
end
setmetatable(class,class.mt)
return class
end
Vector = Class("Vector")
Vector.init = function(self,x,y)
self.x = x
self.y = y
end
Vector.__add = function(self,other)
return Vector(self.x+other.x,self.y+other.y)
end
I have no idea how to do inheritence
I feel like giving up. Im not good at this
I seemed to have achieved multiple inheritance via mixins.
Just need to declare the super functions before creating the sub classes or else it will not mixin the functions.
Class = {}
Class.mt = {}
setmetatable(Class,Class.mt)
Class.mt.__call = function(self,name,...)
local class = {}
class.name = name
class.parents = {...}
class.__index = class
class.mt = {}
for k,v in pairs(class.parents) do
for i,j in pairs(v) do
if
i ~= "init" and
i ~= "parents" and
i ~= "mt" and
i ~= "__index" and
i ~= "name" then class[i] = j end
end
end
class.mt.__call = function(self,...)
local t = {}
setmetatable(t,self)
t.init(t,...)
return t
end
setmetatable(class,class.mt)
return class
end
Vector = Class("Vector")
Vector.init = function(self,x,y)
self.x = x
self.y = y
end
Vector.__add = function(self,other)
return Vector(self.x+other.x,self.y+other.y)
end
Vector.update = function()
print("update from vector")
end
Vector3 = Class("Vector3",Vector)
Vector3.init = function(self,x,y,z)
print("hello")
Vector.init(self,x,y)
self.z = z
end
Vector3.__add = function(self,other)
local v = Vector.__add(self,other)
return Vector3(v.x,v.y,self.z+other.z)
end
a = Vector3(1,2,3)
a.update()
print(a.z)

Related

How to attach rope to player ragdoll and a player (effectively dragging a ragdoll via a rope) without the weird input lag?

I'm first going to start off with my code which is in a Server Script:
local an = Instance.new("Animation")
an.AnimationId = "rbxassetid://11699868187"
local idle = Instance.new("Animation")
idle.AnimationId = "rbxassetid://11699874417"
local ant
local idlet
local canthit = {}
local knockTime = 30
function takeOwnership(model)
for i, v in pairs(model:GetDescendants()) do
if v:IsA("Part") or v:IsA("BasePart") then
repeat
v:SetNetworkOwner(nil)
until v:GetNetworkOwner() == nil
end
end
end
function resetOwernship(model, ply)
for i, v in pairs(model:GetDescendants()) do
if v:IsA("Part") or v:IsA("BasePart") then
v:SetNetworkOwner(ply)
end
end
end
function rag(char)
local ah = Instance.new("IntValue")
ah.Parent = char
ah.Name = "MaxTime"
ah.Value = knockTime
local thib = Instance.new("IntValue")
thib.Parent = char
thib.Name = "Time"
thib.Value = knockTime
for i, v in pairs(char:GetDescendants()) do
if v:IsA("Motor6D") and v.Parent.Name ~= "HumanoidRootPart" then
local Socket = Instance.new("BallSocketConstraint")
local a1 = Instance.new("Attachment")
local a2 = Instance.new("Attachment")
a1.Parent = v.Part0
a2.Parent = v.Part1
Socket.Parent = v.Parent
Socket.Attachment0 = a1
Socket.Attachment1 = a2
a1.CFrame = v.C0
a2.CFrame = v.C1
Socket.LimitsEnabled = true
Socket.TwistLimitsEnabled = true
v:Destroy()
end
end
char.Humanoid.BreakJointsOnDeath = false
char.Humanoid.RequiresNeck = false
end
function unrag(char)
for i,v in pairs(char:GetDescendants()) do
if v:IsA("BallSocketConstraint") then
v.UpperAngle = 0
v.TwistUpperAngle = 0
v.TwistLowerAngle = 0
local Joints = Instance.new("Motor6D",v.Parent)
Joints.Part0 = v.Attachment0.Parent
Joints.Part1 = v.Attachment1.Parent
Joints.C0 = v.Attachment0.CFrame
Joints.C1 = v.Attachment1.CFrame
v:Destroy()
end
end
end
game:GetService("ReplicatedStorage").Jump.OnServerEvent:Connect(function(ply)
if ply.Character and ply.Team == game:GetService("Teams").Survivor then
if ply.Character.Ragdoll.Value == true then
--game:GetService("ReplicatedStorage"):WaitForChild("Message"):FireClient(ply, "Sorry, jumping isn't available for ragdolls right now")
end
end
end)
game.Players.PlayerAdded:Connect(function(p)
if #game:GetService("Teams").Beast:GetPlayers() == 1 then
p.Team = game:GetService("Teams").Survivor
else
p.Team = game:GetService("Teams").Beast
end
p.CharacterAdded:Connect(function(c)
canthit[p] = nil
if p.Team == game:GetService("Teams").Beast then
local theBat = game:GetService("ServerStorage").Bat:Clone()
theBat.Parent = c
theBat.Equipped:Connect(function()
local h = c:FindFirstChild("Humanoid")
if h then
local a = h:FindFirstChild("Animator")
if a then
idlet = a:LoadAnimation(idle)
idlet:Play()
end
end
end)
theBat.Activated:Connect(function()
local h = c:FindFirstChild("Humanoid")
if h then
local a = h:FindFirstChild("Animator")
if a then
ant = a:LoadAnimation(an)
ant:Play()
theBat.Handle.Swoosh:Play()
local thinge = theBat.Handle.Touched:Connect(function(t)
local ply = game.Players:GetPlayerFromCharacter(t:FindFirstAncestorWhichIsA("Model"))
local ragd = ply.Character:FindFirstChild("Ragdoll")
if ragd then
if ragd.Value == true then
return
end
end
if ply and ply.Team == game:GetService("Teams").Survivor and ply ~= p and not canthit[ply] then
theBat.Handle.Hit:Play()
canthit[ply] = true
local char = ply.Character
ragd.Value = true
rag(char)
while not (char.Time.Value <= 0) do
takeOwnership(char)
char.Humanoid:ChangeState(Enum.HumanoidStateType.Physics)
wait(1)
char.Time.Value -= 1
char.HP.Value -= .5
end
if char.HP.Value <= 0 then
char.HP.Value = 0
game:GetService("ReplicatedStorage"):WaitForChild("Message"):FireAllClients(ply.Name.." has been captured!")
char.Humanoid.Health = 0
return
end
char.Time:Destroy()
char.MaxTime:Destroy()
char.Humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
unrag(char)
resetOwernship(char, ply)
ragd.Value = false
coroutine.wrap(function()
wait(5)
canthit[ply] = nil
end)()
end
end)
wait(.2)
thinge:Disconnect()
end
end
end)
theBat.Unequipped:Connect(function()
if idlet then
idlet:Stop()
end
end)
end
end)
end)
So, this is my horrible code for a little game I am making. It's kind of similar to Flee the Facility. In my game, the person who is the 'beast' should be able to drag a player when they are knocked out, but they can't. I tried adding a rope constraint to the ragdoll and the 'beast', but it just makes the beast have input lag and makes it's animations go weird.
I must note that the beast is a random player. I would try setting ownership of the ragdoll'd player to the grabber (which is the 'beast') but I need to set it to the server in order to change the state to Physics. I would use an event and a local script but I do not want this to be exploitable at all.
So, my question is: How do I attach a rope from a player to a ragdolled player without the non-ragdolled player lagging or having weird input lag and weird animations?
Like I said, I tried setting ownership but that wouldn't work as I need server ownership for setting the humanoid's state to physics. Just using takeOwnership() then ChangeState both on the same line wouldn't work so I had to put it in the while loop.

How would I compare results in lua

DISCLAIMER: The title is bad but I dont know how else to word it
Issue: I am trying to compare entities in a FiveM script I am working on and tell if a player is close to a valid animal model and I cant get it to work and the only model being detected is the player its self
Current code:
local QBCore = exports['qb-core']:GetCoreObject()
local animals = GetGamePool('CPed')
local hasTool = false
local hasKnife =
QBCore.Functions.HasItem('Knife', function(result)
if result then
hasTool = true
hasKnife = true
end
end)
for k, v in pairs(animals) do
local animal = animals[k]
local animalModel = GetEntityModel(animal)
local animalHash = GetHashKey(animal)
local boar = GetHashKey('a_c_boar')
local deer = GetHashKey('a_c_deer')
local coyote = GetHashKey('a_c_coyote')
print("Deer: " .. deer .. "boar: " .. boar .. "coyote: " .. coyote)
if animalHash == boar or deer or coyote then
local entPos = GetEntityCoords(v)
local playerPos = GetEntityCoords(PlayerPedId())
if #(entPos - playerPos) < 1.0 then
foundAnimal = v
print("Animal close by" .. animalHash)
break
end
else
print("No animals found")
end
end
Other things I have tried:
local QBCore = exports['qb-core']:GetCoreObject()
local animals = GetGamePool('CPed')
local validAnimals = {
["a_c_boar"] = true,
["a_c_coyote"] = true,
["a_c_crow"] = true,
["a_c_deer"] = true,
["a_c_mtlion"] = true,
["a_c_pig"] = true,
["a_c_rabbit_01"] = true,
}
local hasTool = false
local hasKnife =
QBCore.Functions.HasItem('Knife', function(result)
if result then
hasTool = true
hasKnife = true
end
end)
for k, v in pairs(animals) do
local animal = animals[k]
local animalModel = GetEntityModel(animal)
local animalModelName = GetEntityModel(animalModel)
if validAnimals[animalModelName] then
local entPos = GetEntityCoords(v)
local playerPos = GetEntityCoords(PlayerPedId())
if #(entPos - playerPos) < 2.0 then
foundAnimal = v
print("Found animal" .. foundAnimal .. "!" .. "Model: " .. entModel)
break
end
end
local QBCore = exports['qb-core']:GetCoreObject()
Citizen.CreateThread(function ()
local animals = GetGamePool('CPed')
local validAnimals = {
["a_c_boar"] = true,
["a_c_coyote"] = true,
["a_c_crow"] = true,
["a_c_deer"] = true,
["a_c_mtlion"] = true,
["a_c_pig"] = true,
["a_c_rabbit_01"] = true,
}
local hasTool = false
local hasKnife =
QBCore.Functions.HasItem('Knife', function(result)
if result then
hasTool = true
hasKnife = true
end
end)
for k, v in pairs(animals) do
local entModel = GetEntityModel(v)
if validAnimals[entModel] then
local entPos = GetEntityCoords(v)
local playerPos = GetEntityCoords(PlayerPedId())
if #(entPos - playerPos) < 2.0 then
foundAnimal = v
print("Found animal" .. foundAnimal .. "!" .. " " .. "Model: " .. entModel)
break
end
end)
Edit: I have tried a few other things aswell but i dont have those versions saved
Edit2: The current code the if statement seems like it doesnt even check anything its like all the code inside of it will run even if and the hashes dont match
Edit3: This also could be a distance calculation issue with the vector3 im not sure tho

lua open a file with a table and change certain values

I have a file with a large table. Need to open it, get certain values and replace other values with the new ones. With this example, Females and Males Classroom a and b must equal Teachers Classroom a and b.
Read as much as I can on IO, but I cannot seem to get this to work correctly. Any help will be greatly appreciated.
--file with sample data to test, original file has 7000+lines
theData =
{
["theSchool"] =
{
["theTeachers"] =
{
["theClassroom"] =
{
["a"] = 001,
["b"] = 002,
},
},
["theFemales"] =
{
["theClassroom"] =
{
["a"] = 005,
["b"] = 010,
},
},
["theMales"] =
{
["theClassroom"] =
{
["a"] = 012,
["b"] = 014,
},
},
},
}
Then the function file looks like this
local file = io.open(filepath,'r')
local newCa = '["a"] = '..theData.theSchool.theTeachers.theClassroom.a
local newCb = '["b"] = '..theData.theSchool.theTeachers.theClassroom.b
local replaceFa = '["a"] = '..tostring(theData.theSchool.theFemales.theClassroom.a)
local replaceFb = '["b"] = '..tostring(theData.theSchool.theFemales.theClassroom.b)
local replaceMa = '["a"] = '..tostring(theData.theSchool.theMales.theClassroom.a)
local replaceMb = '["b"] = '..tostring(theData.theSchool.theMales.theClassroom.b)
file:close()
--Will it work?
print("Original Values:")
print(newCa)
print(newCb)
print(replaceFa)
print(replaceFb)
print(replaceMa)
print(replaceMb)
file = io.open(filepath,'r+')
function lines_from(filepath)
lines = {}
for line in io.lines(filepath) do
lines[#lines + 1] = line
end
return lines
end
local lines = lines_from(filepath)
for k,v in ipairs(lines) do
if v == replaceFa then
file:write(newCa..'\n')
elseif v == replaceFb then
file:write(newCb..'\n')
elseif v == replaceMa then
file:write(newCa..'\n')
elseif v == replaceMb then
file:write(newCb..'\n')
else
file:write(v..'\n')
end
--('[' .. k .. ']', v)
end
--replaceF = {[a] = newCa, [b] = newCb}
--replaceM = {[a] = newCa, [b] = newCb}
--file:write(replaceF)
--file:write(replaceM)
--print(tostring(theData.theSchool.theFemales.theClassroom.a))
file:close()
file = io.open(filepath,'r')
--Did it work?
print("New Values:")
print(theData.theSchool.theTeachers.theClassroom.a)
print(theData.theSchool.theTeachers.theClassroom.b)
print(theData.theSchool.theFemales.theClassroom.a)
print(theData.theSchool.theFemales.theClassroom.b)
print(theData.theSchool.theMales.theClassroom.a)
print(theData.theSchool.theMales.theClassroom.b)```
> I'll remove all the print things after it works.
try this solution, loading the table in one read of the file will be faster, and writing is also better with one command write
--- read
local handle = io.open("data.lua",'rb')
local data = handle:read("*a")
handle:close()
data = data .. "\n return theData"
local t = loadstring(data)()
-- edit
theData.theSchool.theTeachers.theClassroom.a = theData.theSchool.theTeachers.theClassroom.a + 1
-- write
local function concat(t, r)
r = r or {}
for k,v in pairs(t) do
if type(v)=="table" then
r[#r+1] = string.format('\t["%s"]={\n',k )
concat(v, r)
r[#r+1] = "\t},\n"
else
r[#r+1] = string.format('\t\t["%s"]=%03s,\n',k ,v )
end
end
return r
end
local r = concat(t)
local text = "theData = { \n " .. table.concat(r) .. "}"
print(text) -- just control
local handle = io.open("data.lua",'wb')
local data = handle:write(text)
handle:close()

self as param, and setting scope?

Can someone please help me with this.
local function TestPrice()
local obj1 = require("myObj")
local obj2 = require("myObj")
obj1:setPrice(30)
obj2:setPrice(40)
print(obj1.price) -- this prints '40'. Setting price on obj2 changes the price in obj1
end
and
-- myObj.lua
local M = {
price = -1;}
local function _setPrice(self, newprice)
self.price = newprice
-- todo other stuff
end
M.setPrice = _setPrice
return M
I thought that by setting self as a param it set the scope. Why does calling this function on obj2 update the value of obj1?
You need a function to create new object
-- myObj.lua
local M = {}
local function _setPrice(self, newprice)
self.price = newprice
-- todo other stuff
end
M.setPrice = _setPrice
M.__index = M
local function create_new_obj()
local obj = {price = -1}
setmetatable(obj, M)
return obj
end
return create_new_obj
-- main.lua
local function TestPrice()
local obj1 = require("myObj")()
local obj2 = require("myObj")()
obj1:setPrice(30)
obj2:setPrice(40)
print(obj1.price, obj2.price)
end
TestPrice()
In your code require load once, and second require give you same object. You should implement some kind of copy method.
-- myObj.lua
local M = {
price = -1;}
local function _setPrice(self, newprice)
self.price = newprice
-- todo other stuff
end
function M:copy()
return {["price"] = self.price, ["setPrice"]=_setPrice, ["copy"] = self.copy}
end
M.setPrice = _setPrice
return M

Lua, is this possible?

I am working on a game using love2d and i haven't quite programmed in lua. Not sure on technical wording so i'll post my code and explain what i'm trying to do:
item = {}
item.stat = {}
player.x = 100
player.y = 100
--
item[0].stat.damage = 10
What i'm trying to do is make an inventory system and an item database. I want to be able to make the item database with the code above so i could add an item like so:
item[1].stat.damage = 10
item[1].stat.speed = 10
item[2].stat.damage = 20
item[2].stat.speed = 5
--
player.inventory[0] = item[1]
player.inventory[1] = item[2]
can someone tell me what coding principle this may so i can research it? I basically want to make a matrix that i can access like above while having the convenience of named arrays instead of saying item[1,"damage"] = 10
Edit:
I realise now i can do item.stat.damage[1] = 10 but i have to setup an array for each one, is there an easier way?
Simply use tables:
player = {}
player.x = 100
print(player.x) -- prints 100
Note that player.x is simply syntactic sugar for player["x"], so the following lines are equivalent:
print(player.x) -- prints 100
print(player["x"]) -- also prints 100
With that in mind, you could construct your game data like this for example:
item = {}
item[1] = {}
item[1].stat = {}
item[1].stat.damage = 10
item[1].stat.speed = 10
item[2] = {}
item[2].stat = {}
item[2].stat.damage = 20
item[2].stat.speed = 5
player = {}
player.x = 100
player.y = 100
player.inventory = {}
player.inventory[1] = item[1]
player.inventory[2] = item[2]
print(player.inventory[2].stat.damage) -- prints 20
print(player["inventory"][2]["stat"]["damage"]) -- equivalent, also prints 20
It is probably a good idea to define functions that create items or players and automatically set all the required fields.
Eventually, you may want to use actual classes and objects (for example, if you want to define methods on your objects).
EDIT:
Here is the example from above with functions create_item, create_player to create items or players. I've used named parameters for these functions so one doesn't have to remember the order of the function parameters (note the curly braces when calling the functions).
function create_item(arg)
local item = {}
item.stat = {}
item.stat.damage = arg.damage
item.stat.speed = arg.speed
return item
end
function create_player(arg)
local player = {}
player.x = arg.x
player.y = arg.y
player.inventory = {}
return player
end
item = {}
item[1] = create_item{damage=10, speed=10}
item[2] = create_item{damage=20, speed=5}
player = create_player{x=100, y=100}
player.inventory[1] = item[1]
player.inventory[2] = item[2]
print(player.inventory[2].stat.damage) -- prints 20
print(player["inventory"][2]["stat"]["damage"]) -- equivalent, also prints 20
You can always shorten your code:
item = {
stat = {},
[0] = { stat = { damage = 10 } },
[1] = { stat = { damage = 10, speed = 10 } },
[2] = { stat = { damage = 20, speed = 5 } },
}
player = { x = 100, y = 100, inventory = { [0] = item[1], [1] = item[2] } }
You can access that code in matrix way like
function item:getstat(index, param)
return self[index] and self[index].stat and self[index].stat[param];
end
function item:setstat(index, param, value)
local t1 = self[index]
if (t1 == nil) then
t1 = {}
self[index] = t1
end
local t2 = t1.stat
if (t2 == nil) then
t2 = {}
t1.stat = t2
end
t2[param] = value
end
print(item:getstat(0, "damage"))
item:setstat(1, "speed", 20)

Resources