Adding Scenery and Actor LOD Source Tutorial

*Created by Cysis on the RealmCrafter: Community Edition forums.*

**Before starting this tut please backup all your work!**

Right one of the classic features of RCS's stupidity is trying to Render **everything** at once. This causes low fps rates and limits the amount of detail you can have in your zones. LOD fixes this and tells your client only to render certain models depending on the players range to them, without affecting certain models for example terrain.

**Scenery LOD**
First start by Opening your **Client.bb** file. Find the section that looks like this...

```
CameraProjMode(GY_Cam, 1)

   ; Render GUI

   CameraProjMode(Cam, 0)

   For S.Scenery = Each Scenery

      HideEntity(S\EN)

   Next

   For T.Terrain = Each Terrain

      HideEntity(T\EN)

   Next

   RenderWorld()

   CameraProjMode(Cam, 1)

   For S.Scenery = Each Scenery

      ShowEntity(S\EN)

   Next

   For T.Terrain = Each Terrain

      ShowEntity(T\EN)

   Next

   PostRenderWorld()   ; DebugBanner update

   UpdateFPS()

```

And replace it with....

```
 CameraProjMode(GY_Cam, 1)

   ; Render GUI

   CameraProjMode(Cam, 0)

   For S.Scenery = Each Scenery

      HideEntity(S\EN)

   Next

   For T.Terrain = Each Terrain

      HideEntity(T\EN)

   Next

   RenderWorld()

   CameraProjMode(Cam, 1)

   For S.Scenery = Each Scenery

      ;LOD scenery

      Select S\SceneryType$

         Case "T"

            ShowEntity(S\EN)

         Case "B"

             If EntityDistance#(S\EN, Cam) < BuildingMaxViewDistance#

                ShowEntity(S\EN)

            Else

                HideEntity(S\EN)

            EndIf

         Case "G"

            If EntityDistance#(S\EN, Cam) < GrassMaxViewDistance#

                ShowEntity(S\EN)

            Else

                HideEntity(S\EN)

            EndIf

         Case "Z"

            If EntityDistance#(S\EN, Cam) < ObjectMaxViewDistance#

               ShowEntity(S\EN)

            Else

               HideEntity(S\EN)

            EndIf

         Default

            ShowEntity(S\EN)

      End Select

   Next

   For T.Terrain = Each Terrain

      ShowEntity(T\EN)

   Next

   PostRenderWorld()   ; DebugBanner update

   UpdateFPS()

```

Next open **ClientAreas.bb** and find...

```
Type Scenery

   Field SceneryID ; Set by user, used for scenery ownerships

   Field EN, MeshID

   Field AnimationMode ; 0 = no animation, 1 = constant animation (loops), 2 = constant (ping-pongs), 3 = animate when selected

   Field ScaleX#, ScaleY#, ScaleZ#

   Field Lightmap$     ; Lightmap filename

   Field RCTE$         ; Used by toolbox editors only

   Field TextureID     ; To alter the texture loaded automatically with the model, if required (65535 to ignore)

   Field CatchRain

   Field Locked

End Type

```

And add this at the end...

```
Field SceneryType$ ;Variable declaration for view distance

```

Should now look like this...

```
Type Scenery

   Field SceneryID ; Set by user, used for scenery ownerships

   Field EN, MeshID

   Field AnimationMode ; 0 = no animation, 1 = constant animation (loops), 2 = constant (ping-pongs), 3 = animate when selected

   Field ScaleX#, ScaleY#, ScaleZ#

   Field Lightmap$     ; Lightmap filename

   Field RCTE$         ; Used by toolbox editors only

   Field TextureID     ; To alter the texture loaded automatically with the model, if required (65535 to ignore)

   Field CatchRain

   Field Locked

   Field SceneryType$ ;Variable declaration for view distance

End Type

```

Under this section add. these are your ranges for the Fade in and Fade out

```
;LOD (Set view distances here)

Const BuildingMinViewDistance# = 230.0 ; If distance < this value will be Visible, else will autofade slowly

Const BuildingMaxViewDistance# = 250.0 ; If distance > this value will be 100% invisible

Const GrassMinViewDistance# = 75.0

Const GrassMaxViewDistance# = 90.0

Const ObjectMinViewDistance# = 130.0

Const ObjectMaxViewDistance# = 150.0

```

Should now look like

