UI modding - support thread

The place to discuss scripting and game modifications for X Rebirth.

Moderators: Scripting / Modding Moderators, Moderators for English X Forum

jth
Posts: 296
Joined: Tue, 3. Jan 06, 23:31
x3

Example wanted for raise_lua_event

Post by jth » Sat, 19. Dec 15, 15:28

Has anyone got a small snippet of code (both md and corresponding lua) that shows how to use raise_lua_event

EDIT

and/or a pointer (URL or just the mod name) to some code that uses a dummy call to some UI code that doesn't actually display anything but returns with some data or does something

Background

I want to use the "Deploy to station" option out of the architect menu without having to get the player to go through starting a conversation and then selecting "Deploy to station" then picking the station.

I could just pinch the code but its fairly long and bad software engineering to do that.

I would simply like to generate an event_conversation_next_section with the architect with a section="cArch_deployatstation" and param of [0,0,$targetstation]

I can do most of this with start_conversation, then listen for event_conversation_started and

Code: Select all

 add_player_choice position="top_left" section="cArch_deployatstation" text="{1002,4009}" choiceparam="[0, 0, $playerstation]" comment="Deploy to Station"/>
but I still need the player to select it and I would like to avoid that

Thanks

jth

User avatar
YorrickVander
Posts: 2689
Joined: Tue, 29. Oct 13, 21:59
x4

Post by YorrickVander » Sat, 19. Dec 15, 17:41

I haven't seen *anything* about this since stefan posted on the subject on page... 4?
X Rebirth - A Sirius Cybernetics Corporation Product

Split irritate visiting pilot with strange vocal patterns.

UniTrader
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 14571
Joined: Sun, 20. Nov 05, 22:45
x4

Post by UniTrader » Sat, 19. Dec 15, 18:01

Sounds to me like you want direct control of the conversation flow without player input? (quasi a add player choice without the player selecting anything) - I have created something like this, search the MD files of my Manager script for "'return'" to find the MD lines and look into the ui folder for the lua side
Will provide links later if needed, currently on the phone
if not stated otherwise everything i post is licensed under WTFPL

Ich mache keine S&M-Auftragsarbeiten, aber wenn es fragen gibt wie man etwas umsetzen kann helfe ich gerne weiter ;)

I wont do Script&Mod Request work, but if there are questions how to do something i will GLaDly help ;)

jth
Posts: 296
Joined: Tue, 3. Jan 06, 23:31
x3

Post by jth » Sat, 19. Dec 15, 19:29

YorrickVander wrote:I haven't seen *anything* about this since stefan posted on the subject on page... 4?
It looks like its in common.xsd dated 14/12/2015 so I think its just been released in 4.00 beta 4 HF2 or 3

I will have a look at UniTrader's suggestion too

jth

jth
Posts: 296
Joined: Tue, 3. Jan 06, 23:31
x3

Post by jth » Sun, 20. Dec 15, 17:26

Ok I have looked at UniTraders code and its exactly what I was looking for and works about as I expected. Thanks UniTrader that saved me a load of time :)

That gets me a fallback position so I thought that I would try and get raise_lua_event to play ball too.

I found the JIRA entry for raise_lua_event which is http://www.egosoft.com:8282/jira/browse/XRUIMOD-19 with a view to getting some insight into the parameters

The magic words say The idea is to add an MD action which calls RaiseLuaEvent() which would then be accessible by UI addons via the RegisterEvent()-callbacks

I decided to experiment on UniTraders ut_conversationcontrol.lua file as that covers both approaches and plugged it into my mod in the usual way

in the md script

Code: Select all

<raise_lua_event name="'HELLO_WORLD'" param="'cArch_deployatstation'"/>
and in the lua code

Code: Select all

local function init()
        ....
	RegisterEvent("HELLO_WORLD", menu.helloworld)
end

function menu.helloworld()
	DebugError("Hello World")
end
and to my surpise in the debug.log I got

[=ERROR=] Hello World

It works or rather I managed to drive it :)

