Jump to content

Shard RPC Gem API


Recommended Posts

Hi, I thought it might be better to asks my questions here instead on steam :D

https://gitlab.com/DSTAPIS/GemCore/wikis/Home

@Zarklord
I would like to use the GEM API to use communication between shards.
For RPC there is some sample code at gitlab, so I think I can handle this. But first I need netvars.. and there is no sample code at gitlab, so I'm not sure how to use that. Simply create my own netvars attached to the world? Do I have to use AddShardComponent("shard_report")? should I use the netvars within shard_report.lua?

The overall task:
My current teleportat mod starts a worldjump always in forest/mastershard.Therefore it saves all playerdata, writes it in a file, generates a new world and loads this playerdata. But it can only save the data from players currently in forest, not the ones from cave.  So I want the forest to notify caves with help of a netvar and then the cave is sending the relevant playerdata via RPC to forest.  Or is there an easier way?

Link to comment
Share on other sites

  • Developer

firstly, due to time constraints mainly, the wiki is sadly horribly outdated, none of the information is wrong persay, but all older, so if your ever unsure or if something doesn't work peek in the code first, and if that doesn't help ask me, until I can update the wiki(which is a really big task)this is just gonna have to be how it is.

as for your netvar "issue", I have a "sample component"(by that I mean a component that is added for shards that uses netvars) at
Gem Core/scripts/components/shard_report.lua but there is also a simpler component that I made for Global Pause at
Global Pause/scripts/components/shard_globalpause.lua both of these use similar concepts, though the Gem Core one has a lot of "Gem Core only code", so its quite a bit more complex.

  • Like 1
Link to comment
Share on other sites

48 minutes ago, Zarklord said:

firstly, due to time constraints mainly, the wiki is sadly horribly outdated, none of the information is wrong persay, but all older, so if your ever unsure or if something doesn't work peek in the code first, and if that doesn't help ask me, until I can update the wiki(which is a really big task)this is just gonna have to be how it is.

as for your netvar "issue", I have a "sample component"(by that I mean a component that is added for shards that uses netvars) at
Gem Core/scripts/components/shard_report.lua but there is also a simpler component that I made for Global Pause at
Global Pause/scripts/components/shard_globalpause.lua both of these use similar concepts, though the Gem Core one has a lot of "Gem Core only code", so its quite a bit more complex.

soo....
I have to write my own component which I will add via AddShardComponent() and I can use shard_globalpause as sample code to write my own (I guess especially the " pausestate " netvar stuff is the one I have to use)?
So there is no ready to use code already within the GEM API for netvars.

edit:
Ah, I wasn't aware that netvars for shard communication already exist in the game and where not added by your API mod , just found the shard_players.lua :)

Edited by Serpens
Link to comment
Share on other sites

@Zarklord

ok I think I finished the code, currently trying to test it, but... how to access the shard component?
I did within modmain:

GLOBAL.SetupGemCoreEnv()
AddShardComponent("shard_teleplayersave")

And now I try to access this component with TheWorld.shard.components.shard_teleplayersave , but this is always nil. (this is how the shard components are accessed for shard_players ... was not able to find code in globalpause mod where shard_globalpause is accessed)

edit:
some more info about my code:
my shard component file looks like this:

 

------------------------------------------------------------------------
--[[ shard_teleplayersave ]]
--------------------------------------------------------------------------

