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); }
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); }
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)); }
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; }
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); }
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; } }
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 }); }
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); } } }