Пример #1
0
        private bool UnpackDelta(ReArrayIdPool <SnapHistory <TSnap, TStatic> > data,
                                 int innerid,
                                 byte[] blob, int blobstart, int blobcount,
                                 ushort timestamp, ushort basisTimestamp)
        {
            SnapHistory <TSnap, TStatic> sh = data.Values[data.IdsToIndices[innerid]];

            int index = sh.FindIndex(timestamp);

            if (index < 0 || index >= sh.Shots.Length)
            {
                return(false); // out of bounds
            }
            int basisIndex = sh.FindIndex(basisTimestamp);

            if (basisIndex < 0 || basisIndex >= sh.Shots.Length)
            {
                return(false); // out of bounds
            }
            Packer.UnpackDelta(ref sh.Shots[index], sh.Shots[basisIndex], blob, blobstart, blobcount);
            sh.Timestamps[index] = timestamp;
            sh.Flags[index]      = SnapHistory <TSnap, TStatic> .FlagGold;

            // handle flag rollover
            Rollover(sh, index, timestamp);

            return(true);
        }
Пример #2
0
        private bool UnpackDelta(ReArrayIdPool <SnapHistory <TSnap, TStatic> > data,
                                 int innerid,
                                 byte[] blob, int blobstart, int blobcount,
                                 ushort timestamp, ushort basisTimestamp)
        {
            SnapHistory <TSnap, TStatic> sh = data.Values[data.IdsToIndices[innerid]];

            int index = sh.FindIndex(timestamp);

            if (index < 0 || index >= sh.Shots.Length)
            {
                return(false); // out of bounds
            }
            int basisIndex = sh.FindIndex(basisTimestamp);

            if (basisIndex < 0 || basisIndex >= sh.Shots.Length)
            {
                return(false); // out of bounds
            }
            Packer.UnpackDelta(ref sh.Shots[index], sh.Shots[basisIndex], blob, blobstart, blobcount);
            sh.Timestamps[index] = timestamp;
            sh.Flags[index]      = SnapHistory <TSnap, TStatic> .FlagGold;

            // ask the server to resimulate from this timestamp
            // to ensure our silver guesses get updated
            NetSnapper.RequestResimulate(timestamp);

            return(true);
        }
Пример #3
0
        public byte PrepGhostSecond(ushort entityid, ushort timestamp)
        {
            // if ``, can't possibly belong to this snapper
            if (entityid >= SecondEntityIdToInnerId.Length)
            {
                return(0);
            }

            // if ``, this snapper doesn't have this entity
            int innerid = SecondEntityIdToInnerId[entityid];

            if (innerid == -1)
            {
                return(0);
            }

            SnapHistory <TSnap, TStatic> h = SecondData.Values[SecondData.IdsToIndices[innerid]];

            TempWriteHistory = h;
            TempWriteIndex   = h.FindIndex(timestamp);

            if (TempWriteIndex < 0)
            {
                return(0);
            }

            return(Packer.PrepPackFull(
                       h.Shots[TempWriteIndex], h.StaticData, out PackInfo));
        }
Пример #4
0
        private bool Deghost(ReArrayIdPool <SnapHistory <TSnap, TStatic> > data,
                             int innerid, ushort timestamp)
        {
            SnapHistory <TSnap, TStatic> sh = data.Values[data.IdsToIndices[innerid]];

            int index = sh.FindIndex(timestamp);

            if (index < 0 || index >= sh.Shots.Length)
            {
                return(false); // out of bounds
            }
            sh.Flags[index] = SnapHistory <TSnap, TStatic> .FlagDeghosted;

            // scroll forward and deghost subsequent timestamps!

            // what to do if deghost and ghost arrive out of order?
            // simple: by only overwriting SILVER flags, we ensure that deghosting
            // will not overwrite fresh / more recent data

            int    nindex   = index + 1;
            ushort nextTime = timestamp;

            while (true)
            {
                if (nindex == sh.Shots.Length)
                {
                    nindex = 0;
                }

                if (nextTime == ushort.MaxValue)
                {
                    nextTime = 0;
                }
                else
                {
                    nextTime++;
                }

                // we can only rollover onto silver flags
                if (sh.Flags[nindex] != SnapHistory <TSnap, TStatic> .FlagSilver && sh.Flags[nindex] != SnapHistory <TSnap, TStatic> .FlagEmpty)
                {
                    break;
                }

                // can only rollover onto subsequent timestamps
                if (sh.Timestamps[nindex] != nextTime)
                {
                    break;
                }

                // now we're ready to roll
                sh.Flags[nindex] = SnapHistory <TSnap, TStatic> .FlagDeghosted;

                nindex++;
            }

            return(true);
        }
