XML:ONLV

From OniGalore
Jump to navigation Jump to search
ONLV : Oni Game Level
XML modding tips
  • See HERE to start learning about XML modding.
  • See HERE if you are searching for information on how to handle object coordinates.
  • See HERE for some typical modding errors and their causes.
XML.png
XML

ONLD << Other file types >> ONSK

switch to OBD page

Unfinished building-60px.jpg

This page is unfinished. Can you fill in any missing information?
If it is not clear which part of the page is unfinished, ask on the talk page.

Todo list
  • tips with cutscene charas: sync pelvis OBAN and partner TRAM
  • notes on camera and film import ?



Level releases, forum threads and wiki pages

Custom levels that have been created so far
OCF threads about level creation
Wiki pages about levels
Free texture resources

Concept phase

Be aware of limitation of level and engine.

  • triangle limit of a game level: ca. 520.000 (500.000 to be on save side)
  • (formerly "XSI") Mod Tool can save dae files with max. 64.000 triangles per object
  • when polygons are too tightly packed the cam will look at too many of them and glitches appear: the visible GQs (GunkQuads) limit is 8192 (2^13), higher numbers will cause render bugs and call BSL message "Exceeded max visible GQs number"; limited solutions to this:
    • decrease the gs_farclipplane_set value
    • hide objects by env_show
    • hide objects by level design
      • for example departments in a building could be quite detailed because the view at the other departments/rooms is blocked by non-transparent walls
  • The camera can look at 2049 transparent textures at once, one more and Oni crashes.
  • characters are visible only within 4099|4099|4099 and -4099|-4099|-4099 world units
  • geometry stops at ca. X=4228|Z=4228 and -4228|-4228 (height not tested)
  • chr_debug_spheres = 1 visualizes collision spheres of characters, then you can check if they fit through a new entrance


Notes on Mod Tool and Google Sketchup

Re-saving a dae file - that was originally made in Sketchup - in Mod Tool can result in a surprising change in size within Oni.

That due to a difference in the length specification.

For example Sketchup dae file has: <unit meter="0.0254000" name="inch" />
Re-saved Mod Tool dae file has: <unit meter="0.1" name="decimetre"></unit>

In that case you would need to open the new dae inside a text editor and change the length specification again.


Level import with OniSplit v0.9.82.0+

Demo files

Demo files can be downloaded here.

First put the new "OniSplit.exe" into the second "lab" folder alongside the xml files.

There's a "build.cmd" file. Those two are the important lines:

OniSplit.exe -create:level out lab.xml
OniSplit.exe -import:pc out level3_Final.dat

The first line create the *.oni files from a master.xml file, in this case "lab.xml". If final, the oni files can be put into a new AE package.

The second line creates level archives which can be used for fast tests. They don't require you to install a package.

Instead of "nosep" you can now also use "pc" for the import. Mac does still use "sep".

If the game crashes while loading (at ca. 90% progress), be sure that the texture's x and y (pixel) dimension are power of two: 512, 256, 128, 64, etc.

If the game crashes while loading (at ca. 50-60% progress), be sure that the BINACJBOCharacters/AISA file has a player character.

If the game crashes while loading (at ca. 5-10% progress), check if all textures were inside the "out" folder.

You can extract the AKEV file to xml, then search for the TXMP array.
THIS script checks which textures are missing by comparing the AKEV*.xml with its *.oni files folder. Adapt the two paths so that it works for you. Alt + 4, insert code, then F5.

"TXMP_marker_door" and "TXMP_marker_ghost" will be missing in the demo's "out" folder.

You can add this between the other two lines in the build.cmd to prevent a crash.