```
Type Scenery

   Field SceneryID ; Set by user, used for scenery ownerships

   Field EN, MeshID

   Field AnimationMode ; 0 = no animation, 1 = constant animation (loops), 2 = constant (ping-pongs), 3 = animate when selected

   Field ScaleX#, ScaleY#, ScaleZ#

   Field Lightmap$     ; Lightmap filename

   Field RCTE$         ; Used by toolbox editors only

   Field TextureID     ; To alter the texture loaded automatically with the model, if required (65535 to ignore)

   Field CatchRain

   Field Locked

   Field SceneryType$ ;Variable declaration for view distance Ramoida

End Type

;LOD (Set view distances here)

Const BuildingMinViewDistance# = 230.0 ; If distance < this value will be Visible, else will autofade slowly

Const BuildingMaxViewDistance# = 250.0 ; If distance > this value will be 100% invisible

Const GrassMinViewDistance# = 75.0

Const GrassMaxViewDistance# = 90.0

Const ObjectMinViewDistance# = 130.0

Const ObjectMaxViewDistance# = 150.0

```

Next Scroll down and find

```
 If S\EN <> 0

            ; Toolbox extras

            If Len(S\RCTE$) > 5

               Select Left$(S\RCTE$, 5)

                  Case "_TREE"

                     If DisplayItems = False

                        swingsty = Int(Mid$(S\RCTE$, 6, 1))

                        evergrn = Int(Mid$(S\RCTE$, 7, 1))

                        S\EN = LoadTree("", evergrn, S\EN, swingsty)

                     EndIf

                  Case "_GRSS"

                     swingsty = Int(Mid$(S\RCTE$, 6, 1))

                     evergrn = Int(Mid$(S\RCTE$, 7, 1))

                     S\EN = LoadGrass("", evergrn, S\EN, swingsty)

                  Case "_RCDN"

                     If DisplayItems = False

                        RotateMesh(S\EN, Pitch#, Yaw#, Roll#)

                        ScaleEntity(S\EN, S\ScaleX#, S\ScaleY#, S\ScaleZ#)

                        ChunkTerrain(S\EN, 3, 3, 3, X#, Y#, Z#)

                        Delete S

                        Goto CancelScenery

                     EndIf

               End Select

            EndIf

            ; Set position/rotation

            PositionEntity S\EN, X#, Y#, Z# : RotateEntity S\EN, Pitch#, Yaw#, Roll#

            ScaleEntity S\EN, S\ScaleX#, S\ScaleY#, S\ScaleZ#

```

Underneath it add

```
;LOD

            S\SceneryType$ = "" ;initiate the variable just in case

            If Instr(Name$, "RCTE\") ;these folders wont be affected by LOD, this is so that models that have actors on it wont disappear causing the actors to fall

S\SceneryType$ = "T" ;If it is Terrain, mark it as "T" ;This will be used at Client.bb

            ;;BUILDINGS

             ElseIf Instr(Name$, "BUILDINGS\")

S\SceneryType$ = "B"

               EntityAutoFade S\EN,BuildingMinViewDistance#,BuildingMaxViewDistance#;If it is an object set autofade

            ;GRASS

            ElseIf Instr(Name$, "GRASS\")

S\SceneryType$ = "G"

               EntityAutoFade S\EN, GrassMinViewDistance#, GrassMaxViewDistance#

            ElseIf Instr(Name$, "OBJECTS\")

               S\SceneryType$ = "Z"

               EntityAutoFade S\EN, ObjectMinViewDistance#, ObjectMaxViewDistance#

            EndIf

```

That section is your file Directories for the different ranges. It has been Set up to already look into your \Data\Meshes folder so you need to add the folders of your models yourself. The way you do this is using

```
Instr(Name$, "FOLDERNAME\")

```

But if you want more than one folder of models affected by that LOD range then simply add.

```
Or Instr(Name$, "FOLDERNAME2\")

```

Next to it on the same line
so it looks a bit like

```
Instr(Name$, "FOLDERNAME\") Or Instr(Name$, "FOLDERNAME2\")

```

etc. **YOU MUST WRITE FOLDER NAMES IN CAPITALS EVEN IF THEY ARE NOT NAMED WITH CAPITALS** also you must have **\** at the end of the name or it wont work. Any folder that isn't listed in these three sections simply wont be affected by LOD and will continue to render as usual.

I believe thats it for scenery LOD give it a try and please post if it's not working i may have missed something.

**Actor LOD**
This one is much simpler to set up.
Open your **Client.bb** and find under **Function UpdateActorInstances()**

