Nominative99

[Help] - Game/Server Crash when Crafting a Custom Heating/Cooling Buff Item

Recommended Posts

Hello Again!

I need some assistance in regards to some custom items I've worked on for a friend. I was recently notified of a game crashing bug that only occurs with more than one person on a sever. Alone it doesn't crash, but once someone joins, boom. The items in question buff the player by temporarily giving them either a cooling or heating radius.

Quote

LUA ERROR stack traceback:
    scripts/components/temperature.lua:370 in (method) OnUpdate (Lua) <250-416>
    scripts/update.lua:202 in () ? (Lua) <159-238>

I am using Ultroman's Aura Code and other references I've looked into to turn the crafter into a walking heater/cooler for a duration of time (the reason for the aura was for possible changes in case my friend wanted that buff to apply to other characters nearby by increasing the buffing range). I definitely screwed up in the heating & cooling, but unfortunately the error log is rather obscure to me, and since it doesn't crash with one player, so I can't seem to pinpoint this. I did browse through any existing examples of say portable heaters, thermal stones and similar items, but I was never comfortable when coding this. It was rather hard for me to tell whether or not my character was warming up or cooling down when these items applied their buff.

Any assistance or insight will be greatly appreciated. I've attached the client_log and two item prefab files.

This is what I have for the Heating. Cooling is pretty much the same but with different temp values.

local assets =
{
	Asset("ANIM", "anim/wyrdflask_heating.zip"),
	Asset("ATLAS", "images/inventoryimages/wyrdflask_heating.xml"),
	
}

local prefabs = {
	"wyrd",
	"wyrdflask"
	}
	
-- HEATING AURA WORKS DIFFERENTLY THIS ONLY APPLIES THE BUFF
-- ONCE BUT THE BUFF LASTS BASED ON WHAT heatingAuraDuration
-- IS. RADIUS IS SET TO 1 SO THAT WYRD IS THE ONLY ONE WHO
-- GETS THE BUFF. 

---------------------------------------
-- LOCAL EASY TO FIND VARIABLES - START
---------------------------------------

-- TUNING.TOTAL_DAY_TIME = 8 MINUTES = 480 SECONDS / X = TOTAL TIME.
-- WORK WITH DIVISION/MULTIPLICATION OF TOTAL DAY TIME
-- EX: TUNING.TOTAL_DAY_TIME * 2 = DAYS
local heatingAuraDuration = TUNING.TOTAL_DAY_TIME/1.6 -- 5 MINUTES
local heatingAuraRadius = 1 -- RADIUS OF AURA
local heatingTick = 0.1 -- DELAY IN WHICH HEATING AURA ACTIVATES WHEN CRAFTED
---------------------------------------
-- LOCAL EASY TO FIND VARIABLES - END
---------------------------------------

--------------------------------
-- WYRD EXCLUSIVE PICKUP - START - 
--CODE REFERENCED FROM maliblues : https://forums.kleientertainment.com/forums/topic/113820-help-preventing-custom-item-from-going-into-backpackschestsetc/?do=findComment&comment=1287064
--------------------------------
local function OnPutInInventory(inst)
	local owner = inst.components.inventoryitem:GetGrandOwner()
	if owner == nil then
	return 
	elseif owner.components.inventory and owner.prefab ~= "wyrd" then 
		inst:DoTaskInTime(0.1, function()
				owner.components.inventory:DropItem(inst)
				owner.components.talker:Say("That flask is cursed...")
		end)
	end

	if owner.components.container then --for chests --test when in backpack with diff owner
		inst:DoTaskInTime(0.1, function()
			owner.components.container:DropItem(inst)
		end)
	end  
end
--------------------------------
-- WYRD EXCLUSIVE PICKUP - END
--------------------------------

------------------------------------------------------
-- RETURNS ORIGINAL FLASK AFTER TIME REACHES 0 - START
------------------------------------------------------
local function OnFinished(inst)
	local owner = inst.components.inventoryitem.owner
	local flask = SpawnPrefab("wyrdflask")
	inst:Remove()
	if owner ~= nil and owner.components.inventory then -- CHECK IF THE OWNER ITEM IS VALID AND NOT A CONTAINER
		owner.components.inventory:GiveItem(flask)
	elseif owner ~= nil and owner.components.container then -- OR IF THE OWNER IS VALID AND IS A CONTAINER
		owner.components.container:GiveItem(flask)
	else
		inst.components.lootdropper:SpawnLootPrefab("wyrdflask") -- DROPS NORMAL FLASK AS BASIC LOOT IN THE CASE OF ABOVE
	end	
end
------------------------------------------------------
-- RETURNS ORIGINAL FLASK AFTER TIME REACHES 0 - END
------------------------------------------------------

-----------------------
-- HEATING CODE - START
-----------------------

-- Heated Character emits constant temperatures depending on the temperature range it's in
local heats = { 30, 40, 60 }

local function GetHeatFn(receiver)
    return heats or 20
end

local function turnOnHeating(receiver)
	receiver:AddTag("HASHEATER")
	receiver:AddComponent("heater")
	receiver.components.heater.heatfn = GetHeatFn
	receiver.components.heater:SetThermics(false, true)
end

local function turnOffHeating(receiver)
	receiver:RemoveTag("HASHEATER")
	receiver:RemoveComponent("heater")
end
-----------------------
-- HEATING CODE - END
-----------------------