Its a bit too simple an example to be useful without parameters so ...

Changed the lua code to

Code: Select all

local function init()
        ....
	RegisterEvent("HELLO_WORLD", menu.helloworld)
	menu.param, menu.param2 = GetMenuParameters()
end

function menu.helloworld()
	DebugError("Hello World" .. menu.param)
end
but its producing an error

[=ERROR=] Error while executing onEvent script for event: HELLO_WORLD.
Errormessage: [string "extensions/station_structural_rebuild/ui/ut_c..."]:67: attempt to concatenate field 'param' (a nil value)

so I guess that is not how you get at the parameter from raise_lua_event :(

EDIT

Experimented a lot and realised that RegisterEvent only has two parameters and finally guessed that the raise_lua_event parameter must come out as the parameter to the function that is called by the event. So came up with some modified lua code

Code: Select all

local function init()
        ....
	RegisterEvent("HELLO_WORLD", menu.helloworld)
end

function menu.helloworld(eventname, eventparam)
	DebugError("Hello World " .. eventname .. " " .. eventparam )
end
which produces

[=ERROR=] Hello World HELLO_WORLD cArch_deployatstation

Its getting there :)

jth

jth
Posts: 296
Joined: Tue, 3. Jan 06, 23:31
x3

Post by jth » Sun, 20. Dec 15, 18:58

At this point I thought that I would try and pass multiple paremeters through but that is not allowed has to be a string, number or component which puts a bit of a spanner in the works as I have two parameters to pass

This is how to pass a component $SR_Station across

Code: Select all

<raise_lua_event name="'HELLO_WORLD'" param="$SR_Station"/>
and

Code: Select all

function menu.helloworld(eventname, eventparam)
	DebugError("Hello World " .. eventname .. " " .. GetComponentData(eventparam, "name") )
end
that produces

[=ERROR=] Hello World HELLO_WORLD Foodstuffs Supply I

The killer here is that there is only one parameter allowed and I have two

So if I have lots of different functions, one for each callback label then it could work although its not ideal

Code: Select all

<raise_lua_event name="'cArch_deployatstation'" param="$SR_Station"/>
and

Code: Select all

local function init()
        ....
	RegisterEvent("cArch_deployatstation", menu.cArch_deployatstation)
end

function menu.cArch_deployatstation(eventname, eventparam)
	DebugError("Hello World " .. eventname .. " " .. GetComponentData(eventparam, "name") )
end
that produces

[=ERROR=] Hello World cArch_deployatstation Foodstuffs Supply I :)

or I guess that I could pass a string that contains the two parameters with a seperator and slice and dice it in the lua script

anyway that will do for today

jth
Last edited by jth on Mon, 21. Dec 15, 12:55, edited 1 time in total.

User avatar
YorrickVander
Posts: 2689
Joined: Tue, 29. Oct 13, 21:59
x4

Post by YorrickVander » Mon, 21. Dec 15, 10:13

For passing multiple data types you could try creating a cue actor and accessing blackboard variables setup in xml. I assume that will be ok as a component to pass across.
X Rebirth - A Sirius Cybernetics Corporation Product

Split irritate visiting pilot with strange vocal patterns.

User avatar
YorrickVander
Posts: 2689
Joined: Tue, 29. Oct 13, 21:59
x4

Post by YorrickVander » Mon, 21. Dec 15, 20:00

I'm a little lost why, on returning to a custom ui element from say a button to link to encyclopedia, the menu stack closes rather than going back as needed. As far as I can see I am not missing anything to facilitate this in my lua file.

The file in question for dissection (still wip but working in game) : https://www.dropbox.com/s/e6bgshn60gvc6 ... t.lua?dl=0
X Rebirth - A Sirius Cybernetics Corporation Product

Split irritate visiting pilot with strange vocal patterns.

UniTrader
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 14571
Joined: Sun, 20. Nov 05, 22:45
x4

Post by UniTrader » Mon, 21. Dec 15, 20:24

