function BaseWeapon.importConfiguration(k,c)if not c or not c:IsA("\067\111\110\102\105\103\117\114\097\116\105\111\110")then for c,A in pairs(c:GetChildren())do if A:IsA("\086\097\108\117\101\066\097\115\101")then local c=A.Name local o=A.Value local b=k.configValues[c]k.configValues[c]=o k:onConfigValueChanged(c,o,b)end end end end function BaseWeapon.setConfiguration(k,c)k:cleanupConnection("\099\111\110\102\105\103\067\104\105\108\100\065\100\100\101\100","\099\111\110\102\105\103\067\104\105\108\100\082\101\109\111\118\101\100")if not c or not c:IsA("\067\111\110\102\105\103\117\114\097\116\105\111\110")then return end for c,A in pairs(c:GetChildren())do if A:IsA("\086\097\108\117\101\066\097\115\101")then k:onConfigValueAdded(A)end end k.connections.configChildAdded=c.ChildAdded:Connect(function(c)if c:IsA("\086\097\108\117\101\066\097\115\101")then k:onConfigValueAdded(c)end end)k.connections.configChildRemoved=c.ChildRemoved:Connect(function(c)if c:IsA("\086\097\108\117\101\066\097\115\101")then k:onConfigValueRemoved(c)end end)end function BaseWeapon.onChildAdded(k,c)if c:IsA("\067\111\110\102\105\103\117\114\097\116\105\111\110")then k:setConfiguration(c)end end function BaseWeapon.onChildRemoved(k,c)if c:IsA("\067\111\110\102\105\103\117\114\097\116\105\111\110")then k:setConfiguration(nil)end end function BaseWeapon.onConfigValueChanged(o,c,k,A) end function BaseWeapon.onRenderStepped(k,c) end function BaseWeapon.onStepped(k,c) end function BaseWeapon.getAnimationController(c)if c.animController then if not c.instanceIsTool or c.animController.Parent and c.animController.Parent:IsAncestorOf(c.instance)then return c.animController end end c:setAnimationController(nil)if c.instanceIsTool then local k=IsServer and c.instance.Parent:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")or c.instance.Parent:WaitForChild("\072\117\109\097\110\111\105\100",math.huge)local A=nil if not k then A=c.instance.Parent:FindFirstChildOfClass("\065\110\105\109\097\116\105\111\110\067\111\110\116\114\111\108\108\101\114")end c:setAnimationController(k or A)return c.animController end end function BaseWeapon.setAnimationController(k,c)if c==k.animController then return end k:stopAnimations()k.animController=c end function BaseWeapon.stopAnimations(c)for c,k in pairs(c.animTracks)do if k.IsPlaying then k:Stop()end end c.animTracks={}end function BaseWeapon.getAnimTrack(k,c)local A=k.animTracks[c]if not A then local o=k:getAnimationController()if not o then warn("\078\111 \097\110\105\109\097\116\105\111\110 \099\111\110\116\114\111\108\108\101\114 \119\104\101\110 \116\114\121\105\110\103 \116\111 \112\108\097\121 ",c)return nil end local b=AnimationsFolder:FindFirstChild(c)if not b then error(string.format("\078\111 \115\117\099\104 \097\110\105\109\097\116\105\111\110 \"\037\115\" ",tostring(c)))end A=o:LoadAnimation(b)k.animTracks[c]=A end return A end function BaseWeapon.reload(A,c,k)if not A.equipped or A.reloading or not A.canReload or A:getAmmoInWeapon()==A:getConfigValue("\065\109\109\111\067\097\112\097\099\105\116\121",30)then return false end if not IsServer then if A.player~=nil and A.player~=Players.LocalPlayer then return end;(A.weaponsSystem.getRemoteEvent("\087\101\097\112\111\110\082\101\108\111\097\100\082\101\113\117\101\115\116")):FireServer(A.instance)A:onReloaded(A.player)else A:onReloaded(c,k);(A.weaponsSystem.getRemoteEvent("\087\101\097\112\111\110\082\101\108\111\097\100\101\100")):FireAllClients(c,A.instance)end end function BaseWeapon.onReloaded(A,c,k)if k and c==Players.LocalPlayer then return end A.reloading=true A.canReload=false if not IsServer then local c=A:getConfigValue("\082\101\108\111\097\100\065\110\105\109\097\116\105\111\110","\082\105\102\108\101\082\101\108\111\097\100")if c then A.reloadTrack=A:getAnimTrack(c)if A.reloadTrack then A.reloadTrack:Play()end end A.curReloadSound=A:tryPlaySound("\082\101\108\111\097\100",nil)if A.curReloadSound then A.curReloadSound.Ended:Connect(function()A.curReloadSound=nil end)end end local o=A:getConfigValue("\082\101\108\111\097\100\084\105\109\101",2)local b=tick()if A.connections.reload~=nil then return end A.connections.reload=RunService.Heartbeat:Connect(function()if not A.reloading then if A.connections.reload then A.connections.reload:Disconnect()A.connections.reload=nil end end if tick()<b+o then return end if A.ammoInWeaponValue then A.ammoInWeaponValue.Value=A:getConfigValue("\065\109\109\111\067\097\112\097\099\105\116\121",30)end if A.connections.reload then A.connections.reload:Disconnect()A.connections.reload=nil end A.reloading=false A.canReload=false end)end function BaseWeapon.cancelReload(A,c,k)if not A.reloading then return end if k and c==Players.LocalPlayer then return end if not IsServer and(not k and c==Players.LocalPlayer)then(A.weaponsSystem.getRemoteEvent("\087\101\097\112\111\110\082\101\108\111\097\100\067\097\110\099\101\108\101\100")):FireServer(A.instance)elseif IsServer and k then(A.weaponsSystem.getRemoteEvent("\087\101\097\112\111\110\082\101\108\111\097\100\067\097\110\099\101\108\101\100")):FireAllClients(c,A.instance)end A.reloading=false A.canReload=true if not IsServer and(A.reloadTrack and A.reloadTrack.IsPlaying)then warn("\083\116\111\112\112\105\110\103 \114\101\108\111\097\100\084\114\097\099\107")A.reloadTrack:Stop()end if A.curReloadSound then A.curReloadSound:Stop()A.curReloadSound:Destroy()A.curReloadSound=nil end end function BaseWeapon.getAmmoInWeapon(c)if c.ammoInWeaponValue then return c.ammoInWeaponValue.Value end return 0 end function BaseWeapon.useAmmo(k,c)if k.ammoInWeaponValue then local A=math.min(c,k.ammoInWeaponValue.Value)k.ammoInWeaponValue.Value=k.ammoInWeaponValue.Value-A k.canReload=true return A else return 0 end end function BaseWeapon.renderCharge(c) end return BaseWeapon

