-
Notifications
You must be signed in to change notification settings - Fork 64
How to contribute to CQUI
There is no pedigree necessary to contribute, all good work is accepted, given it falls under the scope of the project and is well written/commented. No special permission is required to submit a PR for review, and all accepted work is given the proper and fair credit it deserves. I wish you the best of luck in your modding adventures and cannot wait to see what you may contribute
— chaorace
Only trusted contributors and admins may push changes directly to the repo, all other contributors must first push their changes to their own forks before they can be merged upstream. On Github, forking a project creates an identical copy owned by the forking user. Any project on Github can be forked by pressing the "Fork" button on the project page. Once the forking process completes, you will be presented with the project page for your new fork. While this fork may look identical to the main project, it is actually your own personal copy and as such you have full rights to make any and all changes you please. It is in this fork that you can submit the changes that you would like to make to CQUI.
Now that you have your own fork to work with, use the clone link from the fork's project page to create a local copy! Just commit your changes to the fork until you're ready to submit them. Note: While some basic Git knowledge is expected of contributors, there's nothing wrong with learning as you go. For those new to using Git, you may want to use a graphical tool like SourceTree to help smooth out the process
You'll want to familiarize yourself with the way the .lua and .xml files are constructed. The .lua files are written in Lua, a barebones scripting language. Lua lacks much beyond basic control structures and is largely a function-oriented language without much support for object-like constructs; most interactions are precipitated through an event firing/handling system instead. The .xml files are just XML, even if you haven't worked with markup before it should be relatively easy to understand.
Civ VI uses a context system. Contexts are like scopes, anything inside a context can call upon or examine any other member of the context, but nothing external to the context can. Each individual UI element has its own context, meaning one UI element can't normally affect another, each is self contained. Whenever you want to communicate something between contexts, you fire an event (an event is basically a broadcast signal which can be observed from any context). All custom events are members of LuaEvents
; if you want to fire your own custom event, just call it as if it already existed in LuaEvents
(For example, if I wanted to fire a new event I just thought of, I'd call it like so: LuaEvents.CQUI_MyNewEvent( "example", "parameter", 42);
. The parameters are arbitrary as well, provide as many or as few as you like).
Once fired, you must handle the event from whichever contexts you want to react to the event. You can attach handlers to events like so: LuaEvents.CQUI_MyNewEvent.Add( MyHandlerMethod );
(In this scenario, I've defined MyHandlerMethod
elsewhere in the same file, it's just a regular method! You'll want your handler method to have the same number of parameters as the event it is handling). In general, you set up handlers in the Initialize
method from the reacting context's Lua file (the Initialize
method gets invoked once per context on start)
Most contexts are UI contexts, which means they're actually made up of two files, a .lua and an .xml file (these files share the same name, but have a different extension). The XML file describes the actual UI element in terms of components, layout, and dimensions. The Lua file attaches behavior to the UI element and allows it to handle events broadcast by other contexts. The context itself even has a root UI element you can manipulate (it shares a name with the context, for example: the context ActionPanel
comes with an ActionPanel
element); additionally, all named elements in the XML file defining the root element are members of that context's Controls
object (all UI contexts have a Controls
object), so you can access them like so: Controls.MyControlName
(as long as you're in the same context! ActionPanel
's Controls
container is going to look very different from the Controls
container in MinimapPanel
). This allows you to invoke methods built into elements like SetHide
to manipulate them (Example: Controls.MyControlName:SetHide(true);
sets the visibility of MyControlName
to hidden, you can do this from anywhere within the same context).
Colons ( : <-- these) are used when manipulating controls or calling methods from other contexts (Yes, I said earlier you can't invoke methods from other contexts, but there's an exception for game provided contexts, like Game
for example) (Example: Players[Game.GetLocalPlayer()]:GetEra()
). You can even achieve some amount of manipulation over elements from other contexts by using one of these globally accessible contexts: ContextPtr:LookUpControl("/InGame/ActionPanel"):SetHide(true);
(This command, when invoked, will hide the root ActionPanel
element of the ActionPanel
context, even if you're not currently inside the ActionPanel
context). All UI contexts are defined in the /Base/Assets/UI directory of your Civ VI install.
You can find a semi-reliable reference for the methods you can invoke on UI elements here. This is a Civ V reference, so lots of this stuff doesn't line up, but it's currently the best thing we've got. You can also grep for methods in Firetuner
Firetuner is your best friend for testing your methods in action, it's a console plugged directly into the game. To obtain Firetuner, you'll need to download the Civ VI Developer Tools. You can find the Civ VI Developer Tools under the Tools section in Steam. To use Firetuner, you'll need to enable the Tuner setting in the Civ VI options menu, then restart Civ VI. Firetuner itself, once started, will automatically plug into Civ VI without you needing to do anything else. In Firetuner, you can select the context you'd like to attach to via the dropdown near the top-left. Once you're in your desired context, you can play with any method you'd normally have access to from that context and just experiment.Try invoking methods like ContextPtr:LookUpControl("/InGame/ActionPanel"):SetHide(true);
from earlier to see how they work in the console and how they affect UI elements in-game. Challenge: try hiding individual elements inside the Controls
container of another context while outside of it.
On a final note: Civ VI will hotload changes made to any currently loaded mods as you save them, this means you can instantly see the results of your changes to the .lua and .xml files without needing to restart Civ VI. Keep in mind only previously loaded mod files can be hotloaded. In order for new file additions to be recognized, they must be documented in the .modinfo manifest, then the game must be restarted. One should also keep an eye on the Firetuner prompt for error messages if things aren't working as expected after hotloading. Often times hotloading too many times can cause even perfectly good code to act buggy, so consider restarting your game when all else fails!
This is a lot to digest, so don't feel discouraged if you're feeling a bit confused! You do not need a complete theoretical understanding of the Civ VI internals to start modding, this is definitely the kind of thing that comes together in time. The best way to get better at Civ VI modding is complete immersion, so do not feel shy about diving in right away and seeing what you can already do. If you'd like a place to start, consider visiting the issue tracker. It's always populated with new feature requests and bug reports to try your hand at!
Once you're satisfied with your changes, it's time to submit them! But first a few guidelines:
- PRs should have a single purpose. A given PR should be dedicated to tackling a single problem. Avoid bundling multiple new additions or features into a single PR when possible, especially when they do not have much to do with one another. This rule applies less to bugfix PRs: so long as the PR is specifically for bugfixes, the bugs in question do not need to be directly related.
- Each individual commit should have a purpose. Mistakes are unavoidable, it's true, but make the best possible use of existing tools, like the --ammend flag, to avoid creating pointless clutter in your fork. PRs that fail to keep a clean history risk being squashed like so.
- Test your changes thoroughly! There is a review process before PRs are merged, which includes testing, but bugs can and do slip through. As the committer, you are the first line of defense in combating bugs. If that's not enough incentive, a bug-free PR will always get merged faster than one with outstanding issues. Vetting bugs before submitting a PR is an excellent way to expedite the merging process!
- DO NOT reuse PR branches. Please make sure that you're working from a fresh base whenever you're preparing a new PR, failure to do so may require you to cancel your PR and rebase the changes before they can be merged
- There is an overarching style guideline. Any commits that fail to adhere to the guidelines will need to be revised before they can be accepted into the main repo!
A pull request, or PR, is a Github feature that allows changes made in forks to be merged back upstream. Submitting a PR is the last step towards getting the changes in your fork merged to the main CQUI project. To submit a PR, return to your fork's project page and click the "New Pull Request" button. After a moment, you'll be presented with a summary page describing the changes your pull request will be making. If you spot something you didn't mean to include, now would be a good time to go back and remedy that. Once you're confident in your changes, click the "Create Pull Request" button. Finally, you'll need to fill out a title and description for your PR. Once finished, click the "Create Pull Request" button one final time to publish the PR. Once submitted, the PR will be opened as an outstanding issue on the main CQUI project page and the review process will begin. If you're curious, this is how the review process looks. If at all possible, try to be around to help address any concerns or potential revisions that may come up during the review process!