Don't Starve Together

Don't Starve Together

Insight (Show Me+)
 This topic has been pinned, so it's probably important
penguin0616  [developer] 27 Mar, 2021 @ 12:11pm
Adding modded information
So, you've modded something and you want Insight to show information for it. Well, here's what you need to know.

Adding information for a component
The information Insight displays is largely based off of components. It iterates over each entity's components, checks if there's a valid descriptor for it, and runs the descriptor if it exists.
Here's one example of adding a descriptor:
-- modmain.lua local _G = GLOBAL local function AddDescriptors() if not _G.rawget(_G, "Insight") then return end _G.Insight.descriptors.my_component_name = { Describe = function(self, context) local description if context.player.name:find("a") then description = "You have an 'a' in your name!" else description = "You do <color=#ff0000>not</color> have an 'a' in your name.." end return { priority = 0, description = description } end } end AddSimPostInit(AddDescriptors) -- _G.Insight.descriptors may not exist yet, but it will exist at AddSimPostInit.

Note: Descriptor names are unique, and only one can exist for a component. So if there was another descriptor for "my_component_name", this would overwrite it.

Insight calls the Describe function with the parameters self and context.
self is a reference to the component, while context is background information about the player.

A rough example of context's structure is:
context = { player = player_entity, config = { -- configuration from insight ["display_upgradeable"] = true, ... }, external_config = { -- external mod related config ... }, usingIcons = true/false, -- whether the user is using icon formatting lstr = {...}, -- see scripts/language.lua is_server_owner = true/false, etc = {...} }

Descriptors can return nil, or a table. If returning a table, the table should look like in the example.
Priority is used for determing whether information shows up at the top or the bottom of an entity's overall information. Higher priority = higher spot.
Description can be nil or a string. It uses Insight's RichText system.

Adding information for a specific prefab
This follows essentially the same logic as adding information for a component, but with minor changes.
-- modmain.lua local _G = GLOBAL local function AddPrefabDescriptors() if not _G.rawget(_G, "Insight") then return end _G.Insight.prefab_descriptors.my_prefab = { Describe = function(inst, context) local description if context.player.name:find("a") then description = "You have an 'a' in your name!" else description = "You do <color=#ff0000>not</color> have an 'a' in your name.." end return { priority = 0, description = description } end } end AddSimPostInit(AddPrefabDescriptors)

Insight's RichText
Insight's RichText system lets you stylise your text to a small degree. The game's text rendering system is lacking, so we have to make do.
All descriptors' descriptions are run through this system.

It works on a tag based system, similar to XML or HTML.
RichText currently supports 4 stylings: coloring, icon insertion, superscript, subscript.

