Table being nil while it print

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? I wanna use A fire module
  2. What is the issue? So it used a table as matinfo = materials[part.Material] and when I print mat info it print {…} So its a table inside is some property ex [BurnTemp] = 100 but the error at
local burning = info.Temperature >= matInfo.IgnitionTemp and info.PercentBurned < 100

And at the end it print nil,So why is that?

  1. What solutions have you tried so far? Ive tryed debugging and looked here but the solution to my problem is not to be found
All the script from someone 400 line
--Fire simulation script
--Dominik Wandernoth 11/2015

--Global 'constants'
local doDebug = script.Configuration.DoDebug.Value
local ambientTemp = script.Configuration.AmbientTemperature.Value
local convectionMultiplier = 1/script.Configuration.ConvectionSpeed.Value
local conductionMultiplierTouching = 1/script.Configuration.ConductionSpeedTouch.Value
local conductionMuldiplierConnected = 1/script.Configuration.ConductionSpeedWelded.Value
local materialStrength = script.Configuration.MaterialStrength.Value
local damageCharacters = script.Configuration.CharactersTakeDamage.Value
local charDamageThreshold = script.Configuration.CharacterDamageThreshold.Value
local charDamageMultiplier = script.Configuration.CharacterDamageMultiplier.Value
local recalcChance = script.Configuration.RecalcChance.Value
local breakAtPercentBurned = script.Configuration.BreakAtPercentBurned.Value
local deltaTVoxelTransferThreshhold = script.Configuration.DeltaTVoxelTransferThreshhold.Value
local voxelCenterTemperatureWeight = script.Configuration.VoxelCenterTemperatureWeight.Value
local voxelUpTemperatureWeight = script.Configuration.VoxelUpTemperatureWeight.Value
local voxelDownTemperatureWeight = script.Configuration.VoxelDownTemperatureWeight.Value
local voxelSideTemperatureWeight = script.Configuration.VoxelSideTemperatureWeight.Value
local deltaTPartTransferThreshhold = script.Configuration.DeltaTPartTransferThreshhold.Value
local tempBeginGlow = script.Configuration.TempBeginGlow.Value
local tempToMaxGlow = script.Configuration.TempToMaxGlow.Value

--Allow changing them at runtime
script.Configuration.DoDebug.Changed:connect(function() doDebug = script.Configuration.DoDebug.Value end)
script.Configuration.AmbientTemperature.Changed:connect(function() ambientTemp = script.Configuration.AmbientTemperature.Value end)
script.Configuration.ConvectionSpeed.Changed:connect(function() convectionMultiplier = 1/script.Configuration.ConvectionSpeed.Value end)
script.Configuration.ConductionSpeedTouch.Changed:connect(function() conductionMultiplierTouching = 1/script.Configuration.ConductionSpeedTouch.Value end)
script.Configuration.ConductionSpeedWelded.Changed:connect(function() conductionMuldiplierConnected = 1/script.Configuration.ConductionSpeedWelded.Value end)
script.Configuration.MaterialStrength.Changed:connect(function() materialStrength = script.Configuration.MaterialStrength.Value end)
script.Configuration.CharactersTakeDamage.Changed:connect(function() damageCharacters = script.Configuration.CharactersTakeDamage.Value end)
script.Configuration.CharacterDamageThreshold.Changed:connect(function() charDamageThreshold = script.Configuration.CharacterDamageThreshold.Value end)
script.Configuration.CharacterDamageMultiplier.Changed:connect(function() charDamageMultiplier = script.Configuration.CharacterDamageMultiplier.Value end)
script.Configuration.RecalcChance.Changed:connect(function() recalcChance = script.Configuration.RecalcChance.Value end)
script.Configuration.BreakAtPercentBurned.Changed:connect(function() breakAtPercentBurned = script.Configuration.BreakAtPercentBurned.Value end)
script.Configuration.DeltaTVoxelTransferThreshhold.Changed:connect(function() deltaTVoxelTransferThreshhold = script.Configuration.DeltaTVoxelTransferThreshhold.Value end)
script.Configuration.VoxelCenterTemperatureWeight.Changed:connect(function() voxelCenterTemperatureWeight = script.Configuration.VoxelCenterTemperatureWeight.Value end)
script.Configuration.VoxelUpTemperatureWeight.Changed:connect(function() voxelUpTemperatureWeight = script.Configuration.VoxelUpTemperatureWeight.Value end)
script.Configuration.VoxelDownTemperatureWeight.Changed:connect(function() voxelDownTemperatureWeight = script.Configuration.VoxelDownTemperatureWeight.Value end)
script.Configuration.VoxelSideTemperatureWeight.Changed:connect(function() voxelSideTemperatureWeight = script.Configuration.VoxelSideTemperatureWeight.Value end)
script.Configuration.DeltaTPartTransferThreshhold.Changed:connect(function() deltaTPartTransferThreshhold = script.Configuration.DeltaTPartTransferThreshhold.Value end)
script.Configuration.TempBeginGlow.Changed:connect(function() tempBeginGlow = script.Configuration.TempBeginGlow.Value end)
script.Configuration.TempToMaxGlow.Changed:connect(function() tempToMaxGlow = script.Configuration.TempToMaxGlow.Value end)