function BaseWeapon:importConfiguration(config)
	if not config or not config:IsA("Configuration") then
		for _, child in pairs(config:GetChildren()) do
			if child:IsA("ValueBase") then
				local valueName = child.Name
				local newValue = child.Value
				local oldValue = self.configValues[valueName]
				self.configValues[valueName] = newValue
				self:onConfigValueChanged(valueName, newValue, oldValue)
			end
		end
	end
end

function BaseWeapon:setConfiguration(config)
	self:cleanupConnection("configChildAdded", "configChildRemoved")
	if not config or not config:IsA("Configuration") then
		return
	end

	for _, child in pairs(config:GetChildren()) do
		if child:IsA("ValueBase") then
			self:onConfigValueAdded(child)
		end
	end
	self.connections.configChildAdded = config.ChildAdded:Connect(function(child)
		if child:IsA("ValueBase") then
			self:onConfigValueAdded(child)
		end
	end)
	self.connections.configChildRemoved = config.ChildRemoved:Connect(function(child)
		if child:IsA("ValueBase") then
			self:onConfigValueRemoved(child)
		end
	end)
end

function BaseWeapon:onChildAdded(child)
	if child:IsA("Configuration") then
		self:setConfiguration(child)
	end
end

function BaseWeapon:onChildRemoved(child)
	if child:IsA("Configuration") then
		self:setConfiguration(nil)
	end
end

function BaseWeapon:onConfigValueChanged(valueName, newValue, oldValue)

end

function BaseWeapon:onRenderStepped(dt)

end

function BaseWeapon:onStepped(dt)

end

function BaseWeapon:getAnimationController()
	if self.animController then
		if not self.instanceIsTool or (self.animController.Parent and self.animController.Parent:IsAncestorOf(self.instance)) then
			return self.animController
		end
	end

	self:setAnimationController(nil)

	if self.instanceIsTool then
		local humanoid = IsServer and self.instance.Parent:FindFirstChildOfClass("Humanoid") or self.instance.Parent:WaitForChild("Humanoid", math.huge)
		local animController = nil
		if not humanoid then
			animController = self.instance.Parent:FindFirstChildOfClass("AnimationController")
		end

		self:setAnimationController(humanoid or animController)
		return self.animController
	end
end

function BaseWeapon:setAnimationController(animController)
	if animController == self.animController then
		return
	end
	self:stopAnimations()
	self.animController = animController
