-
Notifications
You must be signed in to change notification settings - Fork 69
Configuring a monitor
Monitors are created by adding a RasterPropMonitor into the prop.cfg for the prop you have made.
There's one more module you will need, RasterPropMonitorComputer. Notice that it's a PartModule, not an InternalModule, and requires no configuration. You just need to add it to the pod that will be hosting your IVA. Many other modules in this package also use it to store persistence data and compute all the variables, so you really want it to be there.
WARNING: The configuration relies heavily on direct texture URLs. In all cases, path names must use "/" slashes, and not the other kind. Forgetting that can produce hard to debug configuration errors. To cut down on those, whenever possible, RasterPropMonitor will correct the slash orientation without asking you, so beware if this is not what you expect.
- screenTransform -- the name of the screen object.
- textureLayerID -- Unity name of a texture ID in the object's material that the screen will be printed on. Defaults to "_MainTex". KSP shaders also have "_BumpMap" and "_Emissive".
- fontTransform -- Where to get the font bitmap. You can either place a texture somewhere in GameData and refer to it exactly like you would in a MODEL configuration node (KSP reads in everything that looks like a texture and is stored outside of a PluginData directory, and assigns it an URL) or put the texture on a model transform and give the name of that transform.
- fontDefinition -- An URL (with extension) pointing to a text file that contains the font definition, if you need one different from the default. For explanations, see Making a prop for RasterPropMonitor.
-
extraFont -- Optional, you can have more than one. The definition is the same as in
fontTransform
. You require at least onefontTransform
option so that a default font always exists, but you can switch fonts on the fly using the[font<number>]
tags. extraFont entries are the fonts you will switch to. The font listed infontTransform
is always number 0, while extraFont entries are in order of appearance in the configuration -- 1 is the first extraFont, etc. Extra fonts must have the same dimensions and the same font definition as the default font. - emptyColor -- R,G,B,A of a color that will be used to blank out the screen between refreshes. Everywhere, individual color values range from 0 to 255, i.e. a pure non-transparent red is "255,0,0,255".
- screenWidth/screenHeight -- Number of characters in a line and number of lines.
- screenPixelWidth/screenPixelHeight -- Width and height of the texture to be generated for the screen. You probably want these to be powers of 2, but they don't have to be equal.
- fontLetterWidth/fontLetterHeight -- Width and height of a font cell in pixels. Letters are printed on the screen in pixel-perfect mapping, so one pixel of a font texture will always correspond to one pixel of the generated screen texture -- as a result, you can have less characters in a line than would fit into screenPixelWidth, but can't have more.
- cameraAspect -- Aspect ratio of the camera images when this screen will be used to show them. (See Setting up cameras)
- globalButtons -- A comma-separated list of button transforms. Empty by default, this option is only relevant when you use Page handlers or Background handlers. It can contain empty entries.
- buttonClickSound -- An URL (in the KSP sense) of a sound file that will be played whenever the user clicks a button. Empty by default, optional.
- buttonClickVolume -- Volume of the button click, defaults to 0.5.
- refreshDrawRate,refreshTextRate,refreshDataRate -- The three different refresh rates for the monitor, expressed in number of frames that will be skipped before the specified refresh occurs. Draw is how often the screen will be repainted -- any background, including a camera, will be repainted that often. Text is how often a page definition will be reassembled into actual characters. Data is how often certain more resource-intensive data collection operations will run.
- needsElectricCharge -- Boolean, defaults to true. RasterPropMonitor does not actually consume electric charge (if you feel it is warranted, you can just add the power consumption to ModuleCommand of your pod -- turning RPM props off one by one is not supported anyway) but if this variable is true, the monitor will go blank when no power is available.
- needsCommConnection -- Boolean, defaults to false. When true, if the CommNet connection between the craft and KSC fails, the MFD will go blank.
- defaultFontTint -- Optional. An RGBA color, this tint will be applied to the font when printing unless colortags change it. A normal non-transparent white is the default, if you, e.g. want a transparent font, you can make it something like 255,255,255,128.
- noSignalTextureURL -- Optional. If the page is supposed to display a camera view but can't, because the camera is missing or destroyed, the texture referenced by this URL will be displayed instead.
- doScreenshots -- Optional, defaults to true. If this option is true, whenever you take a screenshot while IVA, a screenshot of the screen of every monitor located in that particular pod will also be saved. If it's false for a particular prop, no screenshots of it will be saved.
- oneshot -- Boolean, defaults to false. For a deeper discussion of what it does, see the "Oneshot mode" section below.
Multiple screens in the same IVA will share their computing modules, but this also means that the lowest refreshTextRate and refreshDataRate among all those given will be used when computing variables. refreshDrawRate remains individual per monitor.
All the components of RasterPropMonitor use the same button handling routines, and beyond a simple name of a transform (which must be located within the same prop as the module that will consume this button) they can also handle expressions in the form of <transform name>|<prop ID>
, (i.e. separated by a pipe character) where "prop ID" is the number of the prop that the button should be located on in the list of props within the internal.cfg, starting with 0. Remember that MODULE{} entries also count for the purposes of computing the prop ID if they are present in the internal.cfg -- if you have an InternalSeat and an InternalCameraTagetHelper in the beginning of the internal.cfg, the first PROP{} in this list actually has prop ID 2. You can use JSIPropIDFinder prop module to help you find the prop ID. If the prop ID you give is negative, the internal model itself will be searched for the transform instead. This also works in lists of globalButtons, for JSIActionGroupSwitch and any other button consumer.
Beware, every time you save the internal from Unity, it will sort the props alphabetically, which may cause prop IDs to change! This may also make configurations which use multiple identical monitors very difficult to maintain, so it's not recommended to use this feature unless you need a unique monitor. Also keep in mind that altering internal.cfg with ModuleManager can sometimes change prop ID numbers.
In general, the same button transform can be shared between any number of actions, and they will always trigger simultaneously -- the only exception being page selection buttons, which behave in a somewhat more complicated manner. (see below)
Page definitions are blocks of PAGE within the module configuration:
PAGE
{
name = firstpage
text = JSI/RasterPropMonitor/Example/ExampleProp/page1.txt
button = buttonR1
}
Parameters within the PAGE block are:
- name -- The unique name of the page. Optional, but it's a very good idea to have it, because it permits the users to alter page definitions using ModuleManager patches, and it is required to use context-aware page button features, or to limit the display of pages based on the available technologies.
- button -- Button transform that will trigger that particular page. A page does not require a button, but if it doesn't have one, it will only be possible to switch to it by using a button redirect, or not possible to switch to it at all. Multiple pages can share the same button -- if they do, clicking on this button will cycle between them. Cycling is in order of page definition, and loops. Selected page will persist, but position in the cycle loop will not. If multiple monitors have their pages assigned to the same button, both monitors will cycle the pages simultaneously, i.e. if monitor A has pages 1 and 2 on the same button as monitor B's pages 3 and 4, pressing the button will cause both monitors to change at once -- A will show page 1, and B will show page 3. Pressing it again will cause pages 2 and 4 to show respectively. Obviously, if the number of pages hanging on each button is not the same, the loop will go out of sync fairly soon.
- default -- If this parameter is set to anything, this page will be the one on the screen when the module finishes loading. If multiple pages happen to have this parameter, the one defined last will be the actual default. The page selected by the user afterwards will persist upon reload of the vessel. (see below)
- lockingPage -- If this parameter is set to anything, the page will lock upon being selected -- only triggering a page which is declared as an "unlocker page" will change the page. This is the simple locking mode.
- disableSwitchingTo -- A more complicated version of page locking, this is an optional comma-separated list of page names. Pages with names which are present in this list will not be switched to while this page is active.
-
unlockerPage -- If this parameter is set to anything, this page is an unlocker page and triggering it will allow you to change from a locked page. Selecting an unlocker page will also force the switch if
disableSwitchingTo
option is used. - textureOverlayURL -- This is a texture URL. If this parameter is present, this texture will be drawn on the screen as the last step of screen rendering, overlaying anything and everything you have previously printed on it. Be aware that the same shader as the one used to print letters is used to display this texture, while the color it is printed with is full brightness white -- so everything said about colors and font bitmaps applies to texture overlays as well.
- textureInterlayURL -- Works the same as an overlay URL -- but this texture will be drawn on the screen once the background, whatever it might be, has finished rendering, but before starting to print the text.
-
localMargins --
<left>,<top>,<right>,<bottom>
-- Margins for page text, in rows/columns of characters, rather than pixels, local for this page only, positive numbers denoting the number of characters to leave empty at the respective side of the screen. Most important when you need extra screen space for something else, like button hints, but are using a page handler. Some page handlers may not observe the right margin directly and will need extra configuration. - defaultFontNumber -- Default font for this particular page only. A number, with 0 being the global default font.
- defaultFontTint -- Default font color for this particular page only.
- textOverlay -- This option can be either straight text or a text file like a page definition. This text is printed on a separate layer after all normal text is printed, but before graphical overlays are applied. Variables do not work in this text, tags do work. This option exists to add static button hints to your page handler pages as appropriate.
- techsRequired -- This option, if present, contains a comma-separated list of technologies (in the career mode sense, and using the same naming as you would use for parts) that are required to be researched to display a particular page. The list is tested when a page is switched to. If at least one of these technologies is unavailable, a fallback page will be switched to instead. If no fallback page is given, the page switch will happen anyway.
-
fallbackOnNoTech -- If the
techsRequred
list contains anything, this option is the name of the page that the monitor will switch to if any of them are not available.
A monitor needs to have at least one page. There is no hard limit to the number of pages. If there is neither any text nor a background in the page block, the screen will be blanked when this page is selected.
Certain pages are "immutable", in that they are drawn once and will not refresh, to improve performance. The pages are mutable if:
- The page has text that contains variables.
- The page has a camera, a background handler or a page handler.
All other pages are immutable.
Page text can be defined in one of three ways:
- A Page Handler, i.e. an InternalModule that will compute and provide the page text. This is defined by a PAGEHANDLER{} block and if found and successfully loaded, takes precedence over interpreting the
text
option. Multiple page handler blocks are allowed per page. If the page handler did not load (either due to not being present in the system or due to linking to a foreign plugin that isn't) the next one defined will be tried, and if none get loaded, thetext
option will be interpreted instead. See Page Handlers - A page definition file. The text option in the PAGE block is treated as an URL (in the KSP sense, i.e. that starts just below GameData, like a MODEL texture URL) of a text file that contains a complete screen definition. It must include a file extension if your file has one. Do not use ".cfg", KSP doesn't like it. Example:
text = MyModGamedataDirectory/Screens/ThatPage.txt
. See Writing page definition files. - If the above fails, i.e. because there is no such file, the text option is interpreted directly. In this case, "$$$" will be replaced with a line break. If you wish to use the { and } format string characters in such a screen definition, you need to replace { with <= and } with =>, because KSP mangles them upon reading from prop.cfg files. This is appropriate to use if you only wish to print very little text on a particular page.
A page background is defined in one of three ways:
- A Background Handler. This works just like a Page Handler but the block is named BACKGROUNDHANDLER{}. It takes precedence over other kinds of background. Multiple background handler blocks are allowed per page. If the background handler did not load (either due to not being present in the system or due to linking to a foreign plugin that isn't) the next one will be tried, and if none got loaded, other background options will take effect. Much of the more advanced functionality is implemented through built-in background handlers. See Background Handlers.
- A textureURL option. This is a texture URL in the usual KSP sense that will be used as a background for this page, and this page only. It will be painted onto the screen and stretched across the entirety of it, exactly like other static texture layers mentioned above.
If you've been reading the above carefully, you probably noticed the following tricks:
- A page button can coexist with a globalButton on the same transform.
- A page can lock itself from switching to other pages while it's active, and in this case, globalButtons which coexist with the page buttons that otherwise would switch a page will be passed to the page itself.
- A page doesn't actually have to have a button, there just isn't any other way to switch to it.
This permits you to arbitrarily reuse page buttons as globalButtons while a certain page is active, but you can complement this with rearranging the page buttons to call other pages as well, which can even let you switch to pages which don't actually have buttons. For this, the PAGE block must contain at least one CONTEXTREDIRECT block:
PAGE
{
...
CONTEXTREDIRECT
{
redirect = pageA,pageB
redirect = pageC,pageD
...
renumber = 3,4
renumber = 5,-1
}
}
While this page is active, a button press that would normally result in switching to page named "pageA" will instead switch to "pageB". There are two basic options, and you can make any number of redirect statements:
-
redirect --
<first page name>,<second page name>
Will make an event that would activate the first page name activate the second page name instead. -
renumber --
<first globalButton number>,<second globalButton number>
-- The same, but for globalButton numbers, i.e. numbers of a button in the globalButton list -- the first one will be replaced with the second. If the second number is -1, pressing (or releasing) the globalButton will not have any effect while this page is active.
There are certain things you need to remember:
- Page redirects are processed before page locks. I.e. if you lock out a page in
disableSwitchingTo
and then redirect a button to it, it just won't switch. - Page redirects are actually a mechanism independent of page locks, and will work even if no page locks are defined.
- Both pages involved in a redirect must have a name for this to work.
- 'pageA' in the above example is not the name of a button -- it is the name of a page. I.e. if you want to recycle a button that is otherwise assigned to two different pages, you will need to add a redirect entry for both of them.
- There's no chaining of redirects. I.e. if 'pageA' redirects to 'pageB', and 'pageB' redirects to 'pageC', pressing the button for 'pageA' will not activate 'pageC'.
At times, you might want to make a printed label that depends on a variable, but auxiliary modules like JSIVariableLabel and friends are unsuitable for one reason or another. In this case, you can create a monitor and put it in oneshot mode:
....
oneshot = true
PAGE
{
...
A monitor in oneshot mode is completely identical to a regular monitor, but renders it's contents only once. Upon doing that, it creates a permanent texture to store the result of the render, places it where the screen was, and selfdestructs to clear memory. This will typically happen upon loading the craft and well before the player ever reaches IVA. The advantage of this approach is that you can use any fonts, tags and variables that RPM is capable of to change the output. The disadvantages, however, are pretty numerous:
- Rendered textures are permanent. Once created in this manner they will not change until the IVA is instantiated again.
- The monitor does not clean up after itself. I.e. if the pages defined for it had any buttons or instantiated any handlers, they will remain and continue to consume resources.
- The whole activity will cause a memory usage spike upon loading the craft, and even though the memory will be freed almost immediately, it might still cause an out of memory crash if the user's memory is overloaded. Avoid doing lots of small labels as individual props for this reason -- this method is appropriate to use if you want to print a page of static information on a wall, for example, but not otherwise.
This is a PartModule. You want to add this module to the capsule that will be hosting the various InternalModules supplied by this package.
MODULE
{
name = RasterPropMonitorComputer
}
There are several optional parameters to configure:
-
storedStrings -- A
|
-separated list of strings which will be accessible as variables namedSTOREDSTRING_<number>
, to permit easily adding things like pod version numbers. Numbering starts with zero. -
triggeredEvents -- A
|
-separated list of strings that name Triggered events that this computer instance will activate.
In addition, per-pod color overrides can be placed in the RPMC Module:
MODULE
{
name = RasterPropMonitorComputer
RPM_COLOROVERRIDE
{
COLORDEFINITION
{
name = ASET_SWITCHER_NAME_POSITIVECOLOR
color = 128, 128, 255, 255
}
}
}
This override changes any use of ASET_SWITCHER_NAME_POSITIVECOLOR with the color listed here for any props in this particular pod. Refer to Named Color for more information on named colors.