Skip to main content

Prefab Snippets

This page provides reusable code snippets for creating and customizing prefabs in Don't Starve Together mods.

Basic Prefab Structure

Simple Item Prefab

-- Define a simple item prefab
local assets = {
Asset("ANIM", "anim/my_item.zip"),
}

local function fn()
-- Create the entity
local inst = CreateEntity()

-- Add required components
inst.entity:AddTransform()
inst.entity:AddAnimState()
inst.entity:AddNetwork()

-- Set up visuals
MakeInventoryPhysics(inst)

inst.AnimState:SetBank("my_item")
inst.AnimState:SetBuild("my_item")
inst.AnimState:PlayAnimation("idle")

-- Add tags
inst:AddTag("item")

-- Make it inspectable
inst.entity:SetPristine()

if not TheWorld.ismastersim then
return inst
end

-- Server-only components
inst:AddComponent("inspectable")
inst:AddComponent("inventoryitem")
inst.components.inventoryitem.imagename = "my_item"
inst.components.inventoryitem.atlasname = "images/inventoryimages/my_item.xml"

-- Make it stackable
inst:AddComponent("stackable")
inst.components.stackable.maxsize = 20

-- Add other components as needed

return inst
end

-- Register the prefab
return Prefab("my_item", fn, assets)

Character Prefab

-- Define a character prefab
local assets = {
Asset("ANIM", "anim/my_character.zip"),
Asset("ANIM", "anim/ghost_my_character_build.zip"),
}

local prefabs = {
"my_character_none",
}

-- Custom starting inventory
local start_inv = {
"flint",
"flint",
"twigs",
"twigs",
}

-- Custom stats
local stats = {
health = 150,
hunger = 150,
sanity = 200,
}

local function common_postinit(inst)
-- Minimap icon
inst.MiniMapEntity:SetIcon("my_character.tex")

-- Tags
inst:AddTag("my_character_tag")

-- Voice
inst.soundsname = "wilson"
end

local function master_postinit(inst)
-- Choose character starting items
inst.starting_inventory = start_inv

-- Set custom stats
inst.components.health:SetMaxHealth(stats.health)
inst.components.hunger:SetMax(stats.hunger)
inst.components.sanity:SetMax(stats.sanity)

-- Set character-specific component values
inst.components.combat.damagemultiplier = 1.0
inst.components.locomotor.walkspeed = 4
inst.components.locomotor.runspeed = 6

-- Add custom component
inst:AddComponent("my_special_component")

-- Set up character-specific abilities
inst:ListenForEvent("ms_becameghost", function(inst)
-- Do something when character dies
end)
end

-- Register the character prefab
return MakePlayerCharacter("my_character", prefabs, assets, common_postinit, master_postinit)

Specialized Prefab Types

Tool Prefab

-- Define a tool prefab
local assets = {
Asset("ANIM", "anim/my_tool.zip"),
Asset("ANIM", "anim/swap_my_tool.zip"),
}

local function fn()
local inst = CreateEntity()

inst.entity:AddTransform()
inst.entity:AddAnimState()
inst.entity:AddNetwork()

MakeInventoryPhysics(inst)

inst.AnimState:SetBank("my_tool")
inst.AnimState:SetBuild("my_tool")
inst.AnimState:PlayAnimation("idle")

-- Add tool tag for actions
inst:AddTag("tool")

-- If it can chop trees
inst:AddTag("CHOP_tool")

-- If it can mine rocks
inst:AddTag("MINE_tool")

inst.entity:SetPristine()

if not TheWorld.ismastersim then
return inst
end

-- Basic components
inst:AddComponent("inspectable")
inst:AddComponent("inventoryitem")

-- Make it equippable
inst:AddComponent("equippable")
inst.components.equippable:SetOnEquip(function(inst, owner)
owner.AnimState:OverrideSymbol("swap_object", "swap_my_tool", "swap_my_tool")
owner.AnimState:Show("ARM_carry")
owner.AnimState:Hide("ARM_normal")
end)

