local TIMEOUT = 2

--------------------------------------------------------------------------
--Server interface
--------------------------------------------------------------------------

local function SetValue(inst, name, value)
    assert(value >= 0 and value <= 255, "Player "..tostring(name).." out of range: "..tostring(value))
    inst[name]:set(math.ceil(value))
end

local function SetDirty(netvar, val)
    --Forces a netvar to be dirty regardless of value
    netvar:set_local(val)
    netvar:set(val)
end

local function PushPausePredictionFrames(inst, frames)
    --Force dirty, we just want to trigger an event on the client
    SetDirty(inst.pausepredictionframes, frames)
end

local function OnHealthDelta(parent, data)
    if not data.overtime then
        --Force dirty, we just want to trigger an event on the client
        SetDirty(parent.player_classified.ishealthpulse, true)
    end
end

local function OnHungerDelta(parent, data)
    if not data.overtime then
        --Force dirty, we just want to trigger an event on the client
        SetDirty(parent.player_classified.ishungerpulse, true)
    end
end

local function OnSanityDelta(parent, data)
    if not data.overtime then
        --Force dirty, we just want to trigger an event on the client
        SetDirty(parent.player_classified.issanitypulse, true)
    end
end

local function OnAttacked(parent)
    --Force dirty, we just want to trigger an event on the client
    SetDirty(parent.player_classified.isattackedpulse, true)
end

local function OnBuildSuccess(parent)
    --Force dirty, we just want to trigger an event on the client
    SetDirty(parent.player_classified.isbuildsuccess, true)
end

local function OnPerformAction(parent)
    --Force dirty, we just want to trigger an event on the client
    SetDirty(parent.player_classified.isperformaction, true)
end

local function OnWormholeTravel(parent)
    --Force dirty, we just want to trigger an event on the client
    SetDirty(parent.player_classified.iswormholetravel, true)
end

local function AddMorgueRecord(inst)
    if inst._parent ~= nil then
        SetDirty(inst.isdeathbypk, inst._parent.deathpkname ~= nil)
        inst.deathcause:set(inst._parent.deathpkname or inst._parent.deathcause)
    end
end

--Temperature stuff
local max_precision_temp = 6
local min_precision_temp = -11
local precision_factor = 4
local coarse_factor = 1
local pivot = math.floor((256 - (max_precision_temp + min_precision_temp) * precision_factor) / 2)

local function SetTemperature(inst, temperature)
    if temperature >= max_precision_temp then
        inst.currenttemperaturedata:set(pivot + max_precision_temp * precision_factor + math.floor((temperature - max_precision_temp) * coarse_factor + .5))
    elseif temperature <= min_precision_temp then
        inst.currenttemperaturedata:set(pivot + min_precision_temp * precision_factor + math.floor((temperature - min_precision_temp) * coarse_factor + .5))
    else
        inst.currenttemperaturedata:set(pivot + math.floor(temperature * precision_factor + .5))
    end
end

--------------------------------------------------------------------------
--Client interface
--------------------------------------------------------------------------

local function DeserializeTemperature(inst)
    if inst.currenttemperaturedata:value() >= pivot + max_precision_temp * precision_factor then
        inst.currenttemperature = (inst.currenttemperaturedata:value() - pivot - max_precision_temp * precision_factor) / coarse_factor + max_precision_temp
    elseif inst.currenttemperaturedata:value() <= pivot + min_precision_temp * precision_factor then
        inst.currenttemperature = (inst.currenttemperaturedata:value() - pivot - min_precision_temp * precision_factor) / coarse_factor + min_precision_temp
    else
        inst.currenttemperature = (inst.currenttemperaturedata:value() - pivot) / precision_factor
    end
end

local function OnEntityReplicated(inst)
    inst._parent = inst.entity:GetParent()
    if inst._parent == nil then
        print("Unable to initialize classified data for player")
    else
        inst._parent:AttachClassified(inst)
        for i, v in ipairs({ "age", "health", "hunger", "sanity", "humanity", "builder", "beaverness" }) do
            if inst._parent.replica[v] ~= nil then
                inst._parent.replica[v]:AttachClassified(inst)
            end
        end
        for i, v in ipairs({ "playercontroller" }) do
            if inst._parent.components[v] ~= nil then
                inst._parent.components[v]:AttachClassified(inst)
            end
        end
    end
end

local function OnHealthDirty(inst)
    if inst._parent ~= nil then
        local percent = inst.currenthealth:value() / inst.maxhealth:value()
        inst._parent:PushEvent("healthdelta", { oldpercent = inst._oldhealthpercent, newpercent = percent, overtime = not inst.ishealthpulse:value() })
        inst._oldhealthpercent = percent
    else
        inst._oldhealthpercent = 1
    end
    inst.ishealthpulse:set_local(false)
end

local function OnIsTakingFireDamageDirty(inst)
    if inst._parent ~= nil then
        if inst.istakingfiredamage:value() then
            inst._parent:PushEvent("startfiredamage")
        else
            inst._parent:PushEvent("stopfiredamage")
        end
    end
end

local function OnIsAttackedPulse(inst)
    if inst._parent ~= nil then
        inst._parent:PushEvent("attacked")
    end
end

local function OnHungerDirty(inst)
    if inst._parent ~= nil then
        local percent = inst.currenthunger:value() / inst.maxhunger:value()
        inst._parent:PushEvent("hungerdelta", { oldpercent = inst._oldhungerpercent, newpercent = percent, overtime = not inst.ishungerpulse:value() })
        if inst._oldhungerpercent > 0 then
            if percent <= 0 then
                inst._parent:PushEvent("startstarving")
            end
        elseif percent > 0 then
            inst._parent:PushEvent("stopstarving")
        end
        inst._oldhungerpercent = percent
    else
        inst._oldhungerpercent = 1
    end
    inst.ishungerpulse:set_local(false)
end

local function UpdateAnimOverrideSanity(parent)
    parent.AnimState:SetClientSideBuildOverrideFlag("insane", parent.replica.sanity:IsCrazy())
end

local function OnSanityDirty(inst)
    if inst._parent ~= nil then
        local percent = inst.currentsanity:value() / inst.maxsanity:value()
        inst._parent:PushEvent("sanitydelta", { oldpercent = inst._oldsanitypercent, newpercent = percent, overtime = not inst.issanitypulse:value() })
        inst._oldsanitypercent = percent

        inst._parent:DoTaskInTime(0, UpdateAnimOverrideSanity)
    else
        inst._oldsanitypercent = 1
    end
    inst.issanitypulse:set_local(false)
end

local function OnBeavernessDirty(inst)
    if inst._parent ~= nil then
        local percent = inst.currentbeaverness:value() / inst.maxbeaverness:value()
        inst._parent:PushEvent("beavernessdelta", { oldpercent = inst._oldbeavernesspercent, newpercent = percent, overtime = false })
        inst._oldbeavernesspercent = percent

        inst._parent:DoTaskInTime(0, UpdateAnimOverrideBeaverness)
    else
        inst._oldbeavernesspercent = 1
    end
end

local function OnHumanityDirty(inst)
    if inst._parent ~= nil then
        local percent = inst.currenthumanity:value() / inst.maxhumanity:value()
        local healthpenaltypercent = inst.humanityhealthpenalty:value() / inst.humanityhealthpenaltymax:value()
        inst._parent:PushEvent("ghostdelta",
        {
            oldpercent = inst._oldsanitypercent,
            newpercent = percent,
            oldhealthpenaltypercent = inst._oldhumanityhealthpenaltypercent,
            newhealthpenaltypercent = healthpenaltypercent,
        })
        inst._oldhumanitypercent = percent
        inst._oldhumanityhealthpenaltypercent = healthpenaltypercent
    else
        inst._oldhumanitypercent = 1
        inst._oldhumanityhealthpenaltypercent = 0
    end
end

local function OnTemperatureDirty(inst)
    DeserializeTemperature(inst)
    if inst._parent == nil then
        inst._oldtemperature = 30
    elseif inst._oldtemperature ~= inst.currenttemperature then
        if inst._oldtemperature < 0 then
            if inst.currenttemperature >= 0 then
                inst._parent:PushEvent("stopfreezing")
            end
        elseif inst.currenttemperature < 0 then
            inst._parent:PushEvent("startfreezing")
        end
        inst._parent:PushEvent("temperaturedelta", { last = inst._oldtemperature, new = inst.currenttemperature })
        inst._oldtemperature = inst.currenttemperature
    end
end

