Lua Objects

Thanks, I had done similer tests with GameEvents.PlayerTurnStarted and PlayerTurnActivated (and failed to get consistent results) but did not try with GameEvents.PlayerTurnStartComplete !

what if you remove the unit's moves left on PlayerTurnStartComplete (to prevent the AI from using it), then try to restore the move and use the UI code later during the AI turn ? (maybe tricky to get an event firing at the correct time)

So I did a bunch of testing on this, because it sounds like it could work, but no luck so far.
Stopping the AI from doing any thing with the units works, but then I've been unable to find a way to get the RequestOperation to work

Every turn these four events get processed in this order: PlayerTurnStarted, PlayerTurnStartComplete, PlayerTurnActivated, PlayerTurnDeactivated
Additionally, the events RemotePlayerTurnBegin and RemotePlayerTurnEnd seem to get called every turn. But their ordering is independent of the order of the other 4

Move points get restored between PlayerTurnStarted and PlayerTurnStartComplete.
The AI seems to do its thing between PlayerTurnStartComplete and PlayerTurnActivated.

The AI could indeed be prevented from acting by setting the unit moves to 0 in PlayerTurnStartComplete
But then regardless of what other Event I tried to put the move restore and operation request in, I couldn't get anything to work.

CanStartOperation always returns true in PlayerTurnStarted and PlayerTurnStartComplete and always returns false in PlayerTurnActivated and PlayerTurnDeactivated, regardless of how I placed the restores

Strangely enough, by immediately checking a units moves after calling the replenish I can confirm the replenish works, however, when back in the UI context method, the amount of moves is back to 0. This happens regardless of whether I check instantly or wait until the next event.

I'm not sure whether the problem is that it's just fundamentally impossible, or that the events are not timed well enough, or whether the move replenish is not working as intended.
 
Can we *now* edit/define exposed member values in the UI context and still get those values from the gameplay script? I wasn't able to do that so I was using different methods to pass UI variables to the gameplay script before.
 
So I did a bunch of testing on this, because it sounds like it could work, but no luck so far.
Stopping the AI from doing any thing with the units works, but then I've been unable to find a way to get the RequestOperation to work

Every turn these four events get processed in this order: PlayerTurnStarted, PlayerTurnStartComplete, PlayerTurnActivated, PlayerTurnDeactivated
Additionally, the events RemotePlayerTurnBegin and RemotePlayerTurnEnd seem to get called every turn. But their ordering is independent of the order of the other 4

Move points get restored between PlayerTurnStarted and PlayerTurnStartComplete.
The AI seems to do its thing between PlayerTurnStartComplete and PlayerTurnActivated.

The AI could indeed be prevented from acting by setting the unit moves to 0 in PlayerTurnStartComplete
But then regardless of what other Event I tried to put the move restore and operation request in, I couldn't get anything to work.

CanStartOperation always returns true in PlayerTurnStarted and PlayerTurnStartComplete and always returns false in PlayerTurnActivated and PlayerTurnDeactivated, regardless of how I placed the restores

Strangely enough, by immediately checking a units moves after calling the replenish I can confirm the replenish works, however, when back in the UI context method, the amount of moves is back to 0. This happens regardless of whether I check instantly or wait until the next event.

I'm not sure whether the problem is that it's just fundamentally impossible, or that the events are not timed well enough, or whether the move replenish is not working as intended.
Damn, that's frustrating !

Can we *now* edit/define exposed member values in the UI context and still get those values from the gameplay script? I wasn't able to do that so I was using different methods to pass UI variables to the gameplay script before.
I was going to answer that I was always able to pass them from UI to gameplay, but now that I think of it, that could explain some inconsistencies in my data...
 
You guys got my hopes up :lol: but maybe it did change I don't know.

Also this might be a stupid question but since we can use Include("File") could we pass variables/functions through that between script and UI that way?
 