end

function BaseWeapon:stopAnimations()
	for _, track in pairs(self.animTracks) do
		if track.IsPlaying then
			track:Stop()
		end
	end
	self.animTracks = {}
end

function BaseWeapon:getAnimTrack(key)
	local track = self.animTracks[key]
	if not track then
		local animController = self:getAnimationController()
		if not animController then
			warn("No animation controller when trying to play ", key)
			return nil
		end

		local animation = AnimationsFolder:FindFirstChild(key)
		if not animation then
			error(string.format("No such animation \"%s\" ", tostring(key)))
		end

		track = animController:LoadAnimation(animation)
		self.animTracks[key] = track
	end

	return track
end

function BaseWeapon:reload(player, fromNetwork)
	if
		not self.equipped or
		self.reloading or
		not self.canReload or
		self:getAmmoInWeapon() == self:getConfigValue("AmmoCapacity", 30)
	then
		return false
	end

	if not IsServer then
		if self.player ~= nil and self.player ~= Players.LocalPlayer then
			return
		end
		self.weaponsSystem.getRemoteEvent("WeaponReloadRequest"):FireServer(self.instance)
		self:onReloaded(self.player)
	else
		self:onReloaded(player, fromNetwork)
		self.weaponsSystem.getRemoteEvent("WeaponReloaded"):FireAllClients(player, self.instance)
	end
end

function BaseWeapon:onReloaded(player, fromNetwork)
	if fromNetwork and player == Players.LocalPlayer then -- make sure localplayer doesn't reload twice
		return
	end

	self.reloading = true
	self.canReload = false

	-- Play reload animation and sound
	if not IsServer then
		local reloadTrackKey = self:getConfigValue("ReloadAnimation", "RifleReload")
		if reloadTrackKey then
			self.reloadTrack = self:getAnimTrack(reloadTrackKey)
			if self.reloadTrack then
				self.reloadTrack:Play()
			end
		end

		self.curReloadSound = self:tryPlaySound("Reload", nil)
		if self.curReloadSound then
			self.curReloadSound.Ended:Connect(function()
				self.curReloadSound = nil
			end)
		end
	end

	local reloadTime = self:getConfigValue("ReloadTime", 2)
	local startTime = tick()

	if self.connections.reload ~= nil then -- this prevents an endless ammo bug
		return
	end
	self.connections.reload = RunService.Heartbeat:Connect(function()
		-- Stop trying to reload if the player unequipped this weapon or reloading was canceled some other way
		if not self.reloading then
			if self.connections.reload then
				self.connections.reload:Disconnect()
				self.connections.reload = nil
			end
		end

		-- Wait until gun finishes reloading
		if tick() < startTime + reloadTime then
			return
		end

		-- Add ammo to weapon
		if self.ammoInWeaponValue then
			self.ammoInWeaponValue.Value = self:getConfigValue("AmmoCapacity", 30)
		end

		if self.connections.reload then
			self.connections.reload:Disconnect()
			self.connections.reload = nil
		end

		self.reloading = false
		self.canReload = false
	end)
end

function BaseWeapon:cancelReload(player, fromNetwork)
	if not self.reloading then
		return
	end
	if fromNetwork and player == Players.LocalPlayer then
		return
	end

	if not IsServer and not fromNetwork and player == Players.LocalPlayer then
		self.weaponsSystem.getRemoteEvent("WeaponReloadCanceled"):FireServer(self.instance)
	elseif IsServer and fromNetwork then
		self.weaponsSystem.getRemoteEvent("WeaponReloadCanceled"):FireAllClients(player, self.instance)
	end

	self.reloading = false
	self.canReload = true

	if not IsServer and self.reloadTrack and self.reloadTrack.IsPlaying then
		warn("Stopping reloadTrack")
		self.reloadTrack:Stop()
	end
	if self.curReloadSound then
		self.curReloadSound:Stop()
		self.curReloadSound:Destroy()
		self.curReloadSound = nil
	end
end

function BaseWeapon:getAmmoInWeapon()
	if self.ammoInWeaponValue then
		return self.ammoInWeaponValue.Value
	end
	return 0
end

function BaseWeapon:useAmmo(amount)
	if self.ammoInWeaponValue then
		local ammoUsed = math.min(amount, self.ammoInWeaponValue.Value)
		self.ammoInWeaponValue.Value = self.ammoInWeaponValue.Value - ammoUsed
		self.canReload = true
		return ammoUsed
	else
		return 0
	end
end

function BaseWeapon:renderCharge()

end

return BaseWeapon