return Class(function(self, inst)

    assert(TheWorld.ismastersim, "shard_teleplayersave should not exist on client")

    --------------------------------------------------------------------------
    --[[ Constants ]]
    --------------------------------------------------------------------------

    local MAX_TARGETS = 10

    --------------------------------------------------------------------------
    --[[ Member variables ]]
    --------------------------------------------------------------------------

    --Public
    self.inst = inst

    --Private
    local _world = TheWorld
    local _ismastershard = _world.ismastershard
    local _requestdata = net_bool(inst.GUID, "shard_teleplayersave._requestdata", "shard_teleplayersave._requestdatadirty") -- value does not matter, everytime it is changed the slave sends data to master
    local shardReceivedList = {}
    
    
    --------------------------------------------------------------------------
    --[[ Private member functions ]]
    --------------------------------------------------------------------------
    
    local function SaveAndSendDataToMaster()
        if not _ismastershard then
            local shardSendList = {}
            for k, v in pairs(SHARD_LIST)
                for i, v1 in ipairs(v.tags) do
                    if v1 == "forest" then
                        table.insert(shardSendList, k)
                    end
                end
            end
        end
        _world.components.worldjump:SavePlayerData() -- will save playerdata within worldjump.player_data_save
        local player_data_save = _world.components.worldjump.player_data_save
        SendShardRPCToServer(SHARD_RPC.TeleSerp.PlayerSave, shardSendList, player_data_save ,shardSendList) -- send it to master (currently only identified by forest Tag...)
    end
    
    local function SavePlayerDatainMaster(shard_id,player_data_save,shardSendList)
        if _ismastershard then
            table.insert(shardReceivedList,shard_id)
            local player_data_save_MASTER = _world.components.worldjump.player_data_save -- this is old data from players left the master. new data from all players currently active at master will be added at last

            for userid, data in pairs(player_data_save) do
                if userid~="saveinventory" and userid~="savebuilder" and userid~="saveage" then
                    if player_data_save_MASTER[userid]==nil then -- new info? add it
                        player_data_save_MASTER[userid] = data
                    else -- we already have stuff from that player? check which is newer
                        if data.timefromsave > player_data_save_MASTER[userid].timefromsave then -- if slave data is newer (higher time value), replace our master data
                            player_data_save_MASTER[userid] = data
                        end
                    end
                end
            end
            
            local missingshards = ExceptionArrays(shardSendList, shardReceivedList)
            if not next(missingshards) then -- sobald shardReceivedList dieselben id enthält wie shardSendList, kann worldjump gemacht werden
                shardReceivedList = {}
                _world.components.worldjump:DoJumpFinalWithCave() -- this will also save for all current players on master
            end
        end
    end
    AddShardRPCHandler("TeleSerp", "PlayerSave", SavePlayerDatainMaster)
    
    --------------------------------------------------------------------------
    --[[ Initialization ]]
    --------------------------------------------------------------------------

    _requestdata:set(false)
    inst:ListenForEvent("shard_teleplayersave._requestdatadirty", function() -- if the master sends a request via netvar to the slaves, save our data and send them via rpc
        if not _ismastershard then -- only do it when you are not master
            SaveAndSendDataToMaster()
            --_world:PushEvent("shard_teleplayersave._requestdata", _requestdata:value()) -- push the event to the world, it will save data and send it via rpc in modmain to the master
        end
    end)

    
    --------------------------------------------------------------------------
    --[[ Public member functions ]]
    --------------------------------------------------------------------------

    function self:RequestPlayerData()
        _requestdata:set(not _requestdata:value()) -- simply change the value, the value itself does not matter,we only want to trigger the dirty functions
    end
    
    --------------------------------------------------------------------------
    --[[ End ]]
    --------------------------------------------------------------------------
    
end)

But that does not work, since its nil =/


And outside of this component I would like to call sth like:

TheWorld.shard.components.shard_teleplayersave:RequestPlayerData()

edit2:
Added the sample code from your docu to the mdworldgenmain, but still the same result, so this was not the reason.. =/

edit3:
just digging some more in API Gem Core code and see several "DEPRECIATED" prints, at least for SetupGemCoreEnv which is also printed within my log...

Edited by Serpens
Link to comment
Share on other sites

  • Developer

couple things/questions.
are you checking to make sure TheWorld.shard.components.shard_teleplayersave is being accessed on the server, and not on the client?
I noticed your adding a ShardRPC from inside the component, while technically no explosions should happen because of that, its generally best to add the RPC outside the component, and use events to "call" functions inside the shard_component.
lastly, you should use a net_event(just do a find in files for it, you will see why you should use it for your usecase.)