OniSplit.exe -create:txmp out env/markers/*.tga


The master xml file

File paths can be either absolute or relative.

The master xml file name determine the bsl folder name and the AKEV and ONLV file name in the output folder.


Mandatory files for level import:

  • level_environment.dae
  • level_bnv.dae
  • level_textures.tga/jpg/png
  • Character.xml or AISA with player
  • ONSK name in <Sky> (can be fake name)
  • ONLD file (for new levels; read on HERE about savegame unlocking)


XML tag content type description
<?xml version="1.0" encoding="utf-8"?> float, flag Ignore this.
<Oni> -
<Level SharedPath="..."> link The master xml file can link to other xml files, most of them are BINACJBO files. The file type gets declared inside the file, so the file name itself doesn't have to contain the type. Ergo, "BINACJBOCharacter.xml" can be given a simpler name like "Character.xml".

Some resources used by those xml files can be found in a "shared" folder. OniSplit copies textures and "physics" objects into the output folder; furniture objects will be integrate into the AKEV. Unused resources in the shared folder will be ignored. That way the final level archive / AE package contains only necessary files which saves the end-user space.

In the demo are various subfolders in shared folder: consoles, doors, furniture, triggers and turrets. Following file types comes there without their file prefixes: CONS, DOOR, TRIG, OFGA. OniSplit recognize them nonetheless.

<Environment> -
<Model> - Used to import level geometry and static objects. See HERE for detailed information.
<Import Path="..."/> link
<Node Id="..."> string informative (space for notes so to say)
<ScriptId> integer Tested with BSL command ...
env_show Id 1 (use 0 to hide)
env_broken Id [Id] (if also second Id is used then objects in that range get counted e.g. 3001, 3018 = 18)
env_texswap Id texture (no file prefix/suffix allowed)
env_shade Id Id R G B

Static objects store their Id in one of AKEV's IDXA instances.

<GunkFlags> flag
AGQG (Gunk) flags (trimmed list)

see OniSplit -help enums for more flags

None
NoCollision
NoObjectCollision
NoCharacterCollision
NoDecal
TwoSided
Invisible
<Rooms> - For detailed information see HERE.

For Google Sketchup BNV tutorial see HERE.

<Import Path="..."/> link File path to *.dae file. BNV data, used to create pathfinding.
<Textures> - With OniSplit v0.9.94.0+ you can use attributes to set the default import formats and max dimensions. For example:
<Textures Format="BGR" AlphaFormat="RGBA" MaxSize="512">

Textures that aren't power of two (2^x) or bigger than 512 will be scaled to be that way. For example: 2003x2000 becomes 512x512.

<Texture Name="..."> string TXMP file name to generate.
<Flags> flag Optional tag. For list of flags see HERE.
<Format> flag
DXT1
BGR
RGBA
BGR555
BGRA5551
BGRA4444
<GunkFlags> flag
AGQG (Gunk) flags (trimmed list)

see OniSplit -help enums for more flags

None
NoCollision
NoObjectCollision
NoCharacterCollision
NoDecal
TwoSided
Invisible
<Image> link File path to *.tga/jpg file.
<Sky> string ONSKfile.oni (without file pre- and suffix)

The import doesn't work with an empty tag. <Sky>clear</Sky> helps here; any other fictional name will also do.

For detailed information see HERE.

<Objects> -
<Import> link File path. Supported files:
Character.xml (has to contain player character if there's no AISA file with it)
Console.xml
Door.xml
Flag.xml
Furniture.xml
Neutral.xml
Particle.xml
PatrolPath.xml
Physics.xml
PowerUp.xml
Sound.xml
Trigger.xml
TriggerVolume.xml
Weapon.xml
<Films> -
<Import> link File path to *.xml file. OniSplit creates a FILM file from it. Used for characters in cutscenes.
<Cameras> -
<Camera Path="..."> link File path to *.dae file. OniSplit creates an OBAN file from it. Used for cutscenes.
<Animation Name="..."/> string Name for the OBAN file.


This is a trimmed version of the master file "lab.xml" from the demo. It's meant to give you a first impression. -- We might upload a smaller demo someday with all features nonetheless.

<?xml version="1.0" encoding="utf-8" ?>
<Oni>
   <Level SharedPath="../shared">
       <Environment>
           <Model>
               <Import Path="env/lab_env.dae"/>
               <Import Path="env/lab_bomber_window.dae"/>
               <Import Path="env/lab_motorcycle.dae">
                   <Node Id="motorcycle">
                       <ScriptId>9</ScriptId>
                       <GunkFlags>NoCollision</GunkFlags>
                   </Node>
               </Import>
           </Model>
           <Rooms>
               <Import Path="env/lab_bnv.dae"/>
           </Rooms>
           <Textures>
               <Texture Name="GOO">
                   <Format>bgra4444</Format>
                   <GunkFlags>NoCollision</GunkFlags>
                   <Image>env/images/GOO.tga</Image>
               </Texture>
           </Textures>
       </Environment>
       <Sky>sunset</Sky>
       <Objects>
           <Import>Character.xml</Import>
           <Import>Furniture.xml</Import>
           <Import>TriggerVolume.xml</Import>
           <Import>Physics.xml</Import>
       </Objects>
       <Films>
           <Import>films/BomberKonRun01.xml</Import>
           <Import>films/BomberKonRun02.xml</Import>
       </Films>
       <Cameras>
           <Camera Path="cameras/BomberCam01.dae">
               <Animation Name="BomberCam01"/>
           </Camera>
           <Camera Path="cameras/BomberCam02.dae">
               <Animation Name="BomberCam02"/>
           </Camera>
       </Cameras>
   </Level>
</Oni>


<Model>

This tag is mandatory (it must be present to avoid errors); the model section contains one import path to the AKEV (level) geometry (*.dae) and can contain additional import paths for exceptions (*.dae).

Data from the demo:

               <Import Path="env/lab_env.dae"/>
               <Import Path="env/lab_motorcycle.dae">
                   <Node Id="motorcycle">
                       <ScriptId>9</ScriptId>
                       <GunkFlags>NoCollision</GunkFlags>
                   </Node>
               </Import>


env_show

The motorcycle has here script id 9. You can show and hide the object with bsl command env_show whereby the second parameter means true or false. Never use 0 as id because it won't work.

env_show 9 1
env_show 9 0

EdT demonstrates here env_show. The objects have collision.


The last original level (syndicate mountain compound) has a big satellite dish platform that can be made hidden. Obviously, such objects/areas can be made to have pathfinding too.


More possible applications of env_show
  • ground/ceiling/objects for cutscenes that become partially destroyed
  • destrucable walls like in Deus Ex 3 (trigger volume, replacing punch anim with punch-through-wall anim)
  • grids in front of ventilation shafts (a little door object could be an alternative)
    • at the moment this can't be done because characters can't sneak under the top edge of the opening (the characters collision spheres are too big)
  • managing object groups with trigger volumes (save multiple objects in one dae file)


Breakable glass with BSL recognition

Broken env objects can be recognized by bsl command env_broken (ID_1, ID_N). However, this whole thing requires additional code to work.

An example is the training level. Let's determine how we can set up such a thing.

First we need a trigger volume like in level 1.

       <TRGV Id="11495">
           <Header>
               <Flags>Locked</Flags>
               <Position>-714.6615 -298 -555.2073</Position>
               <Rotation>0 0 0</Rotation>
           </Header>
           <OSD>
               <Name>tv75</Name>
               <Scripts>
                   <Entry></Entry>
                   <Inside>targets_gone</Inside>
                   <Exit></Exit>
               </Scripts>
               <Teams>255</Teams>
               <Size>400 31 270</Size>
               <TriggerVolumeId>75</TriggerVolumeId>
               <ParentId>0</ParentId>
               <Notes></Notes>
               <Flags>PlayerOnly</Flags>
           </OSD>
       </TRGV>

Now we need some BSL code.

var int inside_target_function;

func void enter_target_function(void)
{
   dprint enter_target_function
   inside_target_function = 1;
}

func void exit_target_function(void)
{
   dprint exit_target_function
   inside_target_function = 0;
}

func void targets_are_not_gone(void)
{
	# CB: turn off the trigger volume and sleep for a second
	# so as not to cause hideous performance loss
	trigvolume_enable tv75 0
	sleep 60
	trigvolume_enable tv75 1
}

func void targets_gone(string ai_name)
{
	if(inside_target_function eq 0)
	{	
		enter_target_function() # catch other "targets_gone" functions to let them do nothing

		var int num_broken = env_broken(3001, 3018);
		# if you only one target use scheme: env_broke(3001, 3001)

		if (num_broken eq 18)
		{
			targets_are_gone();
		}
	
		if (num_broken < 18)
		{
			targets_are_not_gone(); # to set check interval to one second
		}

		exit_target_function
	}
}

func targets_are_gone
{
	trigvolume_enable tv75 0
	# [...]
}
Explanation

Player enters the TV, "targets_gone" gets