public override Object ReadGameDataFromFile(String filename)
 {
     if (dataReadFromFile == null || filename != this.lastReadFileName)
     {
         this.dataReadFromFileIndex = 0;
         dataReadFromFile           = DeSerializeObject <RF2StructWrapper[]>(dataFilesPath + filename);
         this.lastReadFileName      = filename;
     }
     if (dataReadFromFile != null && dataReadFromFile.Length > this.dataReadFromFileIndex)
     {
         RF2StructWrapper structWrapperData = dataReadFromFile[this.dataReadFromFileIndex];
         this.dataReadFromFileIndex++;
         return(structWrapperData);
     }
     else
     {
         return(null);
     }
 }
Beispiel #2
0
        public override Object ReadGameDataFromFile(String filename, int pauseBeforeStart)
        {
            if (this.dataReadFromFile == null || filename != this.lastReadFileName)
            {
                this.dataReadFromFileIndex = 0;

                var filePathResolved = Utilities.ResolveDataFile(this.dataFilesPath, filename);
                dataReadFromFile = DeSerializeObject <RF2StructWrapper[]>(filePathResolved);

                this.lastReadFileName = filename;
                Thread.Sleep(pauseBeforeStart);
            }
            if (dataReadFromFile != null && dataReadFromFile.Length > this.dataReadFromFileIndex)
            {
                RF2StructWrapper structWrapperData = dataReadFromFile[this.dataReadFromFileIndex];
                this.dataReadFromFileIndex++;
                return(structWrapperData);
            }
            else
            {
                return(null);
            }
        }
Beispiel #3
0
        public override Object ReadGameData(Boolean forSpotter)
        {
            lock (this)
            {
                if (!this.initialised)
                {
                    if (!this.InitialiseInternal())
                    {
                        throw new GameDataReadException("Failed to initialise shared memory");
                    }
                }
                try
                {
#if TRACE_BUFFER_READ_ELAPSED_TIME
                    var watch = System.Diagnostics.Stopwatch.StartNew();
#endif
                    extendedBuffer.GetMappedData(ref this.extended);
                    telemetryBuffer.GetMappedData(ref this.telemetry);
                    rulesBuffer.GetMappedData(ref this.rules);

                    // Scoring is the most important game data in Crew Chief sense,
                    // so acquire it last, hoping it will be most recent view of all buffer types.
                    scoringBuffer.GetMappedData(ref this.scoring);

                    // Create a new copy marshalled views.  Thia is necessary because core code caches states, so each
                    // state has to be an individual object.  We can't avoid copy by marshalling directly into wrapper,
                    // because not all marshalling calls fetch new buffer.
                    var wrapper = new RF2StructWrapper()
                    {
                        extended      = this.extended,
                        telemetry     = this.telemetry,
                        rules         = this.rules, // TODO_RF2:  we probably don't need rules buffer if reading for spotter.
                        scoring       = this.scoring,
                        ticksWhenRead = DateTime.UtcNow.Ticks
                    };

                    if (!forSpotter && dumpToFile && this.dataToDump != null)
                    {
                        // Note: this is lossy save, because we only save update if Telemtry or Scoring changed.
                        // Other buffers don't change that much, so it should be fine.

                        // Exclude empty frames.
                        if (wrapper.scoring.mScoringInfo.mNumVehicles > 0 &&
                            wrapper.extended.mSessionStarted == 1)
                        {
                            var hasTelemetryChanged = false;
                            if (wrapper.telemetry.mNumVehicles > 0)
                            {
                                var currTelET = wrapper.telemetry.mVehicles[0].mElapsedTime;
                                hasTelemetryChanged  = currTelET != this.lastTelemetryET;
                                this.lastTelemetryET = currTelET;
                            }

                            var currScoringET = wrapper.scoring.mScoringInfo.mCurrentET;
                            if (currScoringET != this.lastScoringET || // scoring contains new payload
                                hasTelemetryChanged)     // Or, telemetry updated.
                            {
                                // NOTE: truncation code could be moved to DumpRawGameData method for reduced CPU use.
                                // However, this causes memory pressure (~250Mb/minute with 22 vehicles), so probably better done here.
                                wrapper.telemetry.mVehicles = this.GetPopulatedVehicleInfoArray <rF2VehicleTelemetry>(wrapper.telemetry.mVehicles, wrapper.telemetry.mNumVehicles);
                                wrapper.scoring.mVehicles   = this.GetPopulatedVehicleInfoArray <rF2VehicleScoring>(wrapper.scoring.mVehicles, wrapper.scoring.mScoringInfo.mNumVehicles);

                                // For rules, exclude empty messages from serialization.
                                wrapper.rules.mTrackRules.mMessage = wrapper.rules.mTrackRules.mMessage[0] != 0 ? wrapper.rules.mTrackRules.mMessage : null;
                                wrapper.rules.mParticipants        = this.GetPopulatedVehicleInfoArray <rF2TrackRulesParticipant>(wrapper.rules.mParticipants, wrapper.rules.mTrackRules.mNumParticipants);
                                for (int i = 0; i < wrapper.rules.mParticipants.Length; ++i)
                                {
                                    wrapper.rules.mParticipants[i].mMessage = wrapper.rules.mParticipants[i].mMessage[0] != 0 ? wrapper.rules.mParticipants[i].mMessage : null;
                                }

                                int maxmID = 0;
                                foreach (var vehicleScoring in wrapper.scoring.mVehicles)
                                {
                                    maxmID = Math.Max(maxmID, vehicleScoring.mID);
                                }

                                if (maxmID < rFactor2Constants.MAX_MAPPED_IDS)
                                {
                                    // Since serialization to XML produces a lot of useless tags even for small arrays, truncate tracked damage array.
                                    // It is indexed by mID.  Max mID in current set is equal to mNumVehicles in 99% of cases, so just truncate to this size.
                                    wrapper.extended.mTrackedDamages = this.GetPopulatedVehicleInfoArray <rF2TrackedDamage>(wrapper.extended.mTrackedDamages, maxmID + 1);
                                }

                                this.dataToDump.Add(wrapper);
                                this.lastScoringET = currScoringET;
                            }
                        }
                    }

#if TRACE_BUFFER_READ_ELAPSED_TIME
                    watch.Stop();
                    var microseconds = watch.ElapsedTicks * 1000000 / System.Diagnostics.Stopwatch.Frequency;
                    System.Console.WriteLine("Buffer read microseconds: " + microseconds);
#endif
                    return(wrapper);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("rFactor 2 Shared Memory connection failed.");
                    this.DisconnectInternal();
                    throw new GameDataReadException(ex.Message, ex);
                }
            }
        }
        public override Object ReadGameData(Boolean forSpotter)
        {
            lock (this)
            {
                var rF2StateMarshalled = new rF2State();
                if (!initialised)
                {
                    if (!this.InitialiseInternal())
                    {
                        throw new GameDataReadException("Failed to initialise shared memory");
                    }
                }
                try
                {
                    if (this.fileAccessMutex.WaitOne(5000))
                    {
                        try
                        {
                            bool buf1Current = false;
                            // Try buffer 1:
                            using (var sharedMemoryStreamView = this.memoryMappedFile1.CreateViewStream())
                            {
                                var sharedMemoryStream = new BinaryReader(sharedMemoryStreamView);
                                this.sharedMemoryReadBuffer = sharedMemoryStream.ReadBytes(this.SHARED_MEMORY_HEADER_SIZE_BYTES);

                                // Marhsal header
                                var headerHandle = GCHandle.Alloc(this.sharedMemoryReadBuffer, GCHandleType.Pinned);
                                var header       = (rF2StateHeader)Marshal.PtrToStructure(headerHandle.AddrOfPinnedObject(), typeof(rF2StateHeader));
                                headerHandle.Free();

                                if (header.mCurrentRead == 1)
                                {
                                    sharedMemoryStream.BaseStream.Position = 0;
                                    this.sharedMemoryReadBuffer            = sharedMemoryStream.ReadBytes(this.SHARED_MEMORY_SIZE_BYTES);
                                    buf1Current = true;
                                }
                            }

                            // Read buffer 2
                            if (!buf1Current)
                            {
                                using (var sharedMemoryStreamView = this.memoryMappedFile2.CreateViewStream())
                                {
                                    var sharedMemoryStream = new BinaryReader(sharedMemoryStreamView);
                                    this.sharedMemoryReadBuffer = sharedMemoryStream.ReadBytes(this.SHARED_MEMORY_SIZE_BYTES);
                                }
                            }
                        }
                        finally
                        {
                            this.fileAccessMutex.ReleaseMutex();
                        }

                        // Marshal rF2State
                        var handle = GCHandle.Alloc(this.sharedMemoryReadBuffer, GCHandleType.Pinned);
                        rF2StateMarshalled = (rF2State)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(rF2State));
                        handle.Free();

                        RF2StructWrapper structWrapper = new RF2StructWrapper();
                        structWrapper.ticksWhenRead = DateTime.Now.Ticks;
                        structWrapper.state         = rF2StateMarshalled;
                        if (!forSpotter && dumpToFile && this.dataToDump != null)
                        {
                            this.dataToDump.Add(structWrapper);
                        }
                        return(structWrapper);
                    }
                    else
                    {
                        Console.WriteLine("Timed out waiting on rFactor 2 Shared Memory mutex.");
                        return(null);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("rFactor 2 Shared Memory connection failed.");
                    this.Disconnect();
                    throw new GameDataReadException(ex.Message, ex);
                }
            }
        }