How would I return a metatable from a :connect function?

I have been at this for several days now, and i’ve made another topic for this already, i’ve scoured the internet to find

and many more posts, nothing worked, my desire is a very obscure one probably, and I don’t think i’m using object oriented programming correctly because of this, but it must work.

I want to return the metatable newSword from the CollectionService:GetInstanceAddedSignal(foo):Connect(function() to be able to call
this function from a server script:

--server script, only desired parts
Commander = SwordUtils.new({
	Sword = ReplicatedStorage.Swords.Commander,
	Damage = 20,
	AnimSpeed = 2,
	cooldown = 1,
	price = '$4500',
	SetPoints = {Vector3.new(0,2,1),Vector3.new(0,-2,2),Vector3.new(0,0,3),Vector3.new(0,2,4),
		Vector3.new(0,-2,-1),Vector3.new(0,0,0),Vector3.new(0,2,-1),Vector3.new(0,-2,-2),Vector3.new(0,0,-3)}
	
})

Commander:SpawnUnits({FriendlyAI.Noob,50,FriendlyAI["Sword Noob"],50}) -- I need to call this,
-- but I need the metatable to return or else it will error 
--(I think it has to be the metatable)

Entire code: (relevant part is the end return and the top local newSword, this is just one of the solutions i’ve tried.)

function SwordUtils.new(SwordInfo)
	CollectionService:AddTag(SwordInfo.Sword,SwordInfo.Sword.Name)
	
	SwordInfo.Sword:Clone().Parent = game:GetService('StarterPack')
	local newSword
	
	CollectionService:GetInstanceAddedSignal(SwordInfo.Sword.Name):Connect(function(Sword)

		local animChildren = Sword.Animations:GetChildren()
		local toolActivated = false
		local newHitbox
		local projectileInfo = SwordInfo.ProjectileInfo or {} --if first value is nil instead use an empty table so it doesn't error
		local debuffInfo = SwordInfo.DebuffInfo or {}
		newSword = setmetatable({},SwordUtils)
		newSword.Sword = Sword
		newSword.Damage = SwordInfo.Damage
		newSword.ProjectileType = projectileInfo.projectileType
		newSword.ProjectileVelocity = projectileInfo.projectileVelocity
		newSword.LaunchEnemyInfo = nil
		newSword.LaunchesEnemies = false

		if not game:GetService('StarterGui').ShopUi.Main.Swords:FindFirstChild(Sword.Name) then

			local GuiSwordTemplate = ReplicatedStorage.UI.SwordTemplate:Clone()

			GuiSwordTemplate.Name = Sword.Name
			GuiSwordTemplate.Parent = game:GetService('StarterGui').ShopUi.Main.Swords
			GuiSwordTemplate.SwordViewport.Stats.Text = 'Damage: '..tostring(SwordInfo.Damage)
				..'    Cooldown: '..tostring(SwordInfo.cooldown)
				..'    Debuff: '..tostring(debuffInfo.Debuff)
				..'    Projectile: '..tostring(projectileInfo.projectileType)
				..'    Projectile Cooldown: '..tostring(projectileInfo.projectileCooldown)
				..'    Projectile Velocity: '..tostring(projectileInfo.projectileVelocity)
			GuiSwordTemplate.SwordViewport.Price.Text = SwordInfo.price
		end

		local ActiveAbility

		if SwordInfo.Ability then
			Sword.Equipped:Connect(function()
				ActiveAbility = Sword.Parent[SwordInfo.Ability]
				ActiveAbility.Sound.SoundId = Sword.Blade[SwordInfo.Ability].SoundId
				ActiveAbility.Enabled = true
			end)

			Sword.Unequipped:Connect(function()
				ActiveAbility.Enabled = false
			end)
		end

		if projectileInfo and projectileInfo ~= {} then

			local Attacking = false
			local swordEquipped = false
			local findAmbient = Sword:FindFirstChild('Ambient',true)
			Sword.Equipped:Connect(function()
				swordEquipped = true
				if findAmbient then
					findAmbient:Resume()
				end
			end)
			Sword.Unequipped:Connect(function()
				swordEquipped = false
				if findAmbient then
					findAmbient:Pause()
				end
			end)
			ReplicatedStorage.Events.PressedE.OnServerEvent:Connect(function(plr)
				if Attacking == false and swordEquipped == true and projectileInfo ~= {} then

					local Anim = plr.Character.Humanoid:LoadAnimation(Sword.ProjectileAnim)
					Attacking = true
					Anim:Play()
					Anim:AdjustSpeed(projectileInfo.AnimSpeed)
					SwordUtils.FireProjectile(newSword)
					delay(1,function()
						Anim:Stop()
					end)
					delay(projectileInfo.projectileCooldown,function()
						Attacking = false
					end)
				end
			end)
		end
		
		Sword.Activated:Connect(function()
			if toolActivated == false then
				local randomAnim = animChildren[math.random(1,#animChildren)]
				local char = Sword.Parent
				local anim = char.Humanoid:LoadAnimation(randomAnim)
				toolActivated = true

				if newSword.LaunchesEnemies == true then
					SwordUtils.SpawnUnits(newSword,newSword.LaunchEnemyInfo)
				end

				if Sword.Handle:FindFirstChildWhichIsA('Sound') then
					Sword.Handle.Attack:Play()
					if newHitbox == nil then
						newHitbox = RaycastHitbox.new(Sword.Handle)
						newHitbox:SetPoints(Sword.Handle,SwordInfo.SetPoints)
					end
				else
					if Sword.Blade:FindFirstChild('Attack1') then
						local attackSounds = {}
						for number,sound in pairs(Sword.Blade:GetChildren()) do
							if string.match(sound.Name,'Attack') then
								table.insert(attackSounds,sound)
							end
						end
						attackSounds[math.random(1,#attackSounds)]:Play()
					else
						Sword.Blade.Attack:Play()
					end
					if newHitbox == nil then
						newHitbox = RaycastHitbox.new(Sword.Blade)
						newHitbox:SetPoints(Sword.Blade,SwordInfo.SetPoints)
					end
				end
				local Params = RaycastParams.new()
				local playerTable = {char}
				for _,player in pairs(Players:GetPlayers()) do
					table.insert(playerTable,player.Character)
				end
				Params.FilterDescendantsInstances = playerTable
				Params.FilterType = Enum.RaycastFilterType.Blacklist
				newHitbox.RaycastParams = Params
				newHitbox:HitStart()
				newHitbox.OnHit:Connect(function(hit,humanoid)
					if humanoid.Parent.Parent.Name == 'Enemies' then
						if humanoid:FindFirstChild('damageMultiplier') then
							humanoid:TakeDamage(SwordInfo.Damage * humanoid.damageMultiplier.Value)
						else
							humanoid:TakeDamage(SwordInfo.Damage)
						end
						if debuffInfo.Debuff ~= nil then
							Debuffs[debuffInfo.Debuff](humanoid,debuffInfo.duration)
						end
					end
				end)

				anim:Play()
				anim:AdjustSpeed(SwordInfo.AnimSpeed)
				anim.Stopped:Wait()
				task.wait(0.1)
				newHitbox:HitStop()
				task.wait(SwordInfo.cooldown)
				toolActivated = false
			end
		end)
	end)
	print(newSword)
	return newSword
end

this is a cry for help, i’ve not gotten a single answer on my other post that I desperately need solved and I would greatly appreciate if I got an answer within this week, as I really need this solved

Could you not just put it into a module script?

the :SpawnUnits? I could but that would defeat the entire purpose of oop and it would give me less control (also the SwordUtils.new() is inside a modulescript, I just ctrl+c ctrl+v the appropriate parts)
edit: SwordUtils:SpawnUnits() is already in the same module script as SwordUtils.new()

Try setting up the module script this way:

local SwordUtils = {}

SwordUtils.__index = SwordUtils

function SwordUtils.new(SwordInfo)
     local NewSword = {}
     setmetatable(SwordUtils,NewSword)
    -- rest of the code here
    return NewSword
end

function SwordUtils:SpawnUnits()
   --Use self to index the new Sword
end

return SwordUtils

I highly suggest you read this post as well:

1 Like

I kinda need the ‘Sword’ variable from CollectionService:GetInstanceAddedSignal, and yes I have read that post over 2 times to learn oop, really well made, I guess that I can try just referencing the replicatedstorage version of ‘Sword’ and stuff
brb in 5 mins to test this

Oh boy am I stupid, several days of debugging and trying to find an answer only for it to be this:

function SwordUtils.new(SwordInfo)
	CollectionService:AddTag(SwordInfo.Sword,SwordInfo.Sword.Name)

	SwordInfo.Sword:Clone().Parent = game:GetService('StarterPack')
	SwordInfo.Sword:Clone().Parent = game:GetService('StarterPack')
	local projectileInfo = SwordInfo.ProjectileInfo or {} --if first value is nil instead use an empty table so it doesn't error
	local debuffInfo = SwordInfo.DebuffInfo or {}
	local newSword = setmetatable({},SwordUtils)
	newSword.Sword = nil -- gets referenced INSIDE of CollectionService:GetInstanceAddedSignal()
	newSword.Damage = SwordInfo.Damage
	newSword.ProjectileType = projectileInfo.projectileType
	newSword.ProjectileVelocity = projectileInfo.projectileVelocity
	newSword.LaunchEnemyInfo = nil
	newSword.LaunchesEnemies = false

Thanks for helping me realize this!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.