--Perf upgrade (This one is for free so why not)
local max = math.max
local min = math.min
local abs = math.abs
local random = math.random
local pow = math.pow
local vec3 = Vector3.new
local newcf = CFrame.new

--Material properties
--Helper function to load configurations
function loadConfig(folder)
	local out = {}
	out.BurnTemp = folder.BurnTemp.Value
	out.IgnitionTemp = (folder.IsFlammable.Value and folder.IgnitionTemp.Value or math.huge)
	out.SpecificHeat = folder.SpecificHeat.Value
	
	return out
end

--Although we're not going for absolute realism, we do want the materials to compare
--to eachother in a realistic way. Therefore, the following values will be researched.
--[[Sources:
	http://www.tcforensic.com.au/docs/article10.html
	http://www.engineeringtoolbox.com/specific-heat-solids-d_154.html
	http://www.northseaplastics.com/documents/abs_safety_datasheet.pdf
--]]
local materials = {
	[Enum.Material.Plastic] 		= loadConfig(script.Configuration.Materials.Plastic);
	[Enum.Material.SmoothPlastic] 	= loadConfig(script.Configuration.Materials.SmoothPlastic);
	[Enum.Material.Wood] 			= loadConfig(script.Configuration.Materials.Wood);
	[Enum.Material.WoodPlanks] 		= loadConfig(script.Configuration.Materials.WoodPlanks);
	[Enum.Material.Metal] 			= loadConfig(script.Configuration.Materials.Metal);
	[Enum.Material.DiamondPlate]	= loadConfig(script.Configuration.Materials.DiamondPlate);
	[Enum.Material.CorrodedMetal] 	= loadConfig(script.Configuration.Materials.CorrodedMetal);
	[Enum.Material.Foil] 			= loadConfig(script.Configuration.Materials.Foil);
	[Enum.Material.Sand] 			= loadConfig(script.Configuration.Materials.Sand);
	[Enum.Material.Neon] 			= loadConfig(script.Configuration.Materials.Neon);
	[Enum.Material.Ice] 			= loadConfig(script.Configuration.Materials.Ice);
	[Enum.Material.Fabric] 			= loadConfig(script.Configuration.Materials.Fabric);
	[Enum.Material.Grass] 			= loadConfig(script.Configuration.Materials.Grass);
	[Enum.Material.Granite] 		= loadConfig(script.Configuration.Materials.Granite);
	[Enum.Material.Slate] 			= loadConfig(script.Configuration.Materials.Slate);
	[Enum.Material.Pebble]	 		= loadConfig(script.Configuration.Materials.Pebble);
	[Enum.Material.Concrete] 		= loadConfig(script.Configuration.Materials.Concrete);
	[Enum.Material.Cobblestone] 	= loadConfig(script.Configuration.Materials.Cobblestone);
	[Enum.Material.Marble] 			= loadConfig(script.Configuration.Materials.Marble);
	[Enum.Material.Brick] 			= loadConfig(script.Configuration.Materials.Brick);
}

--Performance ugly fix
local lastthrottle = tick()
function throttle(tlimit,name)
	if (tlimit < tick()-lastthrottle) then
		if (doDebug) then print(name .. " throttled at " .. math.floor((tick()-lastthrottle)*100e3)/100 .. " ms") end
		wait()
		lastthrottle = tick()
	end
end

--Temperature voxel system
local voxels = {}
local recalcVoxels = {}

function defaultVoxel()
	return {
		Temperature = ambientTemp;
		DoRecalc = false;
	}
end

local function getVoxel(x,y,z)
	if (voxels[x] == nil or voxels[x][y] == nil or voxels[x][y][z] == nil) then return defaultVoxel() end
	return voxels[x][y][z]
end

local function setVoxel(x,y,z,voxel)
	if (voxels[x] == nil) then voxels[x] = {} end
	if (voxels[x][y] == nil) then voxels[x][y] = {} end
	voxels[x][y][z] = voxel
end

local function registerVoxelUpdate(x,y,z,temp,weight)
	local index = (x .. "," .. y .. "," .. z)
	
	local v = getVoxel(x,y,z)
	v.DoRecalc = true
	setVoxel(x,y,z,v)
	
	if (recalcVoxels[index]) then
		table.insert(recalcVoxels[index][2],{temp,weight})
	else
		recalcVoxels[index] = {Vector3.new(x,y,z),{{temp,weight}}}
	end
end