if you need to access the TheWorld.shard.components.shard_teleplayersave from the client, you need a two part component, one that gets added to shards, and another that gets added to every client and server, the shards send the data to the client<->server component, which sends it to the client.
this is actually what Global Pause does, so I recommend reading its codebase to find out how it all works.

  • Like 1
Link to comment
Share on other sites

21 minutes ago, Zarklord said:

couple things/questions.
are you checking to make sure TheWorld.shard.components.shard_teleplayersave is being accessed on the server, and not on the client?
I noticed your adding a ShardRPC from inside the component, while technically no explosions should happen because of that, its generally best to add the RPC outside the component, and use events to "call" functions inside the shard_component.
lastly, you should use a net_event(just do a find in files for it, you will see why you should use it for your usecase.)

if you need to access the TheWorld.shard.components.shard_teleplayersave from the client, you need a two part component, one that gets added to shards, and another that gets added to every client and server, the shards send the data to the client<->server component, which sends it to the client.
this is actually what Global Pause does, so I recommend reading its codebase to find out how it all works.

TheWorld.shard.components.shard_teleplayersave is only accessed for server and I also tried it to print it in console within the game as a server*
So only access by client needed, fully server based.  So we have no found the reason, why the component is nil =/
I also added print statements to your API Gem to see if the compoennt is added, but the local function AddShardComponent is only called for your shard_report, not for my function. So there seems to be a problem with AddShardComponent...

should I call SetupGemCoreEnv() within  modmain? Or is it Depricated? So what do I have to call first, to be able to use AddShardComponent within modmain?

Yes, I was not sure , you see within the ListenForEvent function that I initially had the code to push an event to the world, like in pause mod. But then I wondered why this is neccessary and added the RPC code within the component.  Can I overall keep it this way and just put the "AddShardRPCHandler" stuff within modmain? (so SendShardRPC will remain within the component) Or should I also move the SendShardRPc into modmain?

*My other thread about client+shard is another topic, there I would like to show a title screen for all clients entering the world, but only if it is the mastershard. I had the intention to make my mod work with all kind of world mods, eg multi worlds and others. So I always hate when there is no other way to check master/slave except "forest"/"cave".. this is true for clients, but also in the shard component code above with the SHARDLIST which does not contain info if it is master or slave, right?

Edited by Serpens
Link to comment
Share on other sites

  • Developer
5 minutes ago, Serpens said:

I also added print statements to your API Gem to see if the compoennt is added, but the local function AddShardComponent is only called for your shard_report, not for my function. So there seems to be a problem with AddShardComponent...

should I call SetupGemCoreEnv() within  modmain? Or is it Depricated? So what do I have to call first, to be able to use AddShardComponent within modmain?

this makes no sense, are you sure your mod is running?
as for the SetupGemCoreEnv being depreciated, that means that its not recommended to use it, but it will remain as gemcore as a legacy option for a very long time, so don't worry about that for now.

  • Like 1
Link to comment
Share on other sites

3 minutes ago, Zarklord said:

this makes no sense, are you sure your mod is running?
as for the SetupGemCoreEnv being depreciated, that means that its not recommended to use it, but it will remain as gemcore as a legacy option for a very long time, so don't worry about that for now.

Just disabled the "isactive" check within my modmain and now it seems to work:

local enabledmods = {}
for _,modname in pairs(_G.TheNet:GetIsServer() and _G.ModManager:GetEnabledServerModNames() or _G.TheNet:GetServerModNames()) do
    enabledmods[_G.KnownModIndex:GetModFancyName(modname)] = true
    print("found enabled mod "..modname.." == "..tostring(_G.KnownModIndex:GetModFancyName(modname)))
end
_G.TUNING.TELEPORTATOMOD.GEMAPIActive = enabledmods["[API] Gem Core"]
-- if _G.TUNING.TELEPORTATOMOD.GEMAPIActiv then
    _G.SetupGemCoreEnv()
    AddShardComponent("shard_teleplayersave")
-- end

 

Edited by Serpens
Link to comment
Share on other sites

  • Developer
Just now, Serpens said:

