Jump to content

Recommended Posts

Hi,

at the moment I'm improving the "Multifunctional Carpet" mod https://steamcommunity.com/sharedfiles/filedetails/?id=506553597
Therefore I implemented, that the bonusses only work, if near to some base buildings: http://forums.kleientertainment.com/topic/68964-check-for-structure-within-range-and-add-light/

Now I need something that shows the player, if all requirements are fullfield.
I thought about adding an small "home" icon somewhere at the edge (configurable position). The easiest way I guess would be to use an already existing icon. But how/where can I see the existing icons? How to open .tex files, or are these not the images?
And how to add and remove this icon for every player in a server_only mod?
 

 

tex is an encrypted png format. To view them (and save as png), as well as do the opposite (save png as tex), you may use Matt's tool:

Note: for tex images to work in DST, they MUST HAVE 1:1 RATIO!!!!!! aka you can't make 400x200 image, it must be 400x400.

Additional info: images in DST work in pairs with atlas images ({filename}.xml). If you know what SPRITEs are, then atlas is a definition of sprite, it's syntax allows you to lock different images within one TEX file. Aka you split image into 4 parts, then you define atlas and <region> different images, mapping them to their names while defining u1=0 u2=0.5 v1=0 v2=0.5 u and v are different axis 0 = 0%, 1 = 100%

I can't really recal but i guess u=0 v=0 is top right corner of an image.

As for how to add an icon into interface, i recommend you look into the Combined Status mod for some code pieces :)

As for how I would do it, player.HUD.controls <-- is the class that defines all the hud DOCKING areas for stuff like icons, so you do AddClassPostInit("widgets/controls").

 

How to add this for a server mod - is a bad question. See the mods can be of 3 types, server-only, client-only or server with all-clients-require-mod.

Difference is, client mod is run on client, server will not do any additional calculation for you, except for the common API calls that are already in the game files. For server only mod, server may do some stuff on it's side, that client should not know of, some calculations, etc. But you want the user to load additional icon and place it somwhere on the HUD, that's client stuff. Also you need the carpet to give all the players bonuses, that's server stuff. Thus you need the mod on server and all the clients. Good for you, that when you place all clients require mod tag, they automaticly download it on join.

Thank you very much! :)

I know what a atlas is, but I did not know that they are used here, thank you for explanation :)

Ok, I will look how it is done in combinied status :)

So I have to set all_clients_require_mod = true and the server/client thing should be solved? To be sure this will work I will upload the whole mod here in another thread first, after I think it is finished :)

 

edit:

is there an easy way to see all the icons that already exist in game, without being forced to convert every single .tex to png?

Edited by Serpens
3 hours ago, Serpens said:

So I have to set all_clients_require_mod = true and the server/client thing should be solved? To be sure this will work I will upload the whole mod here in another thread first, after I think it is finished

I'm not gosu at client-server modding for DST, I've only been doing that for a couple of days, but from what I've learned, there are a few things you should watch out. Aka server side code has a lot more classes and code used over client side. That means that a lot of things should only run on the server, aka put within condition:

if TheNet:IsMasterSim() then

If you don't do that, you might end up referencing function that is not defined (aka defined only on server)

Also do not forget to put

inst.entity:SetPristine()

within prefab 'fn' function to tell DS engine that the code above runs on client and on the server, with data from client and the server, so there's no need for syncing the result, as both client and server with their data will have a simillar output.

3 hours ago, Serpens said:

is there an easy way to see all the icons that already exist in game, without being forced to convert every single .tex to png?

Unfortunately not, infact there are no icons for insulation from what i know, so you should just paint one in the HUD style.

Edited by IvanX

ok... it is very hard to find out how to add icons with the combined status mod.., cause it does soo much more than just adding an icon.
Do you know something different were I could find out how to do it?

Or do you have another idea how to visualise that the bonus is working?
Small glowing of the character, even at day, would be another way, but also the other request for glowing has no answer yet... http://forums.kleientertainment.com/topic/69066-glow-in-dark/

 

I did not get the

if TheNet:IsMasterSim() then ... end

thing yet...
I thought I have to do all stuff, that should be done at the server only in "..."?
But the game crashed with error that TheNet is not known. And if I try GLOBAL.TheNet it is IsMasterSim that is not known...  