inst.components.equippable:SetOnUnequip(function(inst, owner)
owner.AnimState:Hide("ARM_carry")
owner.AnimState:Show("ARM_normal")
end)

-- Add tool component
inst:AddComponent("tool")
inst.components.tool:SetAction(ACTIONS.CHOP, 1.5) -- 1.5x chop efficiency
inst.components.tool:SetAction(ACTIONS.MINE, 1.2) -- 1.2x mine efficiency

-- Add weapon component
inst:AddComponent("weapon")
inst.components.weapon:SetDamage(TUNING.AXE_DAMAGE)

-- Add finite uses
inst:AddComponent("finiteuses")
inst.components.finiteuses:SetMaxUses(100)
inst.components.finiteuses:SetUses(100)
inst.components.finiteuses:SetOnFinished(function(inst)
inst:Remove()
end)

-- Connect tool actions to durability loss
inst.components.finiteuses:SetConsumption(ACTIONS.CHOP, 1)
inst.components.finiteuses:SetConsumption(ACTIONS.MINE, 1.25)

return inst
end

return Prefab("my_tool", fn, assets)

Food Prefab

-- Define a food prefab
local assets = {
Asset("ANIM", "anim/my_food.zip"),
}

local function fn()
local inst = CreateEntity()

inst.entity:AddTransform()
inst.entity:AddAnimState()
inst.entity:AddNetwork()

MakeInventoryPhysics(inst)

inst.AnimState:SetBank("my_food")
inst.AnimState:SetBuild("my_food")
inst.AnimState:PlayAnimation("idle")

-- Add food tag
inst:AddTag("preparedfood")

inst.entity:SetPristine()

if not TheWorld.ismastersim then
return inst
end

-- Basic components
inst:AddComponent("inspectable")
inst:AddComponent("inventoryitem")

-- Make it edible
inst:AddComponent("edible")
inst.components.edible.healthvalue = 20
inst.components.edible.hungervalue = 37.5
inst.components.edible.sanityvalue = 15
inst.components.edible.foodtype = FOODTYPE.VEGGIE

-- Special effect when eaten
inst.components.edible:SetOnEatenFn(function(inst, eater)
if eater.components.temperature ~= nil then
-- Cool down the eater
eater.components.temperature:SetTemperature(eater.components.temperature:GetCurrent() - 10)
end
end)

-- Make it perishable
inst:AddComponent("perishable")
inst.components.perishable:SetPerishTime(TUNING.PERISH_MED)
inst.components.perishable:StartPerishing()
inst.components.perishable.onperishreplacement = "spoiled_food"

-- Make it stackable
inst:AddComponent("stackable")
inst.components.stackable.maxsize = 10

return inst
end

return Prefab("my_food", fn, assets)

Structure Prefab

-- Define a structure prefab
local assets = {
Asset("ANIM", "anim/my_structure.zip"),
}

local prefabs = {
"collapse_small",
}

local function fn()
local inst = CreateEntity()

inst.entity:AddTransform()
inst.entity:AddAnimState()
inst.entity:AddSoundEmitter()
inst.entity:AddNetwork()

-- Make it a structure
inst:AddTag("structure")

-- Set up visuals
inst.AnimState:SetBank("my_structure")
inst.AnimState:SetBuild("my_structure")
inst.AnimState:PlayAnimation("idle")

-- Add minimap icon
inst.entity:AddMiniMapEntity()
inst.MiniMapEntity:SetIcon("my_structure.tex")

-- Make it collidable
MakeObstaclePhysics(inst, 0.5)

inst.entity:SetPristine()

if not TheWorld.ismastersim then
return inst
end

-- Basic components
inst:AddComponent("inspectable")