Just disabled the "isactive" check within my modmain and now it seems to work:


local enabledmods = {}
for _,modname in pairs(_G.TheNet:GetIsServer() and _G.ModManager:GetEnabledServerModNames() or _G.TheNet:GetServerModNames()) do
    enabledmods[_G.KnownModIndex:GetModFancyName(modname)] = true
    print("found enabled mod "..modname.." == "..tostring(_G.KnownModIndex:GetModFancyName(modname)))
end
_G.TUNING.TELEPORTATOMOD.GEMAPIActive = enabledmods["[API] Gem Core"]
-- if _G.TUNING.TELEPORTATOMOD.GEMAPIActiv then
    _G.SetupGemCoreEnv()
    AddShardComponent("shard_teleplayersave")
-- end

 

are you using the gitlab version of gemcore or the workshop version?

  • Like 1
Link to comment
Share on other sites

12 minutes ago, Zarklord said:

are you using the gitlab version of gemcore or the workshop version?

workshop.
I already had truble with this check when caves where enabled. it was false.
But the last time when I printed it in a world without caves into console, the value was true. So no clue what happens there

edti:
also right now (without caves) the value of _G.TUNING.TELEPORTATOMOD.GEMAPIActive is true.

edit2:
Ah a typo :D I missed the "e" from Active" within the if check....
Will move the RPC stuff to modmain now and test and report back..

Edited by Serpens
Link to comment
Share on other sites

@Zarklordokay, I think I did, it, but still only tiny problem:

The dirty function when using net_bool or also the net_event function is called everytime the game is loaded.
With net_bool I can solve this problem by differentiating between true and false, because the value is always false when it is unintentionally called. But with net_event I have no solution.
Are you able to tell me why it is called without netvar:set() or netvar:push() being called? Of course I already removed the line netvar:set(false) within the shard component, so the only place where it is set/push is within self:RequestPlayerData() which is NOT called on game loading (cant see a print of it) so someone else is calling it, maybe your mod?

The component:

------------------------------------------------------------------------
--[[ shard_teleplayersave ]]
--------------------------------------------------------------------------