can you also post the related MD Callback for Conversation Section gYorrick_FlyToLoot ?
does the related MD Callback create new Dialogue Choices or open a further Menu? if not the Conversation automatically ends (thats why i created the conversation flow control - to keep the Menus open if further input is expected by simulating a Player choice)
if not stated otherwise everything i post is licensed under WTFPL

Ich mache keine S&M-Auftragsarbeiten, aber wenn es fragen gibt wie man etwas umsetzen kann helfe ich gerne weiter ;)

I wont do Script&Mod Request work, but if there are questions how to do something i will GLaDly help ;)

User avatar
YorrickVander
Posts: 2689
Joined: Tue, 29. Oct 13, 21:59
x4

Post by YorrickVander » Mon, 21. Dec 15, 20:54

There is none from fly to loot. But I think I see what you're getting at. Will tinker and find out.

To be clear in case of misunderstanding : its not the back button on my ui element that fails. That works as intended and returns to the sidebar. It's when I go from the new ui > encyclopedia entry > back that the menu closes instead of returning to the new element.
X Rebirth - A Sirius Cybernetics Corporation Product

Split irritate visiting pilot with strange vocal patterns.

UniTrader
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 14571
Joined: Sun, 20. Nov 05, 22:45
x4

Post by UniTrader » Mon, 21. Dec 15, 21:17

ah, ok.. sounds to me like you are missing an <event_conversation_returned_to_section/> in your MD part..
if not stated otherwise everything i post is licensed under WTFPL

Ich mache keine S&M-Auftragsarbeiten, aber wenn es fragen gibt wie man etwas umsetzen kann helfe ich gerne weiter ;)

I wont do Script&Mod Request work, but if there are questions how to do something i will GLaDly help ;)

User avatar
YorrickVander
Posts: 2689
Joined: Tue, 29. Oct 13, 21:59
x4

Post by YorrickVander » Mon, 21. Dec 15, 22:12

Hah! Yes, that was it. I was so certain it was a flaw in my lua I didn't think to check for an event in the xml... Nice one Uni you're a star.
X Rebirth - A Sirius Cybernetics Corporation Product

Split irritate visiting pilot with strange vocal patterns.

jth
Posts: 296
Joined: Tue, 3. Jan 06, 23:31
x3

Coerce to component

Post by jth » Wed, 23. Dec 15, 14:01

This code is triggered by

Code: Select all

<raise_lua_event name="'cArch_deployatstation'" param="$playerstation"/>

Code: Select all

function menu.cArch_deployatstation(eventname, eventparam)
	DebugError("Hello World " .. eventname .. " " .. GetComponentData(eventparam, "name") )
	Helper.closeMenuForSubSection(menu, false, eventname, { 0, 0, eventparam})
	menu.cleanup()
end
This code is managing to output

[=ERROR=] Hello World cArch_deployatstation Foodstuffs Supply I

but its then meant to pass a component to cArch_deployatstation

[Scripts] *** Context:md.NPC_Architect.SectionHandler<inst:1e891>: <event_conversation_next_section> section: 'cArch_deployatstation'
[Scripts] *** Context:md.NPC_Architect.SectionHandler<inst:1e891>: [0,0,component.{0x1cba1L}]

but instead it just passes the objectid

[Scripts] *** Context:md.NPC_Architect.SectionHandler<inst:42dae>: <event_conversation_next_section> section: 'cArch_deployatstation'
[Scripts] *** Context:md.NPC_Architect.SectionHandler<inst:42dae>: [0LF,0LF,269100LF]

How do I coerce or change eventparam into a component ?

jth

stefanEgo
Posts: 545
Joined: Thu, 11. Apr 13, 14:12
x4

Post by stefanEgo » Mon, 28. Dec 15, 13:18

@jth: Glad you found out the details about how to use the interface between Lua and MD already. We are aware that the provided interface is quite limited and would like to improve that at some point. Unfortunately, this is not as simple as it might sound. I've added a feature request for you to extend the interface to also allow passing on tables as a parameter which I believe should cover your requirements, no? https://www.egosoft.com:8443/jira/browse/XRUIMOD-102
For the time being serializing the parameters, as you already pointed out, is one way to work around this limitation.

