Register for your free account! | Forgot your password?

You last visited: Today at 10:56

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



Random = Violent Rage

Discussion on Random = Violent Rage within the CO2 Private Server forum part of the Conquer Online 2 category.

Reply
 
Old   #1
 
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,380
Random = Violent Rage

So, putting this in copservers instead of coprogramming due to someone else having had a similar issue with server related random methods.


Issue:

System.Random is obviously pseudo random but works reasonably well.... or DOES it?

When my server runs for long enough (regardless of sharing a single static Random or even if I test by re-setting the random each time it's called) it starts just throwing out junk numbers.


Example:

Code:
public static int RandomNext(int maxVal)
        {
            var v = RND.Next( maxVal);
            if (v > maxVal)
            {
                Console.WriteLine("Resetting random seed!! (Past Max)");
                RND = new Random();
                v = RND.Next(maxVal);
            }
            if (v == 0)
            {
                nullValues++;
                if (nullValues > 5)
                {
                    Console.WriteLine("Resetting random seed!! (Too many Zeros)");
                    RND = new Random();
                    v = RND.Next(maxVal);
                    nullValues = 0;
                }
            }
            else
                nullValues = 0;
            return v;
        }
This is just a super basic example which counts how many times in a row zero is returned.

In virtually ALL of my calls of this code I'm rolling a 100,000 value (percent success accurate to 3 decimal places).

This runs perfectly fine for a very long time... but eventually we start getting zeros thrown almost every time.

I've tried various quick fixes including resetting the random seed, ALWAYS returning from a new random class instead of all these sanity checks... hell we tried reverse engineering tq's own random class from the eudemons source.

No matter what, we always eventually end up with junk values being returned.



Note: Here's our test implementation of tq's random class... I don't consider it that special as anyone could download their source and reverse it damn easy.

Code:
public static int RandGet(int max, bool reset = false)
        {
            if (reset) _randomSeed = UnixTimestamp;

            long x = 0xffffffff;
            double i;
            long final;

            _randomSeed *= 134775813L;
            _randomSeed += 1;
            _randomSeed = Math.Abs(_randomSeed);
            _randomSeed = _randomSeed % x;
            i = _randomSeed / (double)0xffffffff;
            if (i > 1)
            {
                Console.WriteLine("\r\r\r\tReturned Number: " + (long)(max * i) + " where max is: " + max + " Seed state of " + _randomSeed + " i value: " + i +"\r\r");               
            }
            final = (long)(max * i);

            if (final > max)
            {
                Console.WriteLine("\r\r\r\tReturned Number: " + final + " where max is: " + max + " Seed state of " + _randomSeed + " i value: " + i+"\r\r\r");
                Console.WriteLine("ERROR! Invalid number thrown from call stack:");
                Console.WriteLine(Environment.StackTrace.ToString());
                final = new Random().Next(max);
                _randomSeed = UnixTimestamp;
            }
            return (int)final;
        }

What's interesting here is... it works perfectly fine if we try to do massive numbers of iterations (I think most we tested was 100 million in a row without issue)... again if we let it run over TIME (day or so) it starts to return complete garbage (greater than max)

Some examples of junk data being returned...

Returned: 17867370611
Max #: 14
Seed: 3998188691
Value of i: 1276240757.9309


Returned: 4063877655
Max #: 150
Seed: 1023408433
Value of i: 27092485.5720175



So yah... looking for options and also just scratching my head going "wtf" (at the system random, I expected nothing much from a basic reverse engineered tq random generator lol).

What would be causing System.Random to start returning zeros virtually every time we call it when the maxvalue entered was greater than 1 (and most often 100,000)



<edit>

After talking to korv I'm gonna try doing it so that if it returns junk too many times I set the random seed using tq's random generator (cause even if it returns greater then max value, it's still a random seed not related to computer time which I'm fairly sure must be the issue)

Side question. Does Random() by default use Environment.Tickcount to set its seed? A few seconds on google just said it was related to the computer time so I'm fairly sure it is... just curious though.
pro4never is offline  
Old 09/14/2011, 22:16   #2
 
elite*gold: 0
Join Date: May 2011
Posts: 1,769
Received Thanks: 756
If RND is referring to System.Random, then remember it's not exactly random, but it's based on time.

So doing this:
Code:
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Will return the same value all the times.

Where this will return 2 different values:
Code:
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
System.Threading.Thread.Sleep(25);
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
BaussHacker is offline  
Old 09/15/2011, 01:42   #3
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,283
Received Thanks: 4,191
Code:
    [Serializable, ComVisible(true)]
    public class Random
    {
        // Fields
        private int inext;
        private int inextp;
        private const int MBIG = 0x7fffffff;
        private const int MSEED = 0x9a4ec86;
        private const int MZ = 0;
        private int[] SeedArray;

        // Methods
        public Random()
            : this(Environment.TickCount)
        {
        }

        public Random(int Seed)
        {
            this.SeedArray = new int[0x38];
            int num4 = (Seed == -2147483648) ? 0x7fffffff : Math.Abs(Seed);
            int num2 = 0x9a4ec86 - num4;
            this.SeedArray[0x37] = num2;
            int num3 = 1;
            for (int i = 1; i < 0x37; i++)
            {
                int index = (0x15 * i) % 0x37;
                this.SeedArray[index] = num3;
                num3 = num2 - num3;
                if (num3 < 0)
                {
                    num3 += 0x7fffffff;
                }
                num2 = this.SeedArray[index];
            }
            for (int j = 1; j < 5; j++)
            {
                for (int k = 1; k < 0x38; k++)
                {
                    this.SeedArray[k] -= this.SeedArray[1 + ((k + 30) % 0x37)];
                    if (this.SeedArray[k] < 0)
                    {
                        this.SeedArray[k] += 0x7fffffff;
                    }
                }
            }
            this.inext = 0;
            this.inextp = 0x15;
            Seed = 1;
        }

        private double GetSampleForLargeRange()
        {
            int num = this.InternalSample();
            if ((this.InternalSample() % 2) == 0)
            {
                num = -num;
            }
            double num2 = num;
            num2 += 2147483646.0;
            return (num2 / 4294967293);
        }

        private int InternalSample()
        {
            int inext = this.inext;
            int inextp = this.inextp;
            if (++inext >= 0x38)
            {
                inext = 1;
            }
            if (++inextp >= 0x38)
            {
                inextp = 1;
            }
            int num = this.SeedArray[inext] - this.SeedArray[inextp];
            if (num == 0x7fffffff)
            {
                num--;
            }
            if (num < 0)
            {
                num += 0x7fffffff;
            }
            this.SeedArray[inext] = num;
            this.inext = inext;
            this.inextp = inextp;
            return num;
        }

        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public virtual int Next()
        {
            return this.InternalSample();
        }

        public virtual int Next(int maxValue)
        {
            if (maxValue < 0)
            {
                throw new ArgumentOutOfRangeException("maxValue", Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", new object[] { "maxValue" }));
            }
            return (int)(this.Sample() * maxValue);
        }

        public virtual int Next(int minValue, int maxValue)
        {
            if (minValue > maxValue)
            {
                throw new ArgumentOutOfRangeException("minValue", Environment.GetResourceString("Argument_MinMaxValue", new object[] { "minValue", "maxValue" }));
            }
            long num = maxValue - minValue;
            if (num <= 0x7fffffffL)
            {
                return (((int)(this.Sample() * num)) + minValue);
            }
            return (((int)((long)(this.GetSampleForLargeRange() * num))) + minValue);
        }

        public virtual void NextBytes(byte[] buffer)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            for (int i = 0; i < buffer.Length; i++)
            {
                buffer[i] = (byte)(this.InternalSample() % 0x100);
            }
        }

        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public virtual double NextDouble()
        {
            return this.Sample();
        }

        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        protected virtual double Sample()
        {
            return (this.InternalSample() * 4.6566128752457969E-10);
        }
    }
Spirited is offline  
Old 09/15/2011, 02:49   #4
 
-Shunsui-'s Avatar
 
elite*gold: 0
Join Date: Apr 2008
Posts: 1,152
Received Thanks: 321
It works for me just fine, if i declare a static Random as new just once in like Program.cs when the server is starting up. Insted of declaring a new instance every time i'm going to use it. I knew about this problem because of impulse. and it works fine the way i did it.
-Shunsui- is offline  
Old 09/15/2011, 04:26   #5
 
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,380
Quote:
Originally Posted by -Shunsui- View Post
It works for me just fine, if i declare a static Random as new just once in like Program.cs when the server is starting up. Insted of declaring a new instance every time i'm going to use it. I knew about this problem because of impulse. and it works fine the way i did it.
it is a static random. I only reset it if there are junk values being returned.

Quote:
Originally Posted by BaussHacker View Post
If RND is referring to System.Random, then remember it's not exactly random, but it's based on time.

So doing this:
Code:
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Will return the same value all the times.

Where this will return 2 different values:
Code:
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));
System.Threading.Thread.Sleep(25);
Console.WriteLine(new Random().Next(1000000));
Console.WriteLine(new Random().Next(1000000));


