Jump to content

What is a dirty something?


Recommended Posts

Hello! I'm new to modding and I have some questions:

 

1) In layman's terms, what is a dirty variable/function/anything?

 

2) What is the main difference in purposes between player_common and player_classified?

 

3) Which prefab AddPlayerPostInit targets?

 

 

4) What does AddPrefabPostInit do? It appends a function you want to a prefab right after all the main prefab function code but right before the return inst?

 

For example, I wanted to tweak the world prefab, removing the colourcube component to add my own colourcubemanager component. And I used the following in modmain:

AddPrefabPostInit("world", function(inst)          if not GLOBAL.TheNet:IsDedicated() then                    inst:RemoveComponent("colourcube")                    inst:AddComponent("colourcubemanager")          endend)

But it gave me a duplicate entity cpp error. What I used instead was copying the world prefab entirely, changing the name of the component in the line I wanted, and then just:

PrefabFiles = {          "world"}

Which resulted in the other world getting overwritten. And this worked fine.

 

 

5) What is the deal with custom colourcubes?

 

If I put,

day = "images/colour_cubes/mycube_cc.tex"

then the game goes full retard but if I put,

day = resolvefilepath "images/colour_cubes/mycube_cc.tex"

then it works.

Even if I rename the official files to other things inside the official folder and then change the official cube component, it doesn't get it.

Edited by DarkXero
Link to comment
Share on other sites

1. Dirty means it has changed and something needs to happen to "clean" it. In case of network variables it means it needs to be send to clients (E.g. server sets health to 1, causing the variable to become "dirty", and in its next network tick it will add health to the variables that are send to the clients)

 

2. I am not 100% sure, but from examening the code it looks like "player_common" is just the normal prefab, and "player_classified" handles all the networking (for player related events and variables)

 

3. player_common

 

4. That should work, I think, but components names need to be in quotes.

 

5. No idea, probably related to loading tho (setting the texture name doesnt actually load it, i think)

Edited by Sarcen
Link to comment
Share on other sites

That's a great definition for dirty, thanks!

 

 

I checked player_common and player_classified and apparently one uses non networked stuff and the other does, but they share elements like temperature so I don't know how to approach adding things, if using both, one or neither. Prefabs don't need them, server side components also don't, but components for players do.

 

 

That's weird,

AddPlayerPostInit(function(player) player:AddComponent("comp") end)

did not gave me the same results as:

AddPrefabPostInit("player_common", function(player) player:AddComponent("comp") end)

(I used the debug screen and the component was there on the first but not the second.)

 

 

I edited my post. The code had quotes. If there wasn't, there would be a undeclared var error.

 

 

Yes. But it's weird that renaming a file and changing the string totally broke the loader, without practically changing any location or file content.

Link to comment
Share on other sites

Well, I think that player_common never actually gets created, its like a base class.

Thats why AddPlayerPostInit exists, otherwise you would need to add a post init to each other the characters.

Like

AddPrefabPostInit("wilson",...)

AddPrefabPostInit("willow",...)

etc.

Link to comment
Share on other sites

Player_common returns the function MakePlayerCharacter that is used for individual files like Wilson to create and return a full prefab based on parameters.

 

So player_common is not technically a prefab? Then AddPlayerPostInit is a for loop in all prefabs with a player reference?

Link to comment
Share on other sites

modutil.lua:

    env.AddPlayerPostInit = function(fn)        env.AddPrefabPostInitAny( function(inst)            if inst and inst:HasTag("player") then fn(inst) end        end)    end

Is the code it does, so, it will call your function on any prefab that has the tag "player"

Link to comment
Share on other sites

if GLOBAL.TheNet:IsNotDedicated() then

 

I think you want this instead:

          if not GLOBAL.TheNet:IsDedicated() then

From looking at colourcube, though, it's totally different in DST than colourcubemanager was in DS, so if that's your starting point, it would be surprising if there weren't many crashes along the way to fixing it.

Link to comment
Share on other sites

I'll explain the function of point 1 and the purpose of common and player classified with codes. I'm no expert on code behind don't starve together so correct me if I am wrong.

 

1. The purpose of on dirty function is to update client data from host, here an example of my code.

