Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
c983c32
increase player finding range from 50 to 100
s-victor Feb 17, 2022
ae7354b
add force feedback mmap accessing
s-victor Feb 17, 2022
f227afa
only update _player value if player number has changed
s-victor Feb 18, 2022
189b2ea
only update _player value if player number has changed
s-victor Feb 18, 2022
7832c38
removed ==
s-victor Feb 21, 2022
8505817
change playersDriverNum to non-private method so it can be called for…
s-victor Mar 5, 2022
ad691d0
Removed last_found_player_number variable & duplicated calls to playe…
s-victor May 3, 2022
74c4f64
Removed last_found_player_number variable & duplicated calls to playe…
s-victor May 3, 2022
8cb0a99
Merge branch 'master' of https://github.com/s-victor/pyRfactor2Shared…
s-victor May 3, 2022
b6aa69d
Updating player index number in a separated thread at 10ms refresh rate
s-victor May 3, 2022
ea52707
add mInRealtimeFC for index update
s-victor May 3, 2022
d4fd509
removed mInRealtimeFC check for player index
s-victor May 16, 2022
b20a5e0
Added numeric validation to eliminate data reading errors
s-victor Sep 30, 2022
d071fab
add rf2 PID argument for SimInfo for reading data from dedicated server
s-victor Nov 1, 2022
f339e96
properly close mapping before exiting & additional condition check
s-victor Nov 19, 2022
63f7288
Fixed player index checking method, deepcopy Telemetry & Scoring info…
s-victor Nov 20, 2022
9e85564
Fixed players_mid variable that could be referenced before assign.
s-victor Nov 20, 2022
47d02ab
removed 2 unused variables
s-victor Nov 20, 2022
8c6b345
update comments
s-victor Nov 22, 2022
c7b8ae1
update comments, removed unused import
s-victor Nov 23, 2022
01df594
Improved synced methods, separated none-synced methods from synced me…
s-victor Nov 24, 2022
c7c75e4
periodically verify shared memory data version, auto restart memory m…
s-victor Dec 9, 2022
46a679a
set default counter status
s-victor Jan 14, 2023
3789355
Add Linux mmap support through files
berarma Jan 13, 2023
0a0bedd
Merge pull request #1 from berarma/add-linux-support
s-victor Jan 17, 2023
8c97c90
Merge branch 'master' of https://github.com/s-victor/pyRfactor2Shared…
s-victor Feb 11, 2023
47a0c6e
separated player-synced methods into SimInfoSync.py, reverted rF2data…
s-victor Feb 11, 2023
2110f10
change to lowercase filename
s-victor Feb 11, 2023
1480741
fix max vehicle number
s-victor Feb 11, 2023
acc525c
wait until stopped
s-victor Feb 12, 2023
8f5ca72
fallback to mID matching if mIsPlayer fails to retrieve player index,…
s-victor Feb 16, 2023
9b2a330
switch players_mid to instance variable
s-victor Feb 16, 2023
ac756fd
comments
s-victor Feb 16, 2023
355e008
uses player name matching for finding player index
s-victor Feb 26, 2023
ccbe03e
Corrected ctypes-data-types in rF2data.py to match C-data-types in rF…
s-victor Mar 6, 2023
05e4974
Reverted back to mIsPlayer finding method, removed unused code.
s-victor Mar 6, 2023
fa3fd46
fixed data freeze issue that caused by mismatched player's index betw…
s-victor Mar 8, 2023
fee6fe3
fallback to index 99 if not found
s-victor Apr 1, 2023
76a9b54
Make ctypes compatible with Linux
berarma Apr 1, 2023
70c34fc
add hybrid related entries (requires v3.7.15.1 sharedmemory plugin)
s-victor Apr 3, 2023
18d9f84
Merge pull request #2 from berarma/fix-ctypes
s-victor Apr 3, 2023
03f216f
Create shmem files if they don't exist (Linux)
berarma Apr 5, 2023
294f278
separate local player-only data, removed mmap restart
s-victor Apr 7, 2023
10c3f34
add thread check
s-victor Apr 7, 2023
f00ef30
longer update delay while inactive
s-victor Apr 7, 2023
8708ab4
Merge pull request #3 from berarma/linux-mmap
s-victor Apr 7, 2023
30cea3d
fall back to INVALID_INDEX instead
s-victor May 6, 2023
c90c917
fixed a desync problem due to mismatched mID
s-victor May 9, 2023
0725d4c
removed deepcopy
s-victor May 10, 2023
831ec02
revert back to old method to avoid data freeze
s-victor May 10, 2023
3ae14ca
fixed data interruption issue in multiplayer session
s-victor May 11, 2023
63d2aa2
reset local player data if in spectator mode
s-victor May 15, 2023
07d6882
use freezed condition check instead of reset data
s-victor Jun 3, 2023
941b63b
simplify duplicated mmap code
s-victor Jun 4, 2023
0c709eb
simplify access, add restart control
s-victor Jun 21, 2023
35488cd
seprate local player scor & tele index finding method
s-victor Jun 22, 2023
b7d8bf7
add comments for mmap methods
s-victor Jun 22, 2023
32787ce
add direct access mmap
s-victor Jun 22, 2023
7d0dcff
add access mode control, reusable mmap class
s-victor Jun 25, 2023
cedc406
add pid & mode setter
s-victor Jul 8, 2023
8501abb
fix example usage
s-victor Jul 13, 2023
de9d99f
revert back changes to c types to avoid index out of range issue
s-victor Jul 13, 2023
e68b639
change c_char back to c_ubyte to avoid mSectorFlag index out of range
s-victor Jul 13, 2023
8c10032
add player index override
s-victor Jul 13, 2023
4fa69ee
add rf2ScorVeh & rf2TeleVeh methods that combine player and opponents…
s-victor Nov 1, 2023
0a0fa64
move string conversion func to validator
s-victor Nov 1, 2023
dd81af7
update comment
s-victor Nov 1, 2023
8290173
auto-sync non-local player tele index, optimize index matching
s-victor Nov 9, 2023
ea26179
refactor mmap accessing
s-victor Dec 4, 2023
626fbce
rename sim_info_sync to rF2MMap
s-victor Dec 4, 2023
1ae74b9
cleanup duplicates
s-victor Dec 4, 2023
e717293
update logging format
s-victor Dec 4, 2023
0a00771
remove last index check
s-victor Dec 4, 2023
2d89ff6
move mmap methods to outside functions
s-victor Dec 5, 2023
66f0b29
use event wait
s-victor Dec 6, 2023
525bffb
open or create mmap file as binary
s-victor Dec 6, 2023
3de4670
create mID:index dictionary for matching mID
s-victor Dec 8, 2023
8a073e4
unnecessary deepcopy, use shallow copy instead
s-victor Dec 9, 2023
dac3f6c
set initial pause state to False
s-victor Dec 23, 2023
1f06fd6
use dict get
s-victor Dec 28, 2023
7b31720
update docstrings
s-victor Jan 1, 2024
7f0aff1
update annotations
s-victor Jan 1, 2024
626b16d
remove loop
s-victor Jan 3, 2024
922b74b
improved data update version check
s-victor Mar 27, 2024
5103b92
remove unnecessary update method
s-victor Apr 1, 2024
fc3969b
optimize pause check
s-victor Apr 4, 2024
25ca7d9
improve access efficiency, remove unnecessary data copy
s-victor Sep 26, 2024
3d328d6
improve player index & mID finding methods
s-victor Nov 29, 2024
1fcbed2
fixed mmap instance not getting garbage-collected after closed, added…
s-victor Dec 20, 2024
d84e296
fixed player data would prevent mmap from closing while using direct …
s-victor Jan 9, 2025
a975c6d
add missing rF2PluginControl & rF2RulesControl from latest rF2data.cs…
s-victor Jan 9, 2025
6107788
get root logger name for logging, optimize copy access methods, only …
s-victor Feb 18, 2025
9a734e2
remove player-sync code, updated example code for MMapControl
s-victor Mar 11, 2025
25e7c20
optimize buffer copy
s-victor Jun 11, 2025
2068ff2
add helper classes with type hints & annotation reference to rF2data.…
s-victor Jul 19, 2025
c27d425
additional version check to avoid desync
s-victor Jul 22, 2025
da7494f
add __slots__
s-victor Aug 17, 2025
d7ad1aa
add new accessible API data, update test example
s-victor Dec 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions rF2MMap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
"""
rF2 Memory Map Control

Inherit Python mapping of The Iron Wolf's rF2 Shared Memory Tools

Memory map control (by S.Victor)
Cross-platform Linux support (by Bernat)
"""

from __future__ import annotations

import ctypes
import logging
import mmap
import platform

try:
from . import rF2data
from .rF2data import rFactor2Constants
except ImportError: # standalone, not package
import rF2data
from rF2data import rFactor2Constants

PLATFORM = platform.system()
MAX_VEHICLES = rFactor2Constants.MAX_MAPPED_VEHICLES
INVALID_INDEX = -1


def get_root_logger_name():
"""Get root logger name"""
for logger_name in logging.root.manager.loggerDict:
return logger_name
return __name__


logger = logging.getLogger(get_root_logger_name())


def platform_mmap(name: str, size: int, pid: str = "") -> mmap.mmap:
"""Platform memory mapping"""
if PLATFORM == "Windows":
return windows_mmap(name, size, pid)
return linux_mmap(name, size)


def windows_mmap(name: str, size: int, pid: str) -> mmap.mmap:
"""Windows mmap"""
return mmap.mmap(-1, size, f"{name}{pid}")


def linux_mmap(name: str, size: int) -> mmap.mmap:
"""Linux mmap"""
file = open("/dev/shm/" + name, "a+b")
if file.tell() == 0:
file.write(b"\0" * size)
file.flush()
return mmap.mmap(file.fileno(), size)


class MMapControl:
"""Memory map control"""

__slots__ = (
"_mmap_name",
"_mmap_buffer",
"_struct",
"_buffer",
"_version",
"update",
"data",
)

def __init__(self, mmap_name: str, data_struct: ctypes.Structure) -> None:
"""Initialize memory map setting

Args:
mmap_name: mmap filename, ex. $rFactor2SMMP_Scoring$.
data_struct: ctypes data structure, ex. rF2data.rF2Scoring.
"""
self._mmap_name = mmap_name
self._mmap_buffer = None
self._struct = data_struct
self._buffer = bytearray()
self._version = None
self.update = None
self.data = None

def __del__(self):
logger.info("sharedmemory: GC: MMap %s", self._mmap_name)

def create(self, access_mode: int = 0, rf2_pid: str = "") -> None:
"""Create mmap instance & initial accessible copy

Args:
access_mode: 0 = copy access, 1 = direct access.
rf2_pid: rF2 Process ID for accessing server data.
"""
self._mmap_buffer = platform_mmap(
name=self._mmap_name,
size=ctypes.sizeof(self._struct),
pid=rf2_pid
)

if access_mode:
self.data = self._struct.from_buffer(self._mmap_buffer)
self.update = self.__buffer_share
else:
self._buffer[:] = self._mmap_buffer
self.data = self._struct.from_buffer(self._buffer)
self._version = rF2data.rF2MappedBufferVersionBlock.from_buffer(self._mmap_buffer)
self.update = self.__buffer_copy

mode = "Direct" if access_mode else "Copy"
logger.info("sharedmemory: ACTIVE: %s (%s Access)", self._mmap_name, mode)

def close(self) -> None:
"""Close memory mapping

Create a final accessible mmap data copy before closing mmap instance.
"""
self.data = self._struct.from_buffer_copy(self._mmap_buffer)
self._version = None
try:
self._mmap_buffer.close()
logger.info("sharedmemory: CLOSED: %s", self._mmap_name)
except BufferError:
logger.error("sharedmemory: buffer error while closing %s", self._mmap_name)
self.update = None # unassign update method (for proper garbage collection)

def __buffer_share(self) -> None:
"""Share buffer access, may result data desync"""

def __buffer_copy(self) -> None:
"""Copy buffer access, helps avoid data desync"""
# Copy if data version changed
if self.data.mVersionUpdateEnd != self._version.mVersionUpdateEnd == self._version.mVersionUpdateBegin:
self._buffer[:] = self._mmap_buffer


def test_api():
"""API test run"""
# Add logger
test_handler = logging.StreamHandler()
logger.setLevel(logging.INFO)
logger.addHandler(test_handler)

# Test run
SEPARATOR = "=" * 50
print("Test API - Start")
scoring = MMapControl(rFactor2Constants.MM_SCORING_FILE_NAME, rF2data.rF2Scoring)
scoring.create(1)
telemetry = MMapControl(rFactor2Constants.MM_TELEMETRY_FILE_NAME, rF2data.rF2Telemetry)
telemetry.create(1)
extended = MMapControl(rFactor2Constants.MM_EXTENDED_FILE_NAME, rF2data.rF2Extended)
extended.create(1)

print(SEPARATOR)
print("Test API - Read")
version = extended.data.mVersion.decode()
track = scoring.data.mScoringInfo.mTrackName.decode(encoding="iso-8859-1")
vehicles = telemetry.data.mNumVehicles
print(f"plugin ver: {version if version else 'not running'}")
print(f"track name: {track if version else 'not running'}")
print(f"total cars: {vehicles if version else 'not running'}")

print(SEPARATOR)
print("Test API - Close")
scoring.close()
telemetry.close()
extended.close()


if __name__ == "__main__":
test_api()
Loading