By default new Random() sets the seed based on environment tick count (aka computer time) so obviously it will be the same if you keep resetting it/creating new randoms.

If you use the SAME random object and continue calling .Next() from it, it will modify the random seed and give varying values.
pro4never is offline  
Old 09/15/2011, 12:54   #6
 
Mr_PoP's Avatar
 
elite*gold: 0
Join Date: Apr 2008
Posts: 759
Received Thanks: 285
Code:
public class CRandom {
		private int seed = 0;

		public CRandom(int seed) {
			this.seed = seed;
		}

		public short Next() {
			seed *= 0x343fd;
			seed += 0x269EC3;
			return (short)((seed >> 0x10) & 0x7FFF);
		}
	}
that's the basic idea , so everytime u call next it will give u a new random number
Mr_PoP is offline  
Old 10/07/2011, 02:19   #7


 
CptSky's Avatar
 
elite*gold: 0
Join Date: Jan 2008
Posts: 1,443
Received Thanks: 1,175
I have the same problem, but I should be able to fix it. After looking in the Microsoft documentation, I found a comment about this error...

Quote:
There is a very nasty side effect that can happen when the same Random object is used by multiple threads: it just stops working (i.e. there is a race condition which when triggered, the return value from the 'random.Next....' methods will be 0 (for all subsequent calls))