edit:

or do you mean TheWorld:IsMasterSim() ?

Edited by Serpens

Theres actually a component for glowing in the dark, just view heatstone prefab to figure what its called, as for how to add an icon view widget/controls, it has all sorts of areas you can insert your indicator at, docking top right, right, bottom, left, chose one :)

 

I'm on the run atm, may get a look afterwards

hm... looked at widget/controls, again at combinied status, at gesturewheel and several other mods... but I still don't know an easy way to add a simple icon =/ Why is this that difficult?!

From what I've seen so far, it seems I have to open a whole new class with new components lua? And also if I set the icon to self.icon in a class, how to Hide and Show it outside that class?

Naw, you don't need to make a whole new class, you can just use an existing one. The basic class for static images is .. you won't believe it ... "Image" :D

local Image = require "widgets/image" -- in the declaration area at the top
local MyImage = inst:AddChild(Image("myatlas.xml", "myimage.tex"))
MyImage:SetScale(1.1) -- scaleX, scaleY
MyImage:SetPosition(0,-100) -- offset X, offset Y in from widget "inst" docking position

But you have to add that to something, Something that is a WIDGET.

Some possible widgets to put it into are listed in "widgets/controls":

    self.topleft_root
    self.topright_root
    self.bottom_root
    self.top_root
    self.left_root
    self.right_root
    self.bottomright_root
    self.topright_over_root

 

Just do AddClassPostInit("widgets/controls", ...)

And then inst.topleft_root:AddChild...

local Image = GLOBAL.require('widgets/image')
local function BaseIcon(self)
    self.baseicon = self.topleft_root:AddChild(Image("images/baseicon.xml", "baseicon.tex"))
    self.baseicon:SetPosition(0,-100)--(-40, -40, 0)
    self.baseicon:SetScale(1,1)--(-.7, .7, .7)
    -- self.baseicon:Hide()
    self.baseicon:Show()
end
AddClassPostConstruct("widgets/controls", BaseIcon)

but how to hide/show it outside of this function? when I try to call self.baseicon:Show() outside I get: attempt to index global 'self' (a nil value)

local Image = GLOBAL.require('widgets/image')
local function BaseIcon(self)
    local baseicon = self.topleft_root:AddChild(Image("images/baseicon.xml", "baseicon.tex"))
    baseicon:SetPosition(0,-100)--(-40, -40, 0)
    baseicon:SetScale(1,1)--(-.7, .7, .7)
    -- self.baseicon:Hide()
    baseicon:Show()
end
AddClassPostConstruct("widgets/controls", BaseIcon)

-> trying to call basicicon outside -> attempt to index global 'baseicon' (a nil value)

Well a dirty way would be to define a global variable inside modmain.lua, and inside your BaseIcon function do myglobalvariable = ...

The better way would be to address that variable directly from the point of insertion.

controls instance is located within ThePlayer.HUD.controls.baseicon:Show()

But to do so, you obviously need to add a binding to controls. instead of local baseicon, do self.{mymodname}_baseicon = self.topleft_root:AddChild...

thank you.

I have now:

local Image = GLOBAL.require('widgets/image')
local function BaseIcon(self)
    self.HomeBase_baseicon = self.topleft_root:AddChild(Image("images/baseicon.xml", "baseicon.tex"))
    self.HomeBase_baseicon:SetPosition(0,-100)--(-40, -40, 0)
    self.HomeBase_baseicon:SetScale(1,1)--(-.7, .7, .7)
end
AddClassPostConstruct("widgets/controls", BaseIcon)

The call outside of it has to be "GLOBAL.ThePlayer.HUD.controls.HomeBase_baseicon:Hide()"

 

But I see no icon ingame (the baseicon.xml and .tex is just the rain file from combined status mod. I renamed it and replaced "rain" inside of xml file with "baseicon".)

At what position should be the icon with this settings? I guess top left and 100 pixel down? Or could it be behind the crafting menu? What should I set for position to be in the middle of the screen?

Or is there another mistake I made?

 

edit:

ah, should be the name self.HomeBase_baseicon the exact name of the mod? or is just a simular name needed to remember?

Edited by Serpens