local function OnHealthRateDirty(inst)    inst.components.regeneration_arrowcomponent.healthrate = inst.components.regeneration_arrowcomponent.net_healthrate:value()endlocal Regeneration_ArrowComponent = Class(function(self, inst)    self.healthrate = 0.0    self.net_healthrate = net_ushortint(self.inst.GUID, "healthrate", "healthratedirty" )    if TheWorld.ismastersim then    --not host, do nothing for this example    else    --This is the client, add a listener        self.inst:ListenForEvent("healthratedirty", OnHealthRateDirty)    endend

The event listener, listen for this command

self.net_healthrate:set( --Numeric value here )

When a listener hears this command it will execute OnHealthRateDirty(inst), which will update the self.healthrate variable

 

 

2. Player common is the handling of player on the host side, while player_classified is the network handling of Player common data. As @Sarcen has said.

 

The host can access certain aspect of player data while client can only receive from replica component and classified data.

 

For example this code is accessible to the host but not the client. For the client the health component does not exist.

ThePlayer.components.health.currenthealth

How ever both client and host have access to player classified through the replica component. The difference is player classified variable are limited in size, the below code will only give whole number while the code above give it in decimal. The largest net variable I know of is 2 byte(aka short integer. 0 -  65535)

ThePlayer.replica.health.classified.currenthealth:value()

If you want to get a better idea of the interaction of dirty function, I suggest checking out Peter A The Hunt mod.

Link to comment
Share on other sites

rezecib,

 

Thanks for the correction. Of course, I edited my post to make the code that. I was writing it off the top of my head so I didn't remember the exact details.

 

But I did use that because I lifted it from the world prefab when making the modmain. Else, I would not have had a C++ error type but a Lua one.

 

You are correct on colourcubes. DS uses colourcubemanager, and RoG uses colourcube. My colourcubemanager is not the one from DS: the one I use was lifted from the DST files, and then added extra colourcubes, like in the RoG file for the two extra seasons.

 

I just named the file colourcubemanager because I wasn't sure if naming it also colourcube would give preference to the non mod colourcube component and thus, not exist.

 

 

BrokenValkyrie,

 

 

I checked Peter's mod. While it is useful as a starting point, I like the context you guys gave me here.

 

Replicas and their interaction with player_classified are still chinese to me. But as soon as I nail my own component with a replica I'm sure it will be all more clear.

Link to comment
Share on other sites

@DarkXero

I want to steer you into the right direction, your last line has me worried. You do not need to create a replica, it more complicated and the variable REPLICATABLE_COMPONENTS from entityreplica which contains a table of component allowed to be replicated is not accessible(at least not easily). You can write a functional network supported component without using a replica class.

 

You need to learn how to use net variable are used, pay close attention to how a net variable is used, especially when the net variable is given a value using the :set(value) function.

function OnExampleDirty(inst)    inst.components.examplesubcomponent.example = inst.components.examplecomponent.net_example:value()    end self.example = 0 self.net_example = net_ushortint(self.inst.GUID, "example", "exampledirty" ) self.net_example:set(some numeric value)

Have a look at the similar variable where it is prefixed with net_ in Peter A the huntmod. In the above code it is self.example. The most simplest variable to follow in Peter A example is self.hunt_kills and self.net_hunt_kills.

 

self.hunt_kills is accessible from the client and the host is responsible for modifying self.net_hunt_kills.

 

Once you have grasped the concept of net variable I want to give you some advice on working with net variable to avoid some potential headache.

 

The largest net variable is net_ushort int, it only allows storage of whole number between 0 and 65535.

You will need to convert decimal value into integer. You can use this code

math.floor(decimalvalue +  0.5)

You need to check for the range of value before being entered into net variable using :set(value)

I use this which is taken from the classified file.

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

Make good use of this code that is underlined.

if TheWorld.ismastersim then    --host function only    self.localhealth = ThePlayer.component.health.currenthealthelse    --client function onlyend

Some variable and function can only be accessed by host but not client, for example player current health in decimals. You do not want the client attempting to access host only data, otherwise it will cause a crash. ThePlayer.component.health.currenthealth is an example of a value that can only be accessed by host, if attempted to be access on the client side the program will crash. From client perspective ThePlayer.component.health does not exist and it will return a nil value.

 

and finally in mod.info make sure this flag is set to true.

all_clients_require_mod = true

all client must have a copy of the net variable and the local variable which is called from the OnDirty() function. I've done test where the client do not have copy of the net variable while it was not needed it messes up the game. At best you get broken UI and a messy screen, otherwise the game crashes.

 

I am sorry if this confuses you further, attached is a component of my code which uses the net variable code that may give you some idea how it works. Unfortunately it may be as confusing as Peter A The Hunt mod. How ever it contains method handling negative value and a work around to storing small(between 2 and -2) decimal value.

 

If you get confused just keep asking question, don't give up.

regeneration_arrowcomponent.lua

Link to comment
Share on other sites

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
 Share

×
  • Create New...