function voxelTick()
	local requiresRerun = false
	local ticks = 0
	local t = tick()
	for key,value in pairs(recalcVoxels) do
		ticks = ticks + 1
		local temp,wsum = 0,0
		for _,v in pairs(value[2]) do
			temp,wsum = temp+v[1]*v[2],wsum+v[2]
		end
		
		local pos = value[1]
		local voxel = getVoxel(pos.x,pos.y,pos.z)
		temp = temp + voxel.Temperature * voxelCenterTemperatureWeight
		wsum = wsum + voxelCenterTemperatureWeight
		
		local voxUp = getVoxel(pos.x,pos.y+1,pos.z)
		local voxDn = getVoxel(pos.x,pos.y-1,pos.z)
		local voxLt = getVoxel(pos.x-1,pos.y,pos.z)
		local voxRt = getVoxel(pos.x+1,pos.y,pos.z)
		local voxFt = getVoxel(pos.x,pos.y,pos.z-1)
		local voxBk = getVoxel(pos.x,pos.y,pos.z+1)
		
		temp = temp
			+ voxUp.Temperature * voxelUpTemperatureWeight
			+ voxDn.Temperature * voxelDownTemperatureWeight
			+ voxLt.Temperature * voxelSideTemperatureWeight
			+ voxRt.Temperature * voxelSideTemperatureWeight
			+ voxFt.Temperature * voxelSideTemperatureWeight
			+ voxBk.Temperature * voxelSideTemperatureWeight
		wsum = wsum + 4*voxelSideTemperatureWeight + voxelDownTemperatureWeight + voxelUpTemperatureWeight
		
		voxel.Temperature = temp/wsum
		voxel.DoRerun = voxel.Temperature > ambientTemp+10
		
		if (abs(voxUp.Temperature - voxel.Temperature) > deltaTVoxelTransferThreshhold or math.random(0,100) < recalcChance) then registerVoxelUpdate(pos.x,pos.y+1,pos.z,0,0) end
		if (abs(voxDn.Temperature - voxel.Temperature) > deltaTVoxelTransferThreshhold or math.random(0,100) < recalcChance) then registerVoxelUpdate(pos.x,pos.y-1,pos.z,0,0) end
		if (abs(voxLt.Temperature - voxel.Temperature) > deltaTVoxelTransferThreshhold or math.random(0,100) < recalcChance) then registerVoxelUpdate(pos.x-1,pos.y,pos.z,0,0) end
		if (abs(voxRt.Temperature - voxel.Temperature) > deltaTVoxelTransferThreshhold or math.random(0,100) < recalcChance) then registerVoxelUpdate(pos.x+1,pos.y,pos.z,0,0) end
		if (abs(voxFt.Temperature - voxel.Temperature) > deltaTVoxelTransferThreshhold or math.random(0,100) < recalcChance) then registerVoxelUpdate(pos.x,pos.y,pos.z-1,0,0) end
		if (abs(voxBk.Temperature - voxel.Temperature) > deltaTVoxelTransferThreshhold or math.random(0,100) < recalcChance) then registerVoxelUpdate(pos.x,pos.y,pos.z+1,0,0) end
		
		if (not voxel.DoRerun) then
			recalcVoxels[key] = nil
		else
			requiresRerun = true
			recalcVoxels[key][2] = {}
		end
		
		throttle(0.05,"Voxel updates")
	end
	
	return requiresRerun,ticks
end