@jth: Regarding the script error you get: What's going on behind the scene here is related to how components (or rather componentIDs) are handled in the UI and MD. See the section about FFI IDs and Lua IDs here: https://wiki.egosoft.com:1337/X%20Rebir ... d%20guide/
In your case you pass the eventparam to Helper.closeMenuForSubSection. That parameter is then converted (recursively for tables) to a plain integer (see helper.lua Helper.closeMenuForSubSection() and Helper.convertComponentIDs()). Hence when passed back to MD you lost the data type infomration that the ID is actually a component. Therefore in MD you have to tell that the provided "integer" is actually a component and create a componentID again as in (pseudo code):

Code: Select all

component.{$ID}
Again, this limitation is something we'd like to remove at some point to simplify UI modding further. I've added a corresponding JIRA issue for that one now: https://www.egosoft.com:8443/jira/browse/XRUIMOD-103
Stefan Hett

bm01
Posts: 421
Joined: Wed, 22. Jul 09, 22:31
x4

Post by bm01 » Tue, 5. Jan 16, 08:07

Hey.

I ran into a problem with the workshop tool and the buildvcat command.

Basically the ui.xml file is properly inserted in / copied to ext_01, but an empty one (0 byte) is inserted in ext_v361, which prevent the real ui.xml file from being read if I launch X Rebirth 3.61. Removing that empty file worked.

My v361 folder is a copy of my base folder (with minor changes), but without contents.xml and ui.xml. I haven't tried to add ui.xml to v361/ because I don't think that's what we're supposed to do, but maybe I'm wrong.

WorkshopTool output

Sorry if it's not the proper place to report that issue.

KlausM
EGOSOFT
EGOSOFT
Posts: 639
Joined: Wed, 6. Nov 02, 20:31
x4

Post by KlausM » Tue, 5. Jan 16, 15:59

bm01 wrote:My v361 folder is a copy of my base folder (with minor changes), but without contents.xml and ui.xml. I haven't tried to add ui.xml to v361/ because I don't think that's what we're supposed to do, but maybe I'm wrong.
The ui.xml has to be in the v361 folder as well, that should fix your problem. The catalog tool detects that the ui.xml is present in the root folder but missing in v361, so it adds the 0-byte file, which marks it as "deleted".

bm01
Posts: 421
Joined: Wed, 22. Jul 09, 22:31
x4

Post by bm01 » Wed, 6. Jan 16, 12:22

It worked. I should have tested that before posting, sorry!

jth
Posts: 296
Joined: Tue, 3. Jan 06, 23:31
x3

Post by jth » Tue, 19. Jan 16, 14:13

stefanEgo wrote:@jth: Glad you found out the details about how to use the interface between Lua and MD already. We are aware that the provided interface is quite limited and would like to improve that at some point. Unfortunately, this is not as simple as it might sound. I've added a feature request for you to extend the interface to also allow passing on tables as a parameter which I believe should cover your requirements, no? http://www.egosoft.com:8282/jira/browse/XRUIMOD-102
For the time being serializing the parameters, as you already pointed out, is one way to work around this limitation.

@jth: Regarding the script error you get: What's going on behind the scene here is related to how components (or rather componentIDs) are handled in the UI and MD. See the section about FFI IDs and Lua IDs here: http://www.egosoft.com:8292/confluence/ ... rted+guide
In your case you pass the eventparam to Helper.closeMenuForSubSection. That parameter is then converted (recursively for tables) to a plain integer (see helper.lua Helper.closeMenuForSubSection() and Helper.convertComponentIDs()). Hence when passed back to MD you lost the data type infomration that the ID is actually a component. Therefore in MD you have to tell that the provided "integer" is actually a component and create a componentID again as in (pseudo code):

Code: Select all