return Class(function(self, inst)

    assert(TheWorld.ismastersim, "shard_teleplayersave should not exist on client")

    --------------------------------------------------------------------------
    --[[ Constants ]]
    --------------------------------------------------------------------------

    local MAX_TARGETS = 10

    --------------------------------------------------------------------------
    --[[ Member variables ]]
    --------------------------------------------------------------------------

    --Public
    self.inst = inst

    --Private
    local _world = TheWorld
    local _ismastershard = _world.ismastershard
    local _requestdata = net_bool(inst.GUID, "shard_teleplayersave._requestdata", "shard_teleplayersave._requestdatadirty") -- value does not matter, everytime it is changed the slave sends data to master
    local _requestdata = net_event(inst.GUID, "shard_teleplayersave._requestdata")
    
    --------------------------------------------------------------------------
    --[[ Private member functions ]]
    --------------------------------------------------------------------------
    
    local function SaveAndSendDataToMaster()
        print("SaveAndSendDataToMaster")
        if not _ismastershard then
            print("SaveAndSendDataToMaster slave")
            _world.components.worldjump:SavePlayerData() -- will save playerdata within worldjump.player_data_save
            local player_data_save = _world.components.worldjump.player_data_save
            SendShardRPCToServer(SHARD_RPC.TeleSerp.PlayerSave, player_data_save) -- send it to master (currently only identified by forest Tag...)
        end
    end
    

    
    --------------------------------------------------------------------------
    --[[ Initialization ]]
    --------------------------------------------------------------------------

    
    -- inst:ListenForEvent("shard_teleplayersave._requestdatadirty", function(inst) -- if the master sends a request via netvar to the slaves, save our data and send them via rpc
    inst:ListenForEvent("shard_teleplayersave._requestdata", function(inst) -- if the master sends a request via netvar to the slaves, save our data and send them via rpc   
        print("_requestdatadirty")
        if not _ismastershard then -- only do it when you are not master
            -- if _requestdata:value()==true then
                print("_requestdatadirty slave and set true")
                SaveAndSendDataToMaster()
            -- end
        end
    end)
    -- _requestdata:set(false)
    
    --------------------------------------------------------------------------
    --[[ Public member functions ]]
    --------------------------------------------------------------------------
    
    function self:RequestPlayerData()
        print("RequestPlayerData")
        -- _requestdata:set(true) -- simply change the value, the value itself does not matter,we only want to trigger the dirty functions
        _requestdata:push()
    end
    
    
    --------------------------------------------------------------------------
    --[[ End ]]
    --------------------------------------------------------------------------
    
end)

Edited by Serpens
Link to comment
Share on other sites

  • Developer
19 hours ago, Serpens said:

@Zarklordokay, I think I did, it, but still only tiny problem:
--snip--

thats weird I have never had that problem, only weird thing I see with the code is this:
 

--why is this not commented out? binding two netvars to the same entity with the same netvar name can't be making the game happy.
local _requestdata = net_bool(inst.GUID, "shard_teleplayersave._requestdata", "shard_teleplayersave._requestdatadirty") -- value does not matter, everytime it is changed the slave sends data to master

local _requestdata = net_event(inst.GUID, "shard_teleplayersave._requestdata")

 

  • Like 1
Link to comment
Share on other sites

24 minutes ago, Zarklord said:

thats weird I have never had that problem, only weird thing I see with the code is this:
 


--why is this not commented out? binding two netvars to the same entity with the same netvar name can't be making the game happy.
local _requestdata = net_bool(inst.GUID, "shard_teleplayersave._requestdata", "shard_teleplayersave._requestdatadirty") -- value does not matter, everytime it is changed the slave sends data to master

local _requestdata = net_event(inst.GUID, "shard_teleplayersave._requestdata")

 

that was unintended while trying out the differences between bool and event.
But I also had this problem while net_bool was the only code within the file.
I guess I will use net_bool now and only execute the stuff if the value was set to true, this works and we don't have to waste hours to find the other problem :)

edit:
Of course thank you very much for your help and that API :)

Edited by Serpens
Link to comment
Share on other sites

@ZarklordI finally released my adventure mod, using the teleportato mod:
https://steamcommunity.com/sharedfiles/filedetails/?id=1847959350

Following problem:
Of course this mod does change the tasksetdata of the levels to generate the adventure world instead.
It also changes the "overrides" to be able to change weather/day and all of those settings. I already found it strange, that it seems that you can not change few specific settings, you can only overwrite the whole overrides or nothing, is this true?

Anyway:
If I enable your API GEM mod and then start the adventure, the overrides seems to be overwritten by your mod or something else is happpening.
At least the worldsettings are reverted, so we have deafualt seasons and so on, instead of the settings of my adventure mod.
I saw that your api gem mod also has alot of code which has overrides in it.

So could you please clarify if this is a problem of your mod, or if I should change the overrides in a different better way?

edit:
I usually change worldgeneration this way:
 

AddTaskSetPreInitAny(function(tasksetdata)
        tasksetdata.overrides={ -- seems we have to replace the original , cause overrides is nil currently ... and everything not mentioned within here, will be set to default even, if the game location has other values defined...
        start_location = "default",
        task_set = "default",
        layout_mode = "LinkNodesByKeys", -- default for forest
        wormhole_prefab = "wormhole",
        roads = "default",
        world_size  =  _G.PLATFORM == "PS4" and _G.GetRandomItem({"default","default","medium","large"}) or _G.GetRandomItem({"small","default","default","medium","huge"}),
        deerclops  =  _G.GetRandomItem({"rare","default","default","often"}),
        dragonfly  =  _G.GetRandomItem({"rare","default","default","often"}),
        bearger  =  _G.GetRandomItem({"rare","default","default","often"}),
        goosemoose  =  _G.GetRandomItem({"rare","default","default","often"}),
        antliontribute  =  _G.GetRandomItem({"rare","default","default","often"}),
        season_start  =  _G.GetRandomItem({"autumn","autumn","autumn","autumn","autumn","winter","winter","spring","summer"}),
        autumn = _G.GetRandomItem({"veryshortseason","shortseason","shortseason","default","default","default","default","longseason","longseason","verylongseason"}),
        winter = _G.GetRandomItem({"veryshortseason","shortseason","shortseason","default","default","default","default","longseason","longseason","verylongseason"}),
        spring = _G.GetRandomItem({"veryshortseason","shortseason","shortseason","default","default","default","default","longseason","longseason","verylongseason"}),
        summer = _G.GetRandomItem({"veryshortseason","shortseason","shortseason","default","default","default","default","longseason","longseason","verylongseason"}),
      -- ...
}
end)        