--Buncha fancy math to check collisions
local function checkVoxelVsOBB(P,CF,S)
	P=P*4
	S=S/2
	local sx,sy,sz=S.X,S.Y,S.Z
	local x,y,z,a,b,c,d,e,f,g,h,i = CF:components()
	local x1,y1,z1=x+( sx*a+sy*b+sz*c),y+( sx*d+sy*e+sz*f),z+( sx*g+sy*h+sz*i)
	local x2,y2,z2=x+( sx*a+sy*b-sz*c),y+( sx*d+sy*e-sz*f),z+( sx*g+sy*h-sz*i)
	local x3,y3,z3=x+( sx*a-sy*b+sz*c),y+( sx*d-sy*e+sz*f),z+( sx*g-sy*h+sz*i)
	local x4,y4,z4=x+( sx*a-sy*b-sz*c),y+( sx*d-sy*e-sz*f),z+( sx*g-sy*h-sz*i)
	local x5,y5,z5=x+(-sx*a+sy*b+sz*c),y+(-sx*d+sy*e+sz*f),z+(-sx*g+sy*h+sz*i)
	local x6,y6,z6=x+(-sx*a+sy*b-sz*c),y+(-sx*d+sy*e-sz*f),z+(-sx*g+sy*h-sz*i)
	local x7,y7,z7=x+(-sx*a-sy*b+sz*c),y+(-sx*d-sy*e+sz*f),z+(-sx*g-sy*h+sz*i)
	local x8,y8,z8=x+(-sx*a-sy*b-sz*c),y+(-sx*d-sy*e-sz*f),z+(-sx*g-sy*h-sz*i)
	local ux,uy,uz=max(x1,x2,x3,x4,x5,x6,x7,x8),max(y1,y2,y3,y4,y5,y6,y7,y8),max(z1,z2,z3,z4,z5,z6,z7,z8)
	local lx,ly,lz=min(x1,x2,x3,x4,x5,x6,x7,x8),min(y1,y2,y3,y4,y5,y6,y7,y8),min(z1,z2,z3,z4,z5,z6,z7,z8)
	local llx,lly,llz,ulx,uly,ulz=P.X-2,P.Y-2,P.Z-2,P.X+2,P.Y+2,P.Z+2
	if(lx>=llx and lx<=ulx)or(ux>=llx and ux<=ulx)or(ux>=ulx and lx<=llx)then 
	if(ly>=lly and ly<=uly)or(uy>=lly and uy<=uly)or(uy>=uly and ly<=lly)then 
	if(lz>=llz and lz<=ulz)or(uz>=llz and uz<=ulz)or(uz>=ulz and lz<=llz)then 
		local x,y,z,a,b,c,d,e,f,g,h,i = CF:toObjectSpace(newcf(P)):components()
		local x1,y1,z1=x+( 2*a+2*b+2*c),y+( 2*d+2*e+2*f),z+( 2*g+2*h+2*i)
		local x2,y2,z2=x+( 2*a+2*b-2*c),y+( 2*d+2*e-2*f),z+( 2*g+2*h-2*i)
		local x3,y3,z3=x+( 2*a-2*b+2*c),y+( 2*d-2*e+2*f),z+( 2*g-2*h+2*i)
		local x4,y4,z4=x+( 2*a-2*b-2*c),y+( 2*d-2*e-2*f),z+( 2*g-2*h-2*i)
		local x5,y5,z5=x+(-2*a+2*b+2*c),y+(-2*d+2*e+2*f),z+(-2*g+2*h+2*i)
		local x6,y6,z6=x+(-2*a+2*b-2*c),y+(-2*d+2*e-2*f),z+(-2*g+2*h-2*i)
		local x7,y7,z7=x+(-2*a-2*b+2*c),y+(-2*d-2*e+2*f),z+(-2*g-2*h+2*i)
		local x8,y8,z8=x+(-2*a-2*b-2*c),y+(-2*d-2*e-2*f),z+(-2*g-2*h-2*i)
		local ux,uy,uz=max(x1,x2,x3,x4,x5,x6,x7,x8),max(y1,y2,y3,y4,y5,y6,y7,y8),max(z1,z2,z3,z4,z5,z6,z7,z8)
		local lx,ly,lz=min(x1,x2,x3,x4,x5,x6,x7,x8),min(y1,y2,y3,y4,y5,y6,y7,y8),min(z1,z2,z3,z4,z5,z6,z7,z8)
		local llx,lly,llz,ulx,uly,ulz=-S.X,-S.Y,-S.Z,S.X,S.Y,S.Z		
		if(lx>=llx and lx<=ulx)or(ux>=llx and ux<=ulx)or(ux>=ulx and lx<=llx)then 
		if(ly>=lly and ly<=uly)or(uy>=lly and uy<=uly)or(uy>=uly and ly<=lly)then 
		if(lz>=llz and lz<=ulz)or(uz>=llz and uz<=ulz)or(uz>=ulz and lz<=llz)then 
			local sx,sy,sz = min(ux,ulx)-max(lx,llx),min(uy,uly)-max(ly,lly),min(uz,ulz)-max(lz,llz)
			return true,sx*sy*sz
		end end end 
		return false,0
	end end end 
	return false,0
end