Пример #5
0
        public bool PrepDeltaSecond(ushort entityid, ushort timestamp, ushort basisTimestamp,
                                    out byte len)
        {
            len = 0;

            // if ``, can't possibly belong to this snapper
            if (entityid >= SecondEntityIdToInnerId.Length)
            {
                return(false);
            }

            // if ``, this snapper doesn't have this entity
            int innerid = SecondEntityIdToInnerId[entityid];

            if (innerid == -1)
            {
                return(false);
            }

            SnapHistory <TSnap, TStatic> h = SecondData.Values[SecondData.IdsToIndices[innerid]];

            int index = h.FindIndex(timestamp);

            if (index == -1)
            {
                return(false);
            }

            int basisIndex = h.FindIndex(basisTimestamp);

            if (basisIndex == -1)
            {
                return(false);
            }

            TempWriteHistory = h;
            TempWriteIndex   = index;

            len = Packer.PrepPackDelta(
                h.Shots[index],
                h.Shots[basisIndex],
                out PackInfo);

            return(true);
        }
Пример #6
0
        private bool UnpackFull(ReArrayIdPool <SnapHistory <TSnap, TStatic> > data,
                                int innerid,
                                byte[] blob, int blobstart, int blobcount,
                                ushort timestamp)
        {
            SnapHistory <TSnap, TStatic> sh = data.Values[data.IdsToIndices[innerid]];

            int index = sh.FindIndex(timestamp);

            if (index < 0)
            {
                return(false); // out of bounds-- too far in future or past
            }
            Packer.UnpackFull(ref sh.Shots[index], ref sh.StaticData, blob, blobstart, blobcount);
            sh.Timestamps[index] = timestamp;
            sh.Flags[index]      = SnapHistory <TSnap, TStatic> .FlagGold;

            // handle flag rollover
            Rollover(sh, index, timestamp);

            return(true);
        }
Пример #7
0
        private bool UnpackFull(ReArrayIdPool <SnapHistory <TSnap, TStatic> > data,
                                int innerid,
                                byte[] blob, int blobstart, int blobcount,
                                ushort timestamp)
        {
            SnapHistory <TSnap, TStatic> sh = data.Values[data.IdsToIndices[innerid]];

            int index = sh.FindIndex(timestamp);

            if (index < 0)
            {
                return(false); // out of bounds-- too far in future or past
            }
            Packer.UnpackFull(ref sh.Shots[index], ref sh.StaticData, blob, blobstart, blobcount);
            sh.Timestamps[index] = timestamp;
            sh.Flags[index]      = SnapHistory <TSnap, TStatic> .FlagGold;

            // ask the server to resimulate from this timestamp
            // to ensure our silver guesses get updated
            NetSnapper.RequestResimulate(timestamp);

            return(true);
        }
Пример #8
0
        private int Ghost(ReArrayIdPool <SnapHistory <TSnap, TStatic> > data,
                          ushort entityid,
                          byte[] blob, int blobstart, int blobcount,
                          ushort timestamp)
        {
            SnapHistory <TSnap, TStatic> sh = data.Request();

            sh.EntityId      = entityid;
            sh.LeadingIndex  = 0;
            sh.Timestamps[0] = CurrentTime;

            // setup the rest of the future timestamps
            ushort itime = sh.Timestamps[0];

            for (int i = 1; i <= sh.Shots.Length / 2; i++)
            {
                if (itime == ushort.MaxValue)
                {
                    itime = 0;
                }
                else
                {
                    itime++;
                }

                sh.Timestamps[i] = itime;
            }

            // and the past
            itime = sh.Timestamps[0];
            for (int i = 0; i < sh.Shots.Length / 2; i++)
            {
                if (itime == 0)
                {
                    itime = ushort.MaxValue;
                }
                else
                {
                    itime--;
                }

                sh.Timestamps[sh.Shots.Length - 1 - i] = itime;
            }

            int expIndex = sh.FindIndex(timestamp);

            if (expIndex == -1)
            {
                // in this case, we need to just abandon the snapshot we
                // received. This can obviously create issues since we'll
                // need a full snapshot again.

                // however, we still unpack it in full, so the static data
                // can be constructed
                Packer.UnpackFull(ref sh.Shots[0], ref sh.StaticData, blob, blobstart, blobcount);
                sh.Flags[0] = SnapHistory <TSnap, TStatic> .FlagEmpty;
            }
            else
            {
                // if the snapshot we received has a space in the current window,
                // so just unpack into there
                Packer.UnpackFull(ref sh.Shots[expIndex], ref sh.StaticData, blob, blobstart, blobcount);
                sh.Timestamps[expIndex] = timestamp;
                sh.Flags[expIndex]      = SnapHistory <TSnap, TStatic> .FlagGold;
            }

            // return the innerid
            return(sh.PoolId);
        }
