Anything I should add or take out in my Module script?

I am starting to create NPC by using OOP. The reason is because I want to have a lot of NPCs in my game. I am starting to create my OOP Module script but while doing so, I got confused. Like for example, “What type of functions do I need?” or like “How many functions do I need” Here is my module script so far.

local Npc = {}
Npc._index = Npc

--//Creating new Npc\\--
function Npc.new(position,health,model,difficulty)
	local newNpc = {}
	setmetatable(newNpc,Npc)
	
	Npc.isLookingForTarget = false
	Npc.DidNpcFindTarget = false
	
	newNpc.Position = position
	newNpc.Health = health
	newNpc.Model = model
	newNpc.Difficulty = difficulty
	
	return newNpc
end

--//Functions\\--
function Npc:LookForNearbyTarget()
	for _,v in pairs(game.Players:GetChildren()) do
		--//Looking for nearby target...\\--
		return v 
	end
end

function Npc:MovingToTarget()
	
end

return Npc

This doesn’t do anything, it should be

Npc.__index --[[Two underscores]] = Npc
1 Like

Although this is quite a small script, there are a couple of parts that can cause trouble. Let’s start.

  1. Reallocation. Reallocation is the main topic that makes dynamic tables so useful, automated memory allocation. Reallocation occurs in powers of 2, len(table) ^ 2. As you may of seen, reallocation occurs quite often when starting off. Reallocation, although very useful, is costly. You can avoid this table being reallocated 3 times by simply doing :
local newNpc = {
	newNpc.Position = position
	newNpc.Health = health
	newNpc.Model = model
	newNpc.Difficulty = difficulty
}

you could also just rewrite the whole function to be

function Npc.new(position,health,model,difficulty)
	
	Npc.isLookingForTarget = false
	Npc.DidNpcFindTarget = false
	
	return setmetatable ({
	    newNpc.Position = position
	    newNpc.Health = health
	    newNpc.Model = model
	    newNpc.Difficulty = difficulty}, Npc)
end
  1. A small thing that you also do is avoiding the use of ipairs. I do not want to repeat my self as much so you can refer to my previous reply about it.

Helpful source about optimizing lua

1 Like

Appending new elements in an array or dictionary does not automatically reallocate the table to a new reference pointer. You are correct on the fact that Lua utilizes dynamic tables just like most other high-level languages.

As tested with the following code:

-- I'm using vanilla Lua for experimental purposes :p
local ComplexityFactor = 5000
local function Sleep(N)
   return os.execute('sleep '..N)
end

local Hashmap = {}
for i = 1, ComplexityFactor do
   Sleep(0.01)

   Hashmap[i] = math.random(1, 5)
   print(Hashmap)
end

After even 5000 iterations / insertions, the memory address of the array did not reallocate when printing the table. In @RinxfulROBLOX situation all he did was append 4 new keys into his table.

Reallocation in a dynamic table does not occur each time a new key is appended.

No, the new size of the reallocated table isn’t squared. It’s actually multiplied by 2 which is more efficient memory wise. 100,000 * 100,000 would be terrible if we are considering the space complexity of your program. That would also be a waste of RAM.

In Lua, dynamic tables having to reallocate is really nothing to worry about, unless you are implementing your own custom implementation of a dynamic array in lower level languages where static arrays are utilized and memory management is less abstracted from the developer.

1 Like

@DarthFS:

Table rehashing occurs in power of 2. Appending a new key will increase either the size of the hash or the array part of the table, in powers of 2 respectfully. All dictionary like keys will be appended to the hash part in powers of 2, while array like keys will be appended to the array part in powers of 2. Also, if an array part increases by size, then the hash part will also increase in size despite no slots being allocated to it, though this is nothing to worry about since Lua will set the hash part to a dummy node vector so that extremely little - to no memory will be used by the hash part. Same goes when a hash part increases in size.

-- powers: 0, 1, 2, 4, 8, 16, 32, 64 .....

-- each key needs 1 slot!

-- lua will create 1 slot in the hash part when creating this table:
local t = {
   bo = 5 
}

t.e = 5 -- rehash, this key needs another slot! hash part size after rehash: 2
t.c = 1 -- another rehash, needs another slot! hash part size after rehash: 4
t.lo = 5 -- no rehash, previous rehash created 2 more slots!

Another example:

-- lua will create total of 8 slots for this table while creating it

local t = {
    1, -- 1
    2,  -- 2
    3, -- 4
    4, -- 4 (previous rehash allocated 1 more extra slot)
    5, -- 8
}

After even 5000 iterations / insertions, the memory address of the array did not reallocate when printing the table. In @RinxfulROBLOX situation all he did was append 4 new keys into his table.

Onedar most likely confused table rehashing with allocation, as seen by his points.

In Lua, dynamic tables having to reallocate is really nothing to worry about, unless you are implementing your own custom implementation of a dynamic array in lower level languages where static arrays are utilized and memory management is less abstracted from the developer.

It is useful to know a little about how Lua has implemented tables, in the context of optimization. This is also stated in the doc @onedar linked.

1 Like