```
SetPickModes()

   ; Updates for every actor

   For AI.ActorInstance = Each ActorInstance

      ; If it's not dead

      If AI\Attributes\Value[HealthStat] > 0

         ; Fade in (uses \AIMode field which is a server field, to save adding an extra field and using server memory)

         ; DISABLE - uses entityautofade instead

;         If AI\AIMode < 501

;            If AI = Me Or AI = Me\Mount Then AI\AIMode = 499 ; The player and the player's mount do not fade in

;            AI\AIMode = AI\AIMode + 2

;            Alpha# = Float#(AI\AIMode) / 501.0

;            EntityAlpha AI\EN, Alpha#

;            EntityAlpha AI\ShadowEN, Alpha#

;            If AI\WeaponEN <> 0 Then EntityAlpha AI\WeaponEN, Alpha#

;            If AI\ShieldEN <> 0 Then EntityAlpha AI\ShieldEN, Alpha#

;            If AI\HatEN <> 0 Then EntityAlpha AI\HatEN, Alpha#

;         EndIf

         ; Check if this actor is underwater

         AI\Underwater = 0

         If AI\Actor\Environment = Environment_Amphibious

            For W.Water = Each Water

               If EntityY#(AI\CollisionEN) < EntityY#(W\EN) - 0.5

                  If Abs(EntityX#(AI\CollisionEN) - EntityX#(W\EN)) < (W\ScaleX# / 2.0)

                     If Abs(EntityZ#(AI\CollisionEN) - EntityZ#(W\EN)) < (W\ScaleZ# / 2.0)

                        AI\Underwater = Handle(W)

                        PositionEntity(AI\EN, 0, 0, 0)

                        Exit

                     EndIf

                  EndIf

               EndIf

            Next

         EndIf

         If AI\Underwater = 0 Then PositionEntity(AI\EN, 0, MeshHeight#(AI\EN) / -2.0, 0)

```

Under this add

```
EntityAutoFade(AI\EN),55,65 ; adjust these for range values Min,Max

               If EntityDistance(AI\EN,cam) > (50)

                 HideEntity(AI\EN)

             ElseIf EntityDistance(AI\EN,cam) <(45)

                 ShowEntity(AI\EN)

               EndIf

```

Should now look like

```
Function UpdateActorInstances()

   SetPickModes()

   ; Updates for every actor

   For AI.ActorInstance = Each ActorInstance

      ; If it's not dead

      If AI\Attributes\Value[HealthStat] > 0

         ; Fade in (uses \AIMode field which is a server field, to save adding an extra field and using server memory)

         ; DISABLE - uses entityautofade instead

;         If AI\AIMode < 501

;            If AI = Me Or AI = Me\Mount Then AI\AIMode = 499 ; The player and the player's mount do not fade in

;            AI\AIMode = AI\AIMode + 2

;            Alpha# = Float#(AI\AIMode) / 501.0

;            EntityAlpha AI\EN, Alpha#

;            EntityAlpha AI\ShadowEN, Alpha#

;            If AI\WeaponEN <> 0 Then EntityAlpha AI\WeaponEN, Alpha#

;            If AI\ShieldEN <> 0 Then EntityAlpha AI\ShieldEN, Alpha#

;            If AI\HatEN <> 0 Then EntityAlpha AI\HatEN, Alpha#

;         EndIf

         ; Check if this actor is underwater

         AI\Underwater = 0

         If AI\Actor\Environment = Environment_Amphibious

            For W.Water = Each Water

               If EntityY#(AI\CollisionEN) < EntityY#(W\EN) - 0.5

                  If Abs(EntityX#(AI\CollisionEN) - EntityX#(W\EN)) < (W\ScaleX# / 2.0)

                     If Abs(EntityZ#(AI\CollisionEN) - EntityZ#(W\EN)) < (W\ScaleZ# / 2.0)

                        AI\Underwater = Handle(W)

                        PositionEntity(AI\EN, 0, 0, 0)

                        Exit

                     EndIf

                  EndIf

               EndIf

            Next

         EndIf

         If AI\Underwater = 0 Then PositionEntity(AI\EN, 0, MeshHeight#(AI\EN) / -2.0, 0)

   EntityAutoFade(AI\EN),55,65

               If EntityDistance(AI\EN,cam) > (50)

                 HideEntity(AI\EN)

             ElseIf EntityDistance(AI\EN,cam) <(45)

                 ShowEntity(AI\EN)

               EndIf

         ; Show/hide nametags in HideNametags mode 2 (selected only)

         If HideNametags = 2

            If AI\NametagEN <> 0

               If Handle(AI) = PlayerTarget

                  ShowEntity(AI\NametagEN)

               Else

                  HideEntity(AI\NametagEN)

               EndIf

            EndIf

         EndIf

```

And thats it. Again post if you get a MAV so that it can be fixed for everyone!
Save everything and compile an .Exe and try it out!