local function OnTechTreesDirty(inst)
    inst.techtrees.SCIENCE = inst.sciencelevel:value()
    inst.techtrees.MAGIC = inst.magiclevel:value()
    inst.techtrees.ANCIENT = inst.ancientlevel:value()
    if inst._parent ~= nil then
        inst._parent:PushEvent("techtreechange", { level = inst.techtrees })
    end
end

local function OnRecipesDirty(inst)
    if inst._parent ~= nil then
        inst._parent:PushEvent("unlockrecipe")
    end
end

local function Refresh(inst)
    inst._refreshtask = nil
    for k, v in pairs(inst._bufferedbuildspreview) do
        inst._bufferedbuildspreview[k] = nil
    end
    if inst._parent ~= nil then
        inst._parent:PushEvent("refreshcrafting")
    end
end

local function QueueRefresh(inst, delay)
    if inst._refreshtask == nil then
        inst._refreshtask = inst:DoTaskInTime(delay, Refresh)
    end
end

local function CancelRefresh(inst)
    if inst._refreshtask ~= nil then
        inst._refreshtask:Cancel()
        inst._refreshtask = nil
    end
end

local function OnBufferedBuildsDirty(inst)
    CancelRefresh(inst)
    Refresh(inst)
end

local function BufferBuild(inst, recipename)
    local recipe = AllRecipes[recipename]
    local inventory = inst._parent ~= nil and inst._parent.replica.inventory ~= nil and inst._parent.replica.inventory.classified or nil
    if recipe ~= nil and inventory ~= nil and inventory:RemoveIngredients(recipe, inst.ingredientmod:value()) then
        inst._bufferedbuildspreview[recipename] = true
        if inst._parent ~= nil then
            inst._parent:PushEvent("refreshcrafting")
        end
        CancelRefresh(inst)
        QueueRefresh(inst, TIMEOUT)
        SendRPCToServer(RPC.BufferBuild, recipe.sortkey)
    end
end

local function OnIsPerformActionDirty(inst)
    if inst._parent ~= nil and
        inst._parent.bufferedaction ~= nil and
        inst._parent.bufferedaction.ispreviewing then
        inst._parent:ClearBufferedAction()
    end
end

local function CancelPausePrediction(inst)
    if inst._pausepredictiontask ~= nil then
        inst._pausepredictiontask:Cancel()
        inst._pausepredictiontask = nil
        inst.pausepredictionframes:set_local(0)
    end
end

local function OnPausePredictionFramesDirty(inst)
    if inst._parent ~= nil and inst._parent.HUD ~= nil then
        if inst._pausepredictiontask ~= nil then
            inst._pausepredictiontask:Cancel()
        end
        inst._pausepredictiontask = inst.pausepredictionframes:value() > 0 and inst:DoTaskInTime(inst.pausepredictionframes:value() * FRAMES, CancelPausePrediction) or nil
        inst._parent:PushEvent("cancelmovementprediction")
    end
end

--------------------------------------------------------------------------
--Common interface
--------------------------------------------------------------------------

local function OnBuildSuccessDirty(inst)
    if inst._parent ~= nil and TheFocalPoint.entity:GetParent() == inst._parent then
        TheFocalPoint.SoundEmitter:PlaySound("dontstarve/HUD/collect_newitem")
    end
end

local function OnPlayerHUDDirty(inst) --might need to update this to get log meter to show
    if inst._parent ~= nil and inst._parent.HUD ~= nil then
        if inst.ishudvisible:value() then
            inst._parent.HUD:Show()
        else
            inst._parent.HUD:Hide()
        end

        inst._parent.HUD.controls.status:SetGhostMode(inst.isghostmode:value())
        inst._parent:EnableMovementPrediction(not inst.isghostmode:value())

        if inst.ismapcontrolsvisible:value() then
            inst._parent.HUD.controls.mapcontrols.minimapBtn:Show()
        else
            if TheWorld.minimap.MiniMap:IsVisible() then
                TheFrontEnd:PopScreen()
            end
            inst._parent.HUD.controls.mapcontrols.minimapBtn:Hide()
        end
	
		TheWorld.minimap.MiniMap:EnablePlayerMinimapUpdate(not inst.isghostmode:value())
    end
end

local function OnPlayerCameraDirty(inst)
    if inst._parent ~= nil and inst._parent.HUD ~= nil then
        if inst.cameradistance:value() > 0 then
            TheCamera:SetDistance(inst.cameradistance:value())
        else
            TheCamera:SetDefault()
        end
    end
