Log in to reply
 

Snow Mod [Ground Cover] using SHVDN, is it possible?



  • I downloaded the Snow mod to have a look through the source that comes with it but it uses a lot of functionality I don't understand enough to convert to a C# SHVDN compatible set of functions.

    Does anyone know if it is even possible, or if there is an existing instance of it already having been done? It seems like a nice option I could add to my photo-mod, to switch in when the snowing weather is selected.



  • @Frazzlee There's no native to do it, it uses pattern searching and memory patching going off this source code.



  • I suppose I should clarify, this is to turn on the ground covering snow, not the snowy weather effect.

    Looking through some other code I was given, I seem to have some that will probably do the pattern matching... I think. But the code similar to the following, I am just not sure how to implement it.

    if (!bInitialized)
    {
    	bInitialized = true;
    
    	// Unprotect Memory
    	VirtualProtect((void*)addr1, 13, PAGE_EXECUTE_READWRITE, nullptr);
    	VirtualProtect((void*)addr2, 14, PAGE_EXECUTE_READWRITE, nullptr);
    
    	// Copy original Memory
    	memcpy(&original1, (void*)addr1, 13);
    	memcpy(&original2, (void*)addr2, 14);
    }
    

    I am guessing it's going to be an unsafe code solution...

    I was going to say if anyone has any pointers, but that's extremely cheesey. :grin: but any help to convert the functionality over would be very much appreciated.



  • Hey, something i'm sort of good at :stuck_out_tongue_winking_eye:

    I just ported this from my christmas in singleplayer script:

    And yes you will need to enable unsafe code unfortunatley (for the pattern class)

    MemoryAccess.cs:

    using System;
    using System.Runtime.InteropServices;
    
    public static class MemoryAccess
    {
        private static readonly IntPtr CRenderPhaseDeferredLighting_Patch1,
            CRenderPhaseDeferredLighting_Patch2;
    
        static MemoryAccess()
        {
            var pattern = new Pattern("\xE8\x00\x00\x00\x00\x80\x3D\x00\x00\x00\x00\x00\x48\x63\xC8", "x????xx?????xxx");
    
            var result = pattern.Get(0x1A);
    
            if (result != null)
            {
                CRenderPhaseDeferredLighting_Patch1 = result;
            }
    
            result = pattern.Get(0x35);
    
            if (result != null)
            {
                CRenderPhaseDeferredLighting_Patch2 = result;
            }
        }
    
        public static void SetSnowRendered(bool enabled)
        {
            if (enabled)
            {
                Marshal.WriteByte(CRenderPhaseDeferredLighting_Patch1, 0xEB);
                Marshal.Copy(new byte[] { 0x90, 0x90 }, 0, CRenderPhaseDeferredLighting_Patch2, 2);
            }
    
            else
            {
                Marshal.WriteByte(CRenderPhaseDeferredLighting_Patch1, 0x75);
                Marshal.Copy(new byte[] { 0x74, 0x13 }, 0, CRenderPhaseDeferredLighting_Patch2, 2);
            }
        }
    }
    

    Pattern.cs:

    using System;
    using System.Runtime.InteropServices;
    
    public sealed class Pattern
    {
        private string bytes, mask;
    
        public Pattern(string bytes, string mask)
        {
            this.bytes = bytes;
            this.mask = mask;
        }
    
        public unsafe IntPtr Get(string moduleName, int offset)
        {
            Win32Native.MODULEINFO module;
    
            Win32Native.GetModuleInformation(
                Win32Native.GetCurrentProcess(),
                Win32Native.GetModuleHandle(moduleName),
                out module,
                sizeof(Win32Native.MODULEINFO));
    
            var address = module.lpBaseOfDll.ToInt64();
    
            var end = address + module.SizeOfImage;
    
            for (; address < end; address++)
            {
                if (bCompare((byte*)(address), bytes.ToCharArray(), mask.ToCharArray()))
                {
                    return new IntPtr(address + offset);
                }
            }
    
            return IntPtr.Zero;
        }
    
        public unsafe IntPtr Get(int offset = 0)
        {
            return Get(null, offset);
        }
    
        private unsafe bool bCompare(byte* pData, char[] bMask, char[] szMask)
        {
            int i = 0;
    
            for (; i < bMask.Length; i++)
            {
                if (szMask[i] == 'x' && pData[i] != bMask[i])
                {
                    return false;
                }
            }
    
            return true;
        }
    }
    
    public static class Win32Native
    {
        [DllImport("kernel32.dll")]
        public static extern IntPtr GetCurrentProcess();
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);
    
        [DllImport("psapi.dll", SetLastError = true)]
        public static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out MODULEINFO lpmodinfo, int cb);
    
        [StructLayout(LayoutKind.Sequential)]
        public struct MODULEINFO
        {
            public IntPtr lpBaseOfDll;
            public uint SizeOfImage;
            public IntPtr EntryPoint;
        }
    }
    

    Then you can just go

    MemoryAccess.SetSnowRendered(true);
    


  • @CamxxCore Fantastic, once again you come to the rescue.

    I already run my projects with the unsafe code switched on to use your previously life-saving material code, in my helicopter mod.

    Thank you, this will be put to very good use. :slight_smile:

    And you saying "sort of good at", is like Michael Phelps saying he's not bad in a swimming pool. :D



  • @LeeC2202 Theres lots of smart(er) people around here. I just find that stuff pretty interesting XD



  • @CamxxCore I should be even more thankful then, because the other people don't seem to find my problems interesting. :slight_smile:

    P.s. I think you were more correct before the edit. ;)

    It is interesting to see that it uses the Marshal.Copy functions... I have used them before in some bitmap manipulation classes I wrote... never thought that would be applicable here. I guess it's all byte array copy stuff in memory, so I suppose it makes sense if I think about it.



  • Works absolutely perfectly :D



  • @LeeC2202 The first case just sets two NOPs to overwrite the jmp instruction at that address. Second case is just rewriting the original memory (jump if zero). And that looks like an awesome tool (:



  • @CamxxCore Blimey, nopping out JMP instructions, that brings memories back from hacking assembler on the C64. :D

    This mod is probably the longest running mod I have got... I started it out from a request by someone who just disappeared straight after asking and as I learn new things, like how to spawn cars with tuning parts, or find something new that I think will enhance it, it just keeps on growing.

    I originally planned to release it but it didn't seem to gather that much interest then I eventually decided it was the perfect tool for me to just wind down, chill out and watch photos get created. So it turned into my exclusive photo-app. I basically create those presets, save them to disk, find a nice location and play them back at that spot. I never know what's going to appear because the presets were created somewhere else.

    I think this snow addition is probably the last thing I can add to it effects wise, so again, thank you for helping to add that final bit of polish.



  • @LeeC2202 Oh boy way before my time lol! Interesting how not a lot has changed over that amount of time though. In most ways I assume it is pretty similar.



  • @CamxxCore At the core it's all pretty much the same code, just much more advanced with today's processors. Whereas you now have a collection of 8, 16 and 32 bit registers to work with (probably 64-bit now saying that), the C64 had an 8-bit accumulator and two 8-bit registers... that's it.

    I mean, if you look at the green and yellow sections on this page... there wasn't many instructions to learn, not by today's standards. http://www.llx.com/~nparker/a2/opcodes.html

    I haven't actually touched any assembler since doing Gameboy Colour stuff in the early 2000's, that was all Z80 though. But because the fundamentals were so similar between processors, it seemed easier to jump from one language to another. All you were really doing was learning the API for the new machine.

    Anyway, I shall climb out of the chair of reminiscing... it's a dangerous place to sit. :D



  • @LeeC2202 cool stuff



  • @LeeC2202 Here is an x86-64 instruction reference for comparison: http://ref.x86asm.net/coder64.html


  • MODERATOR

    @CamxxCore Glad you helped Lee out. He deserved it, frankly, after having given so much to the community. I'm glad he finally met someone not only able, but willing as well to land him a hand.


Log in to reply
 

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