XML:ONLV: Difference between revisions

From OniGalore
Jump to navigation Jump to search
m (link fix)
mNo edit summary
Line 1: Line 1:
{{XML_File_Header | prev=ONLD | type=ONLV | next=ONSK | name=Oni Game Level}}
{{XML_File_Header | prev=ONLD | type=ONLV | next=ONSK | name=Oni Game Level}}
{{finish}}
;To-do list
* Tips for cutscene characters: sync pelvis OBAN and partner TRAM
* Notes on camera and film import?
* Make new demo level after implementation of final scene import/export, DAE-based CRSA import/export, shared folder bug fix, ENVP recycler
** Try to clean up page a bit
** Also, OniSplit v0.9.99.0+ no longer supports node tags when importing, so instead of…
              <Import Path="env/lab_motorcycle.dae">
                  <Node Id="motorcycle">
                      <ScriptId>9</ScriptId>
                      <GunkFlags>NoCollision</GunkFlags>
                  </Node>
              </Import>
…we need to use:
              <Import Path="env/lab_motorcycle.dae">
                      <ScriptId>9</ScriptId>
                      <GunkFlags>NoCollision</GunkFlags>
              </Import>


__TOC__
__TOC__




==Level releases and resources==
ONLV and AKEV should not be extracted as XML unless it is for the purpose of trouble shooting or research. The extracted XMLs cannot be used for level creation.
===Fan-made levels===
{| class="wikitable sortable autosort by-column-3"
!Date
!Name
!Level number
|-
|TBA
|Oni 2 Angel Studios Tour
|32
|-
|TBA
|Green Room
|26
|-
|2019/09/16
|[http://oni.bungie.org/forum/viewtopic.php?id=2965 Omega Tournament]
|31
|-
|2016/02/13
|[http://oni.bungie.org/forum/viewtopic.php?id=2947 AI Battle]
|7
|-
|2014/01/19
|[http://oni.bungie.org/forum/viewtopic.php?id=2698 Wilderness Preserve]
|17
|-
|2013/09/07
|[http://oni.bungie.org/forum/viewtopic.php?id=2656 Island]
|29
|-
|2013/07/12
|[http://oni.bungie.org/forum/viewtopic.php?id=2640 City]
|28
|-
|2013/06/01
|[http://oni.bungie.org/forum/viewtopic.php?id=2619 Fight Club]
|25
|-
|2012/05/12
|[http://oni.bungie.org/forum/viewtopic.php?id=2357 Old China]
|24
|-
|2012/03/18
|[http://oni.bungie.org/forum/viewtopic.php?id=2302 Boss Battle]
|23
|-
|2012/02/12
|[http://oni.bungie.org/forum/viewtopic.php?id=2271 De Dust Deluxe]
|22
|-
|2012/01/23
|[http://oni.bungie.org/forum/viewtopic.php?id=2242 Parkour Challenge 2]
|21
|-
|2012/01/16
|[http://oni.bungie.org/forum/viewtopic.php?id=2235 Parkour Challenge]
|21
|-
|2011/07/25
|[http://oni.bungie.org/forum/viewtopic.php?id=2001 Mini-Partenon]
|5
|-
|2011/10/03
|[http://oni.bungie.org/forum/viewtopic.php?id=2024 Muro's Lair - Preview]
|20
|-
|2011/07/03
|[http://oni.bungie.org/forum/viewtopic.php?id=1957 Hexagon]
|16
|-
|2011/06/23
|[http://oni.bungie.org/forum/viewtopic.php?id=1938 Junkyard]
|15
|-
|2011/05/01
|[http://mods.oni2.net/node/178 Arena of Hurt (OZG)]
|7
|-
|2010/11/08
|[http://oni.bungie.org/forum/viewtopic.php?id=1736 Arena of Hurt (OTA)]
|7
|-
|2010/11/06
|[http://oni.bungie.org/forum/viewtopic.php?pid=50565#p50565 Martian Colony] AKA "Silly World"
|5
|-
|2010/02/15
|[http://oni.bungie.org/forum/viewtopic.php?id=1506 Maze]
|5
|-
|2008/09/16
|[http://mods.oni2.net/node/4 Arena of Pain]
|30
|}
 
===Forum tutorials on level creation===
* '''[http://oni.bungie.org/forum/viewtopic.php?id=2087 "Creating the Lair - A level tutorial"]'''
* [http://oni.bungie.org/forum/viewtopic.php?pid=53026 "Creating a Custom Oni Level (s10k video tutorials)"]
* [http://oni.bungie.org/forum/viewtopic.php?id=1515 "Creating new levels"]
* [http://oni.bungie.org/forum/viewtopic.php?pid=33838 "Create levels with pathfinding grids"]
* [http://oni.bungie.org/forum/viewtopic.php?id=2000 "More questions about levels"]
* [http://oni.bungie.org/forum/viewtopic.php?id=2003 "Sketchup tutorials for making levels"]
* [http://oni.bungie.org/forum/viewtopic.php?pid=37252#p37252 "Modding Existing levels - Beta" ("Moveable furniture" post)]
 
===Wiki pages on level creation===
* [[New levels]]
* [[Lightmapping levels]]
* [[SketchUp tutorials and tips]]
 
===Free asset sources===
* [http://vk.com/gameready Various game meshes]
* [http://web.archive.org/web/20230601050258/http://tutorialsforblender3d.com/Textures/Textures_index.html Various game textures]
* [https://www.textures.com Various game textures]
 
==Engine limitations==
First you should be aware of the limitations that Oni will place on your level.
 
* The triangle limit of a game level is approx. 520,000 (consider it 500,000 to be on the safe side).
* {{ModTool}} can save DAE files with a maximum of 64,000 triangles per object.
* When polygons are too tightly packed, the camera will look at too many of them and glitches will appear. The limit on visible GQs (Gunk Quads) is 8,192 (2<sup>13</sup>), and higher numbers will cause render bugs and produce the console error message "Exceeded max visible GQs ''number''". There are limited solutions to this:
** Decrease the '''gs_farclipplane_set''' value.
** Hide objects via '''[[#.3CModel.3E|env_show]]'''.
** Hide objects by ''level design''. For example, departments in a building could be quite detailed because the view of the other departments/rooms is blocked by walls.
* The camera can look at 2,049 transparent textures at once; one more, and Oni crashes.
* Characters are visible ''only'' within world coordinates {-4,099, -4,099, -4,099} to {4,099, 4,099, 4,099}.
* Geometry stops outside of (roughly) world coordinates -4,228 to 4,228 on the X and Z axes (vertical axis not tested).
* '''chr_debug_spheres = 1''' visualizes the collision spheres of characters, so you can check if they will fit through an entrance.
 
==Notes on Mod Tool and Google SketchUp==
Re-saving a DAE file in Mod Tool which was originally made in SketchUp can result in a surprising change in size within Oni. This is due to a difference in the specification of a scale unit.
 
: For example, the SketchUp DAE file may have: <tt><unit meter="0.0254000" name="inch" /></tt>
: And the re-saved Mod Tool DAE file may have: <tt><unit meter="0.1" name="decimetre"></unit></tt>
 
In that case you'll need to open the new DAE in a text editor and change the length specification back.
 
==Level import with OniSplit v0.9.82.0+==
You can download OniSplit [http://mods.oni2.net/node/38 HERE] (it also comes with the [[AE]] and is found in the Tools directory of the installation).
 
The level import demo files can be downloaded [http://mods.oni2.net/node/299 HERE].
 
First, put '''OniSplit.exe''' into the second '''lab''' folder alongside the XML files.
 
Look at the file '''build.cmd'''. These are the two important lines:
 
OniSplit.exe -create:level out lab.xml
OniSplit.exe -import:pc out level3_Final.dat
 
The first line creates the *.oni files from a master.xml file, in this case '''lab.xml'''. Once finalized, the resulting .oni files can be put into a new [[Making a mod package|AE package]].
 
The second line creates level archives which can be used for fast tests. They don't require you to install a package through the AE Installer.
 
Instead of "-nosep" you can now also use "-pc" for the import. Macs, however, do use "-sep".
 
If the game crashes while loading at ~90% progress, be sure that the texture's x and y dimensions are powers of two: 64, 128, 256, 512….
 
If the game crashes while loading at ~50-60% progress, be sure that the BINACJBOCharacters or AISA file has a player character defined.
 
If the game crashes while loading ~5-10% progress, check if all your textures were inside the "out" folder.
 
:You can extract the AKEV file to XML, then search for the [[XML:AKEV#TXMA|TXMP Array]].
 
:[http://mods.oni2.net/system/files/AKEV_texture_checker.txt THIS] script checks which textures are missing by comparing the AKEV*.xml with its *.oni files folder. Change 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 build.cmd to prevent a crash.
OniSplit.exe -create:txmp out env/markers/*.tga
 
===The master XML file===
The master XML file's name determines the BSL folder name and the AKEV and ONLV file names in the output folder. File paths in the XML can be either absolute or relative.
 
'''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> (in Windows, this can be a fake name; does the Mac need actual ONSK files?)
* ONLD file for the new level; read [[Making_a_mod_package#Mod_Info.cfg|HERE]] about making sure your level is unlocked (accessible on the Load Game screen)
 
 
{| class="wikitable" width="100%"
!width=150px| XML tag
!width=120px| Content type
! Description
|-
|valign="top"| <Level SharedPath="...">
|valign="top"| link
| The master XML file can link to other XML files. Most of them will be [[OBD:BINA/OBJC#OBJC_types|BINACJBO]] files. The file type is 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 integrated into the AKEV. Unused resources in the shared folder will be ignored. That way the final level archive or AE package contains only the necessary files, saving disk space for the end user.
 
In the demo are various subfolders in the '''shared''' folder: consoles, doors, furniture, triggers and turrets. These file types do not need their file prefixes: CONS, DOOR, TRIG and OFGA. OniSplit will recognize them nonetheless.
 
'''Common mistake:'''
 
CJBO files '''need relative paths to the resource instead of just file names'''. Taking consoles, for example: a standard export to XML gives you "console_data". But to use the shared resources these must be paths like "'''consoles/console_data.oni'''" as they are stored in '''shared/console/'''. Note how the demoed '''shared''' folder is placed next to the [http://mods.oni2.net/node/299 project ("lab")] folder and the XML master file points to it using "../shared".
|-
| <Environment>
| -
|
|-
| <Model>
| -
| Used to import level geometry and static objects. See [[#<Model>|HERE]] for detailed information.
|-
| <Import Path="..."/>
| link
|
|-
| <Node Id="...">
| string
| informational (space for notes)
|-
|valign="top"| <ScriptId>
|valign="top"| integer
| Tested with BSL command ...
: [[#<Model>|env_show ID 1]] (use 0 to hide)
: [[#Breakable glass with BSL recognition|env_broken ID1 [ID2]]] (if a second ID is supplied then objects in the range ID1..ID2 get counted; "3001 3018" would cover 18 objects)
: [[#Texture exchange|env_texswap ID texture]] (no file prefix/suffix allowed)
: [[#env_shade|env_shade ID ID R G B]]
Static objects store their ID in [[XML:AKEV#IDXA_.28quad_group_id.29|one of AKEV's IDXA instances]].
|-
|valign="top"| <GunkFlags>
|valign="top"| flag
|
;AGQG (Gunk) flags (trimmed list)
see ''OniSplit -help enums'' for more flags
:None
:NoCollision
:NoObjectCollision
:NoCharacterCollision
:NoDecal
:TwoSided
:Invisible
|-
|valign="top"| <Rooms>
|valign="top"| -
| For detailed information see [[#<Rooms>|HERE]].
 
For a Google SketchUp BNV tutorial see [http://oni.bungie.org/forum/viewtopic.php?pid=36760#p36760 HERE].
|-
| <Import Path="..."/>
| link
| File path to *.dae file. BNV data, used to create pathfinding.
|-
| <Textures> {{Anchor|textures_tag}}
| -
| 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 with a dimension that isn't a power of two (2<sup>x</sup>) and textures larger than 512px on a side will be resized. For example, 2003x2000 will become 512x512. (What would 257x255 become?)
|-
| <Texture Name="...">
| string
| TXMP file name to generate.
|-
| <Flags>
| flag
| Optional tag. For list of flags see [[XML:TXMP|HERE]].
|-
|valign="top"| <Format>
|valign="top"| flag
|
:DXT1
:BGR
:RGBA
:BGR555
:BGRA5551
:BGRA4444
|-
|valign="top"| <GunkFlags>
|valign="top"| 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.
|-
|valign="top"| <Sky>
|valign="top"| 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 [[XML:ONSK|HERE]].
|-
| <Objects>
| -
|
|-
|valign="top"| <Import>
|valign="top"| link
| File path. Supported files:
: [[XML:BINA/OBJC/CHAR|Character.xml]] (has to contain player character if there's no AISA file with it)
: [[XML:BINA/OBJC/CONS|Console.xml]]
: [[XML:BINA/OBJC/DOOR|Door.xml]]
: [[XML:BINA/OBJC/FLAG|Flag.xml]]
: [[#Furniture.xml|Furniture.xml]]
: [[XML:BINA/OBJC/NEUT|Neutral.xml]]
: [[XML:BINA/OBJC/PART|Particle.xml]]
: [[XML:BINA/OBJC/PATR|PatrolPath.xml]]
: [[#Physics.xml|Physics.xml]]
: [[XML:BINA/OBJC/PWRU|PowerUp.xml]]
: [[XML:SNDD#BINACJBOSound.xml|Sound.xml]]
: [[XML:BINA/OBJC/TRIG|Trigger.xml]]
: [[XML:BINA/OBJC/TRGV|TriggerVolume.xml]]
: [[XML:BINA/OBJC/WEAP|Weapon.xml]]
 
'''NOT''' currently supported (you need to import as regular .oni file):
: [[XML:BINA/OBJC/MELE|Melee.xml]] (overrides global MELE; not used in vanilla levels)
: [[XML:BINA/OBJC/CMBT|Combat.xml]] (overrides global CMBT? not used in vanilla levels)
|-
| <Films>
| -
|
|-
| <Import>
| link
| File path to *.xml file. OniSplit creates a [[XML:FILM|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-down 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 scripting ID 9. You can show and hide the object with the BSL command '''env_show''', where the second parameter means true or false. '''Never use 0 as an ID''' because it won't work.
 
env_show 9 1
env_show 9 0
 
EdT demonstrates env_show [https://www.youtube.com/watch?v=Em6wa5JTQNM here]. Note how the objects have collision.
 
The last vanilla 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
* destructible walls like in Deus Ex: Human Revolution (trigger volume, replacing punch anim with punch-through-wall anim)
* grids in front of ventilation shafts (a small 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)
 
<!-- atm, the effort is not worth the work
<nowiki>https://dl.dropboxusercontent.com/u/139715/OniGalore/TV_triggered_env_show.png</nowiki> (dead link)
: edit: replace 0 by 25
 
If the objects appear to flicker then we could replace the hide_all_object_groups() function with individual TV exit functions.
 
func hide_all_object_groups
{
# env_show id [1|0]
env_show 1 0
env_show 2 0
# ...
env_show 25 0
}
func show_object_group (int grpA, int grpB, int grpC, int grpD, int grpE, int grpF, int grpG, int grpH)
{
env_show (grpA, 1)
env_show (grpB, 1)
env_show (grpC, 1)
env_show (grpD, 1)
env_show (grpE, 1)
env_show (grpF, 1)
env_show (grpG, 1)
env_show (grpH, 1)
# missing arguments are taken to be 0
}
func TV_25_enter
{
hide_all_object_groups
# show object group of entered TV and of neighboring TVs
# (center, north, north east, east, east south, south, south west, west, west north)
# there's a limit of 8 arguments per function
show_object_group 25 1 2 3 4 5 6 7
show_object_group 8
}
# other examples
func TV_6_enter
{
hide_all_object_groups
show_object_group 0 0 00 0 00 00 00 00
show_object_group 22
}
func TV_20_enter
{
hide_all_object_groups
show_object_group 20 21 6 19
}
-->
 
=====Import of object groups=====
'''Mod Tool versus SketchUp'''
 
The meaning and behavior of "groups" greatly differs in these two programs.
 
:'''In SketchUp''' you can group objects which enables you to easily duplicate all objects inside a group and to scale/rotate/translate them all together.
 
:'''In Mod Tool''' grouped objects are still loose, and duplicating a group won't duplicate the objects. To achieve the same effect as in SketchUp, you have to create a hierarchy where any one object is the "parent" and all others the "children".
 
 
'''Google SketchUp'''
 
To create a group, select two or more objects, right-click on the selection and choose "make group".
 
[[Image:ModTool_can_import_objs_in_hierarchies.jpg|right|thumb|Mod Tool can import objects in hierarchies to Oni.]]
'''Mod Tool'''
 
Either use the Explorer (A) or the Schematics (B) to create a hierarchy.
 
:(A) In the Explorer window, drag and drop one or more objects onto another one.
 
:(B) Open the constrain tab at the right side. Select parent object, click "Parent", click the child object(s). Check the result in the Schematics window.
 
:'''Mod Tool: caution when saving to DAE!'''
 
:A normal selection won't do. You have to select the object tree to successfully save a hierarchy. This is the same way that you do it with Oni characters.
<!--
=====Import of smart object groups=====
Let's say there are two groups. If an edit is made to one mesh, the clone in the other group is instantly changed the same way.
 
So that's a smart group. In SketchUp this is named "component". In Mod Tool it's named ???.
:(Can be imported from SketchUp DAE file but causes a crash when re-saving. I guess a script is needed to do the job.)
-->
 
=====Breakable glass with BSL recognition=====
Broken environmental objects can be recognized by the BSL command ''env_broken (ID_1, ID_N)''. However, this 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 [[XML:BINA/OBJC/TRGV|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 triggered. The variable "inside_target_function" should be 0 by default, so we will enter the "if" block. Next, we can assume that the player didn't destroy all glass objects, so "num_broken" will be less than 18; thus, targets_are_not_gone() gets called.
 
The TV function targets_gone() ''would'' be triggered every frame, but targets_are_not_gone() creates a delay between checks: the TV gets deactivated for 60 frames. Then the TV becomes enabled again and will start anew until all glass objects got destroyed or player left the TV.
 
In this case the targets_gone() function will do nothing because "inside_target_function" was set to 1 by the first call.
 
targets_are_gone() eventually disables the TV to prevent memory overflow; this function also contains all the things ("[...]") that you want to happen after the glass target is broken.
 
=====Texture exchange=====
BSL command supported on Windows and Mac:
: env_texswap ID texture
 
Might be useful to switch on/off static and animated textures. (News broadcast screen: running or off or smashed. Lava stream: flowing or stagnating or cooled down. Etc.)
 
A similar effect can be achieved by showing/hiding geometries with different textures as EdT has demonstrated in a private test. That way it should also be possible to have different vertex coloring for an area.
 
=====Vertex coloring=====
[http://web.archive.org/web/20170529111607/http://softimage.wiki.softimage.com/xsidocs/tex_vcolor_CreatingColoratVerticesCAVMaps.htm SoftImage documentation.] Observation: The sniper tower from level 19 Syndicate Mountain Compound can be isolated and re-imported as it is. It will appear quite dark.
 
If we remove "_color" from the object, the shadows will be gone next time we import the tower.
 
Mod Tool: Explorer [8]
 
Object
  |
  +-- Polygon Mesh
        |
        +-- Cluster
              |
              +-- Polygon
              |    |
              |    +-- [...]
              |
              +-- NodeProperties
                    |
                    +-- '''_color'''
                    +-- texcoord (Explicit UVWs)
                          |
                          +-- Vertex_Color_Def
 
So, how do we modify that data?
 
======Single object shading======
If there's already a vertex color property, you can use Shift + W to activate the Paint Vertex Color Tool. With Control + W you can change the brush color. R + Hold Click + Move Mouse let you change the brush size. The more vertices (points) you have, the more detailed you can make the shadows/colors. But keep in mind that too many polygons can destroy collision, making characters fall through the ground.
 
If there's no vertex color property, the first usage of Shift + W will create that property. But you can also manually create it via Property > Color under Vertices Map.
 
======Level-wide shading======
[[Image:light_test_modtool.png|right|thumb]]
[[Image:light_test_ingame.png|right|thumb]]
 
To get general shading/lighting you can set up light sources. "Infinite" lights are useful for global lighting, while "Light Box", "Point", "Neon" and "Spot" are more suitable as local light sources. They can be accessed via Primitives > Light.
 
By default a Mod Tool scene has one Infinite light, but it doesn't shine in every direction so you might want to add more Infinite lights. Let's say one Infinite light for each direction (+X, -X, +Y, -Y, +Z, -Z) with an intensity of circa 0.25 (night) or 0.75 (day).
 
The illumination of those lights can be integrated into the vertex color property. There's some information [http://oni.bungie.org/forum/viewtopic.php?pid=29089#p29089 on OCF here]; the quoted information is in triplicate, so don't get confused by that: at first it's detailed, then summarized, then as a checklist.
 
Basically you can go with the checklist:
 
* Property > Color At Vertices Map
* Property > Render Map
* In render map property page, under Sampling select Vertices Only
* Under Surface Color, choose Enable, then in the box below select Vertex _Color; if that option does not appear, click on the New button next to it
* Under Map, select Illumination only
* Finally, click on the button Regenerate Maps...
 
This must be done for all objects separately.
 
: [http://mods.oni2.net/system/files/vertex_color_script.txt There's a script here]<!--http://mods.oni2.net/node/352--> which can apply vertex color and render maps to all '''selected''' objects. Load it into the script editor with Alt + 4 and hit F5 to run it. (Be sure the script's language was set to VBScript.)
: The variable "overwrite_VC" can be changed.
:: With "1" all existing CAV maps of selected objects will be overwritten. This can take some time.
:: With "0" only selected objects without CAV maps will be the script's target.
 
'''Notes on ModTool view modes'''
* "Constant" let you see the colors of the vertex coloring only.
* "Textured Decal" let you see object textures only.
* "Shaded" let you see the illumination only.
* "Textured" let you see the textured object with illumination and vertex coloring.
 
======env_shade======
If you use '''env_shade''', use it with caution. It completely overwrites the vertex coloring.
 
# BSL command
# env_shade obj_id obj_id R G B
# examples
env_shade 7 7 # object 7 will be black
env_shade 7 7 0 0 0 # object 7 will be black
env_shade 7 7 .31 .999 .5 # object 7 will be quite green
env_shade 7 10 1 1 1 # object 7, 8, 9, 10 lose all their shading
 
=====Baked lightmaps=====
A drawback of this method, AKA shadow maps, is the high number of [[XML:BINA/TMBD|TMBD]] changes and new textures for every wall, requiring a lot of memory. How to create shadow maps:
 
* https://web.archive.org/web/20121105081823/http://www.game-artist.net/forums/support-tech-discussion/5622-burning-shadows-onto-texture-xsi.html
<!-- http://caffeineabuse.blogspot.de/2008/12/cast-shadow-only-lights-in-xsi.html might be also interesting -->
 
Notes on map options:
* "Surface color and illumination": outputs used texture with added shadows
** Can be used to replace original texture
* "Illumination only": output a texture that only contains the shadows
** Can be used on a new overlying, transparent surface
 
=====Standalone lightmaps=====
With this approach there are two meshes, whereby the shadow effects on one mesh get drawn in front of the regular level texture.
 
Compared to the "baked lightmaps" method, this needs more polygons of course. And these polygons are transparent, which is a problem with Oni's limited rendering ability for such textures. However, standalone lightmaps only need a few new textures if used wisely.
 
Read [[Lightmapping levels]] to learn more.
 
[[Image:Oni_Lightmaps_double_polygon_method.jpg|center]]
 
====<Rooms>====
The Rooms tag is mandatory. It contains an import path to BNV and ghosts (*.dae) which are used to create pathfinding grids. For information on the binary data behind this, see [[OBD:AKVA|HERE]].
 
Sample code from the master XML file:
<Import Path="env/lab_bnv.dae"/>
 
 
'''Fundamentals'''
* '''BNVs''' are '''volumes''' (sometimes also named '''rooms''') that have a pathfinding grid assigned to them.
* For practical reasons you only need '''floors and ramps''' to build a BNV. (As seen [http://edt.oni2.net/images/Hideout_BNV.jpg HERE.])
** A BNV polygon can consist of 3 or more points, but it's recommended to use '''shapes with 4 points''' because the other shapes usually waste more grid space. At the moment you can import only '''[[wikt:convex|convex]]''' shapes.
* Secondly, there are so called '''ghosts''' (vertical quads) that connect '''neighboring BNVs'''. AI can only transit from BNV to another through ghosts.
: OniSplit gives error messages for ghosts that don't have 2 neighboring BNVs, for example:
BNV Builder: Ghost 'grid2' has no adjacencies at <-72,41 1,999 -166,6> and <-71 1,999 -168,21>, ignoring
 
'''Tolerance values'''
* Horizontal distance from room to ghost: 1
* Vertical distance from room to ghost: 18
* Ghost's horizontal dimension must be greater than 0
* Under optimal circumstances, pathfinding works on a plane that is +4 world units above or -0.5 below the pathfinding grid
* Normally characters can't pass over low vertical walls such as stairs/curbs if those don't have a ramp under them; near ground level (Y=0) is an exception where characters are allowed to step on a plane that is 4 world units above pathfinding grid; higher planes need a ramp
* Maximum angle of ramp you can go on is 70°; higher angles will make characters fall through to their death (in those cases you might want to add invisible walls/boxes to prevent them from touching the ramp)
 
'''More notes on PF processing'''
* Actually, BNV and ghosts can have any name and don't need any texture.
* During pathfinding calculation, OniSplit creates a new folder called "temp" and a subfolder "grids". There is a file named "''levelname''_grids.dae". That file contains rooms with textures called "bnv_grid_''N''.tga" which mark obstacles in the pathfinding grid. Ghosts will have a transparent texture "'''_marker_ghost'''.tga". You also get these when you export a level. Transparent ghosts make it easier to see the rest of your level if you have many of those planes.
* In Mod Tool, ghosts and rooms can be grouped under a null object. Right-click the null object to select all its children, then use "Selection Only [x]" as your saving option. That way all the planes can be quickly saved to a *.dae file.
* You can influence the pathfinding creation of dangerous zones using danger quads. Read about those [[#Marker textures|HERE]].
* Another kind of influence is the [[#<Model>|gunk flag]] IgnoreGrid. It can be used to tell OniSplit to ignore the object during pathfinding creation. The grids in that place will be white.
 
[[Image:Pathfinding_grid.jpg|thumb|200px|right|'''ai2_showgrids = 1''' in action]]
'''BSL commands'''
* chr_show_bnv = 1
:: shows number of BNVs the player is standing on
* ai2_showgrids = 1
:: shows pathfinding grids
* ai2_chump
:: spawns a friendly Striker that follows the player if possible, makes also pathfinding grids visible
* ai2_chump_stop = 1
:: Striker stops following you
* ai2_chump_stop = 0
:: Striker follows you again
 
=====Pathfinding on uneven ground=====
Pathfinding works on slightly uneven ground as long as the polygons are 0.5 world units beneath or 4 world units above the BNV.
 
For greater surface irregularities, we can use a trick:
* The problematic polygons must be saved to a DAE file and then referenced in the model section as an individual object.
* Then the <GunkFlags> tag needs to be '''''GridIgnore'''''.
* Additionally we create a plane (invisible if necessary) under the object so that Oni doesn't think there's a hole.
* The ghosts must be taller than the highest polygon to be walked on. (This has been tested up to a height of 2,000 world units.)
 
'''Symptoms of too-small ghosts'''
 
A) AI can't run at all.
 
B) AI loses PF ability if the tracked enemy performs animations that are outside of the pathfinding volume. Here's a video (<nowiki>https://youtu.be/vfKPzP5hiCo</nowiki>, dead link) showing these symptoms.
 
'''Missing boundaries'''
 
Let's say you have a BNV, tall ghosts, and a GridIgnore-flagged hill with trees and bushes and stuff.
 
Why do AIs run up against the trees?
: '''Problem:''' There are no red/orange grids that limit the AI's movement. Normally, objects will produce red pathfinding squares around them. But objects that are 20 world units above the BNV are ignored just like objects with the IgnoreGrid flag.
: '''Solution:''' Add simple geometries like ''_marker_impassable fences'' or danger quads near the BNV.
 
'''Disappearing AIs'''
 
The ground is sometimes not solid, and the player and AIs are falling through it.
 
: '''Problem:''' On GridIgnore-flagged uneven ground, AIs can fall through it when they are out of the player's view.
: '''Solution:''' Use either '''chr_lock_active ''AI_name''''' or '''chr_all_active = 1'''
 
=====Debugging=====
'''(OniSplit v0.9.93.0+)'''
[[Image:OniBrowser.jpg|thumb|200px|right|OniBrowser displaying level geometry plus PF and ghosts.]]
 
* '''env_show_ghostgqs = 1''' makes the ghost quads visible
** The original ghost quads can't be seen; per Neo, "they are not included in the octtree and bsp tree"
** To see them you must use the -debug option in the level creation command (available with OniSplit '''v0.9.93.0+''')
OniSplit.exe -create:level ''output_folder'' '''-debug''' ''input_folder''/''master_xml_file''.xml
 
Not all debugging/testing needs to be done in Oni. There is also a [http://mods.oni2.net/node/256 program] (Windows only) which can display the whole level.
 
For example you can load an AKEV*.oni, select the level name, and use the hotkeys [B] and [P] to display BNVs and ghosts.
 
'''Bug prevention:'''
 
After all testing is done, you should compile the level a last time without the -debug option.
 
AIs appear to have trouble shooting through ghost quads that got registered in the octtree/BSP tree as seen here (<nowiki>https://www.youtube.com/watch?v=-ZugVBgBVKc</nowiki>, dead link).
 
=====When OniSplit fails to connect PF quads=====
[[Image:Pathfinding_creation__merge_polygons_to_fix_connections.jpg|thumb|200px|right|Fixed PF in compound level after underground construction...]]
It can help to merge polygons to one object and merge their edges. These become white. (Outer edges are blue.)
 
====<Textures>====
=====...used for exceptions=====
The [[#textures_tag|textures tag]] is mandatory.
 
AKEV textures will be imported by the master XML file automatically; you don't need to add them to that file.
 
: With OniSplit v0.9.82-93.0, the textures' formats will be DXT1 and (for transparent ones) BGRA4444.
: With OniSplit v0.9.94.0+ the textures' formats will be BGR and (for transparent ones) RGBA.
 
To change the default texture import format, use the Texture'''s''' tag. (Possible with OniSplit v0.9.94.0+.)
 
To change the format/flag/gunk flag of a specific texture, use the Texture tag.
 
An example:
 
          <Textures Format="BGR" AlphaFormat="RGBA" MaxSize="512">
                <Texture Name="GOO">
                    <Flags>TwoSided</Flags>
                    <Format>BGRA4444</Format>
                    <GunkFlags>NoCollision</GunkFlags>
                    <Image>env/images/GOO.tga</Image>
                </Texture>
          </Textures>
 
* Use the gunk flag "TwoSided" to make surfaces visible from both sides.
* If the texture comes with the gunk flag "NoCollision" then all objects with that texture will have no collision. Characters would fall through it.
 
Transparency and no collision together would make sense for a water-like substance. The Vago Biotech level uses this approach for the area with green toxic waste.
 
[[Image:making_a_surface_transparent_and_twosided.png|thumb|200px|right|'''Figure 1''']]
 
[[Image:AKEV_single_object_multiple_textures.png|thumb|200px|right|'''Figure 2'''<br>one object with multiple textures, one per polygon cluster]]
[[Image:AKEV_single_object_multiple_textures_ingame.png|thumb|200px|right|'''Figure 3'''<br>blue: two-sided<br>glass: two-sided and transparent<br>random metal: no flag (one-sided)]]
 
 
'''TwoSided and transparent objects'''
 
It's also possible to set this in Mod Tool. For TwoSided-ness, use one image source for diffuse and transparency. (It won't work with two image sources even if both sources use the same image.)
 
For transparency you must additionally use the three checkboxes:
* Transparency: Enable
* Transparency: Use Alpha
* Transparency: Invert
 
See '''Figure 1'''.
 
=====Regular textures=====
OniSplit automatically imports textures of objects in the [[#<Model>|<Model> section]]. Those objects could be considered as AKEV core geometry.
 
 
'''One texture per object'''
 
Furniture and Physics objects are allowed to have only one texture per object. AKEV core geometry can have one texture or multiple textures – that's up to you to decide.
 
 
'''Multiple textures per object'''
 
'''Question:''' How do we apply multiple textures to an AKEV core object?
 
'''Answer:''' Assuming you are using Mod Tool the procedure will be as follows. Repeat this for each cluster you create (except for projection). See also '''Figure 2 and 3'''.
 
* Select some polygons
* Go to Material > Phong
* Hit [7] to open Render Tree
* Add a texture and connect "Image" with "Phong", choose "diffuse" as illumination mode
* Double-click "Image" to open Material page
* In the Texture Projection section, click on "New" and choose a suitable projection
** Do this only if there isn't a projection in the "Texture_Coordinates_AUTO" cluster yet
** OniSplit processes only one texture projection, see '''Figure 4'''
* Choose the texture and UV, then fine-tune the UV via Alt + 7
 
[[Image:AKEV_multiple_textures_one_projection.png|thumb|200px|right|'''Figure 4'''<br>use only one texture projection per object]]
 
Caution: textures will be fixed to one set of flags. You can't use the same texture A for a one-sided cluster/object B and a two-sided cluster/object C. You would need to create a differently-named clone of that texture and apply that to cluster/object C.
 
=====Marker textures=====
Marker textures are used to import certain objects with special flags. Import those objects alongside [[#<Model>|AKEV core]] geometry.
 
Marker textures aren't imported automatically. Add those textures to the final package or plugin yourself, e.g. with some sort of script.
 
OniSplit.exe -create:txmp out env/markers/*.tga
 
The flags Transparent, TwoSided and NoOcclusion are only set if the same texture source is used for diffuse and transparency and if transparency setting are enabled. See the subsection under "[[#...used for exceptions|...used for exceptions]]" called "TwoSided and transparent objects".
 
'''Danger quads'''
 
Pathfinding grids have different colored squares with different meanings.
* white/gray - clear space
* green light - near wall
* green - semi-passable
* green dark - stairs
* blue very light - border 1
* blue light - border 2
* blue - border 3
* blue dark - border 4
* '''orange - danger'''
* red - impassable
 
For detailed information on colors, see [[OBD_talk:AKVA/0x24#EFFECTS_of_various_pathfinding_grid_tile_types|HERE]].
 
Normally, OniSplit decide how to color the grids. But it's possible to add your own danger quads to fine-tune zones of higher danger. Those orange areas will be generated with the 4 different blue borders around it.
 
Danger quads must have "'''_marker_danger'''" as texture name.
 
Results in flags: Transparent TwoSided NoCollision Invisible NoOcclusion Danger
 
 
'''_marker_barrier'''
<!-- Originally this is only used for level-bounding invisible walls? -->
 
Results in flags: Transparent TwoSided(double-check) Invisible NoObjectCollision NoOcclusion
 
 
'''COLLISION (boxes)'''
 
AIs can get stuck in detailed geometry. This can be prevented with collision boxes. In-game the box will be invisible, but has collision so characters can't get through. The pathfinding grid will be red where it comes in contact with the box; the red is followed by a light green and then regular green.
 
[[XML:OFGA|OFGAs]] use the COLLISION texture. Onisplit doesn't automatically apply gunk flags to it. You need to use XML tags for that. Typically it would be <GunkFlags>Invisible NoObjectCollision</GunkFlags>
 
 
'''Stairs'''
 
Texture: '''_marker_stairs'''
 
Normally, characters can't move on stairs because they contain vertical rises. In this case you can use a sloping quad that is above or inside the staircases. It's possible to set the desired flags in the <Model> section, but doing so and exporting these self-made stair ramps is wasted time. Simply apply _marker_stairs to that quad and characters will be able to move on that surface.
 
Resulting flags: Stairs Transparent TwoSided Invisible NoObjectCollision NoOcclusion
 
This has no effect on pathfinding creation. Regularly-textured stair geometry (which intersects the marker quad) will be flagged as NoCharacterCollision.
 
 
'''Impassable'''
 
texture: '''_marker_impassable'''
 
Resulting flags: Transparent TwoSided (<-double-check this) Invisible NoOcclusion
 
Impassable walls are very similar to collision boxes except that particles can also collide with them. The pathfinding grids will be also red, light green, and green.
 
 
'''Blackness a.k.a. jello fix'''
 
Texture: '''_marker_blackness'''
 
Resulting flags: TwoSided NoCollision
 
Simply black walls. No effect on pathfinding creation. The purpose of these walls in Oni is to block out areas outside of a level's outermost wall so that the Jello-cam cannot show the player other parts of the level when it escapes a wall. See [[Jello-cam]] for details.
 
 
'''Doors'''
 
Texture: '''_marker_door'''
 
Resulting flags: DoorFrame Transparent TwoSided NoCollision NoOcclusion
 
Don't use this.
 
====<Objects>====
Information on regular object lists can be looked up here:
: [[XML:BINA/OBJC/CHAR|Character.xml]] (has to contain player character if there's no AISA file with it)
: [[XML:BINA/OBJC/CONS|Console.xml]]
: [[XML:BINA/OBJC/DOOR|Door.xml]]
: [[XML:BINA/OBJC/FLAG|Flag.xml]]
: [[XML:BINA/OBJC/NEUT|Neutral.xml]]
: [[XML:BINA/OBJC/PART|Particle.xml]]
: [[XML:BINA/OBJC/PATR|PatrolPath.xml]]
: [[XML:BINA/OBJC/PWRU|PowerUp.xml]]
: [[XML:SNDD#BINACJBOSound.xml|Sound.xml]]
: [[XML:BINA/OBJC/TRIG|Trigger.xml]]
: [[XML:BINA/OBJC/TRGV|TriggerVolume.xml]]
: [[XML:BINA/OBJC/WEAP|Weapon.xml]]
 
=====Furniture.xml=====
The AKEV core geometry is more or less the overall structure of the level while this furniture file adds standard objects (e.g. crates and desks) to it.
 
{| class="wikitable" width="100%"
!width=150px| XML tag
!width=120px| Content type
! Description
|-
| <Objects>
| -
| This tag marks the file as BINACJBO.
|-
| <Furniture>
| -
| This tag marks the file as FURN.
|-
| <Header>
|
|
|-
|valign="top"| <Flags>
|valign="top"| flag
| Optional tag. Ignore it. Those flags were used in the past.
:None
:Locked
:PlacedInGame
:Temporary
:Gunk
|-
| <Position>
| float x3
| Optional tag. X Y Z position.
|-
| <Rotation>
| float x3
| Optional tag. X Y Z rotation.
|-
| <OSD>
| -
|
|-
|valign="top"| <Class>
|valign="top"| link
| File path to an [[XML:OFGA|OFGA]] (*.oni) file. Make sure that the OFGA comes with the files it needs: M3GM and TXMP.
 
An OFGA can hold multiple M3GMs. That 3D content will then be integrated into the AKEV.
|-
|valign="top"| <Particle>
|valign="top"| string
| This name gets written into <Tag> inside ONLV (ENVP section) and can be used with BSL commands, e.g. you can take control over a particle via '''particle BSL_name start'''. For more commands, see [[XML:BINA/OBJC/PART#BSL_support|HERE]].
 
Take care with the naming of new OFGA files. The particle name will be composed of 2 parts separated by an "_" underscore. '''Examples:'''
 
: FURN <Particle>test</Particle> + OFGA <Tag>streetlight</Tag> = '''test_streetlight'''
: FURN <Particle></Particle> + OFGA <Tag>streetlight</Tag> = '''_streetlight'''
: FURN <Particle>test</Particle> + OFGA <Tag></Tag> = '''test_'''
|}
 
 
;Example
 
<?xml version="1.0" encoding="utf-8"?>
<Oni>
    <Objects>
        [...]
        <Furniture>
            <Header>
                <Flags>Gunk</Flags>
                <Position>-62.692 -29 108.35</Position>
                <Rotation>181.522 356.021 178.114</Rotation>
            </Header>
            <OSD>
                <Class>furniture/V_tctf_bigvan.oni</Class>
                <Particle></Particle>
            </OSD>
        </Furniture>
        [...]
    </Objects>
</Oni>
 
 
=====Physics.xml=====
This file is for objects with "physics". Unlike AKEV core geometry or furniture, these objects can be animated.
 
: A small video tutorial on [https://www.youtube.com/watch?v=CFNseg_2UxA how to create a simple animated object]
 
{| class="wikitable" width="100%"
!width=150px| XML tag
!width=120px| Content type
! Description
|-
| <Physics>
| -
|
|-
| <Object Name="...">
| string
| Use a unique name for each object.
|-
|valign="top"| <ScriptId>
|valign="top"| integer
| Tested with BSL command...
:obj_create ID [ID]
:obj_kill ID [ID]
:env_anim ID [ID]
:env_setanim ID [ID]
The scripting ID will be stored in the ONLV's OBOA instance.
|-
|valign="top"| <Flags>
|valign="top"| flag
|
;Object setup flags
:None
:InUse
:NoCollision
:NoGravity
:FaceCollision
|-
|valign="top"| <Physics>
|valign="top"| flag
| Optional tag for an Object.
:None
:Static
:Linear
:Animated
:Newton (used with <Flags> FaceCollision to [https://www.youtube.com/watch?v=YICB7qugrtc make an object pushable])
:: For a pushable object don't use import sub-tags such as animation name, flags, etc. Just use <Import Path="..." '''/'''> or <Import Url="..." '''/'''>
|-
| <Position>
| float x3
| Optional tag of Object. Only used for non-animated objects. X Y Z position.
|-
| <Rotation>
| float x3
| Optional tag of Object. Only used for non-animated objects. X Y Z rotation.
|-
| <Scale>
| float
| Optional tag of Object. Only used for non-animated objects.
|-
|
<Import Path="...">
 
<Import Url="...">
|valign="top"| link
|valign="top"| This tag comes in two variants. It doesn't matter what variant you use.
|-
| <Animation Name="...">
| link
| File path to *.dae file.
|-
|valign="top"| <Flags>
|valign="top"| flag
| Optional tag of Animation. For more information on those flags look [[XML:OBAN|OBAN]] page.
 
;Object animation flags
:None
:Loop
:PingPong
:RandomStart
:AutoStart
:Local
|-
| <End>
| integer
| Optional tag of Animation. Frame number. Used to define the end of an OBAN from a *.dae file.
|-
| <Start>
| integer
| Optional tag of Animation. Frame number. Used to define the start of an OBAN from a *.dae file.
|}
 
 
;Example
 
For documentation purposes, the file here has been trimmed down.
<?xml version="1.0" encoding="utf-8"?>
<Oni>
    <Physics>
        [...]
        <Object Name="motorcycle">
            <ScriptId>8</ScriptId>
            <Flags>FaceCollision</Flags>
            <Import Url="motorcycle/export.dae">
                <Animation Name="motorcycle02">
                    <Flags>AutoStart</Flags>
                    <End>880</End>
                </Animation>
                <Animation Name="motorcycle02_stop">
                    <Start>881</Start>
                </Animation>
            </Import>
        </Object>
        [...]
    </Physics>
</Oni>
 
In this example, OniSplit takes the file "export.dae", looks at the parts it contains, and creates geometry files from it.
* M3GMhubs_rear.oni
* M3GMhubs.oni
* M3GMmotorcycle.oni
It's convenient that hierarchies are supported here.
 
The motorcycle is made of 3 parts so 3 object animations ([[XML:OBAN|OBAN]]) will be created up to frame 880. Then OniSplit creates 3 more OBANs starting from frame 881.
 
The reason for the interruption at frame 880 is probably to give Barabas a little more camera time in the cutscene.
 
;Notes about BSL usage:
 
The Vago Lab cutscene script uses the motorcycle objects and animations like this:
env_show 8 0 # hide static motorcycle parts or else they would be visible
env_show 9 0 # while Konoko is still riding her animated motorcycle
env_show 10 0 # the static motorcycle is separated into objects 8, 9 and 10
# Static and animated objects are totally independent from each other.
# They are stored in different arrays so their script IDs can use the same numbers.
obj_create 8 10 # create all animation-ready motorcycle parts
env_anim 8 10 # animate those parts (not necessary if OBAN flag is "AutoStart")
# The first animations would loop because of "AutoStart", so get the
# right timing to apply the other animations. "motorcycle02_stop"
# and the others will not loop because they don't have "AutoStart".
env_setanim 8 hubs_stop
env_setanim 9 hubs_rear_stop
env_setanim 10 motorcycle02_stop
obj_kill 8 10 # delete all animated parts
env_show 9 1 # show static motorcycle model where Konoko parks her bike
 
=====Corpses.xml=====
'''(OniSplit v0.9.96.0+)'''
 
'''(Import)'''
 
CRSA corpses can now be imported from an XML file if registered in the master file. See [[#CRSA|HERE]]. (Two formats available.)
 
Direct import is not yet supported by OniTools.
 
----
 
For indirect import, see [http://oni.bungie.org/forum/viewtopic.php?id=2657 HERE] (OniTools v7.1.5+) on how to get corpse data.
 
When you process your XML master file, use OniSplit version 0.9.94.0+. Older OniSplit versions like 0.9.86.0 may generate ONLV files that are not re-packable with newer versions.
 
 
'''(Export)'''
 
With Neo's matrix-to-Euler code, the rotations can be recovered from CRSA. But due to the character's hierarchy, things get messy again (<nowiki>https://dl.dropboxusercontent.com/u/139715/OniGalore/CRSA_to_Mod_Tool_wip.png</nowiki>, dead link). (WIP code (<nowiki>https://dl.dropboxusercontent.com/u/139715/temp/CRSA_to_Mod_Tool.txt</nowiki>, dead link))
 
A workaround might be to save characters without animations, destroy their hierarchy, apply the local rotations / global translation and glue everything together again.
 
==Level reimport==
===Export of static geometry===
After the .oni files have been exported, the extraction of objects can fail if their textures can't be found. Those objects probably use textures stored in level 0.
 
In that case use the "-search" argument to make the correct extractions. The commands will look like this:
 
OniSplit.exe -export level0_files level0.dat
OniSplit.exe -export levelX_files levelX.dat
OniSplit.exe -extract:dae levelX_geometry levelX_files/AKEV*.oni -search level0_files
 
Possible output files:
* ''level''_bnv.dae
* ''level''_cons.dae
* ''level''_door.dae
* ''level''_env.dae
* ''level''_env_markers.dae
* ''level''_furn.dae
* ''level''_script_''N''.dae (by OniSplit v0.9.90.0+)
* ''level''_trig.dae
* ''level''_turr.dae
 
Reimporting DAE files (except for env_markers) will merge them with "env" (the core AKEV geometry).
 
===Export of animated geometry and cameras===
'''(OniSplit v0.9.90.0+)'''
 
This is also known as a scene export. All content exported by the scene file will be combined and saved in a single DAE.
 
OniSplit.exe -extract:dae path_to/output_directory path_to/scene.xml
 
For the following example, the scene.xml must be present in a folder containing all files used by the scene. In this case it's level3_Final ("lab").
 
<Scene>
<Node Name="camera">
      <Camera />
      <Animation>OBANCamout01.oni</Animation>
      <Animation>OBANCamout02.oni</Animation>
      <Animation>OBANCamout03.oni</Animation>
      <Animation>OBANCamout04.oni</Animation>
      <Animation>OBANCamout05.oni</Animation>
      <Animation>OBANCamout06.oni</Animation>
  </Node>
  <Node Name="motorcycle02">
      <Geometry>M3GMmotorcycle02.oni</Geometry>
      <Animation>OBANmotorcycle02.oni</Animation>
      <Animation>OBANmotorcycle02_stop.oni</Animation>
      <Node Name="hubs">
          <Geometry>M3GMhubs.oni</Geometry>
          <Animation>OBANhubs.oni</Animation>
          <Animation>OBANhubs_stop.oni</Animation>
      </Node>
      <Node Name="hubs_rear">
          <Geometry>M3GMhubs_rear.oni</Geometry>
          <Animation>OBANhubs_rear.oni</Animation>
          <Animation>OBANhubs_rear_stop.oni</Animation>
      </Node>
  </Node>
  </Scene>
 
When you load the DAE in [[Mod Tool|XSI]] you'll find the motorcycle and the intro cutscene camera. If you select the camera (for better visibility) and press play, you'll get to see the motorcycle intro animation that you know from the game.
 
For real-time playback, click on the "Playback" option button and then choose "Real-Time Playback".
 
 
;File structure
* The scene contains one or more '''nodes'''.
* Each node represents '''either one 3D object or one camera''' whereby the node name determines the object name inside the DAE.
** 3D objects do have a '''<Geometry>''' tag.
** Cameras do have a '''<Camera />''' tag.
** Each 3D object or camera can have '''one or multiple <Animation>''' tags. Multiple animations will be combined.
** 3D objects can be organized in a '''hierarchy''' that is created with the help of '''sub-nodes'''. Each sub-node can also have animations.
 
 
;Scene import
According to Neo that feature is still under development. RIP.
 
===Recycle object lists===
The following files can be reused under <Objects> without any drawback:
* BINACJBOCharacter.xml
* BINACJBOFlag.xml
* BINACJBONeutral.xml
* BINACJBOParticle.xml
* BINACJBOPatrol Path.xml
* BINACJBOPowerUp.xml
* BINACJBOSound.xml
* BINACJBOTrigger Volume.xml
* BINACJBOWeapon.xml
 
===Lock lights===
Door lock lights must be transferred by hand from old an ONLV (ENVP instance) to a) a new ONLV or b) an OBJC particle file.
 
For method b), you could use [http://mods.oni2.net/system/files/extract_ENVP.txt THIS] script. The advantage is that you don't need to edit the new ONLV afterwards.
 
===OBJC and vertex coloring===
* Object (XML) import via <Object> tag (master XML file) will get you objects without any vertex coloring. (OniSplit will pick *.oni class files from the shared folder.)
* Object (DAE) import via <Model> tag (master SML file) should get you objects with vertex coloring, but no BSL functions. In that case you must add the corresponding OBJC files by hand.
 
You can choose between these two methods for consoles, triggers, turrets and furniture without particles. Doors and furniture ''with'' particles always require the XML method.
 
===Manual reimport of physics===
Don't want to make a scene.xml and physics.xml file? All animated physics can be restored if you aren't afraid of post-editing the ONLV.
 
# Look in the original level folder and copy the OBAN and M3GM files to your project's output folder.
# Create your level. Then convert the new ONLV to XML. Now you are able to compare the new and old ONLV file.
# Get all original OBOA instances that aren't doors or empty.
# Each OBOA has a <Geometry> tag which links to an M3GA instance by ID. Collect all the M3GAs that are used by your OBOAs.
# Add these collected OBOAs and M3GAs to your new ONLV. Make sure that your M3GA IDs aren't already taken; change them if necessary.
# Save the ONLV and convert to .oni. Make a package or plugin and test your reimported level.
 
===Demo files===
Level 19 reimport (<nowiki>https://dl.dropboxusercontent.com/u/139715/OniGalore/Level_19_reimport.zip</nowiki>, dead link)
 
Demo files were already provided at the top of this page (Chapter 3 — Vago Biotech), also a reimport, but it uses a bit different setup. For example, it imports animated objects from *.dae files, which result in a few bugs: Konoko's motorcycle is too low, at another point it is completely missing, and the van at the end of the level has some strange unnecessary gunk attached.
 
In this second demo, the ENVP and OBOA/M3GA instances were manually reimported. So, if you enjoy REing stuff, try to make sense of the second demo, too.
 
Known issues are:
* Doors and trigger don't have vertex shading. (Also not possible with normal level creation.)
* Consoles tend to have a collision issue with the player, keeping him trapped. (Jump backwards to escape.)
** This issue might get solved by using a single BINACJBOConsole.xml file. Or we can try to edit the collision boxes of compound_cons.dae.
 
So now, how about accessible towers and underground passages or ventilation shafts? ;D The [http://mods.oni2.net/node/119 Prone Mode mod] is so useless right now; let's change this!
 
==Level export==
This section is only about XML files. For DAE exporting, see [[#Level_reimport|HERE]].
 
Most parts of an Oni level are contained by ONLV and AKEV. For AKEV's XML tags, see [[XML:AKEV|HERE]].


You would only want to export those two files as XML if you want to check if a texture or an object really made it into the level or not.
If you want to create new level check out the '''[[Creating a level|corresponding tutorial]]'''.


===ONLV===
==ONLV==
{| class="wikitable" width="100%"
{| class="wikitable" width="100%"
!width=150px| XML tag
!width=150px| XML tag
Line 1,442: Line 59:
|}
|}


===OBOA===
==OBOA==
Used for movable/moving objects.
Used for movable/moving objects.


Line 1,525: Line 142:
|}
|}


===ONOA===
==ONOA==
Used by static objects (imported by object list).
Used by static objects (imported by object list).


Line 1,560: Line 177:
  ONOA <QuadList> -> ONOA IDXA -> AKEV AGQG by order
  ONOA <QuadList> -> ONOA IDXA -> AKEV AGQG by order


===ENVP===
==ENVP==
{| class="wikitable" width="100%"
{| class="wikitable" width="100%"
!width=150px| XML tag
!width=150px| XML tag
Line 1,601: Line 218:
|}
|}


===CRSA===
==CRSA==
[[Image:ONLV_CRSA_XSI_aided_import.jpg|thumb|200px]]
[[Image:ONLV_CRSA_XSI_aided_import.jpg|thumb|200px]]


Line 1,702: Line 319:
If you created CRSA data using the Mod Tool addon, add <Oni> and </Oni> tags at the start and end of the file.
If you created CRSA data using the Mod Tool addon, add <Oni> and </Oni> tags at the start and end of the file.


===M3GA===
==M3GA==
There can be one M3GA instance per animated object. Animated meshes of doors are embedded in ONLV. All other animated meshes are stored outside it as M3GM files.
There can be one M3GA instance per animated object. Animated meshes of doors are embedded in ONLV. All other animated meshes are stored outside it as M3GM files.


Line 1,726: Line 343:
|}
|}


===M3GM===
==M3GM==
Read about them here [[XML:M3GM|HERE]]. Note that M3GMs have their own component instances: PNTA, VCRA (x2), TXCA, IDXA (x2). Doors store their animated model in ONLV, while the static model comes from BINACJBODOOR.oni, which also links to M3GM files.
Read about them here [[XML:M3GM|HERE]]. Note that M3GMs have their own component instances: PNTA, VCRA (x2), TXCA, IDXA (x2). Doors store their animated model in ONLV, while the static model comes from BINACJBODOOR.oni, which also links to M3GM files.


===IDXA===
==IDXA==
{| class="wikitable" width="100%"
{| class="wikitable" width="100%"
!width=150px| XML tag
!width=150px| XML tag

Revision as of 10:25, 2 November 2023

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


ONLV and AKEV should not be extracted as XML unless it is for the purpose of trouble shooting or research. The extracted XMLs cannot be used for level creation.

If you want to create new level check out the corresponding tutorial.

ONLV

XML tag Content type Description
<ONLV id="..."> integer ONLV's instance number. Should be 0.
<Name> char[64] Name of BSL folder.
Save game slot and level number are defined inside ONLD.
<Environment> link Link to AKEV via file name (AKEVname, don't use file suffix .oni)
Level geometry.
<Objects> link Link to OBOA via instance number (#N).
The OBOA instance holds doors, animated objects (usually for cutscenes) and pushable objects (which are not used the original game due to unfinished physics code).
<SkyBox> link Link to ONSK via file name (ONSKname, don't use file suffix .oni)
This is the skybox.
<Characters> link Link to AISA via file name (AISAname, don't use file suffix .oni)
This "AI Setup Array" is an alternative character list. BINACHAR is more powerful.
<ObjectQuadMap> link Link to ONOA via instance number (#N).
This "Object Array" holds functional objects – doors, furniture, turrets, triggers and consoles. In addition, it appears that the engine only searches for door-type objects.
<Particles> link Link to ENVP via instance number (#N).
These "Environment Particle" are traditionally only used for door lock lights and particles used by OFGAs.
<Corpses> link Link to CRSA via instance number (#N).
This is a "Corpse Array". It's used to spawn dead characters such as Chung in Chapter 1.

OBOA

Used for movable/moving objects.

XML tag Content type Description
<OBOA id="..."> integer Instance ID. Should be 1.
<Objects> - Array of <OBOAObject> tags.
<OBOAObject> - There are always 32 empty objects plus those that are actually used
<Geometry> "#" + integer Link to M3GA instance. Doors have two separate models: an animated and a static one. If this <Geometry> links to a door, it will be the animated model.
<Animation> link OBANname.
<Particle> # + integer Link to ENVP instance. There can be multiple ENVP instances – one for a lock light and others for additional particles.
<Flags> flags
None
InUse
NoCollision (any effect? no collision is default behavior)
NoGravity
FaceCollision (for doors)
<DoorGunkId> int32 The index of the door frame GQ (only used for door objects)
<DoorId> int32 Only used for doors; in the case of double doors, both doors have the same ID and they are flagged as "InUse FaceCollision"
<PhysicsType> flags
None
Static
Linear (pushable object)
Animated (animated via OBAN)
Newton (same as Linear)
<ScriptId> int32 Scripting ID; used by BSL function obj_create; "65535" means not used.
<Position> vector Float x3. Not used for animated objects.
<Rotation> quaternion Float x4. Not used for animated objects.
<Scale> float Not used for animated objects.
<Transform> matrix Float 3*3 + 3 more floats for the X Y Z position of the object. For more information on the matrix, see OBD:CRSA. Used for animated objects.
<Name> char[64] Name of the object; informational only.

ONOA

Used by static objects (imported by object list).

XML tag Content type Description
<ONOA id="..."> integer Instance ID.
<Elements> - This is an int32 array for the <ONOAElement> tags.
<ONOAElement> -
<ObjectId> integer Object ID and type to which this quad belongs (see AKEV's AGQG for details).
Actual object IDs can also be found in BINA/OBJC/####.
<QuadList> "#" + integer Link to IDXA instance. Each object has its own IDXA instance.

Where do the links go to again?

ONOA <ObjectId> -> AKEV AGQG -> BINA/OBJC/#### by type and ID
ONOA <QuadList> -> ONOA IDXA -> AKEV AGQG by order

ENVP

XML tag Content type Description
<ENVP id="..."> integer Instance ID.
<Particles> - This is an int16 array for the <ENVPParticle> tags. If there's not going to be any contents, you put <Particles /> here.
<ENVPParticle> -
<Class> char[64] BINA3RAPfile.oni (don't use file prefix/suffix).
<Tag> char[48] Particle's scripting name for BSL commands; see OFGA for more information on name composition.
<Transform> matrix Float 3*3 + 3 more floats for the X Y Z position of the particle. For more information on the matrix, see OBD:CRSA.
<DecalScale> int32, int32 X Y
<Flags> flag
None
NotInitiallyCreated

CRSA

ONLV CRSA XSI aided import.jpg

Wanted: "How to add corpses" tutorial

Some related information can be found at Authoring custom camera animations.
XML tag Content type Description
<CRSA id="..."> integer Instance ID.
<FixedCount> integer The array capacity of <Corpses> is larger than the number of "fixed"/"used" corpses in order to allow the engine to store new corpses at runtime. "Fixed" means that those corpses are never overwritten/deleted at runtime – all new corpses are stored after the "fixed" ones. This means that "fixed" <= "used" <= "capacity".
<UsedCount> integer
<Corpses> - This is an int32 array for the <CRSACorpse> tags. By default, Oni wants 20 slots for corpses. Unused corpses have their matrix and bounding box filled with zeroes.
<CRSACorpse> - New corpses can be made with the BSL command make_corpse filename and some hex-editing. The pose of the corpse is taken from the player character. The contents of the files thus created can then be inserted as elements in a level's CRSA.
<CharacterClass> link ONCCname
<Transforms> - There are 19 <Matrix4x3> for each <Transforms> (which represents a body part).
<Matrix4x3> matrix Float 3x3 + float x3 for the last 3 values (X Y Z position). For more information about the matrix, see OBD:CRSA.
<BoundingBox> - Bounding box of the whole corpse.
<Min> float x3
<Max> float x3

The level importer supports importing corpses from an XML file with the same format as described above or the following simplified format:

XML tag Content type Description
<Corpses>
<Corpse> -
<Class> link ONCCname
<Transforms> - There are 19 <Matrix> for each <Transforms> (which represents a body part).
<Matrix> matrix Float 3x3 + float x3 for the last 3 values (X Y Z position). For more information about the matrix, see OBD:CRSA.
<BoundingBox> - Bounding box of the whole corpse. Optional; if not provided, OniSplit will generate an approximate one. Currently it doesn't try to locate the ONCC to compute an exact bounding box.
<Min> float x3
<Max> float x3

An empty Corpse element (<Corpse />) is treated as unused and placed at the end of the array. If no such empty elements are provided, OniSplit automatically adds 5. OniSplit also ensures that there are at least 20 corpses in the array.

If you created CRSA data using the Mod Tool addon, add <Oni> and </Oni> tags at the start and end of the file.

M3GA

There can be one M3GA instance per animated object. Animated meshes of doors are embedded in ONLV. All other animated meshes are stored outside it as M3GM files.

XML tag Content type Description
<M3GA id="..."> integer Instance ID.
<Geometries> - This is an int32 array for the <Link> tags.
<Link> link
#N (instance number) (for non-door)
M3GMname (for door)

It can happen that you see here references to DAE files. This happens when the ONLV was created with some older OniSplit version (like 0.9.86.0) and if the ONLV was converted to xml in absence of the resources used by M3GA.

M3GM

Read about them here HERE. Note that M3GMs have their own component instances: PNTA, VCRA (x2), TXCA, IDXA (x2). Doors store their animated model in ONLV, while the static model comes from BINACJBODOOR.oni, which also links to M3GM files.

IDXA

XML tag Content type Description
<IDXA id="..."> integer Instance ID.
<Indices> - This is an Int32 array for the <Int32> tags.
<Int32> int32
From ONOA to AGQG elements
Link to <AGQGQuad>s in AGQG by order. (The array in AGQG starts with 0, so for example <Int32>6</Int32> would link to the 7th <AGQGQuad>.)
From M3GM to PNTA elements
Read more HERE.
From M3GM to VCRA elements
Read more HERE.

Level files hierarchy

(un)colored cell = file stripped cell = embedded instance
ONLV
Chart fork right.gif AKEV
Chart descend.gif Chart fork right.gif PNTA
Chart descend.gif Chart fork right.gif PLEA
Chart descend.gif Chart fork right.gif TXCA
Chart descend.gif Chart fork right.gif AGQG
Chart descend.gif Chart fork right.gif AGQR
Chart descend.gif Chart fork right.gif AGQC
Chart descend.gif Chart fork right.gif AGQC
Chart descend.gif Chart fork right.gif AGDB
Chart descend.gif Chart fork right.gif TXMA
Chart descend.gif Chart descend.gif Chart turn right.gif TXMP
Chart descend.gif Chart fork right.gif AKVA
Chart descend.gif Chart fork right.gif AKEB
Chart descend.gif Chart fork right.gif IDXA
Chart descend.gif Chart fork right.gif AKBP
Chart descend.gif Chart fork right.gif ABNA
Chart descend.gif Chart fork right.gif AKOT
Chart descend.gif Chart descend.gif Chart fork right.gif OTIT
Chart descend.gif Chart descend.gif Chart fork right.gif OTLF
Chart descend.gif Chart descend.gif Chart fork right.gif QTNA
Chart descend.gif Chart descend.gif Chart turn right.gif IDXA
Chart descend.gif Chart fork right.gif AKAA
Chart descend.gif Chart turn right.gif AKDA
Chart fork right.gif OBOA
Chart descend.gif Chart fork right.gif M3GA
Chart descend.gif Chart descend.gif Chart turn right.gif M3GM
Chart descend.gif Chart descend.gif Chart fork right.gif PNTA
Chart descend.gif Chart descend.gif Chart fork right.gif VCRA
Chart descend.gif Chart descend.gif Chart fork right.gif TXCA
Chart descend.gif Chart descend.gif Chart fork right.gif IDXA
Chart descend.gif Chart descend.gif Chart turn right.gif TXMP
Chart descend.gif Chart fork right.gif OBAN
Chart descend.gif Chart turn right.gif ENVP
Chart fork right.gif ONMA
Chart fork right.gif ONFA
Chart fork right.gif ONTA
Chart turn right.gif ONSK
Chart descend.gif Chart fork right.gif TXMP
Chart fork right.gif AISA
Chart descend.gif Chart fork right.gif ONCC
Chart descend.gif Chart turn right.gif ONWC
Chart fork right.gif AITR
Chart fork right.gif ONSA
Chart fork right.gif OBDC
Chart descend.gif Chart turn right.gif M3GM
Chart descend.gif Chart fork right.gif PNTA
Chart descend.gif Chart fork right.gif VCRA
Chart descend.gif Chart fork right.gif TXCA
Chart descend.gif Chart fork right.gif IDXA
Chart descend.gif Chart turn right.gif TXMP
Chart fork right.gif ONOA
Chart descend.gif Chart turn right.gif IDXA
Chart fork right.gif ENVP
Chart turn right.gif CRSA
Chart turn right.gif ONCC