local function checkOBBVsOBB(CF1,S1,CF2,S2)
	S1 = S1 / 2
	S2 = S2 / 2
	local sx,sy,sz=S2.X,S2.Y,S2.Z
	local x,y,z,a,b,c,d,e,f,g,h,i = CF1:toObjectSpace(CF2):components()
	local x1,y1,z1=x+( sx*a+sy*b+sz*c),y+( sx*d+sy*e+sz*f),z+( sx*g+sy*h+sz*i)
	local x2,y2,z2=x+( sx*a+sy*b-sz*c),y+( sx*d+sy*e-sz*f),z+( sx*g+sy*h-sz*i)
	local x3,y3,z3=x+( sx*a-sy*b+sz*c),y+( sx*d-sy*e+sz*f),z+( sx*g-sy*h+sz*i)
	local x4,y4,z4=x+( sx*a-sy*b-sz*c),y+( sx*d-sy*e-sz*f),z+( sx*g-sy*h-sz*i)
	local x5,y5,z5=x+(-sx*a+sy*b+sz*c),y+(-sx*d+sy*e+sz*f),z+(-sx*g+sy*h+sz*i)
	local x6,y6,z6=x+(-sx*a+sy*b-sz*c),y+(-sx*d+sy*e-sz*f),z+(-sx*g+sy*h-sz*i)
	local x7,y7,z7=x+(-sx*a-sy*b+sz*c),y+(-sx*d-sy*e+sz*f),z+(-sx*g-sy*h+sz*i)
	local x8,y8,z8=x+(-sx*a-sy*b-sz*c),y+(-sx*d-sy*e-sz*f),z+(-sx*g-sy*h-sz*i)
	local ux,uy,uz=max(x1,x2,x3,x4,x5,x6,x7,x8),max(y1,y2,y3,y4,y5,y6,y7,y8),max(z1,z2,z3,z4,z5,z6,z7,z8)
	local lx,ly,lz=min(x1,x2,x3,x4,x5,x6,x7,x8),min(y1,y2,y3,y4,y5,y6,y7,y8),min(z1,z2,z3,z4,z5,z6,z7,z8)
	local llx,lly,llz,ulx,uly,ulz=-S1.X,-S1.Y,-S1.Z,S1.X,S1.Y,S1.Z
	if(lx>=llx and lx<=ulx)or(ux>=llx and ux<=ulx)or(ux>=ulx and lx<=llx)then 
	if(ly>=lly and ly<=uly)or(uy>=lly and uy<=uly)or(uy>=uly and ly<=lly)then 
	if(lz>=llz and lz<=ulz)or(uz>=llz and uz<=ulz)or(uz>=ulz and lz<=llz)then 
		local x,y,z,a,b,c,d,e,f,g,h,i = CF2:toObjectSpace(CF1):components()
		local x1,y1,z1=x+( sx*a+sy*b+sz*c),y+( sx*d+sy*e+sz*f),z+( sx*g+sy*h+sz*i)
		local x2,y2,z2=x+( sx*a+sy*b-sz*c),y+( sx*d+sy*e-sz*f),z+( sx*g+sy*h-sz*i)
		local x3,y3,z3=x+( sx*a-sy*b+sz*c),y+( sx*d-sy*e+sz*f),z+( sx*g-sy*h+sz*i)
		local x4,y4,z4=x+( sx*a-sy*b-sz*c),y+( sx*d-sy*e-sz*f),z+( sx*g-sy*h-sz*i)
		local x5,y5,z5=x+(-sx*a+sy*b+sz*c),y+(-sx*d+sy*e+sz*f),z+(-sx*g+sy*h+sz*i)
		local x6,y6,z6=x+(-sx*a+sy*b-sz*c),y+(-sx*d+sy*e-sz*f),z+(-sx*g+sy*h-sz*i)
		local x7,y7,z7=x+(-sx*a-sy*b+sz*c),y+(-sx*d-sy*e+sz*f),z+(-sx*g-sy*h+sz*i)
		local x8,y8,z8=x+(-sx*a-sy*b-sz*c),y+(-sx*d-sy*e-sz*f),z+(-sx*g-sy*h-sz*i)
		local ux,uy,uz=max(x1,x2,x3,x4,x5,x6,x7,x8),max(y1,y2,y3,y4,y5,y6,y7,y8),max(z1,z2,z3,z4,z5,z6,z7,z8)
		local lx,ly,lz=min(x1,x2,x3,x4,x5,x6,x7,x8),min(y1,y2,y3,y4,y5,y6,y7,y8),min(z1,z2,z3,z4,z5,z6,z7,z8)
		local llx,lly,llz,ulx,uly,ulz=-S2.X,-S2.Y,-S2.Z,S2.X,S2.Y,S2.Z	
		if(lx>=llx and lx<=ulx)or(ux>=llx and ux<=ulx)or(ux>=ulx and lx<=llx)then 
		if(ly>=lly and ly<=uly)or(uy>=lly and uy<=uly)or(uy>=uly and ly<=lly)then 
		if(lz>=llz and lz<=ulz)or(uz>=llz and uz<=ulz)or(uz>=ulz and lz<=llz)then 
			local sx,sy,sz = min(ux,ulx)-max(lx,llx),min(uy,uly)-max(ly,lly),min(uz,ulz)-max(lz,llz)
			return true,sx*sy*sz
		end end end 
		return false,0
	end end end 
	return false,0
end

local function getVoxelIntersects(part)
	local s = part.Size
	local dim = vec3(max(s.x,4),max(s.y,4),max(s.z,4))/2
	local intersections = {}
	local sum = 0
	for x = -dim.x,dim.x,4 do
		for y = -dim.y,dim.y,4 do
			for z = -dim.z,dim.z,4 do
				local p = part.CFrame * newcf(x,y,z)
				p = vec3(math.floor(p.x/4 + 0.5),math.floor(p.y/4 + 0.5),math.floor(p.z/4 + 0.5))
				local c,s = checkVoxelVsOBB(p,part.CFrame,part.Size)
				if (c) then
					intersections[p] = s
					sum = sum + s
				end
			end
		end
	end
	for k,v in pairs(intersections) do intersections[k] = v/sum end
	return intersections
end

--Template voxel
--Voxel = {
--	Temperature = 20;
--	DoRecalc = false;
--}


--Is the part in water?
local function isSubmerged(part)
	local s = math.max(2,part.Size.magnitude/2)
	local region = Region3.new(part.Position-Vector3.new(1,1,1)*s,part.Position+Vector3.new(1,1,1)*s)
	region = region:ExpandToGrid(4)
	local material, occupancy = game.Workspace.Terrain:ReadVoxels(region, 4)
	local size = material.Size
	for x = 1, size.X do
		for y = 1, size.Y do
			for z = 1, size.Z do
				if (material[x][y][z] == Enum.Material.Water and occupancy[x][y][z] > 0.5) then
					return true
				end
			end
		end
	end
	return false
end

