I have some strange LUA errors

Hello everyone, I’m trying to do something with LUA but i have a dilema:

I have codded some LUA stuff but if only the server execute it, when launching the server have this error:


[ERROR] lua/includes/util.lua:171: attempt to index a string value with bad key ('IsValid' is not part of the string library)
  1. error - [C]:-1
   2. __index - lua/includes/extensions/string.lua:310
    3. IsValid - lua/includes/util.lua:171
     4. unknown - gamemodes/base/gamemode/shared.lua:295

else if client execute it, I have this error:



[ERROR] lua/includes/util.lua:171: attempt to index a string value with bad key ('IsValid' is not part of the string library)
  1. error - [C]:-1
   2. __index - lua/includes/extensions/string.lua:310
    3. IsValid - lua/includes/util.lua:171
     4. GetPlayerColor - gamemodes/base/entities/entities/gmod_hands.lua:43
      5. bind - lua/matproxy/player_color.lua:28
       6. unknown - lua/includes/modules/matproxy.lua:56


Problem is that i really don’t have information where my error comes from :confused: (when i remove the doors.lua file, I have no more errors so it is surely this file)
Here is the code:


local meta = FindMetaTable("Entity")

function door(ply)
	local trace = ply:GetEyeTrace().Entity
	return trace
end

function meta:IsOwnable()
	return true
end

function meta:SetOwner(duration,owner)
	if meta:IsOwnable() then
		self:SetNWInt("time" , duration)
		self:SetNWString("owner" , owner)
	end
end


function meta:GetTimer()
	if meta:IsOwnable() then
		return self:GetNWInt("time")
	end
end

function meta:SetBank(Owner)
	if meta:IsOwnable() then
		self:SetNWString("owner","Bank")
	end
end

function meta:GetOwner()
	if meta:IsOwnable() then
		return self:GetNWString("owner","Bank")
	else
		return "Not ownable"
	end
end



function meta:DecrTimer(val)
	if meta:IsOwnable() then
		self:SetNWInt("time",meta:GetTimer() - val)
	end
	if meta:GetTimer() < 0 then
		self:SetOwner("Bank")
	end
end

--[[function meta:Owned()
	if meta:IsOwnable() and meta:GetOwner() ~= "Bank" then
		true
	else
		false
	end
end
--]]

--[[function tick()
	for k,v in pairs(Entity.GetAll()) do
		if v:GetOwner() != "Bank" then
			DecrTimer(1)
		end
	end
end]]--


function own_Door( ply,cmd,args,str )
	val = tonumber(str)
	if not val or val < 0 then
		ply:ChatPrint("Error with time")
	else
		door(ply):SetOwner(val,ply:GetPlayerInfo()["guid"])
		ply:ChatPrint("You successfully owned a door")
	end
end

function get_owner(ply)
	ply:ChatPrint(door(ply):GetOwner())
end

concommand.Add("own",own_Door)
concommand.Add("owner",get_owner)

if some generous guy could help me, it would be so great! (And sorry for my english, it isn’t my native language)

On the server, line 295 of the base gamemode shared file (as described in your error), is OnViewModelChanged.

Both offending lines are IsValid(ply), where ply is either a viewmodel owner or weapon owner, so somehow you’re setting the owner of the weapon and viewmodel to a string instead of a player.

Why:

You’re overriding the entire entity metatable to add new functions to every single entity. This isn’t completely a bad thing, but you have to be very careful to not override any functions that already exist on any other entities.

So when you did function meta:SetOwner, you removed the code on clientside/serverside entities that sets the owner of weapons (the person carrying them), replacing those default functions with incompatible code.

Solution:

Put all of your meta table overrides in a table.

local meta = FindMetaTable(“Entity”)
meta.MyModNameKaostic = {}
local metasafe = meta.MyModNameKaostic

and then instead of “function meta:DecrTimer(val)” you do “function metasafe:DecrTimer(val)”, and if you need to reference your custom functions outside of this file you can do ent.MyModNameKaostic:DecrTimer()

For the same reason (not overriding other peoples code with incompatible code) you should localize any functions and variables that you only use within the file you’re coding them in. If you won’t need “own_Door” anywhere but in this single code file, put the word local before the word function so that it won’t exist outside this file and won’t override anything beyond this file.

If you DO want that function in other files, make yourself a global table to hold them in with a unique name.

MyModNameKaostic = {}
function MyModNameKaostic.own_Door()

or

local function own_Door()

No. doing A.B:C() will pass B as “self” to C(), and not A as you’d want here. Proper way is A.B.C(A) or just use prefixes like ent:MyCrap_SetOwner()

Thanks a lots! I should have think of this problem :confused:
I will now use mymod_function() for all my function (the meta.mymod is an elegant way to deal with it, but I still have problem difficult to resolve with this)

I still have a little issue with self:GetClass(), I can’t manage to use it for my IsOwnable() function

Im having this error:


[ERROR] gamemodes/cnr/gamemode/cnr/door.lua:9: Tried to use a NULL entity!
  1. GetClass - [C]:-1
   2. cnr_IsOwnable - gamemodes/cnr/gamemode/cnr/door.lua:9
    3. cnr_GetOwner - gamemodes/cnr/gamemode/cnr/door.lua:38
     4. unknown - gamemodes/cnr/gamemode/cnr/door.lua:85
      5. unknown - lua/includes/modules/concommand.lua:54


the code is this :



function meta:cnr_IsOwnable()
	local class = self:GetClass()
	if (class == "func_door" or class == "func_door_rotating" or class == "prop_door_rotating") then
		return true
	else
		return false
	end
end

According to http://wiki.garrysmod.com/page/Entity/GetClass I don’t see why it doesn’t work =P
and (I know it is not a reference) DarkRP use the same function exactly like I do :confused:

thanks for your futur help!

Try replacing the local class = self:GetClass() with
[lua]local class = “” --setting it to an empty string using two quotes, and doing this local variable creation outside of the ‘if then else’ statement below so that it can be used outside of that statement
if self != NULL && IsValid(self) && self.GetClass then class = self:GetClass() end --self.GetClass refers to a variable representing the function on the entity, so this checks if it exists before we try to call it[/lua]

just some error prevention, most importantly checking that the entity “exists” because gmod is weird that way

Thanks man, but it still not working, the self is always a NULL



function meta:cnr_IsOwnable()
	local class = "not working" --setting it to an empty string using two quotes, and doing this local variable creation outside of the 'if then else' statement below so that it can be used outside of that statement
	if self != NULL && IsValid(self) && self.GetClass then class = self:GetClass() end --self.GetClass refer	s to a variable representing the function on the entity, so this checks if it exists before we try to call it
	if (class == "func_door" or class == "func_door_rotating" or class == "prop_door_rotating") then
		print(class)
		return true
	else
		print(class)
		return false
	end
end


and it always output not working :confused:

IsValid already checks for NULL., so you dont need this bit: “self != NULL &&”.

As for the error, you are probably calling the function incorrectly. You must call it like this:

my_entity**:**cnr_IsOwnable()

NOT LIKE THIS:

my_entity**.**cnr_IsOwnable()

add this:

print(self==NULL)
print(type(self))
print(self.GetClass)
print(self.IsValid)

what’s the output?

I found my mistake, I was calling meta:cnr_IsOwnable, but i should call self:cnr_IsOwnable

so i got another question:

the big difference between meta and self? Because I understand that meta is a table, and self is the entity, but why and when do we need to use meta instead of self?

You only use meta to add new methods/functions to all entities/players/etc.

You use self for everything else.

Entity.IsValid returns false if Entity is NULL.

he’s doing overrides so you can’t rule anything out

[editline]18th July 2015[/editline]

the meta table is just a big table of default data that every new entity created will inherit a copy of

anything in the meta is applied to entities upon their creation as a part of them

so ‘self’ in a function in the metatable refers to the metatable literally, but is intended for use with the entity the function is later applied to

edit the metatable to set some functions for all entities to have

run your new functions on the entities themselves

you don’t “use meta instead of self”

Thanks for all your interresting and usefull answer! (love this forum for this and no: U NOOB GO LEARN), i’m still new, but now I understand more thing in LUA :slight_smile:

One last (no i’m joking, I have thousands of questions) but i need to make the timer of the doors decreasing each minutes (or hours or when I want in fact) but i’m trying with the tick() hook, but i can’t make it

I have try something like this:



function minute()
	tim = (RealTime() *66 /60) % 60
	if flag == 0 then
		flag = 1
		if tim == 0 then
			-- do my stuff
		end
		print (math.floor(tostring(tim)))
	else
		flag = 0 
	end
end

hook.Add( "Tick", "cnr_tick", minute )

but it has 2 problems:
-it does run every tick instead of 1 each second (flag part) (I get more than 50 times the tim variable printed)
-it doesn’t run when no one is online

as I can get time, executing this function 1 times per hour is sufficient/needed, but 1 time per tick make the server lag/ram horribly and I can’t manage to find another hook that may be used for it :confused:

You could use timer.Create() and make the function activate every so seconds

Do you mean you want something to happen upon the stroke of each hour, or at a regular interval of something like “every five minutes”.

In either case, there’s no reason to worry about making it happen when players are online.



local HasAnnouncedHour = false
timer.Create("MyUniqueTimerName",5,0,function()
     local minute = tonumber(os.date("%M",os.time()))
     if minute == 0 then
          if !HasAnnouncedHour then --if hasannouncedhour is false; the ! symbol inverts the true/false
               print("OMG IT IS A NEW HOUR NOW")
               HasAnnouncedHour = true
          end
     else
          HasAnnouncedHour = false
     end
end)


This will print an announcement hourly, on the hour, so long as the server’s clock is correctly set to the minute.

The HasAnnouncedHour stuff ensures that it only announces it once. This script checks every five seconds.

[editline]18th July 2015[/editline]

To do something simply every five minutes, just replace the timer function with only the print test or whatever else you want to happen, and change the 5 seconds to 605*

Thanks man, now I understand a little more of all of this!