end

local function DoSnapCamera()
    TheCamera:Snap()
end

local function OnPlayerCameraSnap(inst)
    if inst._parent ~= nil and inst._parent.HUD ~= nil then
        if TheWorld.ismastersim then
            TheCamera:Snap()
        else
            inst:DoTaskInTime(0, DoSnapCamera)
        end
    end
end

local function OnPlayerFadeDirty(inst)
    if inst._parent ~= nil and inst._parent.HUD ~= nil then
        if inst.fadetime:value() > 0 then
            TheFrontEnd:Fade(inst.isfadein:value(), inst.fadetime:value() / 10)
        else
            TheFrontEnd:SetFadeLevel(inst.isfadein:value() and 0 or 1)
        end
    end
end

local function OnWormholeTravelDirty(inst)
    if inst._parent ~= nil and inst._parent.HUD ~= nil then
        TheFocalPoint.SoundEmitter:PlaySound("dontstarve/common/teleportworm/travel")
    end
end

local function OnMorgueDirty(inst)
    if inst._parent ~= nil and inst._parent.HUD ~= nil then
        Morgue:OnDeath({
            pk = inst.isdeathbypk:value() or nil,
            killed_by = inst.deathcause:value(),
            days_survived = inst._parent.replica.age:GetDisplayAgeInDays(),
            character = inst._parent.prefab,
            location = "unknown",
            world = TheWorld.meta ~= nil and TheWorld.meta.level_id or "unknown",
            server = TheNet:GetServerName(),
        })
    end
end

local function RegisterNetListeners(inst)
    if TheWorld.ismastersim then
        inst._parent = inst.entity:GetParent()
        inst:ListenForEvent("healthdelta", OnHealthDelta, inst._parent)
        inst:ListenForEvent("hungerdelta", OnHungerDelta, inst._parent)
        inst:ListenForEvent("sanitydelta", OnSanityDelta, inst._parent)
        inst:ListenForEvent("attacked", OnAttacked, inst._parent)
        inst:ListenForEvent("builditem", OnBuildSuccess, inst._parent)
        inst:ListenForEvent("buildstructure", OnBuildSuccess, inst._parent)
        inst:ListenForEvent("performaction", OnPerformAction, inst._parent)
        inst:ListenForEvent("actionfailed", OnPerformAction, inst._parent)
        inst:ListenForEvent("wormholetravel", OnWormholeTravel, inst._parent)
    else
        inst.ishealthpulse:set_local(false)
        inst.ishungerpulse:set_local(false)
        inst.issanitypulse:set_local(false)
        inst.pausepredictionframes:set_local(0)
        inst:ListenForEvent("healthdirty", OnHealthDirty)
        inst:ListenForEvent("istakingfiredamagedirty", OnIsTakingFireDamageDirty)
        inst:ListenForEvent("isattackedpulse", OnIsAttackedPulse)
        inst:ListenForEvent("hungerdirty", OnHungerDirty)
        inst:ListenForEvent("sanitydirty", OnSanityDirty)
        inst:ListenForEvent("beavernessdirty", OnBeavernessDirty)
        inst:ListenForEvent("humanitydirty", OnHumanityDirty)
        inst:ListenForEvent("temperaturedirty", OnTemperatureDirty)
        inst:ListenForEvent("techtreesdirty", OnTechTreesDirty)
        inst:ListenForEvent("recipesdirty", OnRecipesDirty)
        inst:ListenForEvent("bufferedbuildsdirty", OnBufferedBuildsDirty)
        inst:ListenForEvent("isperformactiondirty", OnIsPerformActionDirty)
        inst:ListenForEvent("pausepredictionframesdirty", OnPausePredictionFramesDirty)

        OnIsTakingFireDamageDirty(inst)
        OnTemperatureDirty(inst)
        if inst._parent ~= nil then
            UpdateAnimOverrideSanity(inst._parent)
        end
    end

    inst:ListenForEvent("isbuildsuccessdirty", OnBuildSuccessDirty)
    inst:ListenForEvent("playerhuddirty", OnPlayerHUDDirty)
    inst:ListenForEvent("playercameradirty", OnPlayerCameraDirty)
    inst:ListenForEvent("playercamerasnap", OnPlayerCameraSnap)
    inst:ListenForEvent("playerfadedirty", OnPlayerFadeDirty)
    inst:ListenForEvent("iswormholetraveldirty", OnWormholeTravelDirty)
    inst:ListenForEvent("morguedirty", OnMorgueDirty)
    OnPlayerHUDDirty(inst)
    OnPlayerCameraDirty(inst)

    --Fade is initialized by OnPlayerActivated in gamelogic.lua