Coloring
local colored_text = "I like the colors <color=#0000cc>blue</color> and <color=#00cc00>green</color>. Hey, a <color=MOB_SPAWN>bearger</color>!"
The spacing is extremely important in tags, and they must obey the format outlined in the example.
Color can equal a hexadecimal color code, or they can be a specific color stored in _G.Insight.COLORS.
I sometimes store frequently used colors, such as MOB_SPAWN (which is #ee6666) in the COLORS table so I don't have to change multiple strings.

Icon Insertion
Probably the trickiest to work with out of all of the features. The gist of it is that an icon must exist in the icon_list table for it to work.
That table can be found in scripts/assets.lua
local text_with_icons = "You have a big <icon=health> sir, but your <icon=sanity> is weak."
Where <icon=health> is the health meter icon, and <icon=sanity> is the sanity meter icon.

Superscript, subscript
local super_and_sub = "2<sup>10</sup> is 1024. log<sub>b</sub>x = y."

That's pretty much it. There's a ton of examples in scripts/descriptors. So if there's a specific information style you want to use, just look at the responsible descriptor.
Let me know if you have any questions.
Last edited by penguin0616; 21 Jul, 2022 @ 1:19pm
< >
Showing 1-12 of 12 comments
Serp 21 Jul, 2022 @ 2:35am 
I think one should add within the local function a check if Insight mod is enabled by checking if the global variable exist:
if _G.rawget(_G,"Insight") and _G.Insight~=nil then
Otherwise it will most likely crash if the mod runs withoug Insight enabled?!
penguin0616  [developer] 21 Jul, 2022 @ 1:19pm 
Originally posted by Serp:
I think one should add within the local function a check if Insight mod is enabled by checking if the global variable exist:
if _G.rawget(_G,"Insight") and _G.Insight~=nil then
Otherwise it will most likely crash if the mod runs withoug Insight enabled?!
Thanks, code was adjusted.
Serp 31 Jul, 2022 @ 6:26pm 
How to add information to things that already have a descriptor without overwriting it? (I want just append to the description string)
penguin0616  [developer] 31 Jul, 2022 @ 7:15pm 
Originally posted by Serp:
How to add information to things that already have a descriptor without overwriting it? (I want just append to the description string)

I was writing an example in response to your question, and realized that there's no good way to do it at the moment since descriptors' Describe can return a bunch of nils or tables. I'll have to think about what can be done.

That being said, here's the example. This sort of thing is probably the best option at the moment.
local Insight = _G.Insight if type(Insight.descriptors.burnable) == "table" and Insight.descriptors.burnable.Describe then local oldDescribe = Insight.descriptors.burnable.Describe Insight.descriptors.burnable.Describe = function(self, context, ...) local packed = Insight.env.pack(oldDescribe(self, context, ...)) for i,v in ipairs(packed) do if v and v.name == "burnable" and v.description then -- apply description changing logic here v.description = "Stuff: " .. v.description break end end return Insight.env.vararg(packed) end end
Last edited by penguin0616; 31 Jul, 2022 @ 7:15pm
Serp 31 Jul, 2022 @ 8:45pm 
thanks, so my final code to append sth on the edible component is working like this:
(edited after your first response)

local _G = GLOBAL local function AddDescriptors() if not _G.rawget(_G, "Insight") then return end local oldDescribe = nil if _G.Insight.descriptors.edible==false then return end -- if it is false something went wrong in Insight so we can not change it, must be fixed within Insight if type(_G.Insight.descriptors.edible) == "table" then if _G.Insight.descriptors.edible.Describe then oldDescribe = _G.Insight.descriptors.edible.Describe end else _G.Insight.descriptors.edible = {} end _G.Insight.descriptors.edible.Describe = function(self, context,...) local my_description = "my edible description" if oldDescribe~=nil then -- if anyone already added a description, do not overwrite it, but add stuff to it local packed = _G.Insight.env.pack(oldDescribe(self, context, ...)) local old_description = "" if my_description~=nil then for i,v in ipairs(packed) do if v and v.name == "edible" then old_description = v.description or "" v.description = old_description.."\n"..my_description -- append description break end end end return _G.Insight.env.vararg(packed) else return { priority = 10, description = my_description } end end end AddSimPostInit(AddDescriptors)

small question:
The code checks for "v.name", while your example code in the first post does not return a "name". Is this added automatically by your mod? Or should we always add a name to the returned values?
And maybe also add "alt_description" to your example.
Last edited by Serp; 31 Jul, 2022 @ 10:26pm
penguin0616  [developer] 31 Jul, 2022 @ 10:12pm 
Originally posted by Serp:
small question:
The code checks for "v.name", while your example code in the first post does not return a "name". Is this added automatically by your mod? Or should we always add a name to the returned values?
And maybe also add "alt_description" to your example.

It's another one of those issues in the example where modding the describe functions is difficult. If a descriptor returns a table without a name field, it gets automatically added in later. I specify the name ahead of time if the Describe returns multiple tables, since it's a requirement in that case. When there isn't a name, you just hope it's the first return.

In your case, since you're modifying edible, it already has the name so you should be okay.

I would change this:
if type(_G.Insight.descriptors.edible) == "table" and _G.Insight.descriptors.edible.Describe then oldDescribe = _G.Insight.descriptors.edible.Describe else _G.Insight.descriptors.edible = {} end
to remove the else & table assignment,
If it's not a table, that means it's probably false, which means it likely hit an error during loading. You'd just be suppressing the error at that point, which is not recommended. Better to see why it's erroring.
Serp 31 Jul, 2022 @ 10:27pm 
Originally posted by penguin0616:
I would change this:
to remove the else & table assignment,
If it's not a table, that means it's probably false, which means it likely hit an error during loading. You'd just be suppressing the error at that point, which is not recommended. Better to see why it's erroring.
hm... simply removing it does not work, because it also may be "nil" if no other mod defined it yet. (the code should also work to be compatible to other mods that are adding descriptions, also to things Insight does not add one).

I edited the code above to check for "false" and only set edible a new table if is no table yet. Unless you need no other "non-table" values, this should be fine now I guess.
Last edited by Serp; 31 Jul, 2022 @ 10:28pm
penguin0616  [developer] 31 Jul, 2022 @ 10:30pm 
Originally posted by Serp:
hm... simply removing it does not work, because it also may be "nil" if no other mod defined it yet. (the code should also work to be compatible to other mods that are adding descriptions, also to things Insight does not add one).

I edited the code above to check for "false" and only set edible a new table if is no table yet. Unless you need no other "non-table" values, this should be fine now I guess.


descriptors is a metatable. When you index it to check for a descriptor, it first tries to load it if it hasn't been loaded yet. The descriptor should never be nil. It will always be a table or false.
Last edited by penguin0616; 31 Jul, 2022 @ 10:31pm
Wonderlarr 28 Sep, 2022 @ 4:37am 
How can I remove a component descriptor for a specific prefab? I have a unique case where I'm using the Fueled component in a sortof weird way within my mod which insight is detecting as Fuel Efficiency being 1.6666666667%. I'd like to hide this, since although it's accurate, it's already cluttered enough https://i.imgur.com/vIMoo1i.png
penguin0616  [developer] 1 Oct, 2022 @ 8:33pm 
@Skylarr I'm debating adding a "AddDescriptorPostDescribe" function. I feel that would likely work. Thoughts?
penguin0616  [developer] 24 Jan, 2023 @ 6:07pm 
I've added AddDescriptorPostDescribe(modname, descriptor, callback) for modders to use (inside of the Insight environment).
The callback is called with the component and table of data returned from the descriptor's Describe.
penguin0616  [developer] 1 Aug, 2024 @ 3:32pm 
@伺夜 I don't understand the request.
< >
Showing 1-12 of 12 comments
Per page: 1530 50