Beispiel #1
0
        private bool Begin()
        {
            IntPtr cellPtr;

            Memory.InvokeCdecl(GidFileGenerationTask.addr_EnterLock);
            try
            {
                cellPtr = Memory.InvokeCdecl(GidFileGenerationTask.addr_WSLoadCellByCoordinates, this.Parent.WorldSpace.Cast <NetScriptFramework.SkyrimSE.TESWorldSpace>(), this.X, this.Y);
            }
            catch
            {
                GidFileGenerationTask.KillProcess();
                return(false);
            }
            finally
            {
                Memory.InvokeCdecl(GidFileGenerationTask.addr_ExitLock);
            }

            if (cellPtr == IntPtr.Zero)
            {
                return(false);
            }

            this.Cell = MemoryObject.FromAddress <NetScriptFramework.SkyrimSE.TESObjectCELL>(cellPtr);
            if (this.Cell == null)
            {
                throw new NullReferenceException("this.Cell");
            }

            return(true);
        }
Beispiel #2
0
        private void Init()
        {
            var fi = new System.IO.FileInfo(ProgressFilePath);

            if (fi.Exists)
            {
                lock (ProgressLocker)
                {
                    using (var fs = new System.IO.StreamReader(ProgressFilePath))
                    {
                        string l;
                        while ((l = fs.ReadLine()) != null)
                        {
                            l = l.Trim();

                            if (string.IsNullOrEmpty(l))
                            {
                                continue;
                            }

                            this.ProgressDone.Add(l);
                        }
                    }
                }

                IsResuming = ProgressDone.Count != 0;
            }

            if (this.ProgressDone.Count == 0)
            {
                var dir = new System.IO.DirectoryInfo("Data/Grass");
                if (!dir.Exists)
                {
                    dir.Create();
                }

                var files = dir.GetFiles();
                foreach (var x in files)
                {
                    if (x.Name.EndsWith(".dgid", StringComparison.OrdinalIgnoreCase) || x.Name.EndsWith(".cgid", StringComparison.OrdinalIgnoreCase))
                    {
                        x.Delete();
                    }
                }
            }

            this.FileStream = new System.IO.StreamWriter(ProgressFilePath, true);

            string tx;

            if (IsResuming)
            {
                tx = "Resuming grass cache generation now.\n\nThis will take a while!\n\nIf the game crashes you can run it again to resume.\n\nWhen all is finished the game will say.\n\nOpen console to see progress.";
            }
            else
            {
                tx = "Generating new grass cache now.\n\nThis will take a while!\n\nIf the game crashes you can run it again to resume.\n\nWhen all is finished the game will say.\n\nOpen console to see progress.";
            }
            GidFileGenerationTask.ShowMessageBox(tx);
        }
Beispiel #3
0
        private void warn_extend_without_cache()
        {
            var ls = new List <string>();

            ls.Add("Warning!! You have enabled ExtendGrassDistance without using pre-generated grass. This could lead to unstable game. Either disable ExtendGrassDistance or pre-generate grass cache files. In order to use pre-generated grass cache you will need UseGrassCache=True and OnlyLoadFromCache=True");
            ls.Add("Check nexus page of 'No Grass In Objects' mod for more information on how to do this.");
            //ls.Add("This warning won't be shown again next time you start game.");

            try
            {
                var fi = new System.IO.FileInfo("Data/NetScriptFramework/Plugins/GrassControl.warned.txt");
                if (fi.Exists)
                {
                    return;
                }

                using (var sw = fi.CreateText())
                {
                    sw.WriteLine("Dummy file to track whether the following warning was shown:");
                    sw.WriteLine();
                    sw.Write(string.Join(Environment.NewLine + Environment.NewLine, ls));
                }
            }
            catch
            {
            }

            GidFileGenerationTask.ShowMessageBox(string.Join("\n\n", ls));
        }
Beispiel #4
0
        internal GidFileWorldGenerateTask(GidFileGenerationTask parent, NetScriptFramework.SkyrimSE.TESWorldSpace ws, string wsName)
        {
            this.Parent     = parent;
            this.WorldSpace = ws;
            this.Name       = wsName;
            _grid           = new GidFileCellGenerateTask[129 * 129];

            ugrid = Memory.ReadInt32(GidFileGenerationTask.addr_uGrids + 8);
            uhalf = ugrid / 2;
        }
Beispiel #5
0
        private bool Process()
        {
            if (this.Cell == null)
            {
                return(false);
            }

            double pct = 0.0;

            if (this.Parent.TotalCellDo > 0)
            {
                pct = Math.Max(0.0, Math.Min((double)this.Parent.DidCellDo / (double)this.Parent.TotalCellDo, 1.0)) * 100.0;
            }

            string msg = "Generating grass for " + this.Parent.Name + "(" + this.X + ", " + this.Y + ") " + pct.ToString("0.##") + " pct, world " + (GidFileGenerationTask.DoneWS + 1) + " out of " + GidFileGenerationTask.TotalWS;

            GidFileGenerationTask.write_all_message(msg);

            using (var alloc = Memory.Allocate(0x20))
            {
                Memory.WriteZero(alloc.Address, 0x20);

                Memory.WriteFloat(alloc.Address, this.Cell.CoordinateX * 4096.0f + 2048.0f);
                Memory.WriteFloat(alloc.Address + 4, this.Cell.CoordinateY * 4096.0f + 2048.0f);
                Memory.WriteFloat(alloc.Address + 8, 0.0f);

                try
                {
                    Memory.InvokeCdecl(GidFileGenerationTask.addr_SetPlrTo, NetScriptFramework.SkyrimSE.PlayerCharacter.Instance.Cast <NetScriptFramework.SkyrimSE.PlayerCharacter>(), alloc.Address, alloc.Address + 0x10, this.Cell.Cast <NetScriptFramework.SkyrimSE.TESObjectCELL>(), 0);
                }
                catch
                {
                    GidFileGenerationTask.KillProcess();
                    return(false);
                }
            }

            return(true);
        }
Beispiel #6
0
        internal static void run_freeze_check()
        {
            while (true)
            {
                if (cur_state != 1)
                {
                    break;
                }

                int last = System.Threading.Interlocked.CompareExchange(ref _lastDidSomething, 0, 0);
                int now  = Environment.TickCount;

                if (unchecked (now - last) < 60000)
                {
                    System.Threading.Thread.Sleep(1000);
                    continue;
                }

                //NetScriptFramework.Main.CriticalException("Grass generation appears to have frozen! Restart the game.", false);
                GidFileGenerationTask.KillProcess();
                return;
            }
        }
Beispiel #7
0
        internal static void apply()
        {
            var addr = Main.GameInfo.GetAddressOf(13148, 0x2B25 - 0x2220, 0, "E8");

            Memory.WriteNop(addr, 5);

            addr = Main.GameInfo.GetAddressOf(13190, 0xD40 - 0xC70, 0, "E8");
            Memory.WriteHook(new HookParameters()
            {
                Address       = addr,
                IncludeLength = 5,
                ReplaceLength = 5,
                Before        = ctx =>
                {
                    System.Threading.Interlocked.Increment(ref queued_grass_counter);
                }
            });

            addr = Main.GameInfo.GetAddressOf(13190, 0xD71 - 0xC70, 0, "48 8B 74 24 48");
            Memory.WriteHook(new HookParameters()
            {
                Address       = addr,
                IncludeLength = 5,
                ReplaceLength = 5,
                Before        = ctx =>
                {
                    System.Threading.Interlocked.Exchange(ref queued_grass_mode, 0);
                }
            });

            addr = Main.GameInfo.GetAddressOf(15202, 0xA0E - 0x890, 0, "8B 05");
            Memory.WriteHook(new HookParameters()
            {
                Address       = addr,
                IncludeLength = 0,
                ReplaceLength = 6,
                Before        = ctx =>
                {
                    ctx.AX = new IntPtr(ChosenGrassGridRadius);
                }
            });

            addr = Main.GameInfo.GetAddressOf(13138, 0, 0, "48 8B 51 38");
            Memory.WriteHook(new HookParameters()
            {
                Address       = addr,
                IncludeLength = 0,
                ReplaceLength = 8,
                Before        = ctx =>
                {
                    var cellPtr = Memory.ReadPointer(ctx.CX + 0x38);
                    Memory.InvokeCdecl(addr_AddGrassNow, Memory.ReadPointer(addr_GrassMgr), cellPtr, ctx.CX + 0x48);

                    var cell = MemoryObject.FromAddress <NetScriptFramework.SkyrimSE.TESObjectCELL>(cellPtr);
                    if (cell != null)
                    {
                        var ws = cell.WorldSpace;
                        if (ws != null)
                        {
                            string wsn = ws.EditorId;
                            int x      = cell.CoordinateX;
                            int y      = cell.CoordinateY;

                            cur_instance.WriteProgressFile(GidFileGenerationTask.KeyCell, wsn, x, y);
                        }
                    }

                    System.Threading.Interlocked.Decrement(ref queued_grass_counter);
                }
            });
            Memory.WriteUInt8(addr + 8, 0xC3, true);

            NetScriptFramework.SkyrimSE.Events.OnFrame.Register(e =>
            {
                if (cur_state == 1)
                {
                    if (System.Threading.Interlocked.CompareExchange(ref queued_grass_counter, 0, 0) != 0)
                    {
                        return;
                    }

                    if (System.Threading.Interlocked.Exchange(ref queued_grass_mode, 1) != 0)
                    {
                        return;
                    }

                    System.Threading.Interlocked.Exchange(ref _lastDidSomething, Environment.TickCount);

                    if (!cur_instance.RunOne())
                    {
                        if (GidFileGenerationTask.Crashed)
                        {
                            GidFileGenerationTask.KillProcess();
                            NetScriptFramework.SkyrimSE.Main.Instance.QuitGame = true;
                            return;
                        }

                        cur_state = 2;

                        write_all_message("Grass generation finished successfully!");
                        NetScriptFramework.Main.CriticalException("Grass generation finished successfully!", false);
                        NetScriptFramework.SkyrimSE.Main.Instance.QuitGame = true;
                    }
                }
            }, 200, 0);

            // Allow game to be alt-tabbed and make sure it's processing in the background correctly.
            addr = Main.GameInfo.GetAddressOf(35565, 0x216 - 0x1E0, 0, "74 14");
            Memory.WriteUInt8(addr, 0xEB, true);

            NetScriptFramework.SkyrimSE.Events.OnMainMenu.Register(e =>
            {
                Memory.WriteUInt8(Main.GameInfo.GetAddressOf(508798) + 8, 1); // Skyrim.ini [General] bAlwaysActive=1
                Memory.WriteUInt8(Main.GameInfo.GetAddressOf(501125) + 8, 0); // Skyrim.ini [Grass] bAllowLoadGrass=0
            });
        }
Beispiel #8
0
        private void init()
        {
            this.Settings     = new Settings();
            _settingsInstance = this.Settings;
            this.Settings.RayCastCollisionLayers = string.Join(" ", new CollisionLayers[]
            {
                //CollisionLayers.Unidentified,
                CollisionLayers.Static, // most world objects like house, stairs, crates
                CollisionLayers.AnimStatic,
                //CollisionLayers.Transparent, // very thin static? projectiles do not collide
                //CollisionLayers.Clutter, // misc objects like brooms, pots
                //CollisionLayers.Trees, // all flora! not only trees but bushes and plants too
                //CollisionLayers.Props, // signs, chains, flags
                //CollisionLayers.Water,
                CollisionLayers.Terrain, // terrain object like rock, boulder and mountain
                //CollisionLayers.Ground, // actual terrain height map, we do NOT want this
                CollisionLayers.DebrisLarge,
                //CollisionLayers.TransparentSmall,
                //CollisionLayers.TransparentSmallAnim,
                //CollisionLayers.InvisibleWall,
                CollisionLayers.StairHelper,
            }.Select(q => ((int)q).ToString()));
            this.Settings.Load();

            if (this.Settings.UseGrassCache && new System.IO.FileInfo(GidFileGenerationTask.ProgressFilePath).Exists)
            {
                GidFileGenerationTask.apply();

                Events.OnMainMenu.Register(e =>
                {
                    _did_mainMenu = 1;
                }, 5000, 1);

                Events.OnFrame.Register(e =>
                {
                    if (_did_mainMenu == 0)
                    {
                        return;
                    }

                    if (_did_mainMenu == 1)
                    {
                        _did_mainMenu++;
                    }
                    else if (_did_mainMenu == 2)
                    {
                        _did_mainMenu++;

                        GidFileGenerationTask.cur_state = 1;

                        GidFileGenerationTask._lastDidSomething = Environment.TickCount;
                        var t = new System.Threading.Thread(GidFileGenerationTask.run_freeze_check);
                        t.Start();

                        var gf = new GidFileGenerationTask();
                    }
                });

                this.Settings.ExtendGrassDistance = false;
            }

            if (this.Settings.ProfilerReport)
            {
                profiler = new Profiler();

                // Track when console is opened.
                {
                    var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(50177, 0, 0, "40 53 48 83 EC 20");
                    Memory.WriteHook(new HookParameters()
                    {
                        Address       = addr,
                        IncludeLength = 6,
                        ReplaceLength = 6,
                        Before        = ctx =>
                        {
                            var p = profiler;
                            if (p != null)
                            {
                                p.Report();
                            }
                        }
                    });
                }

                // Track the time taken in create grass function.
                {
                    // 4D10
                    var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15204, 0, 0, "48 8B C4 4C 89 40 18");
                    Memory.WriteHook(new HookParameters()
                    {
                        Address       = addr,
                        IncludeLength = 7,
                        ReplaceLength = 7,
                        Before        = ctx =>
                        {
                            var p = profiler;
                            if (p != null)
                            {
                                p.Begin();
                            }
                        }
                    });

                    // 5923
                    addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15204, 0x5923 - 0x4D10, 0, "48 81 C4 F0 08 00 00");
                    Memory.WriteHook(new HookParameters()
                    {
                        Address       = addr,
                        IncludeLength = 7,
                        ReplaceLength = 7,
                        Before        = ctx =>
                        {
                            var p = profiler;
                            if (p != null)
                            {
                                p.End();
                            }
                        }
                    });
                }
            }

            if (this.Settings.RayCast)
            {
                Events.OnMainMenu.Register(e =>
                {
                    string formsStr = this.Settings.RayCastIgnoreForms;
                    var cachedList  = CachedFormList.TryParse(formsStr, "GrassControl", "RayCastIgnoreForms", false, true);
                    if (cachedList != null && cachedList.All.Count == 0)
                    {
                        cachedList = null;
                    }

                    this.Cache = new RaycastHelper(this.Version, this.Settings.RayCastHeight, this.Settings.RayCastDepth, this.Settings.RayCastCollisionLayers, cachedList);
                }, 0, 1);

                var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15212, 0x723A - 0x6CE0, 0, "F3 0F 10 75 B8");

                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 5,
                    ReplaceLength = 5,
                    Before        = ctx =>
                    {
                        var land = MemoryObject.FromAddress <TESObjectLAND>(ctx.SI);
                        float x  = Memory.ReadFloat(ctx.SP + 0x40);
                        float y  = Memory.ReadFloat(ctx.SP + 0x44);
                        float z  = ctx.XMM7f;

                        if (land != null)
                        {
                            var cache = this.Cache;
                            if (cache != null && !cache.CanPlaceGrass(land.ParentCell, land, x, y, z))
                            {
                                ctx.Skip();
                                ctx.IP = ctx.IP + (0x661 - 0x23F);
                            }
                        }
                    },
                });
            }

            if (this.Settings.SuperDenseGrass)
            {
                // Make amount big.
                {
                    var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15202, 0xAE5 - 0x890, 0, "C1 E1 07");
                    int mode = Math.Max(0, Math.Min(12, this.Settings.SuperDenseMode));
                    if (mode != 7)
                    {
                        Memory.WriteUInt8(addr + 2, (byte)mode, true);
                    }
                }
            }

            if (this.Settings.ExtendGrassCount)
            {
                // Create more grass shapes if one becomes full.
                {
                    var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15220, 0x433 - 0x3C0, 0, "0F 84");
                    Memory.WriteNop(addr, 6);

                    addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15214, 0x960 - 0x830, 0, "48 39 18 74 0A");
                    Memory.WriteHook(new HookParameters()
                    {
                        Address       = addr,
                        IncludeLength = 0,
                        ReplaceLength = 5,
                        Before        = ctx =>
                        {
                            if (Memory.ReadPointer(ctx.AX) == ctx.BX)
                            {
                                var shapePtr = Memory.ReadPointer(ctx.AX + 8);
                                if (shapePtr != IntPtr.Zero)
                                {
                                    shapePtr = Memory.ReadPointer(shapePtr);
                                    if (shapePtr != IntPtr.Zero)
                                    {
                                        int hasSize = Memory.ReadInt32(shapePtr + 0x190) * Memory.ReadInt32(shapePtr + 0x194) * 2;
                                        if (hasSize < 0x20000)
                                        {
                                            ctx.IP = ctx.IP + (0xF - 5);
                                        }
                                    }
                                }
                            }
                        },
                    });
                }

                // Fix bug related to coordinates which causes game to want to put all grass into 1 or 2 shapes.
                // This can't work, there's more places in game where game expects it to be * 12 :(

                /*{
                 *  // 1401B4D10
                 *  // 1401B4E0D
                 *  // 1401B4E3C
                 *  var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15204, 0xE0D - 0xD10, 0, "B8 AB AA AA 2A");
                 *  Memory.WriteHook(new HookParameters()
                 *  {
                 *      Address = addr,
                 *      IncludeLength = 0,
                 *      ReplaceLength = (0x3C - 0xD),
                 *      Before = ctx =>
                 *      {
                 *          Memory.WriteInt32(ctx.SP + (0x928 - 0x8B8), Memory.ReadInt32(ctx.SP + (0x928 - 0x8E8)));
                 *          Memory.WriteInt32(ctx.BP - 0x60, Memory.ReadInt32(ctx.SP + (0x928 - 0x8EC)));
                 *      },
                 *  });
                 *
                 *  // 1401B5940
                 *  // 1401B59C8
                 *  // 1401B59FD
                 *  addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15205, 0xC8 - 0x40, 0, "B8 AB AA AA 2A");
                 *  Memory.WriteHook(new HookParameters()
                 *  {
                 *      Address = addr,
                 *      IncludeLength = 0,
                 *      ReplaceLength = (0xFD - 0xC8),
                 *      Before = ctx =>
                 *      {
                 *          int what = Memory.ReadInt32(ctx.SP + (0x238 - 0x200));
                 *          Memory.WriteInt32(ctx.SP + (0x238 - 0x1E4), what);
                 *          ctx.R15 = new IntPtr(what);
                 *
                 *          Memory.WriteInt32(ctx.SP + (0x238 - 0x1E8), Memory.ReadInt32(ctx.SP + (0x238 - 0x1FC)));
                 *      },
                 *  });
                 *
                 *  // 1401B6200
                 *  // 1401B6252
                 *  // 1401B6282
                 *  addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15206, 0x52, 0, "B8 AB AA AA 2A");
                 *  Memory.WriteHook(new HookParameters()
                 *  {
                 *      Address = addr,
                 *      IncludeLength = 0,
                 *      ReplaceLength = (0x82 - 0x52),
                 *      Before = ctx =>
                 *      {
                 *          int what = Memory.ReadInt32(ctx.SP + (0x318 - 0x2E4));
                 *          Memory.WriteInt32(ctx.SP + (0x318 - 0x2DC), what);
                 *          ctx.BX = new IntPtr(what);
                 *
                 *          what = Memory.ReadInt32(ctx.SP + (0x318 - 0x2E8));
                 *          Memory.WriteInt32(ctx.SP + (0x318 - 0x2D4), what);
                 *          ctx.SI = new IntPtr(what);
                 *      },
                 *  });
                 *
                 *  // Fixup coordinates when it's making the shape later.
                 *  // 1401B7830
                 *  // 1401B7F04
                 *  // 1401B7F17
                 *  addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15214, 0xF04 - 0x830, 0, "8D 04 40 C1 E0 0E");
                 *  Memory.WriteHook(new HookParameters()
                 *  {
                 *      Address = addr,
                 *      IncludeLength = 0,
                 *      ReplaceLength = 0x11 - 4,
                 *      Before = ctx =>
                 *      {
                 *          ctx.XMM1f = (float)((double)ctx.AX.ToInt32Safe() * 4096.0);
                 *      },
                 *  });
                 *  addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15214, 0xF17 - 0x830, 0, "8D 04 40 C1 E0 0E");
                 *  Memory.WriteHook(new HookParameters()
                 *  {
                 *      Address = addr,
                 *      IncludeLength = 0,
                 *      ReplaceLength = 0x24 - 0x17,
                 *      Before = ctx =>
                 *      {
                 *          ctx.XMM0f = (float)((double)ctx.AX.ToInt32Safe() * 4096.0);
                 *      },
                 *  });
                 * }*/
            }

            if (this.Settings.UseGrassCache)
            {
                GidFileCache.FixFileFormat();
            }

            if (this.Settings.ExtendGrassDistance)
            {
                DistantGrass.ReplaceGrassGrid(this.Settings.WriteDebugMessages, this.Settings.OnlyLoadFromCache);
            }

            if (this.Settings.EnsureMaxGrassTypesPerTextureSetting > 0)
            {
                addr_MaxGrassPerTexture = NetScriptFramework.Main.GameInfo.GetAddressOf(501615);

                var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(18342, 0xD63 - 0xCF0, 0, "44 8B 25");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 7,
                    Before        = ctx =>
                    {
                        int max = Math.Max(this.Settings.EnsureMaxGrassTypesPerTextureSetting, Memory.ReadInt32(addr_MaxGrassPerTexture + 8));
                        ctx.R12 = new IntPtr(max);
                    },
                });
            }

            if (this.Settings.OverwriteGrassDistance >= 0.0f)
            {
                var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(528751, 0, 0, "F3 0F 10 05");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8,
                    Before        = ctx =>
                    {
                        ctx.XMM0f = this.Settings.OverwriteGrassDistance;
                    }
                });

                addr = NetScriptFramework.Main.GameInfo.GetAddressOf(528751, 0xC10 - 0xBE0, 0, "F3 0F 10 15");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8,
                    Before        = ctx =>
                    {
                        ctx.XMM2f = this.Settings.OverwriteGrassDistance;
                    }
                });

                addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15210, 0xBD - 0xA0, 0, "F3 0F 10 05");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8,
                    Before        = ctx =>
                    {
                        ctx.XMM0f = this.Settings.OverwriteGrassDistance;
                    },
                });

                addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15202, 0x4B1B - 0x4890, 0, "F3 0F 10 15");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8,
                    Before        = ctx =>
                    {
                        ctx.XMM2f = this.Settings.OverwriteGrassDistance;
                    }
                });

                addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15202, 0x4AF3 - 0x4890, 0, "F3 0F 58 05");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8,
                    Before        = ctx =>
                    {
                        ctx.XMM0f += this.Settings.OverwriteGrassDistance;
                    }
                });

                addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15202, 0x49F7 - 0x4890, 0, "F3 0F 10 05");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8,
                    Before        = ctx =>
                    {
                        ctx.XMM0f = this.Settings.OverwriteGrassDistance;
                    }
                });
            }

            if (this.Settings.OverwriteGrassFadeRange >= 0.0f)
            {
                var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15202, 0xAEB - 0x890, 0, "F3 0F 10 05");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8,
                    Before        = ctx =>
                    {
                        ctx.XMM0f = this.Settings.OverwriteGrassFadeRange;
                    }
                });

                addr = NetScriptFramework.Main.GameInfo.GetAddressOf(528751, 0xB, 0, "F3 0F 58 05");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8,
                    Before        = ctx =>
                    {
                        ctx.XMM0f += this.Settings.OverwriteGrassFadeRange;
                    }
                });
            }

            if (this.Settings.OverwriteMinGrassSize >= 0)
            {
                var addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15202, 0x4B4E - 0x4890, 0, "66 0F 6E 05");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8 + 3,
                    Before        = ctx =>
                    {
                        ctx.XMM0f = Math.Max(1, this.Settings.OverwriteMinGrassSize);
                    }
                });

                addr = NetScriptFramework.Main.GameInfo.GetAddressOf(15212, 0x6DBB - 0x6CE0, 0, "66 0F 6E 0D");
                Memory.WriteHook(new HookParameters()
                {
                    Address       = addr,
                    IncludeLength = 0,
                    ReplaceLength = 8 + 3,
                    Before        = ctx =>
                    {
                        ctx.XMM1f = Math.Max(1, this.Settings.OverwriteMinGrassSize);
                    }
                });
            }

            if (this.Settings.ExtendGrassDistance)
            {
                if (!this.Settings.UseGrassCache || !this.Settings.OnlyLoadFromCache)
                {
                    NetScriptFramework.SkyrimSE.Events.OnMainMenu.Register(e =>
                    {
                        warn_extend_without_cache();
                    }, 0, 1);
                }
            }
        }