The naming convention is just to never get a collision with another mod. I mean if you just named it a baseicon, what are the odds that some other guy would do the same? :p

For middle of the screen there's

    self.containerroot

although I would not recommend adding a status icon there ;)

Almost forgot, you need to define all your assets at the beginning of modmain.lua

Assets = {
    Asset("ATLAS", "images/baseicon.xml"),
}

Also positioning 0,-100 from top left would put image outside the screen, try 100,100

this is sooooo complicated >.<

I just tried

Assets = {
    Asset("ATLAS", "images/baseicon.xml"),
}

local Image = GLOBAL.require('widgets/image')
local function BaseIcon(self)
    self.HomeBase_baseicon = self.topleft_root:AddChild(Image("images/baseicon.xml", "baseicon.tex"))
    self.HomeBase_baseicon:SetPosition(100,100)--(-40, -40, 0)
    self.HomeBase_baseicon:SetScale(1,1)--(-.7, .7, .7)
end
AddClassPostConstruct("widgets/controls", BaseIcon)

GLOBAL.ThePlayer.HUD.controls.HomeBase_baseicon:Show()

So I added the Show() command directly under this in the mainmod.lua, but this is causing an crash with "attempt to index field 'ThePlayer' (a nil value)"

The other part were I try to show the icon does look like this, so called in the CheckBase function, which causes no error, but I can't see the icon, although the base check works (checked it with prints):

local function CheckBase(inst) -- checks, if the player is near all required buildings
    local x, y, z = inst.Transform:GetWorldPosition()
    local structures = GLOBAL.TheSim:FindEntities(x, y, z, GetModConfigData("base_range"),"structure",{"tree","sapling","stump"}) 
    local science = GetModConfigData("science")
    local alchemy = GetModConfigData("alchemy")
    local cookpot = GetModConfigData("cookpot")
    local chest = GetModConfigData("chest")
    local dryrack = GetModConfigData("dryrack")
    local lightningrod = GetModConfigData("lightningrod")
    local farm = GetModConfigData("farm")
    local birdcage = GetModConfigData("birdcage")
    local light = GLOBAL.GetClosestInstWithTag("lightsource", inst, GetModConfigData("base_range")) 
    if not light then light = GetModConfigData("light") end
    for i, v in ipairs(structures) do
        if v.prefab=="researchlab" then
            science = true
        elseif v.prefab=="researchlab2" then 
            alchemy = true
        elseif v.prefab=="cookpot" or v.prefab=="cookpot_survival" then
            cookpot = true
        elseif v.prefab=="treasurechest" or v.prefab=="pandoraschest" or v.prefab=="skullchest" or v.prefab=="minotaurchest" then
            chest = true
        elseif v.prefab=="meatrack" then
            dryrack = true
        elseif v.prefab=="lightning_rod" then
            lightningrod = true
        elseif v.prefab=="slow_farmplot" or v.prefab=="fast_farmplot" then
            farm = true
        elseif v.prefab=="birdcage" then
            birdcage = true
        end
    end
    if light and science and alchemy and cookpot and chest and dryrack and lightningrod and farm and birdcage then
        GLOBAL.ThePlayer.HUD.controls.HomeBase_baseicon:Show()
        return true
    end
    -- GLOBAL.ThePlayer.HUD.controls.HomeBase_baseicon:Hide() 
    return false
end


if GetModConfigData("rain_reduction_wooden") ~= 1 or GetModConfigData("rain_reduction_checker")~= 1 or GetModConfigData("rain_reduction_carpet")~= 1 then
    AddComponentPostInit("moisture", function(self)
        local _GetMoistureRate = self.GetMoistureRate
        self.GetMoistureRate = function(self)
            if _GetMoistureRate(self)>0 then -- only check it, if object is getting wet
                local tile, data = self.inst:GetCurrentTileType()
                if (tile == GLOBAL.GROUND.CARPET and GetModConfigData("rain_reduction_carpet")~=1) or (tile == GLOBAL.GROUND.WOODFLOOR and GetModConfigData("rain_reduction_wooden")~=1) or (tile == GLOBAL.GROUND.CHECKER and GetModConfigData("rain_reduction_checker")~=1) then
                    if GetModConfigData("base_required_rainproof")==0 or CheckBase(self.inst) then -- give bonus if no base is required or if there is a base
                        if (tile == GLOBAL.GROUND.CARPET) then
                            return math.max(0,_GetMoistureRate(self)*GetModConfigData("rain_reduction_carpet")) 
                        elseif (tile == GLOBAL.GROUND.WOODFLOOR) then
                            return math.max(0,_GetMoistureRate(self)*GetModConfigData("rain_reduction_wooden")) 
                        elseif (tile == GLOBAL.GROUND.CHECKER) then
                            return math.max(0,_GetMoistureRate(self)*GetModConfigData("rain_reduction_checker")) 
                        end
                    end
                end
            end
            return _GetMoistureRate(self)
        end
    end)