-- Make it workable (can be hammered)
inst:AddComponent("workable")
inst.components.workable:SetWorkAction(ACTIONS.HAMMER)
inst.components.workable:SetWorkLeft(4)
inst.components.workable:SetOnFinishCallback(function(inst, worker)
-- Play destruction effects
inst.components.lootdropper:DropLoot()

local fx = SpawnPrefab("collapse_small")
fx.Transform:SetPosition(inst.Transform:GetWorldPosition())
fx:SetMaterial("wood")

inst:Remove()
end)

-- Make it drop loot when destroyed
inst:AddComponent("lootdropper")
inst.components.lootdropper:SetLoot({"boards", "boards", "twigs"})

-- Make it burnable
MakeSmallBurnable(inst, TUNING.MED_BURNTIME)
MakeSmallPropagator(inst)

-- Make it saveable
inst:AddComponent("hauntable")
inst.components.hauntable:SetHauntValue(TUNING.HAUNT_TINY)

return inst
end

return Prefab("my_structure", fn, assets)

Advanced Prefab Techniques

Prefab with Custom Actions

-- Define a prefab with custom actions
local assets = {
Asset("ANIM", "anim/my_special_item.zip"),
}

-- Define the custom action in modmain.lua
--[[
local MYACTION = Action({priority=10, mount_valid=true})
MYACTION.str = "Activate"
MYACTION.id = "MYACTION"
MYACTION.fn = function(act)
if act.target and act.target.components.myactionable then
return act.target.components.myactionable:DoMyAction(act.doer)
end
return false
end

-- Add the action to the component action handler
AddComponentAction("SCENE", "myactionable", function(inst, doer, actions, right)
if right and inst:HasTag("myactionable") then
table.insert(actions, ACTIONS.MYACTION)
end
end)
]]--

-- Create a component for the action
local MyActionable = Class(function(self, inst)
self.inst = inst
self.uses = 10

-- Add tag for action filtering
inst:AddTag("myactionable")
end)

function MyActionable:DoMyAction(doer)
if self.uses <= 0 then
return false
end

-- Do something when action is performed
self.uses = self.uses - 1

-- Create some effect
local fx = SpawnPrefab("sparkle")
fx.Transform:SetPosition(self.inst.Transform:GetWorldPosition())

-- Maybe give the user something
if doer.components.inventory then
local reward = SpawnPrefab("goldnugget")
doer.components.inventory:GiveItem(reward)
end

-- Remove the item when uses are depleted
if self.uses <= 0 then
self.inst:Remove()
end

return true
end

-- Save/load
function MyActionable:OnSave()
return {uses = self.uses}
end

function MyActionable:OnLoad(data)
if data and data.uses then
self.uses = data.uses
end
end

-- Prefab function
local function fn()
local inst = CreateEntity()

inst.entity:AddTransform()
inst.entity:AddAnimState()
inst.entity:AddNetwork()

MakeInventoryPhysics(inst)

inst.AnimState:SetBank("my_special_item")
inst.AnimState:SetBuild("my_special_item")
inst.AnimState:PlayAnimation("idle")

-- Add tag for the action
inst:AddTag("myactionable")

inst.entity:SetPristine()

if not TheWorld.ismastersim then
return inst
end

-- Basic components
inst:AddComponent("inspectable")
inst:AddComponent("inventoryitem")

-- Add our custom component
inst:AddComponent("myactionable")

return inst
end

return Prefab("my_special_item", fn, assets)

Prefab with State Graph

-- Define a prefab with a state graph
local assets = {
Asset("ANIM", "anim/my_creature.zip"),
}

local prefabs = {
"meat",
}

-- Create a brain for AI behavior
local brain = require "brains/my_creature_brain"

