This is the home page for the Matt Raykowski space.
- Werewolf - my little indie MORPG.
- NeL Handbook- my "in development" NeL Book
- Entity Management System - a design document for a proposed entity management system for NeL
- NeL Game Launcher
- Designing AGOT BG Online
- My Facebook Page
- Our family album
- Notepad for Translation Plugin
I just happened to be digging around the mission code trying to get some of my questions answered through the code. I came across the fact that guild missions are only partially implemented, the code seems to be there but significant portions are commented out and are done essentially in pseudo-code. I thought this might be a nice feature request to put up in the issue tracker for someone to work on as a good chunk of it already appears to be there and since Ryzom (the game) isn't using it the risk of impacting others is pretty low.
Then I realized there are no guilds or ways to get set up for a guild in Ryzom Core's Open Shard. So I thought I'd throw together a little mini-post on how to set up a shard to allow guild creation. I'll skip the bits we assume to be true, that you've set up your shard correctly and that you are the first player registered with the shard.
Create NPC In World Editor
The first step is to create an NPC in World Editor that will be responsible for handing out guild creation requests. If you look at your shop_categories.cfg in data_shard you'll note that one of the available categories is "guild_creator."
- So open up newbieliand.worldedit
- Add the urban_newbieland.primitive
- Expand the rangers_starting_city npc_manager
- Expand the important_npcs npc_zone
- Add a new npc_group
- Accept the default parameters
- Set the name to something such as guild_masters
- Under "guild_masters" add a new npc_bot
- Set the name to nbland_guild_master$fct_nb_guildmaster$
- Add two chat_parameters lines:
- menu: MENU_WHOAMI WHOAMI_GUILDMASTER
- Optional: Add four equipment lines (just to set the color to differentiate the NPC.)
- CHANDS : 0
- CBODY : 4
- CLEGS : 4
- CFEETS : 4
- CARMS : 0
- Note: 0 is red and 4 is blue.
- Set the sheet_client to company_of_the_drill_loge_master_z_h_b1
- Save your changes.
- Move the Prim Point representing your NPC to where you want it located.
- Start/restart your shard.
- Log in to your shard as your player.
- Optional: Grant yourself :DEV: privileges
- Note: This only needs to be done if you haven't already done it
- Open the EGS Console
- Execute: setPrivs 1 :DEV:
- In the chat dialog execute: /a Money 1000000 to give yourself enough money to start a guild. (Requires elevated privs, obviously.)
- Choose the Create Guild action on your NPC and enter the details.
- View your guild info.
That's the essence of matters. There are many more guild-related topics such as guild_rolemasters, guild_caretakers, and charges. Hope this helps get you all starts!
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.
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:
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.
Today I helped the developer of the Georges Editor Qt rewrite with a curious problem - one which I have written about here in the past in more detail. He created an Object Viewer Qt widget plugin that he could load using Qt's tools and thus promote from within Qt Designer/Creator. This makes perfect sense and doesn't violate any notion of the usage of NeL. Except that he isn't loading the DLL using NeL's CLibrary class - he's loading it using QPluginLoader instead. Due to the nature of address relocation in Windows he predictably ran into problems: folders he added to NLMISC::CPath in his main application where not available in his library and he couldn't determine why.
The correct fix is to load the library as a Pure NeL Library. However due to the fact that he wanted this to be a Qt plugin and widget converting the loading to NeL's was not an option. So I suggested that he create a not-so-pure NeL Library by manually passing the application context rather than relying on the the NeL loader. Here's how we did it:
Now one thing that is important to note is that we implemented the setter method in the source file and not in the header. If the header is included into a source file in the implementing application then it will be duplicated in that address space thus throwing erroneous exceptions via the nlassert to check if the context is initialized. If somehow the call to the method doesn't assert it also will not accomplish what is necessary - the implementation must be in a source code file in the library that is being loaded.
A quick summary of what we did and what is happening: we added a new member to a class in the DLL call _LibContext which is a CLibraryContext. We then added a method that exists in the DLL's address space that allows the loading application to call and set this _LibContext value with its own context. Then after loading the DLL using Qt's loader we manually populate the library's context using the local CApplicationContext thruogh the context interface.
All of the NeL singletons, such as CPath, are safe signletons which means that their references are tracked in the application context. On Windows the lack of address relocation is compounded by the fact that NLMISC is statically linked to all implementing binaries. DLLs are considered binaries for sake of this argument. We pass the application context containing the references to the actual singletons to downstream libraries so that calls to it are effectively re-routed to the instance instantiated in the application.
After GSoC ends Google hosts a Mentor Summit at the fabled Googleplex and the WorldForge folks invited me to come and attend and meet them. Some of you may already know but I "got my feet wet" with open source when I lurked around and general took up space in the WorldForge project. At the time I was going to school to be a 3D animator so I found myself amused with trying to figure out their art pipeline and getting content into it. At the time it was quite the process and since the main functioning client was 2D I was mostly useless since I can't draw. But regardless I met some amazing people whom are still with the project and whose abilities still humble me.
I had the pleasure of meeting and spending time over the weekend with Kai Blin (kblin or kai) and Erik Hjortsberg (erik on irc.worldforge.net). It was nice to finally meet them and we had many great conversations about the challenges in our space - notably MMO and virtual world development. Erik proposed (and ran) a FOSS Gaming session at the summit which I think was very successful. It was a nice experience because we had some great minds from projects like Wesnoth and CrystalSpace as well as some who are new to the FOSS game scene. As you can see from the session notes the conversation really focused on the things that challenge FOSS games the most and it seemed like most people agreed - non-programmer community members are one of the largest challenges. The question of how do you recruit, engage and enable individuals like concept creators, artists, musicians, sound engineers and so on. Jeremy Rosen (aka boucman) from Wesnoth had a lot of good comments in this session about how their project has worked with and embraced artists. I think we can learn a lot from these projects.
There were many great sessions on a variety of topics. I missed a few on Sunday that I truly would have like to have attended such as the session on Non-Coding Communities, Git for Data, Continuous Integration and LLVM.
I did attend a session on Static Code Analysis. The gentleman from SDL (Andreas Schiffler who maintains SDL_gfx) who ran this session spoke specifically about tools like splint which are great tools but riddled with false positives. Others talked about competitive commercial tools and their failings. All in all I think it would be great to have something like this integrated into our CDash builds so we could do something like a monthly full integration run (pull, configure, build clean, run unit tests with coverage and dynamic analysis plus static analysis) but it seems like a flawed tool for daily work. Regardless hearing the varying positions and experiences on static analysis was very useful.
In light of the recent announcement of the Mac App Store by Apple there was also a session about this very topic. The session was interesting and we spent a lot of time talking about the restrictions that Apple puts on projects/products that go into the App Store for iPhone. Jeremy Rosen of Wesnoth shared some of the stories around getting Wesnoth into the App Store for the iPhone and iPad. In reality it sounds like most of the limitations are essentially reasonable. I pointed out that we tend to forget that projects like Debian have onerous restrictions on how things are packaged, where they can run and so on. The session did really get me to thinking about what it would take to port Ryzom Core to iOS so that projects based on Ryzom Core could more easily go through the process of getting into the App Store. It sounds like we have a long way to go.
For kicks I attended a Distributed Version Control session which was essentially a session on how to use Darcs and how Darcs works. While I don't think I'd even remotely entertain moving to Darcs it was helpful to visualize the DVCS field through another set of eyes and it made me consider more complex branching and workflow. Plus it was a good opportunity to bring up our the dreaded non-code management conversation (aka art and artists and user-friendly interfaces.)
The final session I attended, due to the time of my flight and wanting to just hang out a bit after lunch with the WorldForge guys, was the Advanced Trolling session. This was a pretty hilarious session and someone was video taping it so I'm hoping it will appear on YouTube some time in the near future. It was a comical approach on essentially how do you identify and cope with trolls in your open source user community. It was performed from the perspective of teaching you TO troll as a means of combating trolls (hence Troll University).
All said I hope I have the opportunity to go next year.
I know this is a much overdue post seeing as how my last post as was 7 months ago. Back then I had ambition with Werewolf and was working on getting some of it up and running. I was also busy with Neloid - which still sits waiting eagerly for my attention. Shortly after that post I heard from the new owners of Ryzom that they wanted to open source and 2 months later we worked together to release Ryzom in total. They released all of the source code for the servers, clients, tools, etc and all of the visual media but only a taste of the leveldesign data - enough to get you started and show you the basics of the system. Needless to say I've been very busy with Ryzom Core. We had a very great and very talented student through Google Summer of Code 2010 courtesy of the WorldForge project.
Ports and Tools
In 7 months some pretty exciting progress has been made. While I was still just a NeL coder we were pretty close to OSX support but it was kludged together using MacPorts stuff and X11. Far from native but more or less working. We also were limited to using Windows/MFC for graphics in a viewport. Todat we have a fully functioning, approved official Ryzom client running on Linux and a native OSX client that we have been using in the community as well as pending approval for use with the official Ryzom game. Through Dzmitry's GSoC object, which was to convert the legacy Object Viewer tool to Qt and ensure that it was cross-platform we have improved the accessibility of Ryzom and created a re-usable way to place NeL in a Qt widget. This has lead to another project by aquiles to convert Georges Editor to Qt where he has begun converting the core functionality of the existing MFC (Windows-only) tool as well as adding a number of usability improvements. For example when you have a sheet open with a shape it will open a mini Object Viewer to display that 3D shape if it can find it in your path.
Building Game Data and the Database
Kaetemi has truly rocked the house with his work on the replacement build_gamedata pipeline. This crucial piece of the puzzle has been broken and unused for as long as I can recall. The original form was an absurd combination of MS batch scripts, Cygwin shell scripts and Cygwin tools. The new tool is very flexible and written entirely in Python. With the exception of the export portion of the tool (which presently relies fully on 3DSMAX to export data out of the .max database) the tool could theoretically run anywhere. Just writing the code to do the job wasn't the full story. Kaetemi also worked through the full asset database to produce a list of items that were missing an needed for the tool to run correctly as well as identified files that needed to be fixed and how to fix them. This happens because much of this data was created as long ago as 2002 and in a much older version of MAX and older variants of the NeL Export plugin. He has been able to demonstrate that the tool does exactly what it is supposed to. Much work still has to go into finding the missing sheets that cause the client to not run. Tthere are families of sheets that aren't necessary for the newbieland continent but the client expects them to exist. We've been working to identify these and create placeholders in the leveldesign data.
There's still a lot of knowledge to work through but it's encouraging how much work we've done so far and how many great example wiki tutorials our community has produced. One of the most popular and interesting ones is the one by aquiles on Adding Creatures . The sneaky fellow put together a great wiki article while I've been dragging my feet putting together my notes on my creation creation video series I want to create. His is brief and to the point but gets you cleanly from having just yubos walking around to having armas walking around too. I plan on describing a little more in the creation sheet creation process. I'll describe proper naming form (which is optional) as well as the various "layers" of parent forms and why they exist the way they do. I'll also try and cover some of the important values you can change on the sheet with a demonstration of creating a different type of creature using Georges Editor, rebuilding the sheets and then placing them into the world using a new spawning area. For the impatient his tutorials get the job done though!
Finally Kervala has been hard at work merging Ryzom patches. This is going to take quite awhile so please be patient while the builds float in and out of cleanliness. Don't worry, I sent him to You Broke The Build just for giggles. We've been getting the nightly builds working cleanly. We still struggle with one of the virtual machines that takes 200+ minutes to build the full Ryzom Core platform but I do have one that does it handily. Hopefully I can start doing continuous builds so that people can track the progress. What builds are presently working are available through our CDash Dashboard . If you have a machine that you don't mind churning on builds at midnight and throughout the day we would greatly appreciate some variety in our builds. We really need a reliable Windows machine for builds!