end

 

You can't put it directly under, that's like way before anything is even initialized, you hardly "listed" your "want-to-inits" there :)

Uhm. are you sure your condition successes? I mean... It's .. and and and and and and. Like if you have ALL those prefabs next to you. And what are those GetModConfigData pieces? they are clearly ignored as you redefine your variables a few lines below :)

16 minutes ago, IvanX said:

You can't put it directly under, that's like way before anything is even initialized, you hardly "listed" your "want-to-inits" there :)

Uhm. are you sure your condition successes? I mean... It's .. and and and and and and. Like if you have ALL those prefabs next to you. And what are those GetModConfigData pieces? they are clearly ignored as you redefine your variables a few lines below :)

ah ok :)

yes the conditions are filled ;) as I said, here I have print statements that prints all the time when the requirements are fullfilled, it is ~2 times per second, so the Show() is called very very often (this is no problem, isn't it?)
And yes GetModConfigData pieces are all absolutely right , they are only overriden, if they are found ;) (the GetModConfigData is true, if it should not be needed and false if it is needed to get the bonus)

Here's a clean version of your function btw:

Except I would rather Put GetModConfigData somwhere outside, save it as Player props maybe.

local function CheckBase(inst) -- checks, if the player is near all required buildings
    local x, y, z = inst.Transform:GetWorldPosition()
    local structures = GLOBAL.TheSim:FindEntities(x, y, z, GetModConfigData("base_range"), nil, nil, ["structure","lightsource"])
    for i, v in ipairs(structures) do
        if   GetModConfigData("light")    and v:HasTag("lightsource")
          or GetModConfigData("science")  and  v.prefab=="researchlab"
          or GetModConfigData("alchemy")  and  v.prefab=="researchlab2"
          or GetModConfigData("cookpot")  and (v.prefab=="cookpot" or v.prefab=="cookpot_survival")
          or GetModConfigData("chest")    and (v.prefab=="treasurechest" or v.prefab=="pandoraschest" or v.prefab=="skullchest" or v.prefab=="minotaurchest")
          or GetModConfigData("dryrack")  and  v.prefab=="meatrack"
          or GetModConfigData("lightningrod") and v.prefab =="lightning_rod"
          or GetModConfigData("farm")     and (v.prefab=="slow_farmplot" or v.prefab=="fast_farmplot")
          or GetModConfigData("birdcage") and  v.prefab=="birdcage"
        then
          GLOBAL.ThePlayer.HUD.controls.HomeBase_baseicon:Show()
          return true
        end
    end
    return false
end

If it really runs all the time, that's probably because you have all mod options enabled, if you disable one, none will fire at all :).

 

As for why else it could not be showing... try controls.containerroot, maybe?

self.foodcrafting = self.containerroot:AddChild(...)

That's how I add my widgets into "controls" class. If it doesn't work here, then I guess there's problem with atlas/tex.

Edited by IvanX

thanks, it looks much cleaner, but your function does not work =/  I replaced the ["structure","lightsource"] with {"structure","lightsource"]}.

The if ... then condition is wrong (does not work). I have to think about it tomorrow how it is right, but all in all it is good, thanks :)
(the ModConfigData is true for all things that are not required and false for all things that are required. And if it is found within range, it was set to true in my code, so if everything required is there, the whole functions returns true)

 

Could you please tell me the complete code for your  self.foodcrafting = self.containerroot:AddChild(...) example?
So that it has to work...

Edited by Serpens
7 minutes ago, IvanX said:

It's kinda self.containerroot:AddChild( Image(atlas, filename) ), sorry about [], you're :) a bit confused sometimes, have to program on 4 different languages and only lua uses {} for numeric arrays.

Ah, I thought it would be much more to change, but you really ment only replacing self.topleft_root with self.containerroot :D
And I saw it works! The icon is there :)
And what does it mean now?

8 minutes ago, IvanX said:

That either topleftroot is hidden, (:Show() required), or you need to mess with coordinates more, or idk :)

but I can also use self.containerroot and setposition to a corner with eg. -500,-500 or simular? Or is this not possible?

About the stuff i wrote earlier considering u1 u2 v1 v2:

I was wrong u1 u2 is X coordinate from left to right, v1 v2 is Y coordinate from bottom to top.

And the tex image must be square, but it would throw a warning if it's not a power of 2 aka 32, 64, 128, 256, 512, 1024, 2048

5 minutes ago, Serpens said:

but I can also use self.containerroot and setposition to a corner with eg. -500,-500 or simular? Or is this not possible?

Nope, different monitors, different sizes, you need to use another docking. Try simply creating your own docking widget

self.HomeBase_root = self:AddChild(Widget(""))
self.HomeBase_root:SetHAnchor(ANCHOR_LEFT)
self.HomeBase_root:SetVAnchor(ANCHOR_TOP)
self.HomeBase_root:SetScaleMode(SCALEMODE_PROPORTIONAL)
self.HomeBase_root:SetMaxPropUpscale(MAX_HUD_SCALE)
self.HomeBase_root = self.HomeBase_root:AddChild(Widget(""))

Then insert image into this root instead

thanks :)

I found out the setposition i the problem... When I do self.topleft_root  without changign position, I can see an quarter of the icon on the top left :)

But with setposition 100,100 or -100,-100 I cant see it... But with 100,-100 everything is fine. Thank you very much!! :)

 

The problem left now will be to make sure that every player can see it, without generating problems for the other stuff the mod does, wich should be client only...

@IvanX just for informing you:

I had to revert most of the BaseCheck() changes you made, because I think this can't work. The for loop as to be done completey to find out if a base is build. The if condition can't be in the loop itself. So I think I have to define variables outside of the loop and change them in the loop.

It looks that way now:
 

local function CheckBase(inst) -- checks, if the player is near all required buildings
        local x, y, z = inst.Transform:GetWorldPosition()
        local structures = GLOBAL.TheSim:FindEntities(x, y, z, GetModConfigData("base_range"), nil, nil, {"structure","lightsource"})
        local science = GetModConfigData("science")
        local alchemy = GetModConfigData("alchemy")
        local cookpot = GetModConfigData("cookpot")
        local chest = GetModConfigData("chest")
        local dryrack = GetModConfigData("dryrack")
        local lightningrod = GetModConfigData("lightningrod")
        local farm = GetModConfigData("farm")
        local birdcage = GetModConfigData("birdcage")
        local light = GetModConfigData("light")
        for i, v in ipairs(structures) do
            if v.prefab=="researchlab" then
                science = true
            elseif v.prefab=="researchlab2" then 
                alchemy = true
            elseif v.prefab=="cookpot" or v.prefab=="cookpot_survival" then
                cookpot = true
            elseif v.prefab=="treasurechest" or v.prefab=="pandoraschest" or v.prefab=="skullchest" or v.prefab=="minotaurchest" then
                chest = true
            elseif v.prefab=="meatrack" then
                dryrack = true
            elseif v.prefab=="lightning_rod" then
                lightningrod = true
            elseif v.prefab=="slow_farmplot" or v.prefab=="fast_farmplot" then
                farm = true
            elseif v.prefab=="birdcage" then
                birdcage = true
            elseif v:HasTag("lightsource") then
                light = true
            end
            if light and science and alchemy and cookpot and chest and dryrack and lightningrod and farm and birdcage then -- stop search, if everything was found already
                break
            end
        end
        if light and science and alchemy and cookpot and chest and dryrack and lightningrod and farm and birdcage then
            GLOBAL.ThePlayer.HUD.controls.HomeBase_baseicon:Show()
            return true
        end
        GLOBAL.ThePlayer.HUD.controls.HomeBase_baseicon:Hide() 
        return false
    end

 

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
×
  • Create New...