everything I dont add to that overrides, will be set to default instead of the user chosen worldsetting.

Edited by Serpens
Link to comment
Share on other sites

  • Developer
23 minutes ago, Serpens said:

@ZarklordI finally released my adventure mod, using the teleportato mod:
https://steamcommunity.com/sharedfiles/filedetails/?id=1847959350

Following problem:
Of course this mod does change the tasksetdata of the levels to generate the adventure world instead.
It also changes the "overrides" to be able to change weather/day and all of those settings. I already found it strange, that it seems that you can not change few specific settings, you can only overwrite the whole overrides or nothing, is this true?

Anyway:
If I enable your API GEM mod and then start the adventure, the overrides seems to be overwritten by your mod or something else is happpening.
At least the worldsettings are reverted, so we have deafualt seasons and so on, instead of the settings of my adventure mod.
I saw that your api gem mod also has alot of code which has overrides in it.

So could you please clarify if this is a problem of your mod, or if I should change the overrides in a different better way?

edit:
I usually change worldgeneration this way:
 


AddTaskSetPreInitAny(function(tasksetdata)
        tasksetdata.overrides={ -- seems we have to replace the original , cause overrides is nil currently ... and everything not mentioned within here, will be set to default even, if the game location has other values defined...
        start_location = "default",
        task_set = "default",
        layout_mode = "LinkNodesByKeys", -- default for forest
        wormhole_prefab = "wormhole",
        roads = "default",
        world_size  =  _G.PLATFORM == "PS4" and _G.GetRandomItem({"default","default","medium","large"}) or _G.GetRandomItem({"small","default","default","medium","huge"}),
        deerclops  =  _G.GetRandomItem({"rare","default","default","often"}),
        dragonfly  =  _G.GetRandomItem({"rare","default","default","often"}),
        bearger  =  _G.GetRandomItem({"rare","default","default","often"}),
        goosemoose  =  _G.GetRandomItem({"rare","default","default","often"}),
        antliontribute  =  _G.GetRandomItem({"rare","default","default","often"}),
        season_start  =  _G.GetRandomItem({"autumn","autumn","autumn","autumn","autumn","winter","winter","spring","summer"}),
        autumn = _G.GetRandomItem({"veryshortseason","shortseason","shortseason","default","default","default","default","longseason","longseason","verylongseason"}),
        winter = _G.GetRandomItem({"veryshortseason","shortseason","shortseason","default","default","default","default","longseason","longseason","verylongseason"}),
        spring = _G.GetRandomItem({"veryshortseason","shortseason","shortseason","default","default","default","default","longseason","longseason","verylongseason"}),
        summer = _G.GetRandomItem({"veryshortseason","shortseason","shortseason","default","default","default","default","longseason","longseason","verylongseason"}),
      -- ...
}
end)        

everything I dont add to that overrides, will be set to default instead of the user chosen worldsetting.

I don't have the time to look into this, at this moment, but I have seen this and I will look at it, just not this second.

  • Like 1
Link to comment
Share on other sites

11 minutes ago, Zarklord said:

I don't have the time to look into this, at this moment, but I have seen this and I will look at it, just not this second.

no problem, tell me if/what I should post more code/information to save you the time to read all my mod code.

Link to comment
Share on other sites