There are some solutions at the bottom of the page.

PS. I know that it's a bump...
CptSky is offline  
Thanks
3 Users
Old 10/07/2011, 07:09   #8
 
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,380
Quote:
Originally Posted by CptSky View Post
I have the same problem, but I should be able to fix it. After looking in the Microsoft documentation, I found a comment about this error...





There are some solutions at the bottom of the page.

PS. I know that it's a bump...
Thank you SO much for the bump.

It's obviously being called from multiple threads as I started organizing all my randoms into a single static class (to AVOID and simplify the debugging of issues) Which I'm sure made it worse.

It most likely started as a much less pressing issue and as I noticed it I tried to centralize my randoms so that I could track the issue more easily.

Thanks a bunch. Maybe this will finally re-spark my pserver development as hellmouth has been stagnant since it really started ******* me off (Any time I added stuff and a decent amount of ppl on it would start happening and cause all sorts of havoc to the server)
pro4never is offline  
Old 10/07/2011, 18:14   #9


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,126
Received Thanks: 2,518
Shoulda created a random based on the amount of solar radiation detected in our atmosphere, ive heard thats one of the best randoms available
Korvacs is offline  
Thanks
1 User
Old 10/07/2011, 19:47   #10
 
elite*gold: 0
Join Date: May 2011
Posts: 1,769
Received Thanks: 756
Quote:
Originally Posted by Korvacs View Post
Shoulda created a random based on the amount of solar radiation detected in our atmosphere, ive heard thats one of the best randoms available
If it just was that easy.
BaussHacker is offline  
Old 10/07/2011, 19:47   #11
 
.Kinshi's Avatar
 
elite*gold: 0
Join Date: Dec 2010
Posts: 341
Received Thanks: 255
Quote:
Originally Posted by Korvacs View Post
Shoulda created a random based on the amount of solar radiation detected in our atmosphere, ive heard thats one of the best randoms available
Haha! Actually made me lol irl
.Kinshi is offline  
Old 10/07/2011, 22:30   #12


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,126
Received Thanks: 2,518
Quote:
Originally Posted by .Kinshi View Post
Haha! Actually made me lol irl
You laugh but its an actual method to generate seeds! Same with quantum wave decay, that can be used as a random number generator.
Korvacs is offline  
Old 10/08/2011, 03:07   #13
 
.Kinshi's Avatar
 
elite*gold: 0
Join Date: Dec 2010
Posts: 341
Received Thanks: 255
Quote:
Originally Posted by Korvacs View Post
You laugh but its an actual method to generate seeds! Same with quantum wave decay, that can be used as a random number generator.
Oh yes, I just did not expect a response like that :P
.Kinshi is offline  
Reply


Similar Threads Similar Threads
Quiet Rage LV3 or Mad Rage LV3?
02/21/2011 - Grand Chase Philippines - 18 Replies
When Sieghart's ST arrives, which one will you choose and why? For me I'd use Quite Rage since I don't use Rage that much so that I can block and heal without worrying about the rage bar depleting too fast.
Rage!
03/13/2010 - 9Dragons - 3 Replies
Hi all, i have one idea, culd some1 make a hack for 9d vn, to have permanent rage? I mean wen rage is 100% and active it to never end till u change the map or something! That well be cool! :) Ty!;);)
Rage
04/24/2006 - Conquer Online 2 - 6 Replies
umm just wondering f rage skill can be always hit or activated?



All times are GMT +1. The time now is 10:56.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.