component.{$ID}
Again, this limitation is something we'd like to remove at some point to simplify UI modding further. I've added a corresponding JIRA issue for that one now: http://www.egosoft.com:8282/jira/browse/XRUIMOD-103
Thanks for the information

I have modified my script a bit to incorporate a ConvertStringToLuaID(eventparam) which seems to get it into the right format

Code: Select all

-- Auto answer for structural rebuild conversations
local utf8 = require("utf8")

local menu = {
	name = "STRebuildConversationControl"
}

local function init()
	Menus = Menus or { }
	table.insert(Menus, menu)
	if Helper then
		Helper.registerMenu(menu)
	end
	RegisterEvent("cArch_deployatstation", menu.cArch_deployatstation)
end

function menu.cArch_deployatstation(eventname, eventparam)
	DebugError(eventname .. " - " .. GetComponentData(eventparam, "name") .. " " .. string.format("0x%x", eventparam))
	Helper.closeMenuForSubSection(menu, false, eventname, { 0, 0, ConvertStringToLuaID(eventparam)})
	menu.cleanup()
end

function menu.cleanup()
end

init()
If I run it then I get

[=ERROR=] cArch_deployatstation - Foodstuffs Supply I 0x1c50f
[=ERROR=] Invalid call to UnregisterEvent(). Given script function must be a function but is 'nil'
[=ERROR=] Invalid call to UnregisterEvent(). Given script function must be a function but is 'nil'

but it does trigger the call into the Architect script

[Scripts] *** Context:md.NPC_Architect.SectionHandler<inst:1d6db>: <event_conversation_next_section> section: 'cArch_deployatstation'
[Scripts] *** Context:md.NPC_Architect.SectionHandler<inst:1d6db>: [0LF,0LF,component.{0x1c50fL}]

and the CV dutifully deploys to the station