end

--------------------------------------------------------------------------

local function fn()
    local inst = CreateEntity()

    inst.entity:AddNetwork()
    inst.entity:Hide()
    inst:AddTag("CLASSIFIED")

    --Age variables
    inst.agetime = net_float(inst.GUID, "age.agetime", "agetimedirty")
    inst.isagingpaused = net_bool(inst.GUID, "age.ispaused", "isagingpauseddirty")

    --Health variables
    inst._oldhealthpercent = 1
    inst.currenthealth = net_byte(inst.GUID, "health.currenthealth", "healthdirty")
    inst.maxhealth = net_byte(inst.GUID, "health.maxhealth", "healthdirty")
    inst.healthpenalty = net_byte(inst.GUID, "health.penalty", "healthdirty")
    inst.istakingfiredamage = net_bool(inst.GUID, "health.takingfiredamage", "istakingfiredamagedirty")
    inst.issleephealing = net_bool(inst.GUID, "health.healthsleep")
    inst.ishealthpulse = net_bool(inst.GUID, "health.dodeltaovertime")

    --Hunger variables
    inst._oldhungerpercent = 1
    inst.currenthunger = net_byte(inst.GUID, "hunger.current", "hungerdirty")
    inst.maxhunger = net_byte(inst.GUID, "hunger.max", "hungerdirty")
    inst.ishungerpulse = net_bool(inst.GUID, "hunger.dodeltaovertime")
	
	--Beaverness variables
	inst.currentbeaverness = net_byte(inst.GUID, "beaverness.current", "beavernessdirty")
	inst.maxbeaverness = net_byte(inst.GUID, "beaverness.max", "beavernessdirty")

    --Sanity variables
    inst._oldsanitypercent = 1
    inst.currentsanity = net_byte(inst.GUID, "sanity.current", "sanitydirty")
    inst.maxsanity = net_byte(inst.GUID, "sanity.max", "sanitydirty")
    inst.sanitypenalty = net_byte(inst.GUID, "sanity.penalty", "sanitydirty")
    inst.sanityrate = net_byte(inst.GUID, "sanity.rate")
    inst.issanitypulse = net_bool(inst.GUID, "sanity.dodeltaovertime")

    --Humanity variables
    inst._oldhumanitypercent = 1
    inst._oldhumanityhealthpenaltypercent = 0
    inst.currenthumanity = net_byte(inst.GUID, "humanity.current", "humanitydirty")
    inst.maxhumanity = net_byte(inst.GUID, "humanity.max", "humanitydirty")
    inst.humanityhealthpenalty = net_byte(inst.GUID, "humanity.healthpenalty", "humanitydirty")
    inst.humanityhealthpenaltymax = net_byte(inst.GUID, "humanity.healthpenaltymax", "humanitydirty")
    inst.ishumanitypaused = net_bool(inst.GUID, "humanity.ispaused", "humanitydirty")

    --Temperature variables
    inst._oldtemperature = 30
    inst.currenttemperature = 30
    inst.currenttemperaturedata = net_byte(inst.GUID, "temperature.current", "temperaturedirty")
    SetTemperature(inst, inst.currenttemperature)

    --PlayerController variables
    inst._pausepredictiontask = nil
    inst.pausepredictionframes = net_tinybyte(inst.GUID, "playercontroller.pausepredictionframes", "pausepredictionframesdirty")
    inst.iscontrollerenabled = net_bool(inst.GUID, "playercontroller.enabled")
    inst.iscontrollerenabled:set(true)

    --Player HUD variables
    inst.ishudvisible = net_bool(inst.GUID, "playerhud.isvisible", "playerhuddirty")
    inst.ismapcontrolsvisible = net_bool(inst.GUID, "playerhud.ismapcontrolsvisible", "playerhuddirty")
    inst.isghostmode = net_bool(inst.GUID, "playerhud.isghostmode", "playerhuddirty")
    inst.isattackedpulse = net_bool(inst.GUID, "playerhud.isattackedpulse", "isattackedpulse")
    inst.ishudvisible:set(true)
    inst.ismapcontrolsvisible:set(true)

    --Player camera variables
    inst.cameradistance = net_smallbyte(inst.GUID, "playercamera.distance", "playercameradirty")
    inst.camerasnap = net_bool(inst.GUID, "playercamera.snap", "playercamerasnap")

    --Player front end variables
    inst.isfadein = net_bool(inst.GUID, "frontend.isfadein", "playerfadedirty")
    inst.fadetime = net_smallbyte(inst.GUID, "frontend.fadetime", "playerfadedirty")
    inst.iswormholetravel = net_bool(inst.GUID, "frontend.iswormholetravel", "iswormholetraveldirty")
    inst.isfadein:set(true)

    --Builder variables
    inst.isbuildsuccess = net_bool(inst.GUID, "builder.isbuildsuccess", "isbuildsuccessdirty")
    inst.techtrees = deepcopy(TECH.NONE)
    inst.sciencebonus = net_tinybyte(inst.GUID, "builder.science_bonus")
    inst.magicbonus = net_tinybyte(inst.GUID, "builder.magic_bonus")
    inst.ancientbonus = net_tinybyte(inst.GUID, "builder.ancient_bonus")
    inst.ingredientmod = net_tinybyte(inst.GUID, "builder.ingredientmod")
    inst.sciencelevel = net_tinybyte(inst.GUID, "builder.accessible_tech_trees.SCIENCE", "techtreesdirty")
    inst.magiclevel = net_tinybyte(inst.GUID, "builder.accessible_tech_trees.MAGIC", "techtreesdirty")
    inst.ancientlevel = net_tinybyte(inst.GUID, "builder.accessible_tech_trees.ANCIENT", "techtreesdirty")
    inst.isfreebuildmode = net_bool(inst.GUID, "builder.freebuildmode", "recipesdirty")
    inst.recipes = {}
    inst.bufferedbuilds = {}
    for k, v in pairs(AllRecipes) do
        inst.recipes[k] = net_bool(inst.GUID, "builder.recipes["..k.."]", "recipesdirty")
        inst.bufferedbuilds[k] = net_bool(inst.GUID, "builder.buffered_builds["..k.."]", "bufferedbuildsdirty")
    end
    inst.ingredientmod:set(1)
    inst.sciencelevel:set(inst.techtrees.SCIENCE)
    inst.magiclevel:set(inst.techtrees.MAGIC)
    inst.ancientlevel:set(inst.techtrees.ANCIENT)

    --Combat variables
    inst.lastcombattarget = net_entity(inst.GUID, "combat.lasttarget")
    inst.canattack = net_bool(inst.GUID, "combat.canattack")
    inst.minattackperiod = net_float(inst.GUID, "combat.minattackperiod")
    inst.canattack:set(true)
    inst.minattackperiod:set(4)

    --Stategraph variables
    inst.isperformaction = net_bool(inst.GUID, "sg.isperformaction", "isperformactiondirty")

    --Locomotor variables
    inst.runspeed = net_float(inst.GUID, "locomotor.runspeed")
    inst.runspeed:set(TUNING.WILSON_RUN_SPEED)

    --Morgue variables
    inst.isdeathbypk = net_bool(inst.GUID, "morgue.isdeathbypk", "morguedirty")
    inst.deathcause = net_string(inst.GUID, "morgue.deathcause")

    --Delay net listeners until after initial values are deserialized
    inst:DoTaskInTime(0, RegisterNetListeners)

    if not TheWorld.ismastersim then
        inst._refreshtask = nil
        inst._bufferedbuildspreview = {}

        --Client interface
        inst.OnEntityReplicated = OnEntityReplicated
        inst.BufferBuild = BufferBuild

        return inst
    end

    inst.entity:AddTransform() --So we can follow parent's sleep state
    inst.entity:SetPristine()

    --Server interface
    inst.SetValue = SetValue
    inst.PushPausePredictionFrames = PushPausePredictionFrames
    inst.AddMorgueRecord = AddMorgueRecord
    inst.SetTemperature = SetTemperature

    inst.persists = false

    return inst
end

return Prefab("player_classified", fn)