Runtime error setting data to be persisted

this topic has been thoroughly discussed
Finding this thorough discussion is not so simple. There are no messages with "context" in the title. There are next to no uses of the word "context" in the body of messages. I have looked at all Gedemon's messages that seem even slightly on topic and can find none that make it any clearer than mud, although it's possible that I have failed to find the correct message through a lack of clues. I've searched for "expose" and got only
Basically, you either save data from within UI context or expose GameConfiguration.SetValue to other contexts.

I found this http://modiki.civfanatics.com/index.php?title=Context_(Civ5_Type), but I'm unclear (and highly doubtful over) whether it's relevant to Civ VI and "isolation scope" does not appear to be a Lua term. Even if it's just talking about scope I don't see how it helps me work out how to get around it — I see no way to write code in UI scope that could, for instance, absorb an event created from the non-UI scope. I can also not see how I ended up in the non-UI scope to start with. I tried searching for UI and got "The search could not be completed because the search keywords were too short, too long, or too common."
 
the part about the difference between UI/script context for lua files here (the type is defined in modbuddy or the .modinfo file)
https://forums.civfanatics.com/threads/information-from-firaxis-developer-on-the-mod-tools.611291/
I don't see anything in there that tells me how to define the type in either modbuddy or the .modinfo file :(

I have coded an event consumer that can pick up my attempt to save a string across context, presuming that LuaEvents still works that way as it did in Civ V, but I can't even get it to initialise in any context in which it will actually be able to run GameConfiguration.SetValue: As you can see from the commented out code I've been experimenting in my attempts to get it to at least run the print('LuaEvents.SetValue.Add(onSetValue)'), which it never does.
Code:
function onSetValue(key, value).

    print('onSetValue')
    GameConfiguration.SetValue(key,value)
end

--function InitialiseUILua()
    print('LuaEvents.SetValue.Add(onSetValue)')
    LuaEvents.SetValue.Add(onSetValue)
--end

--Events.LoadScreenClose.Add(InitialiseUILua)
 
Well this is getting really weird now.

I thought I'd managed to get my script in UserInterface scope by adding an xml to set the context:
Code:
<Context>
    <UserInterface FileName="UI_Scope" ID="UI_Scope"/>
</Context>
but the SetValue just disappears into a black hole. i.e. With the following code only the prints before it appear
Code:
function onSetValue(key, value)
    print('onSetValue')
    print('key, value: '..key..', '..value)
    GameConfiguration.SetValue(key,value);
    print("After")
    local recovered = GameConfiguration.GetValue(key)
    print('recovered: '..recovered)
end

print('LuaEvents.SetValue.Add(onSetValue)')
LuaEvents.SetValue.Add(onSetValue)
Note that it appears to have not set the value as well, or at least if I then save and reload the game GetValue returns nil.
 
It seems that all I've achieved by throwing an event and then consuming it to run SetValue is to erase the error message. It seems that the <UserInterface/> element that I thought was changing the context is not, because if it was really setting the context to UserInterface context it should be able to run GameConfiguration.SetValue, as that's the text at the top of the spreadsheet. I guess it must work differently in Civ VI than in Civ V, which leaves me still unaware of how to set context in Civ VI :(
 
@Gedemon I found the following comment in your SaveLoad.lua: "This is an InGame context because GameConfiguration.SetValue is nil in scripts context".

That raises the question: How is it set to InGame context? Please explain.
 
In the c++ side of the code, Firaxis decide to expose the function to UserInterface (UI/InGame) or Script (GamePlayScript) context in Lua.

The data from GamePlayScript is synchronized with the data used by the DLL, while the data in UI context is cached (from Firaxis developer comment linked in my previous post).

For example, if you call Unit:GetDamage() at the same time from a UI and Script context, it may not give the same result, especially if there are combats to process at that moment.

I don't now the reason behind this distinction, but if it allows faster scripts, I'm all for it.
 
Thanks. It's all starting to make some sense now. It's finally twigged that Context in ModBuddy has to be a custom property.

Of course having gained the ability to SetValue I've lost the ability to create a unit. I've tried resorting to a separate .lua with an event consumer to do that, but so far without success. I thought that by defining the following file under AddGameplayScripts, which allowed me to make a unit before I changed the context of the main script it would work, but it doesn't :(. There's no error message and the first print works, but I don't get the unit.
Code:
function onCreateUnit(pPlayer, iUnitIndex, iX, iY)
    print('pPlayer:GetID(), iUnitIndex, iX, iY: '..pPlayer:GetID()..', '..iUnitIndex..', '..iX..', '..iY)
    pPlayer:GetUnits():Create(iUnitIndex, iX, iY)
    print('After')
end

function OnLoadScreenCloseGameplay()
    print('OnLoadScreenCloseGameplay start')
    LuaEvents.CreateUnit.Add(onCreateUnit)
end

Events.LoadScreenClose.Add(OnLoadScreenCloseGameplay)

P.S. Sorry for being so terse. I have no excuse apart from the obvious, frustration at this obtuse system.
 
the consumption of an event adopts the context of where it was thrown
Not true apparently. I changed my code to check, not the context directly, but whether or not SetValue returns nil. I also added code to find at what point Create breaks:
Code:
function onCreateUnit(pPlayer, iUnitIndex, iX, iY)

    if GameConfiguration.SetValue then
        print('GameConfiguration.SetValue true')
    else
        print('GameConfiguration.SetValue false')
        print(GameConfiguration.SetValue)
    end
    print('pPlayer:GetID(), iUnitIndex, iX, iY: '..pPlayer:GetID()..', '..iUnitIndex..', '..iX..', '..iY)
    if pPlayer:GetUnits().Create then
        print('pPlayer:GetUnits().Create true')
    else
        print('pPlayer:GetUnits().Create false')
        print(pPlayer:GetUnits().Create)
    end
    if pPlayer:GetUnits() then
        print('pPlayer:GetUnits() true')
    else
        print('pPlayer:GetUnits() false')
        print(pPlayer:GetUnits())
    end
    if pPlayer then
        print('pPlayer true')
    else
        print('pPlayer false')
        print(pPlayer)
    end
    pPlayer:GetUnits():Create(iUnitIndex, iX, iY)
    print('After')
end

function OnLoadScreenCloseGameplay()
    print('OnLoadScreenCloseGameplay start')
    LuaEvents.CreateUnit.Add(onCreateUnit)
end

Events.LoadScreenClose.Add(OnLoadScreenCloseGameplay)
It seems that neither works because the output I got was:
Code:
 ForceSensitive_Gameplay: GameConfiguration.SetValue false
 ForceSensitive_Gameplay: nil
 ForceSensitive_Gameplay: pPlayer:GetID(), iUnitIndex, iX, iY: 0, 103, 6, 17
 ForceSensitive_Gameplay: pPlayer:GetUnits().Create false
 ForceSensitive_Gameplay: nil
 ForceSensitive_Gameplay: pPlayer:GetUnits() true
 ForceSensitive_Gameplay: pPlayer true
which leaves me wondering if an event consumed in code set up in a different context than the context of the code that threw the event loses context entirely :(.

P.S. Note the use of .Create not :Create. :Create doesn't work in this scenario at all — it's invalid syntax. I presume that the "." will still establish whether Create exists, as it's not like I'm passing it parameters. Please correct me if this isn't the case.
 
when/how are you calling LuaEvents.CreateUnit(pPlayer, iUnitIndex, iX, iY) ?
 
Top Bottom