Пример #9
0
        // predicts forward a whole tick
        // this returns true if all impulse entities have conf snapshots
        // indicating that we can turn up the impulseTimestamp
        public bool ClientPredictTick(ushort confTimestamp)
        {
            ushort prevConfTimestamp = confTimestamp;
            if (prevConfTimestamp == 0)
                prevConfTimestamp = ushort.MaxValue;
            else
                prevConfTimestamp--;

            bool noMissingImpulse = true;

            for (int d = 0; d < NentDatas.Length; d++)
            {
                ReArrayIdPool<SnapHistory<TSnap, TStatic>> data = NentDatas[d];
                for (int i = 0; i < data.Count; i++)
                {
                    SnapHistory<TSnap, TStatic> h = data.Values[i];

                    if (h.PrevFlag == SnapHistory<TSnap, TStatic>.FlagEmpty
                        || h.PrevFlag == SnapHistory<TSnap, TStatic>.FlagDeghosted)
                        continue; // if the prev flag is empty, this entity does 
                                  // not exist yet 

                    // if the entity has impulse, we may need to predict
                    // if the current timestamp is after the impulse timestamp
                    if (h.HasImpulse
                        && ((NetSnapper.SimulateTimestamp >= h.ImpulseTimestamp
                            && !(NetSnapper.SimulateTimestamp >= ushort.MaxValue - 500
                                 && h.ImpulseTimestamp <= 500))
                            || (NetSnapper.SimulateTimestamp <= 500
                                && h.ImpulseTimestamp >= ushort.MaxValue - 500)))
                    {
                        // cases:
                        // 0. if SimulateTimestamp is before h.ImpulseTimestamp, don't
                        //    predict, do normal interp
                        // 1. if this entity has a gold snapshot in SimulateTimestamp + I,
                        //    then don't predict; use the server result
                        // 2. if not, advance a predicted result

                        // case 0 is accounted for by the if statement above
                        
                        // case 1
                        int confIndex = h.FindIndex(confTimestamp);
                        if (confIndex != -1 
                            && h.Flags[confIndex] == SnapHistory<TSnap, TStatic>.FlagGold
                            && h.ImpulseTimestamp == NetSnapper.SimulateTimestamp)
                        {
                            // in this case, our job is easy, we have a server confirmed snap
                            // so we just use that
                            h.ImpulseShot = h.Shots[confIndex];
                            //NetSnapper.Server.NetLogger.Log(NetSnapper.SimulateTimestamp + " / " + confTimestamp + " F");
                        }
                        else
                        {
                            // case 2
                            // in this case, we must predict based on the current ImpulseShot

                            // because we got here, we are missing a conf for this impulse
                            // so we can't move up the NetSnapper's ImpulseTimestamp
                            noMissingImpulse = false;

                            if (h.ImpulseTimestamp == NetSnapper.SimulateTimestamp)
                            {
                                // special consideration: if this is our first impulse,
                                // we must populate ImpulseShot

                                // if we have a confirmed shot for the previous timestamp,
                                // we should use that
                                // if we don't, this must be our first prediction, so we
                                // can simply use the previous snapshot
                                int prevConfIndex = h.FindIndex(prevConfTimestamp);
                                if (prevConfIndex != -1
                                    && h.Flags[prevConfIndex] == SnapHistory<TSnap, TStatic>.FlagGold)
                                {
                                    h.ImpulseShot = h.Shots[prevConfIndex];
                                    //NetSnapper.Server.NetLogger.Log(h.ImpulseTimestamp + " / " + prevConfTimestamp + " C");
                                }
                                else
                                {
                                    h.ImpulseShot = h.Shots[h.PrevIndex];
                                    //NetSnapper.Server.NetLogger.Log(h.ImpulseTimestamp + " / " + prevConfTimestamp + " P");
                                }
                            }

                            // first, check if we have an input
                            // we could only have an input if we are the owner of this object
                            byte inputPid = Advancer.GetInputPlayer(h.ImpulseShot, h.StaticData);
                            if (inputPid == Server.OurPlayerId)
                            {
                                // now check if we have any inputs
                                // if so, process them
                                if (!InputChecker(h, ref h.ImpulseShot, inputPid, NetSnapper.TickMSTarget))
                                {
                                    // if not, do a normal advance
                                    Advancer.AdvanceLogic(AdvancerConfig, h, ref h.ImpulseShot, NetSnapper.TickMSTarget);
                                }
                            }
                            else
                            {
                                // if we couldn't have an input, just do a normal advance
                                Advancer.AdvanceLogic(AdvancerConfig, h, ref h.ImpulseShot, NetSnapper.TickMSTarget);
                            }
                        }
                    }

                    // even if we did impulse above, we still want to interp
                    // because we may need to create silver snapshots to use for
                    // blending or impulse later

                    // if we have a gold from the server, we don't need to do anything
                    // because the current shot is already good
                    if (h.CurrentFlag == SnapHistory<TSnap, TStatic>.FlagGold)
                        continue;

                    // (you might notice from the following, that we resimulate silver
                    //  flags [client guesses] each tick; this way they continue to update
                    //  their guesses if new server info arrives)

                    // if not, we need to create a silver for the current shot
                    // we know the previous is gold or silver already, since we checked
                    // for empty or ghost way back above

                    // so we know the prev is good for interp, but is the next?
                    // if the next is also good for interp, we'll just interp
                    h.Shots[h.CurrentIndex] = h.Shots[h.PrevIndex];
                    if (h.NextFlag == SnapHistory<TSnap, TStatic>.FlagGold
                        || h.NextFlag == SnapHistory<TSnap, TStatic>.FlagSilver)
                    {
                        Advancer.InterpTickLogic(h);
                    }
                    else
                    {
                        // otherwise, do extrapolation 
                        Advancer.AdvanceLogic(AdvancerConfig, h, ref h.Shots[h.CurrentIndex], NetSnapper.TickMSTarget);
                    }

                    // save our guess snapshot as a new silver
                    Nents.ClientSaveSimIntoCurrent(h);
                }
            }

            return noMissingImpulse;
        }