.... however if I then re-run the whole mod again on the same station then it does something very strange :(

Mod pseudo code

Code: Select all

Build a new station on the same spot
Clone the station structure
Calculate the difference in cost betwen the new and old stations

Ask if you want to procede

If Yes
Move the NPC's over
Rename the new station
Delete the old station
Recreate the Architect on the original CV
Deploy to station  -- this is where the lua comes in

Code: Select all

              <start_conversation actor="$Architect" conversation="st_struct_rebuild"/>
              <raise_lua_event name="'cArch_deployatstation'" param="$playerstation"/>
[=ERROR=] cArch_deployatstation - aOld Foodstuffs Supply I 0x33bce
[General] ======================================
[General] ======================================
[=ERROR=] Invalid call to UnregisterEvent(). Given script function must be a function but is 'nil'
[=ERROR=] Invalid call to UnregisterEvent(). Given script function must be a function but is 'nil'
[=ERROR=] cArch_deployatstation - aOld Foodstuffs Supply I 0x33bce
[=ERROR=] Invalid call to UnregisterEvent(). Given script function must be a function but is 'nil'
[=ERROR=] Invalid call to UnregisterEvent(). Given script function must be a function but is 'nil'

What it is doing is re-running the second half of the md script. There are some debug_text commands in there and I get two complete sets of debug comments for the second half

I can also actually hear the beep beep of it opening two conversations

Unfortunately the two instances of the second half of the script interfere with each other and the CV fails to "Deploy to station" the second time :(

I think that it may be something to do with Helper.closeMenuForSubSection which may be going back to the "Ask if you want to procede" and running it again

I have a feeling that there is something in the functions that closeMenuForSubSection calls that is generating the two lines

[=ERROR=] Invalid call to UnregisterEvent(). Given script function must be a function but is 'nil'
[=ERROR=] Invalid call to UnregisterEvent(). Given script function must be a function but is 'nil'

What I really need it to do is a bare bones closeMenuForSubSection and do not return back anywhere

I have had a look at the other possibilities in helper.lua but don't really know what to do

Help :)

Regards

jth

stefanEgo
Posts: 545
Joined: Thu, 11. Apr 13, 14:12
x4

Post by stefanEgo » Wed, 20. Jan 16, 15:51

@jth: From the looks at the presented code, everything seems right. Guessing, the two UnregisterEvent() errors you get are related to the code in helper.lua: clearMenu() (which is triggered by ur call to Helper.closeMenuForSubSection()).

These two UnregisterEvent() calls are unregistering event callbacks which are registered by your call to Helper.registerMenu() so that part seems to be fine at first glimpse.

All I could imagine is that for whatever reason in ur case Helper is nil (you can check that by adding some output there). In this case you would register a callback (cArch_deployatstation) which then triggers the UnregisterEvent-calls without the corresponding events having been registered first and (what would trigger the error) the actual callback functions not having been defined.

What causes that, I cannot determine by the provided code here.

Maybe that info helps you to trace the problem down a bit?

If not, maybe you can provide a sample addon which I could test directly?
Stefan Hett

jth
Posts: 296
Joined: Tue, 3. Jan 06, 23:31
x3

Uniquely identifying a production module within a station

Post by jth » Thu, 21. Jan 16, 14:09

I am working on some code to put a throttle on production modules

The heavy lifting needs to be done in lua code

I am intending to replace the menu_production code with a customised version.

menu_production gets passed two parameters, the station and the production module

A lot of stations have more than one production line of the same type.

In a FoodStuffs Supply I need to be able to identify which Valley forge is which. So that I can adjust the throttle later, on the right one.

Obviously I cannot use objectID as they change every time the game is reloaded.

Is it possible to get the build stage of a particular production module or find a couple of parameters that combined together uniquely identify a specfic production module within a station ?

It needs to be valid over save games and survive the player extending the station ....

jth
EDIT 18:40

Put together some code borrowed heavily from menu_buildtree.lua that goes through the station buildtree and finds the buildstage for each production module

Code: Select all

	DebugError("Station is " .. GetComponentData(menu.object, "name"))
	DebugError("Module is " .. GetComponentData(menu.module, "name"))

	DebugError("Module " .. tostring(menu.module))
	menu.buildtree = GetBuildTree(menu.object)
	table.sort(menu.buildtree, function (a, b) return a.name < b.name end)
	for seqidx, seqdata in ipairs(menu.buildtree) do
		if seqdata.sequence == "a" then
			modules = GetBuildStageModules(menu.object, "", 0)
			for _, module in ipairs(modules) do
				if module.library == "moduletypes_production" then
					DebugError("[a,0] " .. module.name .. " " .. tostring(module.component))
				end
			end
		end
		for stageidx, stagedata in ipairs(seqdata) do
			if stagedata.stage <= seqdata.currentstage or menu.task == "building" then
				DebugError("[" .. seqdata.sequence .. "," .. stagedata.stage .. "] " .. stagedata.name .. " " .. tostring(stagedata.primarycomponent))
			end
		end
	end
results

[General] ======================================
[=ERROR=] Station is Foodstuffs Supply I
[General] ======================================
[General] ======================================
[=ERROR=] Module is Liquor Still
[General] ======================================
[General] ======================================
[=ERROR=] Module ID: 16881844
[General] ======================================
[General] ======================================
[=ERROR=] [a,0] Foodstuff Fac ID: 16819627
[General] ======================================
[General] ======================================
[=ERROR=] [a,1] Foodstuff Fac ID: 16878931
[General] ======================================
[General] ======================================
[=ERROR=] [b,1] Valley Forge ID: 16819617
[General] ======================================
[General] ======================================
[=ERROR=] [b,2] Valley Forge ID: 16879060
[General] ======================================
[General] ======================================
[=ERROR=] [c,1] Liquor Still ID: 16881844
[General] ======================================
[General] ======================================
[=ERROR=] [d,1] Argnu Paradise ID: 16879153
[General] ======================================
[General] ======================================
[=ERROR=] [e,1] Spice Tubes ID: 16803969
[General] ======================================
[General] ======================================
[=ERROR=] [f,1] Container Storage ID: 16882068
[General] ======================================

A good days work :)

Post Reply

Return to “X Rebirth - Scripts and Modding”