And another question:
Is there already a mod that lets you enable several mods at once? Eg you have 70+ mods installed and want your favourit 55 of them to enable everytime.  

I saw there is a "batch eanble mods" mod, but only working for client mods. Is there another one working for server mods?
If not, how about using your librarymanager to enable batches of server mods? Of course here we only need the enable part, not the downloading.

Link to comment
Share on other sites

  • Developer
On 8/30/2019 at 12:46 PM, Serpens said:

no problem, tell me if/what I should post more code/information to save you the time to read all my mod code.

well, after much code inspection, I have discovered the issue, and sadly their is no way for me to seamlessly detect on my end when AddTaskPreInit/AddLevelPreInit is used to deviate from the leveldataoverride/worldgenoverride that the game uses, what this means, is I'm gonna add a bypass somewhere, that when set will prevent my code from overriding stuff set via those PreInits, I'll send a pull request to your mod when I have all the details worked out, so expect that semi soon.

  • Like 1
Link to comment
Share on other sites

1 hour ago, Zarklord said:

well, after much code inspection, I have discovered the issue, and sadly their is no way for me to seamlessly detect on my end when AddTaskPreInit/AddLevelPreInit is used to deviate from the leveldataoverride/worldgenoverride that the game uses, what this means, is I'm gonna add a bypass somewhere, that when set will prevent my code from overriding stuff set via those PreInits, I'll send a pull request to your mod when I have all the details worked out, so expect that semi soon.

Thank you, although it wont be a perfect solution, if every worldgen-overrides mod has to add code to make it compatible to your api gem.
Why are you changing/doing stuff with the overrides in your gem api at all?
Generally: And is there a way to only overwrite some of the override values, while maintaining the user worldsettings for the rest of them? Or maintaining overrides from a previous mod?

can you explain to me why/what you do with overrides? or is it too complicated?

How about my idea for a batch-enabler also working for server mods? I would like to use such a mod. Do you think a variation of you library (without the downloading part) can be used for this, to enable ~50+ mods at once?

Link to comment
Share on other sites

  • Developer
2 hours ago, Serpens said:

Thank you, although it wont be a perfect solution, if every worldgen-overrides mod has to add code to make it compatible to your api gem.
Why are you changing/doing stuff with the overrides in your gem api at all?
Generally: And is there a way to only overwrite some of the override values, while maintaining the user worldsettings for the rest of them? Or maintaining overrides from a previous mod?

can you explain to me why/what you do with overrides? or is it too complicated?

the reason it gets overwritten is that I make the worldgenoverride.lua(dedicated servers)/leveldataoverride.lua(changing any options post world gen which a mod could allow you to do), get applied(for the reasons listed), so I don't have a choice about that.

as for the second bit, I can make a global override(prevents any leveldataoverride/worldgenoverride from loading), and also a option that allows you to protect individual options, and let worldsettings control the rest.

Edited by Zarklord
  • Like 1
Link to comment
Share on other sites

  • Developer

@Serpens I have implemented the functionality allowing you to block specific or all overrides set by leveldataoverride/worldgenoverride.
to set this, do this:

local overrides --this would be whatever your setting to set your overrides.
overrides.blockoverrides = overrides.blockoverrides or {}
overrides.blockoverrides["Your Mod Name"] = {"world_size" = true, "branching" = true}--list of overrides that should be blocked from getting set.
--or:
overrides.blockoverrides["Your Mod Name"] = true --block all overrides from getting set.
--if your setting your overrides from multiple places, make sure to ensure you aren't deleting you existing mod table.

I have yet to push this update to the workshop, but I'll tell you when that happens.

Edited by Zarklord
  • Like 1
Link to comment
Share on other sites

10 hours ago, Zarklord said:

@Serpens I have implemented the functionality allowing you to block specific or all overrides set by leveldataoverride/worldgenoverride.
to set this, do this:


local overrides --this would be whatever your setting to set your overrides.
overrides.blockoverrides = overrides.blockoverrides or {}
overrides.blockoverrides["Your Mod Name"] = {"world_size" = true, "branching" = true}--list of overrides that should be blocked from getting set.
--or:
overrides.blockoverrides["Your Mod Name"] = true --block all overrides from getting set.
--if your setting your overrides from multiple places, make sure to ensure you aren't deleting you existing mod table.

I have yet to push this update to the workshop, but I'll tell you when that happens.

thanks. could you explain it a bit more?
1) why a local? are you able to read locals from other mods?
2) defined anywhere in modworlgenmain? Or within Taskset/LevelPreInit?
3) what overrides are blocked? Only the ones from your mod, or also the ones from the game? So if I set "overrides.blockoverrides["Your Mod Name"] = true " will this "only" mean that my mod will work like it alreday does without GEM API, or is there more functionality?
4) with "existing mod table" you are refferring to this "local overrides" ? Or which mod table do you mean? But how can I check if a local "at multiple places" is already defined or not?


 

Edited by Serpens
Link to comment
Share on other sites

  • Developer
8 hours ago, Serpens said:

thanks. could you explain it a bit more?
1) why a local? are you able to read locals from other mods?
2) defined anywhere in modworlgenmain? Or within Taskset/LevelPreInit?
3) what overrides are blocked? Only the ones from your mod, or also the ones from the game? So if I set "overrides.blockoverrides["Your Mod Name"] = true " will this "only" mean that my mod will work like it alreday does without GEM API, or is there more functionality?
4) with "existing mod table" you are refferring to this "local overrides" ? Or which mod table do you mean? But how can I check if a local "at multiple places" is already defined or not?


 

1) it doesn't have to be, that was an example. the table that is called "overrides" should be the same table you define your overrides in.
2) defined in the same place you define your overrides.
3) would make the mod function how it does without Gem Core, if you defined a list, it would block only those specific overrides from getting set by my mod.
4) I merely mean that if you defined the ["Your Mod Name"] = {} table previously, make sure you don't clobber the table when you update/adjust it.

Edited by Zarklord
  • Like 1
Link to comment
Share on other sites

  • Developer

@Serpens I decided against having people raw setting the overrides(though nothing is stopping you from doing that, I just have a helper function now), so I made this:

gemrun("overridesblocker", overrides, modname, overrides_to_block, alwaysupdate)
--"overridesblocker" is how the gemrun function finds the helper function, just leave it as "overridesblocker"
--overrides is the overrides table where you stored your custom overrides.
--modname is your mods modname
--overrides_to_block is an array(I use ipairs to traverse that table) of overrides to block(like the variable name says), you can still pass true to block all the overrides.
--alwaysupdate is a true/false that will make custom set overrides be permanant(you don't want this, as it would make your any overrides you apply be the new "default")
--if your in your modmain, gemrun is inside the global environment, so make sure to put GLOBAL. before it...

This update to gemcore will be pushed once the main branch gets its next patch(I'm waiting on a feature I asked to be implemented there get released)...

Edited by Zarklord
  • Like 1
Link to comment
Share on other sites

7 minutes ago, Zarklord said:

@Serpens I decided against having people raw setting the overrides(though nothing is stopping you from doing that, I just have a helper function now), so I made this:


gemrun("overridesblocker", overrides, modname, overrides_to_block, alwaysupdate)
--"overridesblocker" is how the gemrun function finds the helper function, just leave it as "overridesblocker"
--overrides is the overrides table where you stored your custom overrides.
--modname is your mods modname
--overrides_to_block is an array(I use ipairs to traverse that table) of overrides to block(like the variable name says), you can still pass true to block all the overrides.
--alwaysupdate is a true/false that will make custom set overrides be permanant(you don't want this, as it would make your any overrides you apply be the new "default")
--if your in your modmain, gemrun is inside the global environment, so make sure to put GLOBAL. before it...

This update to gemcore will be pushed once the main branch gets its next patch(I'm waiting on a feature I asked to be implemented there get released)...

yes, guess it is better to have such a helper function, cause I still did not understand where to put the overrides variable otherwise :D
As soon as it is live I will try it and report back if there are any problems :)

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...