---------------------
-- START OF AURA CODE
---------------------
local onEndAura = function(receiver, wyrdflask_heatingGUID, wyrdHeatingAura)

	-- Fail-safe.
	if not receiver or not receiver:IsValid() then
		return
	end

	-- If the receiver has the heating aura task, cancel it.
	if receiver[wyrdHeatingAura] then
		receiver[wyrdHeatingAura]:Cancel()
		receiver[wyrdHeatingAura] = nil
	end

	turnOffHeating(receiver)
end

local onApplyAura = function(receiver, wyrdflask_heating)
	-- "receiver" = Player
	-- "wyrdflask_heating" = Item applying the aura

	-- Fail-safe.
	if not receiver or not receiver:IsValid() then
		return
	end
	
	-- Use the created entitie's unique ID to create a unique name.
	local wyrdflask_heatingGUID = wyrdflask_heating.GUID
	
	--Create a single instance of the aura to prevent stacking from multiples of the same flask.
	local wyrdHeatingAura = "wyrdHeatingAuraID"
	
	-- If the receiver does not already have our heating aura on from this particular
	-- wyrdflask_heating, start the heating aura task, and store it in a variable on the receiver.
	if not receiver[wyrdHeatingAura] then
		-- TASK APPLIES HEATING EFFECT
		receiver[wyrdHeatingAura] = receiver:DoTaskInTime(heatingTick, function(receiver)
		turnOnHeating(receiver)
		end)
	end
	
	
	-- Ending the Aura after some time
	-- Create a unique variable-name to store the end-aura task on the receiver.
	local endwyrdHeatingAura = "wyrdHeatingEntireAura"
	
	-- If the receiver already has an end-aura task, then we need to cancel it,
	-- so we can restart it with a refreshed end-time.
	if receiver[endwyrdHeatingAura] then
		receiver[endwyrdHeatingAura]:Cancel()
		receiver[endwyrdHeatingAura] = nil
	end
	
	-- Use DoTaskInTime to schedule calling the function that ends the aura after a while without renewals.
	-- We store the task on the receiver using our unique variable-name.
	receiver[endwyrdHeatingAura] = receiver:DoTaskInTime(heatingAuraDuration, onEndAura, wyrdflask_heatingGUID, wyrdHeatingAura)
end

local applyAuraInRange = function(inst)
	-- Store the position of the aura-emitting entity in x, y, z variables.
	local x,y,z = inst.Transform:GetWorldPosition()
	
	-- Any player that is not a ghost or in limbo.
	-- AURA RADIUS = 1 - MAKES IT SO WYRD IS THE ONLY ONE WITH THE HEATING BUFF
	local ents = TheSim:FindEntities(x, y, z, 1, {"player"}, {"playerghost", "INLIMBO"}, nil)
	
	-- Apply the aura to any of the found entities within the radius, including the aura-emitting
	-- entity itself if it fits the tag-list parameters!
	for i, v in ipairs(ents) do
		onApplyAura(v, inst)
	end
end
-------------------
-- END OF AURA CODE
-------------------

-- Write a local function that creats, customizes, and returns an instance of the prefab.
local function fn(Sim)
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddNetwork()
	
    MakeInventoryPhysics(inst)
	
	inst.AnimState:SetBank("wyrdflask_heating")
    inst.AnimState:SetBuild("wyrdflask_heating")
    inst.AnimState:PlayAnimation("idle")
	
	MakeInventoryFloatable(inst, "small", 0.2)
	
    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end
	
	--inst:AddTag("undroppable")
	inst:AddComponent("lootdropper")
    inst:AddComponent("inspectable")
    inst:AddComponent("inventoryitem")
	inst.components.inventoryitem:SetOnPutInInventoryFn(OnPutInInventory)
	inst.components.inventoryitem.keepondeath = true
	inst.components.inventoryitem:EnableMoisture(false)
	inst.components.inventoryitem.atlasname = "images/inventoryimages/wyrdflask_heating.xml"
	
	inst:AddComponent("fueled")
	inst.components.fueled:InitializeFuelLevel(heatingAuraDuration)
	inst.components.fueled:StartConsuming()
    inst.components.fueled:SetDepletedFn(OnFinished)
	
	MakeHauntableLaunch(inst)
    inst:DoTaskInTime(0, applyAuraInRange) -- APPLY THE AURA INSTANTLY
	
    return inst
end

-- Finally, return a new prefab with the construction function and assets.
return Prefab( "wyrdflask_heating", fn, assets)

client_log.txt

wyrdflask_heating.lua

wyrdflask_cooling.lua

Edited by Nominative99

Share this post


Link to post
Share on other sites
Ultroman    655

It's telling you exactly what is wrong.

[00:07:10]: [string "scripts/components/temperature.lua"]:370: attempt to perform arithmetic on local 'heat' (a table value)

That means: "Hey, I tried doing math on line 370 with the 'heat' value you gave me, but it's not a number, it's a list of numbers. What do you expect me to do with that?"

This. You can't do this. You have to pick a numeric value in GetHeatFn and return it. This function is where you're supposed to calculate the range-weighted value and return it.

-- Heated Character emits constant temperatures depending on the temperature range it is in
local heats = { 30, 40, 60 }

local function GetHeatFn(receiver)
    return heats or 20
end

 

Sorry for the late reply. I don't know how I've missed this for a month :o

Edited by Ultroman

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now