RNG: Difference between revisions

3,298 bytes added ,  14 April 2019
updated
(updated)
Line 1: Line 1:
'''RNG''' or '''Random Number Generation''' is the game's method of generating a pseudorandom short. By doing this, the game can make things like dust movement seem random<ref>https://www.youtube.com/watch?v=MiuLeTE2MeQ</ref>.
'''RNG''' or '''Random Number Generator''' is the game's [https://en.wikipedia.org/wiki/Pseudorandom_number_generator pseudorandom number generator]. It allows the game can make things like dust movement seem random<ref>https://www.youtube.com/watch?v=MiuLeTE2MeQ</ref>.
==Technical description==
==Technical description==
The RNG variable is a short, which is a number from 0 to 65535 inclusive. When an [[object]], [[snow]], or something else wants to call RNG, it takes the current RNG value and runs it through the '''RNG function''', below. It uses the result in its own calculations and also stores the result to the RNG variable. Thus, the RNG variable is equal to the last used RNG value. Every [[frame]], every object is iterated through in order of [[object slot]]s and may choose whether to call RNG once, multiple times, or not at all.
The RNG consists of two parts: the evolution function (also known as the RNG function), and the seed. Whenever something (usually an [[object]]) wants to use the RNG, it calls the evolution function. The evolution function will read the seed, perform a series of mathematical operations on it, and return the new value of the seed. This means that the seed always reflects the last value that the RNG function returned. Because each object can load, unload, and use RNG multiple times per frame, the RNG function is often called an unpredictable number of times every frame. This makes the game's randomness often unpredictable even if you know the RNG function.
===The RNG function===
===The RNG function===
Here is pseudocode of the RNG function. Note that it relies heavily on bitwise/binary operations, specifically the XOR operation.
  <nowiki>
  <nowiki>
unsigned short rng_function (unsigned short input) {
set RNGSeed to 0
     if (input == 0x560A) input = 0;
 
     unsigned short S0 = (unsigned char)input << 8;
function RNG:
     S0 = S0 ^ input;
     if RNGSeed = 22026:
     input = ((S0 & 0xFF) << 8) | ((S0 & 0xFF00) >> 8);
        set RNGSeed to 0
     S0 = ((unsigned char)S0 << 1) ^ input;
 
     short S1 = (S0 >> 1) ^ 0xFF80;
    set value A to (the last byte of RNGSeed) shifted to the left by 1 byte
     if ((S0 & 1) == 0) {
     set value A to (value A) XOR (RNGSeed)
         if (S1 == 0xAA55) input = 0;
      
         else input = S1 ^ 0x1FF4;
     set RNGSeed to value A
    }
    swap the bytes of RNGSeed
     else input = S1 ^ 0x8180;
   
    return (unsigned short)input;
    set value A to (the last byte of value A) shifted to the left by 1 bit
}
    set value A to (value A) XOR (RNGSeed)
     set value B to (value A) shifted to the right by 1 bit
     set value B to (value B) XOR 1111111110000000 (binary)
   
     if the last bit of value A is 0:
         if value B is 43605:
            set RNGSeed to 0
         else:
            set RNGSeed to (value B) XOR 0001111111110100 (binary)
     else:
        set RNGSeed to (value B) XOR 1000000110000000 (binary)
   
    return RNGSeed
</nowiki>
</nowiki>
Here is a walkthrough.
We begin with the seed set to, say, 64917. This is 1111110110010101 in binary.<br>
First, this seed is not equal to 22026, so we don't set it to 0.<br>
Each byte is 8 bits (1s or 0s), so the first byte of the seed is 11111101 and the last byte is 10010101. We set value A to the last byte 1001010, shifted to the left 1 byte. This means 1 byte of 0s are added onto the end. Value A now has the value 1001010100000000 in binary.<br>
Now we XOR value A with the seed. XOR, or Exclusive Or, is a bitwise operation that acts on each bit in the numbers. It takes the corresponding pairs of bits in each number, and checks if they are the same or not. If they are the same, a 0 is put into a new number at the location the pair of bits both had in their original numbers; if they are not the same, a 1 is put.
<nowiki>
    11111101 10010101 - seed
XOR 10010101 00000000 - value A
---------------------
    01101000 10010101 - new number
          ^        ^ 1 and 0 are different, so the new number has a 1 in this place.
          1 and 1 are the same, so the new number has a 0 in this place.
</nowiki>
Value A is set to this new number. Then the bytes of value A are swapped and the seed is set to that, so the seed becomes 1001010101101000.
The current state is:<br>
- Seed: 1001010101101000<br>
- Value A: 0110100010010101
The last byte of value A is 10010101, and shifting this to the left by 1 bit gives 100101010. Value A is set to that, so it becomes 0000000100101010. It's XORed with the seed again, and value A is set to the new value:
<nowiki>
    10010101 01101000 - seed
XOR 00000001 00101010 - value A
---------------------
    10010100 01000010 - new value A
</nowiki>
Now we declare value B, and set it to value A but shifted to the right one bit. Value A is 1001010001000010, so value B becomes 0100101000100001.<br>
Value B is now XORed with the number 1111111110000000, which is a so-called "magic number": its purpose is not clear in the code.
<nowiki>
    01001010 00100001 - value B
XOR 11111111 10000000 - magic number
---------------------
    10110101 10100001 - new value B
</nowiki>
The current state is:<br>
- Seed: 1001010101101000<br>
- Value A: 1001010001000010<br>
- Value B: 1011010110100001
The last bit of value A is 0, so we look at value B. In decimal, it is 46497, not 43605, so the seed will be set to value B XOR 0001111111110100. This is another magic number.
<nowiki>
    10110101 10100001 - value B
XOR 00011111 11110100 - magic number
---------------------
    10101010 01010101 - new seed
</nowiki>
Now we return the seed. 1010101001010101 in decimal is 43605, which is the expected result.
===Description===
===Description===
[[File:RNG Graph.png|500px|right|A graph showing notable RNG values and indices in SM64.]]
[[File:RNG Graph.png|500px|right|A graph showing notable RNG values and indices in SM64.]]