Last Update: 2023-08-01
Components Overview
API Version: 624447
Components are the fundamental building blocks for entity behavior in Don't Starve Together. The game uses a component-based architecture where entities (players, creatures, items, etc.) are composed of various components that define their functionality.
API Version Information
All components in this documentation are based on Don't Starve Together API version 624447. This version number corresponds to the game build version and ensures compatibility between mods and the game. When creating mods, make sure to test them with the latest game version, as component behavior may change between updates.
What are Components?
Components are self-contained modules that handle specific aspects of an entity's behavior. Each component is responsible for a particular feature or capability of an entity. For example:
- A
health
component manages an entity's health state - A
combat
component handles attacking and being attacked - An
inventory
component allows an entity to carry items
By combining different components, the game creates complex entities with diverse behaviors.
Using Components
Components are attached to entities and then configured to create the desired behavior:
-- Create a basic entity
local entity = CreateEntity()
-- Add components
entity:AddComponent("health")
entity:AddComponent("combat")
-- Configure components
entity.components.health:SetMaxHealth(100)
entity.components.combat:SetDefaultDamage(10)
Core Components
Some of the most commonly used components in Don't Starve Together include:
Component | Purpose |
---|---|
Combat | Handles attacking and being attacked |
Health | Manages health, damage, and death |
Inventory | Allows carrying and using items |
Weapon | Defines item attack behavior |
Temperature | Manages temperature effects |
Hunger | Handles food and starvation |
Sanity | Controls mental state and effects |
Burnable | Makes entity flammable |
Cookable | Allows entity to be cooked |
Workable | Makes entity interact with tools |
Growable | Allows entity to grow over time |
Perishable | Makes items spoil over time |
Locomotor | Controls entity movement |
Builder | Manages crafting capabilities |
Edible | Defines food properties |
Eater | Allows entity to consume food |
Container | Provides storage capabilities |
Stackable | Allows items to stack |
Equippable | Allows items to be equipped |
Inspectable | Enables examination by players |
Trader | Manages trading interactions |
LootDropper | Controls item drops |
Other Components | Additional specialized components |
Component Lifecycle
Components have several lifecycle methods:
- Constructor: Called when the component is created
- OnRemoveFromEntity: Called when the component is removed
- OnSave: Called when the game is saved to serialize component state
- OnLoad: Called when the game is loaded to deserialize component state
Component Communication
Components can communicate with each other through:
-
Direct Access: Components can directly access other components on the same entity
-- Health component accessing combat component
local damage = self.inst.components.combat.defaultdamage -
Events: Components can trigger and listen for events
-- Trigger an event
self.inst:PushEvent("attacked", {attacker = attacker, damage = damage})
-- Listen for an event
self.inst:ListenForEvent("death", OnDeath)
Component Interactions
Components are designed to work together to create complex behaviors. Understanding how components interact is crucial for effective modding. Here are common interaction patterns:
Health and Combat Interaction
The Health and Combat components work closely together to manage damage and death:
-- Combat component deals damage to the Health component
function Combat:DoAttack(target)
if target.components.health ~= nil then
local damage = self:CalcDamage(target)
target.components.health:DoDelta(-damage)
if target.components.health:IsDead() then
self:OnKill(target)
end
end
end
Inventory and Equippable Interaction
The Inventory component manages equipped items through the Equippable component:
function Inventory:Equip(item)
if item.components.equippable ~= nil then
local eslot = item.components.equippable.equipslot
local old_item = self:GetEquippedItem(eslot)
if old_item ~= nil then
self:Unequip(eslot)
end
item.components.equippable:OnEquip(self.inst)
self.equipslots[eslot] = item
self.inst:PushEvent("equipped", {item = item, eslot = eslot})
end
end
Container and Inventory Interaction
Containers work with the Inventory system to store and transfer items:
function Container:GiveItem(item, slot)
if self.inst.components.inventory ~= nil then
-- First try to add to existing stacks
for i, v in pairs(self.slots) do
if v.prefab == item.prefab and v.components.stackable ~= nil and
v.components.stackable:CanStack(item) then
return v.components.stackable:Put(item)
end
end
-- Then try to find an empty slot
local emptyslot = slot or self:GetFirstEmptySlot()
if emptyslot ~= nil then
self.slots[emptyslot] = item
return item
end
end
return nil
end
Common Interaction Patterns
-
State Management: Components often manage different aspects of an entity's state and notify each other of changes
- Health notifies Combat when health reaches zero
- Temperature notifies Health when freezing/overheating damage occurs
-
Resource Management: Components work together to manage resources
- Hunger affects Health regeneration
- Fuel components interact with Burnable components
-
Action Chains: Components form chains of actions
- Combat triggers LootDropper when killing an entity
- Workable triggers resource drops when finished working
-
Buff Systems: Components apply and manage buffs/debuffs
- Equippable items provide buffs to Temperature, Combat, etc.
- Food items affect Hunger, Health, and Sanity
Understanding these interaction patterns helps when creating or modifying components to ensure they integrate properly with the existing system.
Creating Custom Components
While modding, you can create custom components to add new behaviors:
local MyComponent = Class(function(self, inst)
self.inst = inst
self.value = 10
end)
function MyComponent:DoSomething()
print("Doing something with value:", self.value)
end
return MyComponent
Then register and use the component:
local MyComponent = require "components/mycomponent"
AddComponentPostInit("mycomponent", MyComponent)
-- Later, add to an entity
entity:AddComponent("mycomponent")
entity.components.mycomponent:DoSomething()
Component Replication
For multiplayer synchronization, many components have corresponding replica components that exist on both server and client. Replica components contain only the data needed by clients for rendering and prediction.
For example, the health
component has a health_replica
counterpart that replicates the current health value to clients without exposing all server-side health logic.
Best Practices
When working with components:
- Keep components focused: Each component should handle one specific aspect of functionality
- Use events for cross-component communication when appropriate
- Avoid circular dependencies between components
- Clean up event listeners in OnRemoveFromEntity to prevent memory leaks
- Use the existing component architecture rather than creating workarounds