-- Create state graph for the creature
local states = {
State {
name = "idle",
tags = {"idle", "canrotate"},

onenter = function(inst)
inst.AnimState:PlayAnimation("idle_loop", true)
inst.Physics:Stop()
end,
},

State {
name = "walk",
tags = {"moving", "canrotate"},

onenter = function(inst)
inst.AnimState:PlayAnimation("walk_loop", true)
end,
},

State {
name = "attack",
tags = {"attack", "busy"},

onenter = function(inst)
inst.AnimState:PlayAnimation("attack")
inst.components.combat:StartAttack()
end,

timeline = {
TimeEvent(15*FRAMES, function(inst)
inst.components.combat:DoAttack()
inst.SoundEmitter:PlaySound("dontstarve/creatures/my_creature/attack")
end),
},

events = {
EventHandler("animover", function(inst)
inst.sg:GoToState("idle")
end),
},
},
}

local function fn()
local inst = CreateEntity()

inst.entity:AddTransform()
inst.entity:AddAnimState()
inst.entity:AddSoundEmitter()
inst.entity:AddDynamicShadow()
inst.entity:AddNetwork()

-- Set up physics
MakeCharacterPhysics(inst, 50, 0.5)

-- Set up animations
inst.AnimState:SetBank("my_creature")
inst.AnimState:SetBuild("my_creature")
inst.AnimState:PlayAnimation("idle_loop", true)

-- Add tags
inst:AddTag("monster")
inst:AddTag("hostile")

inst.entity:SetPristine()

if not TheWorld.ismastersim then
return inst
end

-- Add components
inst:AddComponent("inspectable")

-- Add locomotion
inst:AddComponent("locomotor")
inst.components.locomotor.walkspeed = 3
inst.components.locomotor.runspeed = 5

-- Add combat
inst:AddComponent("combat")
inst.components.combat:SetDefaultDamage(20)
inst.components.combat:SetAttackPeriod(2)
inst.components.combat:SetRange(2, 3)

-- Add health
inst:AddComponent("health")
inst.components.health:SetMaxHealth(200)

-- Add loot
inst:AddComponent("lootdropper")
inst.components.lootdropper:SetLoot({"meat", "meat"})

-- Set up state graph
inst:SetStateGraph("SGmy_creature")

-- Set up AI brain
inst:SetBrain(brain)

return inst
end

-- Register the prefab
return Prefab("my_creature", fn, assets, prefabs)

Prefab with Network Replication

-- Define a prefab with network replication
local assets = {
Asset("ANIM", "anim/my_networked_item.zip"),
}

local function fn()
local inst = CreateEntity()

inst.entity:AddTransform()
inst.entity:AddAnimState()
inst.entity:AddNetwork()

MakeInventoryPhysics(inst)

inst.AnimState:SetBank("my_networked_item")
inst.AnimState:SetBuild("my_networked_item")
inst.AnimState:PlayAnimation("idle")

-- Add network variables
inst.charge_level = net_byte(inst.GUID, "my_networked_item.charge", "chargedirty")
inst.active = net_bool(inst.GUID, "my_networked_item.active", "activedirty")

-- Initialize network values
inst.charge_level:set(5)
inst.active:set(false)

-- Add client-side handlers
inst:ListenForEvent("chargedirty", function()
-- Update visual based on charge level
local charge = inst.charge_level:value()
inst.AnimState:OverrideSymbol("meter", "my_networked_item", "meter_" .. charge)
end)

inst:ListenForEvent("activedirty", function()
-- Update visual based on active state
if inst.active:value() then
inst.AnimState:PlayAnimation("active_loop", true)
else
inst.AnimState:PlayAnimation("idle")
end
end)

inst.entity:SetPristine()

if not TheWorld.ismastersim then
return inst
end

-- Server-side components
inst:AddComponent("inspectable")
inst:AddComponent("inventoryitem")

-- Add custom component to manage charge
inst:AddComponent("mychargeableitem")
inst.components.mychargeableitem.onchargechanged = function(charge)
inst.charge_level:set(charge)
end

inst.components.mychargeableitem.onactivated = function(active)
inst.active:set(active)
end

return inst
end

return Prefab("my_networked_item", fn, assets)

These snippets demonstrate various prefab creation techniques for Don't Starve Together modding. Adapt them to your specific needs when creating custom items, characters, creatures, or structures.