Log in to reply

MILO starter guide!

  • I've always got the impression the Eclipse Tower was, at one point, meant to represent the pinnacle of downtown architecture. Personally, I've always deemed the Eclipse Tower rather unimaginative. So, I set out to take one of the fancy Eclipse Penthouse interiors, and move it to 3 Alta Street -- a much fancier building, IMHO, in the 'banking' district. I adapted my own (private) version of SPA for that. Today I succeeded:

    Since I ran into some snares along the way, I decided to make a small beginner's guide about MILO loading, so it will be easier for future peeps playing with MILO files.

    For starters, what is MILO? I don't even know for sure, as this game's innards appear to be notoriously undocumented (at least officially); but it's reasonable to assume it stands for Moveable Interior LOader. The idea behind a MILO is rather brilliant, really. Instead of hard-coding all your build's objects coordinates, you create a ymap file with just relative coordinates (relative to a, preferably nearby, virtual 'root' prim). That ymap is typically embedded in a CMloArchetypeDef container, inside a ytyp file. Like apa_int_mp_h_08.ytyp, used in my project. It creates a CMloArchetypeDef called apa_V_mp_h_08, in this case. You can use this interior name in your own MILO loader. Like in the 3alta_aqua_interior_milo_.ymap I created (which is essentially just an adapted copy of apa_v_mp_h_08_c.ymap):

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <flags value="1"/>
      <contentFlags value="73"/>
      <streamingExtentsMin x="-12739.02000000" y="-10075.14000000" z="-989.30100000"/>
      <streamingExtentsMax x="7260.98200000" y="9924.85600000" z="5010.69900000"/>
      <entitiesExtentsMin x="-12739.02000000" y="-10075.14000000" z="-989.30100000"/>
      <entitiesExtentsMax x="7260.98200000" y="9924.85600000" z="5010.69900000"/>
        <Item type="CMloInstanceDef">
          <flags value="1572864"/>
          <guid value="752431654"/>
          <position x="-266.301" y="-952.1876" z="95.0"/>
          <rotation x="0.00000000" y="0.00000000" z="0.5701291" w="0.8215551"/>
          <scaleXY value="1.00000000"/>
          <scaleZ value="1.00000000"/>
          <parentIndex value="-1"/>
          <lodDist value="60.00000000"/>
          <childLodDist value="0.00000000"/>
          <numChildren value="0"/>
          <ambientOcclusionMultiplier value="255"/>
          <artificialAmbientOcclusion value="255"/>
          <tintValue value="0"/>
          <groupId value="0"/>
          <floorId value="0"/>
          <numExitPortals value="4"/>
          <MLOInstflags value="0"/>
        <numStreetLights value="0"/>
        <category value="0"/>
        <version value="0"/>
        <flags value="0"/>

    (Don't forget to set the proper physicsDictionaries too, V_mp_h_08 in this case)

    One thing you'll notice, is that you really don't need a Parent loader (most game's MILO's are 'children' of often up to 3-4 levels of inheritance): it works well enough stand-alone. (I was a bit lazy on the extends, but the interior will be totally invisible from the outside anyway). Also note:

    <flags value="1"/>

    This is not the usual '0', so the ymap isn't loaded automagically on startup, but only on request. Other contentFlags than 73 are possible, but 73 is a sure bet.

    As a sidenote, still well worth mentioning, I think, CodeWalker is awesome! You can just grab the 'root prim' of an entire MILO instance with it, and move/rotate it around as a whole, for your convenience! Chapeau for this great mod!

    Now, back to business. One vital step, is that your own MILO loader needs a proper _manifest.ymf entry, telling the game where it can find the CMloInstanceDef dependency! Like so:


    (Thanks to @nkjellman, for having published his Leftover Interiors from Beta mod, so I could study it, and get a clue).

    Using this bit of code snippet @Alex106 provided, earlier today (for disabling the MILO physics, after removal), you are now ready to use your own MILO:

    int MPMapAltaStApt = Function.Call<int>(Hash.GET_INTERIOR_AT_COORDS, -266.301f, -952.1876f, 95.0f);
    Function.Call(Hash.SET_INTERIOR_ACTIVE, MPMapAltaStApt, true);
    Function.Call(Hash.DISABLE_INTERIOR, MPMapAltaStApt, false);

    (You can use 'ToggleIPL' for this in SPA, btw: plenty examples therein).

    That will be it for today! In a next installment, I will address how to make your own moveable CMloArchetypeDef map entries (we still need a good tool to re-calculate fixed coordinated to relative ones, IMHO).

    And thanks to the above ppl, and to the always helpful @Cyron43, of course, for kindly giving me access to his bunker loader code. :)

  • Just for fun, another apartment I did, for my monochromatic needs:

    This time at 4 Integrity Way

    I obviously swapped out some artwork. For some I had to rebake the ydr, so as only to keep the frame, and then placed another picture right in (which is a bitch, honestly, without a MILO editor). It's all in good fun, though. :) And once CodeWalker starts supporting interior editing, the sky's the limit!

  • Today I want to talk a bit about adding your own objects to an interior. But before that, now hear this!

    What the eye don't see, Rockstar don't get away with. :P Because CodeWalker shows everything, mercilessly! So, where are all these extra props in the monochrome interior?! mono with all objects

    So, wrote a small sub to re-enable them:

        Public Sub LoadMonoMapMissingObjects()
                Dim MONO As Integer = Native.Function.Call(Of Integer)(Hash.GET_INTERIOR_AT_COORDS, -17.42973, -599.6702, 92.616)
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_booze_a")
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_booze_b")
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_booze_c")
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_smokes_a")
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_smokes_b")
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_smokes_c")
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_strip_a")
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_strip_b")
                Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_strip_c")
                Native.Function.Call(Hash.REFRESH_INTERIOR, MONO)
            Catch ex As Exception
                logger.Log(ex.Message & " " & ex.StackTrace)
            End Try
        End Sub

    It would appear the author of SPA forgot to enable the extra props for ALL the fancy, changeable interiors! The names to enable can be found in the <entitySets> of each pertinent ymap.

    But on to business, now. In the above vid, I needed to re-bake apa_mp_h_05_dining_art_temp1, so as to only keep the frame. That's because the mesh area for the image is coded to just show a small section of the image. So, I kept the frame-only, and positioned a new image at the proper location, bwgirl_artwallm, in this case.

    For starters, you must make a new object part of the MILO map itself (placing it inside with an external ymap will cause it to remain invisible). Furthermore, You can't just add a CEntityDef anywhere! A MILO is made up of rooms; and rooms have attachedObjects: an integer array of object numbers. If you just insert a CEntityDef entry randomly (like you can do with regular ymaps), things will start to go vewy, vewy, wrong :P So, we add our extra object at the very end, right before <rooms> starts. Like so:

            <Item type="CEntityDef">
              <flags value="1572864"/>
              <guid value="3300474395"/>
              <position x="-16.111643" y="-0.215" z="2.372117"/>
              <rotation x="0.00000000" y="0.00000000" z="0.7071067" w="-0.7071067"/>
              <scaleXY value="1.660000000"/>
              <scaleZ value="1.660000000"/>
              <parentIndex value="-1"/>
              <lodDist value="30.00000000"/>
              <childLodDist value="0.00000000"/>
              <numChildren value="0"/>
              <ambientOcclusionMultiplier value="255"/>
              <artificialAmbientOcclusion value="255"/>
              <tintValue value="0"/>
              <bbMin x="-21.10761000" y="-7.62902900" z="-0.28539990"/>
              <bbMax x="9.08784800" y="20.36355000" z="8.10063500"/>
              <blend value="1.00000000"/>
              <flags value="96"/>
              <portalCount value="5"/>
              <floorId value="0"/>
              <exteriorVisibiltyDepth value="-1"/>
              <attachedObjects content="int_array">

    That way it won't interfere with the existing attachedObjects numbering. The numbering itself is, regret to say, still rather opaque to me. Whatever type I counted, the last object is never anything near the amount matching a sensible 'last' entry. :) This isn't a real problem, though, as you can just take the highest attachment number found (217, in this case) and add 1 to it for your own entry.

    So, which room to add it to? I found out limbo is a good choice, as it seems to encompass the entire interior space. If you attach it elsewhere, like the bedroom, the object will zip out of scope (literally become invisible outside said room). So, in this case, I simply added 218 to the 'limbo' room; and voila, you now successfully added an extra object to the MILO map!

    EDIT: N.B. On rooms, apa_mp_h_05_dining_art_temp1 is a funky little prop. At first I couldn't understand why it was such a ridiculously long rectangle shape, spanning the entire area. Now I realize they did so, because the first floor is (amongst other things) made up of both a dining area and an adjacent living room space. So, to keep the painting visible from the living room area as well, they made it so big as to keep its root center inside the living room. One learns a lot studying these things. :)

  •         Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_strip_a")
            Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_strip_b")
            Native.Function.Call(Hash._ENABLE_INTERIOR_PROP, MONO, "apart_hi_strip_c")

    LOL, I'm beginning to suspect that maybe you're not supposed to enable all 3 sets at once. :) Maybe, in real Online, you either get a, b, or c. depending on the MILO choice (also a, b, or c). Anyone know?

  • @meimeiriver only apart_hi_smokes_a, apart_hi_smokes_b and apart_hi_smokes_c can't be activated all at once because there's 3 ashtrays (a = empty ; b = half full ; c = full) and 3 lighters in the same spot
    alt text

  • @Alex106 Thank for clarifying that. :) The way I now implemented this, is the way I outlined above: I will enable either set a, b, or c, depending on the a b, or c apartment in question (only at Eclipse tower all 3 are present by default). Otherwise it was just too much.

    P.S. Looks like you spawned the apartment with Simple Trainer. Kudos on them for not having forgotten about the extra props! And I should really check on other apartments as well, to see whether there are perchance other <entitySets> too that can be enabled.

    EDIT: P.P.S. There's no smoking in my apartments. :) So I never enable the cigarettes.

  • @Dekurwinator Like I said in my start-post "(I was a bit lazy on the extents, but the interior will be totally invisible from the outside anyway)." Basically, those extents I used encompass the entire game world. :) But you can't see the interior from the outside at all. Each room has an entry defined, like:

          <exteriorVisibiltyDepth value="-1"/>

    So, nothing outside the bbMin/bbMax values of each room is visible anyway from the outside. (Not sure exteriorVisibiltyDepth actually governs that, but the interior is utterly invisible from the outside).

    The game actually has the following defined for apa_v_mp_h_08_c

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <flags value="1"/>
      <contentFlags value="73"/>
      <streamingExtentsMin x="-847.78050000" y="274.92320000" z="126.11340000"/>
      <streamingExtentsMax x="-727.78050000" y="394.92320000" z="246.11340000"/>
      <entitiesExtentsMin x="-807.75500000" y="313.81560000" z="185.88590000"/>
      <entitiesExtentsMax x="-779.97330000" y="344.04010000" z="194.21380000"/>
        <Item type="CMloInstanceDef">
          <flags value="1572864"/>
          <guid value="752431654"/>
          <position x="-787.78050000" y="334.92320000" z="186.11340000"/>
          <rotation x="0.00000000" y="0.00000000" z="-0.70710690" w="-0.70710680"/>
          <scaleXY value="1.00000000"/>
          <scaleZ value="1.00000000"/>

    But yeah, I should create some cleaner extents. :)

  • @Dekurwinator said in MILO starter guide!:

    @meimeiriver well i just check forum and these values just poke my eyes ;p im not scripter i just looked at it like i look at ymap (im always work manual with this things) ;p

    And you were right to point it out! :) It's kinda funny, that when I started experimenting with the MILO's, I constantly thought the IPL's just wouldn't spawn, as I kept camming up inside, say, the 3 Alta building, and saw absolutely nothing present! (You can see some of the 'cheaper' interiors, btw). All the time, LOL, it was actually there, but you have to cam right inside the interior for it to become visible! :)

Log in to reply

Looks like your connection to GTA5-Mods.com Forums was lost, please wait while we try to reconnect.