Пример #10
0
        private int Ghost(ReArrayIdPool <SnapHistory <TSnap, TStatic> > data,
                          ushort entityid,
                          byte[] blob, int blobstart, int blobcount,
                          ushort timestamp)
        {
            SnapHistory <TSnap, TStatic> sh = data.Request();

            sh.EntityId = entityid;
            Packer.UnpackFull(ref sh.Shots[0], ref sh.StaticData, blob, blobstart, blobcount);
            sh.Timestamps[0] = timestamp;
            sh.Flags[0]      = SnapHistory <TSnap, TStatic> .FlagGold;
            sh.LeadingIndex  = 0;

            // now, figure how close we are to current time
            // under normal conditions, we should be receiving snapshots
            // very close to the CurrentTime
            int expIndex = sh.FindIndex(CurrentTime);

            // however, if the expIndex is -1, it means the snapshot
            // we just received is outside the current window
            // (because CurrentTime relative to it is outside the window)
            if (expIndex == -1)
            {
                // in this case, we need to just abandon the snapshot we
                // received. This can obviously create issues since we'll
                // need a full snapshot again.
                sh.Timestamps[0] = CurrentTime;
                sh.Flags[0]      = SnapHistory <TSnap, TStatic> .FlagEmpty;
            }
            else
            {
                // in this case, we're within the window, so let's
                // just set the leading index properly.
                sh.LeadingIndex = expIndex;
                sh.Timestamps[sh.LeadingIndex] = CurrentTime;
            }

            // setup the rest of the future timestamps
            ushort itime = sh.Timestamps[0];

            for (int i = 1; i <= sh.Shots.Length / 2; i++)
            {
                if (itime == ushort.MaxValue)
                {
                    itime = 0;
                }
                else
                {
                    itime++;
                }

                sh.Timestamps[i] = itime;
            }

            // and the past
            itime = sh.Timestamps[0];
            for (int i = 0; i < sh.Shots.Length / 2; i++)
            {
                if (itime == 0)
                {
                    itime = ushort.MaxValue;
                }
                else
                {
                    itime--;
                }

                sh.Timestamps[sh.Shots.Length - 1 - i] = itime;
            }

            // return the innerid
            return(sh.PoolId);
        }