--Temperature to color
--http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
--These "magic numbers" come from research I've done at the above website; In fact, this is their code converted into Lua.
function tempToColor3(tmpKelvin)
	--Temperature must fall between 1000 and 40000 degrees
	if (tmpKelvin < 1000) then tmpKelvin = 1000 end
	if (tmpKelvin > 40000) then tmpKelvin = 40000 end
	
	--All calculations require tmpKelvin / 100, so only do the conversion once
	tmpKelvin = tmpKelvin / 100
	
	--Calculate each color in turn
	
	local r,g,b = 0,0,0
	
	--First: red
	if (tmpKelvin <= 66) then
		r = 255
	else
		--Note: the R-squared value for this approximation is .988
		local tmpCalc = tmpKelvin - 60
		tmpCalc = 329.698727446 * (tmpCalc ^ -0.1332047592)
		r = tmpCalc
		if (r < 0) then r = 0 end
		if (r > 255) then r = 255 end
	end
	
	--Second: green
	if (tmpKelvin <= 66) then
		--Note: the R-squared value for this approximation is .996
		local tmpCalc = tmpKelvin
		tmpCalc = 99.4708025861 * math.log(tmpCalc) - 161.1195681661
		g = tmpCalc
		if (g < 0) then g = 0 end
		if (g > 255) then g = 255 end
	else
		--Note: the R-squared value for this approximation is .987
		local tmpCalc = tmpKelvin - 60
		tmpCalc = 288.1221695283 * (tmpCalc ^ -0.0755148492)
		g = tmpCalc
		if (g < 0) then g = 0 end
		if (g > 255) then g = 255 end
	end
	
	--Third: blue
	if (tmpKelvin >= 66) then
		b = 255
	elseif (tmpKelvin <= 19) then
		b = 0
	else
		--Note: the R-squared value for this approximation is .998
		local tmpCalc = tmpKelvin - 10
		tmpCalc = 138.5177312231 * math.log(tmpCalc) - 305.0447927307
		
		b = tmpCalc
		if (b < 0) then b = 0 end
		if (b > 255) then b = 255 end
	end
	return Color3.new(r/255,g/255,b/255)
end

--Register all parts 
parts = {}

function registerPart(dir)
	local glowPart = dir:clone()
	glowPart.Material = "Neon"
	glowPart.Size = dir.Size + vec3(0.1,0.1,0.1) --Glow part should be slightly bigger to avoid Z-Fighting
	glowPart.Transparency = 1
	glowPart.Name = "HeatGlow"
	glowPart.CanCollide = false
	glowPart.Parent = dir
	
	glowPart:ClearAllChildren()
	
	local glowLight = Instance.new("PointLight")
	glowLight.Brightness = 0
	glowLight.Color = Color3.new(1,0,0)
	glowLight.Parent = dir
	
	local w = Instance.new("Weld")
	w.Part0 = dir
	w.Part1 = glowPart
	w.Parent = dir
	
	Instance.new("BlockMesh",glowPart)
	local fireParticles = script.FireParticles:clone()
	fireParticles.Parent = dir
	
	parts[dir] = { 
		Temperature = ambientTemp; 
		Phase = "NotInit"; 
		DoRecalc = true; 
		Fire = fireParticles; 
		Light = glowLight;
		PercentBurned = 0; 
		Glow = glowPart;
	}
end
function registerParts(dir)
	if (dir:IsA("BasePart") and not dir:IsA("Terrain") and parts[dir] == nil and dir.Size.Magnitude < 100) then
		registerPart(dir)
	end
	
	for _,part in pairs(dir:children()) do
		if (part.Name ~= "HeatGlow") then registerParts(part) end
	end
	
	throttle(0.05,"Part registration")
end