Code:
include("File")
adds the contents of whatever is in the file called "File" into the lua code at the point where the include("File") is positioned. You can therefore use it to add identical functions or variable names/values into multiple files, but it is not in any way dynamic, and does not allow passing of changes in the values assigned to these variables between contexts. So you cannot use it to pass info back and forth. Even if two Gameplay scripts both have the same include statement, changes to the value of a variable that was stated in "Flie" in the first of these Gameplay Scripts will not generally be picked up in the second -- the second will continue to use the original unaltered value that was established for that variable name within "File".

You need to think of the "include" command as saying
add the text contents of the file called "File" at this position

The problem with including the same file into both a Gameplay Script and a UI Script is that methods that are valid in UI are not always valid in Gameplay and vice versa, and the wrong method in the wrong context (UI or Gameplay) will either lock the game or cause the file to fail loading. So you must ensure that the entire contents of such a file are valid in both UI and Gameplay.
 
Last edited:
It’s not clear from your post, but do you run all this ops within AI events or LocalPlayer events?

Not entirely sure what you mean. I've got lua scripts in both the gameplay and ui contexts and am using events (mostly GameEvents.PlayerTurnStartComplete) to execute code

Also, aren’t you trying to mix functions from different contexts? I mean, FinishMoves is in Gameplay, and RequestOperation is in UI, aren’t they?
For the UI it also could matter if the unit is selected or not. Plus I came across a differemt behavior in the game because of that. See here https://forums.civfanatics.com/threads/popup-wont-open-via-uimanager-queuepopup.629561/.

Yes, I had to split my code to make this possible. I'm hooking up both the UI and Gameplay based code using events. I've both tried to do the ordering of code executions purely through those game events, and also through using ExposedMembers to execute in the other context. I could confirm the latter was in fact capable of executing Gameplay-context inside of code triggered in the UI-context
 
I am refering to this:
but then I've been unable to find a way to get the RequestOperation to work
UI might expect that the unit is selected. The game internally moves units in its own "enginy" way, but RequestOperation and RequestCommand are designed to be used within UI context.
 
I am refering to this:

UI might expect that the unit is selected. The game internally moves units in its own "enginy" way, but RequestOperation and RequestCommand are designed to be used within UI context.

I'm calling these in the UI context. I've also suspected that selection may be important and tried manually calling the SelectUnit function. The result was a lot of noise, and the unit bar popping in and out during AI turns, but with no impact on the ability to use UnitManager.RequestOperation. It's clear RequestOperation was never really intended to be used this way, but sometimes it still ends up being possible.
Not sure yet whether RequestCommand does work, it's a little harder to test.

Interestingly, CityManager.RequestOperation does in fact work (at least for some units) and overrides all AI building choices, which is something I'm going to heavily abuse for AI+.
 
I was going to answer that I was always able to pass them from UI to gameplay, but now that I think of it, that could explain some inconsistencies in my data...

Do we know the reason why there are separate contexts for UI and gameplay?

Does the UI run in a separate thread to gameplay?

If so (which maybe the case cos Civ VI is noticeably more multi-threaded than Civ V) then is it thread safe to pass parameters?

AFAIK Lua doesn't appear to have been designed with thread safety in mind (unlike say Scala, a language I'm a lot more experienced with). IDK

Perhaps passing parameters between contexts might cause hangs or deadlocks.

Just sayin' :)
 
Do we know the reason why there are separate contexts for UI and gameplay?
It was to speed up the game. And yes, UI and Gameplay run in different threads.

Firaxis' design intent for Civ6 was to eliminate as much as possible the need for complex "gameplay" scripts by moving the crazy stuff we did in Civ5 with lua into the XML/SQL Dynamic Modifiers system. The game's DLL therefore directly runs the Modifiers code, and is about 100 - 1000 times faster than execution in lua ever can be. Because of this approach to what can be done in mods, they did not implement a lot of things in the Gameplay context because the assumption was this would all be done in the XML and executed by the DLL at "game-engine" level. Plus they also wanted to make complex modding more accessible, which the DynamicModifiers and GameEffects systems do, but at a price that if Firaxis did not think of the need for EFFECT_X or REQUIREMENT_X or COLLECTION_X there is no way to achieve an effect with the DynamicModifiers system -- which a completely-implemented Gameplay lua API would take care of (as it pretty much darn near did in Civ5).
 
