Skip to end of metadata
Go to start of metadata

Object Viewer Qt Plugins

In my last post I discussed using NeL's safe singleton's in libraries that aren't "Pure NeL." The reason this subject came up was because aquiles was porting the "object viewer" viewport logic to a plugin that he could dynamically load into Georges Editor Qt (GEQT.) For awhile now dnk-88 has been working on adding a plugin architecture to Object Viewer Qt (OVQT.) While I think that plugin architecture has a long way to go it has arrived. One of our GCI students implemented a "Sheet Builder" plugin using this architecture - it essentially implements the "make_sheet_id" command line tool but provides an easy to use dialog in Object Viewer Qt.

The reason I chose this tool to be one of the first is because when new Ryzom Core users are developing and experimenting with sheet modifications the two tools they're required to run are make_sheet_id and sheets_packer - these update the sheet ID database and the packed client sheets, respectively. They're not complicated tools but it is easy to screw up the config files or command line arguments. The exercise also provided us with an opportunity to showcase the plugin architecture with a plugin that's simple enough to be viewed as an example and still provide use.

Ultimately the plan is to have OVQT be the one-stop-shop for content developers. I know that aquiles is considering and maybe even already working on porting GEQT to be an OVQT plugin - being able to quickly switch back and forth between media and sheets will be beneficial but there are some challenges left to be answered before we undertake porting so many things to OVQT plugins. I had dnk-88 remind me just a couple days ago that I should not rush the process - design decisions need to be made for one and we need to determine how to manage multiple viewports/scenes concurrently. The idea now is to have a "per application" tab style. The ultimate goal being that World Editor will be rewritten as an OVQT plugin as well. Being able to switch rapidly back and forth between Object Viewer, Georges and World Editor will streamline the content development process but all three "applications" require a NeL viewport that functions indepedently of the others.

Object Viewer Qt Tasks

  • The settings functionality must be modified to allow for pooled "pages" of settings. This is so when a plugin that requires configuration is loaded all configuration and settings are located in a centralized place.
  • Multiple independent NeL Scene/Driver/Viewports per-plugin must be tested.
  • More TBD.

Georges Editor Qt Tasks

  • Completion of editing functionality.
  • Implementation of form (sheet) creation functionality.
  • Ultimately converting to be a plugin for OVQT.

Future Application Conversions

Here is a list of Qt and non-Qt applications that we will be porting to the OVQT Plugin Architecture over time:

  • Convert disp_sheet_id to display the sheet ID database in a read-only grid.
  • Convert sheets_packer to pack and display the progress of packing sheets for development clients.
  • Convert words_dic_qt to be a dockable widget - it is useful for searching for string IDs and will be the basis of future I18N editing functionality in OVQT.
  • Convert tile_edit_qt to be an application tab. The functionality reliant on the PIC library will need to be replaced and it will need to be refactored into a tabbed layout instead of a myriad of independent fixed-size windows.
  • Convert mission_compiler to Qt, optimally as a plugin.

Building Teleports

One aspect of Ryzom Core that has been harassing me for awhile is that we have been unable to determine how to add non-NPC teleports into the game. A great number of these exist in the official game but since, to my knowledge, they're not adding new content they didn't know how to add *new* teleport locations. I spoke with one individual who walked me through how to set up a bit of this in World Editor but a critical component of the process was still lacking.