function doCalc()
	local requiresRerun = false
	local calcs = 0
	for part,info in pairs(parts) do
		if (info.DoRecalc or random(0,100) < recalcChance) then --Randomly choose to recalculate anyways, based on the config option
			calcs = calcs + 1
			local markForDelete = false
			
			--First, get the material properties table
			local matInfo = materials[part.Material]
			
			--Average ambient temperature & Setting voxel temp
			local intersects = getVoxelIntersects(part)
			local temp = 0
			for k,v in pairs(intersects) do 
				local voxel = getVoxel(k.x,k.y,k.z)
				temp = temp + v*voxel.Temperature
			end
			
			--Let's deal with burning/not burning first
			--if matInfo == nil then return end
			print(matInfo)
			local burning = info.Temperature >= matInfo.IgnitionTemp and info.PercentBurned < 100
			
			--Being submerged might change this
			if (isSubmerged(part)) then
				local s = part.Size
				local surfaceArea = 2*(s.y*s.z+s.x*s.z+s.x*s.y)
				local delta = (temp - info.Temperature) / max((part:GetMass() * matInfo.SpecificHeat * convectionMultiplier * 3)/surfaceArea,1)
				info.Temperature = info.Temperature + delta
			end
			
			if (burning) then
				local flameTemp = matInfo.BurnTemp
				local s = part.Size
				local surfaceArea = 2*(s.y*s.z+s.x*s.z+s.x*s.y)
				local delta = (flameTemp - info.Temperature) / max((part:GetMass() * matInfo.SpecificHeat * convectionMultiplier)/surfaceArea,1)
				info.Temperature = info.Temperature + delta
				
				local colorTemp = max(flameTemp,info.Temperature)*2
				local color1,color2 = tempToColor3(colorTemp),tempToColor3(colorTemp/2)
				info.Fire.Enabled = true
				--info.Fire.Size = part.Size.magnitude*2
				info.Fire.Color = ColorSequence.new(color1,color2)
				info.Fire.Acceleration = Vector3.new(0,info.Temperature/100,0)
				
				local volume = s.x*s.y*s.z
				
				info.PercentBurned = info.PercentBurned + (info.Temperature / matInfo.IgnitionTemp) * (surfaceArea/volume) * (1/materialStrength)
				
				if (info.PercentBurned > breakAtPercentBurned and not info.Burnt) then
					part.BrickColor = BrickColor.new("Really black")
					part:breakJoints()
					
					--Unions like to force color, so we'll tell it to turn black anyways
					if (part:IsA("UnionOperation")) then
						part.UsePartColor = true
					end
					
					info.Burnt = true
					
					local w = Instance.new("Weld")
					w.Part0 = part
					w.Part1 = part:findFirstChild("HeatGlow")
					w.Parent = w.Part0
				end
				if (info.PercentBurned >= 100) then markForDelete = true end
				
				info.Glow.Material = Enum.Material.Neon
				info.Glow.Transparency = 1-min(max(0,(info.Temperature-tempBeginGlow)/tempToMaxGlow),1)
				info.Glow.Color = tempToColor3(info.Temperature*2)
				
				info.Light.Brightness = min(max(0,(info.Temperature-tempBeginGlow)/tempToMaxGlow),1)+1
				info.Light.Color = color1
				
				info.DoRecalc = true
				requiresRerun = true
			else
				--Get to ambient temperature
				local s = part.Size
				local surfaceArea = 2*(s.y*s.z+s.x*s.z+s.x*s.y)
				local delta = (temp - info.Temperature) / max((part:GetMass() * matInfo.SpecificHeat * convectionMultiplier)/surfaceArea,1)
				info.Temperature = info.Temperature + delta
				
				info.Fire.Enabled = false
				
				--0 is freezing point. Ice.
				if (info.Temperature > 0) then
					info.Glow.Material = Enum.Material.Neon
					info.Glow.Transparency = 1-min(max(0,(info.Temperature-tempBeginGlow)/tempToMaxGlow),1)
					info.Glow.Color = tempToColor3(info.Temperature*2)
				else
					info.Glow.Material = Enum.Material.Ice
					info.Glow.Transparency = 1+max(info.Temperature/100,-1)
					info.Glow.BrickColor = BrickColor.new("Pastel blue")
				end
				
				info.Light.Brightness = min(max(0,(info.Temperature-tempBeginGlow)/tempToMaxGlow),1)
				info.Light.Color = tempToColor3(info.Temperature*2)
				
				local rec = math.abs(ambientTemp - info.Temperature) > deltaTPartTransferThreshhold or math.abs(temp - info.Temperature) > deltaTPartTransferThreshhold
				info.DoRecalc = rec
				requiresRerun = requiresRerun or rec
			end
			
			for k,v in pairs(intersects) do 
				registerVoxelUpdate(k.x,k.y,k.z,info.Temperature,v)
				
				--
				registerVoxelUpdate(k.x,k.y+1,k.z,info.Temperature,v)
				registerVoxelUpdate(k.x+1,k.y,k.z,info.Temperature,v)
				registerVoxelUpdate(k.x-1,k.y,k.z,info.Temperature,v)
				registerVoxelUpdate(k.x,k.y,k.z+1,info.Temperature,v)
				registerVoxelUpdate(k.x,k.y,k.z-1,info.Temperature,v)
			end
			
			--Heat transfer between touching and connected parts
			for _,p in pairs(part:GetTouchingParts()) do
				local c,s = checkOBBVsOBB(part.CFrame,part.Size+vec3(0.2,0.2,0.2),p.CFrame,p.Size+vec3(0.2,0.2,0.2))
				if (c and s>0 and parts[p]) then
					local partTemp = parts[p].Temperature
					local delta = (partTemp - info.Temperature) / max((part:GetMass() * matInfo.SpecificHeat * conductionMultiplierTouching)/s,1)
					info.Temperature = info.Temperature + delta
					if (abs(partTemp - info.Temperature) > deltaTPartTransferThreshhold) then parts[p].DoRerun = true requiresRerun = true end
				end
			end
			for _,p in pairs(part:GetConnectedParts()) do
				local c,s = checkOBBVsOBB(part.CFrame,part.Size+vec3(0.2,0.2,0.2),p.CFrame,p.Size+vec3(0.2,0.2,0.2))
				if (c and s>0 and parts[p]) then
					local partTemp = parts[p].Temperature
					local delta = (partTemp - info.Temperature) / max((part:GetMass() * matInfo.SpecificHeat * conductionMultiplierTouching)/s,1)
					info.Temperature = info.Temperature + delta
					if (abs(partTemp - info.Temperature) > deltaTPartTransferThreshhold) then parts[p].DoRerun = true requiresRerun = true end
				end
			end
			
			--Marked for deletion?
			if (markForDelete) then
				spawn(function()
					parts[part] = nil
					part.Transparency = 1
					part.CanCollide = false
					part.Anchored = false
					part:ClearAllChildren()
					
					local particles = script.BreakParticles:clone()
					particles.Parent = part
					wait(0.1)
					particles:Emit(128)
					
					local debris = game:GetService("Debris")
					debris:AddItem(part,2)
				end)
			end
			
			throttle(0.05,"Part updates")
		end
		if (part.Parent == nil) then
			parts[part] = nil
		end
	end
	
	return requiresRerun,calcs
end

--Connect to update triggers
updateIsRunning = false
function onUpdateTrigger()
	if (updateIsRunning) then return end
	updateIsRunning = true
	
	local recalc1,c1 = true,0
	local recalc2,c2 = true,0
	while recalc1 or recalc2 do 
		local t = tick()
		recalc1,c1 = doCalc()
		recalc2,c2 = voxelTick()
		if (doDebug) then
			print("-------------------------")
			print("Part updates: " .. c1)
			print("Voxel updates: " .. c2)
			print("Time to calc: " .. math.floor((tick()-t)*100e3)/100 .. " ms")
		end
		
		for _,a in pairs(game:GetService("Players"):GetPlayers()) do
			if (damageCharacters and
				a.Character and 
				a.Character:FindFirstChild("Torso") and 
				a.Character:FindFirstChild("Humanoid")) then
				
				local intersects = getVoxelIntersects(a.Character.Torso)
				local temp = 0
				for k,v in pairs(intersects) do 
					local voxel = getVoxel(k.x,k.y,k.z)
					temp = temp + v*voxel.Temperature
				end
				if (temp > charDamageThreshold) then
					a.Character.Humanoid.Health = a.Character.Humanoid.Health - temp*charDamageMultiplier
				end
			end
		end
		wait()
	end
	
	updateIsRunning = false
end

--External run enables
local library = {}

--Method to set the temperature of a part
function library:SetPartTemperature(part,temp)
	if (part == nil) then return end
	if (parts[part] == nil) then registerParts(part) end
	parts[part].Temperature = temp
	parts[part].DoRecalc = true
	
	onUpdateTrigger()
end

--Method to get the temperature of a part
function library:GetPartTemperature(part)
	if (parts[part]) then return parts[part].Temperature end
end

--Setting voxel temperatures at world coordinates
function library:SetVoxelTemperature(x,y,z,temperature)
	x,y,z = math.floor(x/4),math.floor(y/4),math.floor(z/4)
	local vox = getVoxel(x,y,z)
	vox.Temperature = temperature
	setVoxel(x,y,z,vox)
end

--Getting voxel temperatures at world coordinates
function library:GetVoxelTemperature(x,y,z)
	x,y,z = math.floor(x/4),math.floor(y/4),math.floor(z/4)
	return getVoxel(x,y,z).Temperature
end

--Setting configuration options
function library:SetConfiguration(name,value)
	local config = script.Configuration:FindFirstChild(name)
	if (config) then
		local type1 = type(config.Value) 
		local type2 = type(value)
		if (type1 ~= type2) then 
			warn("Configuration on " .. name .. " could not be set: Type mismatch, expected " .. type1 .. ", got " .. type2) 
			return false
		end
		config.Value = value
		return true
	else
		warn("Configuration on " .. name .. " could not be set: Configuration value does not exist.") 
		return false
	end
end

--Reading configuration options
function library:GetConfiguration(name,value)
	local config = script.Configuration:FindFirstChild(name)
	if (config) then
		return config.Value
	else
		warn("Could not get configuration on " .. name .. ": Configuration value does not exist.") 
		return nil
	end
end

--Registering a whole model of parts
function library:RegisterParts(group)
	registerParts(group)
end

--Getting a list of registered parts
function library:GetRegisteredParts()
	local output = {}
	for index,_ in pairs(parts) do output[#output+1] = index end
	return output
end

--Registering individual parts
function library:RegisterPart(part)
	registerPart(part)
end

--Checking if a part is registered
function library:IsPartRegistered(part)
	return parts[part] ~= nil
end

--Removes a part from the simulation
function library:UnregisterPart(part)
	if (part:FindFirstChild("HeatGlow")) then part.HeatGlow:Destroy() end
	if (part:FindFirstChild("FireParticles")) then part.FireParticles:Destroy() end
	parts[part] = nil
end

--Clears all parts from the simulation
function library:UnregisterAllParts()
	for part,_ in pairs(parts) do
		library:UnregisterPart(part)
	end
end

--Function to clear all voxel's info
function library:ClearVoxels()
	voxels = {}
end

--Players should be flammable :D
function onJoin(p)
	p.Changed:connect(function(prop)
		if (prop == "Character") then
			wait(1)
			print("Handling character for",p)
			for _,a in pairs(p.Character:children()) do
				if (a:IsA("BasePart")) then
					library:SetPartTemperature(a,ambientTemp)
				end
			end
		end
	end)
end
game:GetService("Players").PlayerAdded:connect(onJoin)
for _,p in pairs(game:GetService("Players"):GetPlayers()) do
	onJoin(p)
end

--Alrighty, go for it.
onUpdateTrigger()

--Make the exposed functions accessible externally
return library