I don't think modifiers can replace scripting, it allows nearly infinite variations using the core rules of the game and is fantastic for civilizations/leaders modding, but it's completely useless when you want to change those core rules.
 
I don't think modifiers can replace scripting, it allows nearly infinite variations using the core rules of the game and is fantastic for civilizations/leaders modding, but it's completely useless when you want to change those core rules.
I agree. I was just explaining what it is that we have, and what Firaxis' intent seems to have been. What we actually want or need as mod-makers is another vat of haggus entirely.
 
And yes, UI and Gameplay run in different threads.

Then modders have to be careful about passing values between the gameplay and UI context. It is inter process communication.

This is already challenging with open published APIs. Here we know next to nothing about these APIs apart from introspection by the modding community. Civ VI is already pretty flaky, so modders should take care not to add any more contention.

Anyway, like you, I expect the reason you would want to access the other context is cos of API.

In particular, for my scenario Colonization of The New World, I try to score VP for artefacts. But the API to help determine the type of a great work is in the UI context. So I was also thinking of trying to access the UI context from gameplay.

But now on second thought, this may be a very bad idea and avoided if at all possible, cos they run in different threads.

So any suggestions how to do this? I also looked at the event for when a resource is removed, cos archeology is considered a resource, but it gets called twice. Also it seems a little hacky to me :p
 
Last edited:
AFAIK you won't crash the game doing that, you just need to keep in mind that UI is working on cached data, while gameplay use game core data.
 
So it is possible to send informations from UI context to Gameplay context and vice versa? I am still a Lua beginner. So can someone explain this to me please?

E.g. I want to to check if a city is an original capital city in gameplay context. The function IsOriginalCapital is only available in UI context, so I need to find a way to pass this information to my gameplay script.
Another reason why I need to send informations from one context to another is that I want to use the UI-function GameConfiguration.SetValue to save datas from gameplay context (see https://forums.civfanatics.com/threads/saving-loading-simple-tables-with-a-game.609397/)
 
So it is possible to send informations from UI context to Gameplay context and vice versa? I am still a Lua beginner. So can someone explain this to me please?

E.g. I want to to check if a city is an original capital city in gameplay context. The function IsOriginalCapital is only available in UI context, so I need to find a way to pass this information to my gameplay script.
Another reason why I need to send informations from one context to another is that I want to use the UI-function GameConfiguration.SetValue to save datas from gameplay context (see https://forums.civfanatics.com/threads/saving-loading-simple-tables-with-a-game.609397/)
in the page you've linked, see
Code:
ExposedMembers.SaveTableToSlot = SaveTableToSlot

at the end of the first code block (the one in UI context)

it then allows the use of
Code:
ExposedMembers.SaveTableToSlot(t, "myTable")

in any context, once all files are loaded.

you can also pass values using LuaEvents as shown here :
https://forums.civfanatics.com/threads/help-with-changegoldbalance.623730/#post-14900833
 
So it is possible to send informations from UI context to Gameplay context and vice versa? I am still a Lua beginner. So can someone explain this to me please?

E.g. I want to to check if a city is an original capital city in gameplay context. The function IsOriginalCapital is only available in UI context, so I need to find a way to pass this information to my gameplay script.

Code:
-- UI

function FunctionInUI(args)
    local pCity = -- Get the City
    if pCity:IsOriginalCapital() then
        LuaEvents.Tiramisu_OriginalCity_Event(someOtherArgs)
    end
end

GameEvents.SomeEvent.Add(FunctionInUI)

-- Gameplay

function FunctionInGameplay(someOtherArgs)
    -- Do stuff
end

LuaEvents.Tiramisu_OriginalCity_Event.AdD(FunctionInGameplay)

LuaEvents (like all Events) will run functions from both contexts when called.

Hm ninjaing's really boring now isn't it :(
 
Back
Top Bottom