I'll give an abbreviated description of the content design process.

  • Open your region primitive file (e.g. region_newbieland.primitive)
  • Expand to the continent primitive and select it.
  • Right click on the continent (e.g. newbieland) and add a new teleport_triggers primitive.
  • Optional: Name the teleport_triggers - since you can have multiple you may want to make it in order to organize your teleport triggers.
  • Right click on the teleport_triggers primitive and add a teleport_trigger
  • Double click on the new teleport_trigger
    • Set the name.
    • Check auto_teleport if the trigger should automatically initiate the teleport when a player comes in contact with it.
    • Set the pacs_trigger_id (see rant #1 below.)
    • Click OK
  • Right click on the teleport_trigger and add a teleport_destination
  • Double click the teleport_destination
    • Set the name.
    • Set the icon - matters if this is not an auto_teleport trigger.
    • Set a place_name, used for describing the location using the phrase manager.
    • Set the teleport_spawn_zone
    • Click OK
  • Create a teleport_spawn_zones under the continent, if one does not already exist.
    • Right click on teleport_spawn_zones and add a teleport_spawn_zone
    • Select and then place the teleport_spawn_zone
    • Double click the teleport_spawn_zone
      • Set a name, this should match what you entered in the teleport_destination
      • Set a radius.
      • Set type to normal.
      • Optional: check use_z value and set a z value.
        • This depends on what "side" of the teleport you're doing. For example if you're doing fy_cn_sheriff your entrance will be set to use_z and a z value of -3 I think. On the 2nd floor your teleport spawn zone will use_z and have a z value of 12. To be certain what this z value is you will want to check the MAX object. See Rant #2.

Rant 1 - Determining PACS Trigger Id

The first and most challenging part of this process was determining how the system tied a trigger object to a position in the world. All of the logic in the source code used pacs_trigger_id to find a CTrigger and tie that CTrigger to a destination (e.g. CTPDestination.) Logically this has to be trigger by a PACS primitive and the only way these get loaded in will be through the PACS banks or "manually" from the landscape_col_prim_pacs_list.txt file. The latter file is a list of all pacs_prim objects exported by build_gamedata. For example you'll find fy_bt_sheriff_ok_elevator_armurie1er.pacs_prim in this file but it's not referenced as an object in fy_cn_sheriff.max but there is a fy_bt_sheriff_ok_elevator_armurie1er.max with a single PACS Box object in it at the origin. So still no position data. So what's the deal you might ask? It took some looking but finally I found it: ryzom_servershare's CContinentContainer class has an initPacsPrim method which loads all of the .pacs_prim files into a list and then a loadPacsPrim method that goes through a continent's instance groups and checks to see if any of the objects in the instance group have an instance shape string set which matches the name of a pacs_prim loaded in initPacsPrim. Got that? An object in FY_CN_Sheriff.max has its instance shape value set to the name of the pacs_prim (minus the extension.)

So lets determine the "ascenseurs" that FY_CN_Sherif uses.

  • Open FY_CN_Sherif.max
  • Click "Select By Name"
  • Choose Fy_bt_sheriff_ok_elevator_armurie and click OK
  • Note that it selects an object on the 2nd floor.
  • Click the Utilities tab.
  • Click NeL Export
  • Click Node Properties
  • Choose the Instance tab
  • Note the Instance Shape field is populated with: Fy_bt_sheriff_ok_elevator_armurie

If you repeat this process you'll note that FY_CN_Sheriff actually has *four* trigger primitives:

  • fy_bt_sheriff_ok_ascen_1er
  • fy_bt_sheriff_ok_ascen_rdc
  • fy_bt_sheriff_ok_elevator_armurie_1er
  • fy_bt_sheriff_ok_elevator_armurie_rdc

Each one of these represents some location, such as the elevator from the entrance to the 1st floor, the elevator from the 1st floor back down, the elevator from the 1st floor to the armory, and the elevator back down. Take one of these and find it, for example open w:\database\Stuff\Fyros\Decors\Vegetations\Fy_bt_sheriff_ok_ascen_1er.max. Note that the file name matches the pacs_prim filename one-to-one - this will always be true. Also note it is in a weird directory. Select the object, the only object in the scene, go to the Modifiers tab and scroll down to the PACS Box parameter rollout. Note User data 1 has a value of 336. This is the value you use for pacs_trigger_id.

Rant 2 - Determining Teleport Spawn Zone Placement

Determining your z placement is usually easy - open the structure in MAX and find the appropriate z level. If you open FY_CN_Sheriff.max you'll notice the platform at the top of the stairs is at -3 and the platform at the top of the elevator is 12. Where to place it in X,Y coordinates is a big challenge. You'll have to reference the IG location and the relative coordinates by looking up the IG center location through the continent sheet (see Villages.IGList) and then extrapolate from the center of the IG to the location of the arrival spawn point. Sorry, that's the best I have so far. The other option is to load the client in offline mode and jump to the location and take note of the coordinates then keying the teleport_spawn_zone's point coordinates.

Buildings With Interiors (Indoors Continent)

I have not yet figured out teleporting to buildings with large interiors. I have noted that there are a number of World Editor parameters specifically for this though. This will come with the next blog post I hope.

Labels: