internal RaycastHelper(int version, float rayHeight, float rayDepth, string layers, CachedFormList ignored)
        {
            this.Version   = version;
            this.RayHeight = rayHeight;
            this.RayDepth  = rayDepth;
            this.Ignore    = ignored;

            var   spl  = (layers ?? "").Split(new[] { ' ', ',', '\t', '+' }, StringSplitOptions.RemoveEmptyEntries);
            ulong mask = 0;

            foreach (var x in spl)
            {
                int y;
                if (int.TryParse(x, System.Globalization.NumberStyles.None, null, out y) && y >= 0 && y < 64)
                {
                    mask |= (ulong)1 << y;
                }
            }
            this.RaycastMask = mask;
        }
Exemplo n.º 2
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);
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Tries to parse from input. Returns null if failed.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="pluginForLog">The plugin for log.</param>
        /// <param name="settingNameForLog">The setting name for log.</param>
        /// <param name="warnOnMissingForm">If set to <c>true</c> warn on missing form.</param>
        /// <param name="dontWriteAnythingToLog">Don't write any errors to log if failed to parse.</param>
        /// <returns></returns>
        public static CachedFormList TryParse(string input, string pluginForLog, string settingNameForLog, bool warnOnMissingForm = true, bool dontWriteAnythingToLog = false)
        {
            if (string.IsNullOrEmpty(settingNameForLog))
            {
                settingNameForLog = "unknown form list setting";
            }
            if (string.IsNullOrEmpty(pluginForLog))
            {
                pluginForLog = "unknown plugin";
            }

            var ls  = new CachedFormList();
            var spl = input.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var x in spl)
            {
                string idstr;
                string file;

                int ix = x.IndexOf(':');
                if (ix <= 0)
                {
                    if (!dontWriteAnythingToLog)
                    {
                        NetScriptFramework.Main.Log.AppendLine("Failed to parse " + settingNameForLog + " for " + pluginForLog + "! Invalid input: `" + x + "`.");
                    }
                    return(null);
                }

                idstr = x.Substring(0, ix);
                file  = x.Substring(ix + 1);

                if (!idstr.All(q => (q >= '0' && q <= '9') || (q >= 'a' && q <= 'f') || (q >= 'A' && q <= 'F')))
                {
                    if (!dontWriteAnythingToLog)
                    {
                        NetScriptFramework.Main.Log.AppendLine("Failed to parse " + settingNameForLog + " for " + pluginForLog + "! Invalid form ID: `" + idstr + "`.");
                    }
                    return(null);
                }

                if (string.IsNullOrEmpty(file))
                {
                    if (!dontWriteAnythingToLog)
                    {
                        NetScriptFramework.Main.Log.AppendLine("Failed to parse " + settingNameForLog + " for " + pluginForLog + "! Missing file name.");
                    }
                    return(null);
                }

                uint id = 0;
                if (!uint.TryParse(idstr, System.Globalization.NumberStyles.HexNumber, null, out id))
                {
                    if (!dontWriteAnythingToLog)
                    {
                        NetScriptFramework.Main.Log.AppendLine("Failed to parse " + settingNameForLog + " for " + pluginForLog + "! Invalid form ID: `" + idstr + "`.");
                    }
                    return(null);
                }

                id &= 0x00FFFFFF;

                var form = NetScriptFramework.SkyrimSE.TESForm.LookupFormFromFile(id, file);
                if (form == null)
                {
                    if (!dontWriteAnythingToLog && warnOnMissingForm)
                    {
                        NetScriptFramework.Main.Log.AppendLine("Failed to find form " + settingNameForLog + " for " + pluginForLog + "! Form ID was " + id.ToString("X") + " and file was " + file + ".");
                    }
                    continue;
                }

                if (ls.Ids.Add(form.FormId))
                {
                    ls.Forms.Add(form);
                }
            }

            return(ls);
        }