robloxmemoryapi 0.2.9.1__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robloxmemoryapi-0.2.9.1/src/robloxmemoryapi.egg-info → robloxmemoryapi-0.3.0}/PKG-INFO +2 -2
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/README.md +1 -1
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/pyproject.toml +1 -1
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/instance.py +155 -13
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0/src/robloxmemoryapi.egg-info}/PKG-INFO +2 -2
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/LICENSE.md +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/setup.cfg +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/__init__.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/__init__.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/luau/__init__.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/luau/parser.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/memory.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/offsets.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/__init__.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/bytecode/decryptor.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/bytecode/encryptor.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/datastructures.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/fflags.py +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/SOURCES.txt +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/dependency_links.txt +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/requires.txt +0 -0
- {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robloxmemoryapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python Library that abstracts reading and writing data from the Roblox DataModel
|
|
5
5
|
Author-email: upio <notpoiu@users.noreply.github.com>, mstudio45 <mstudio45@users.noreply.github.com>, ActualMasterOogway <ActualMasterOogway@users.noreply.github.com>
|
|
6
6
|
License: Copyright 2025 upio, mstudio45, master oogway
|
|
@@ -37,7 +37,7 @@ This was made by [upio](https://github.com/notpoiu), [mstudio45](https://github.
|
|
|
37
37
|
|
|
38
38
|
Join our [Discord](https://discord.gg/FJcJMuze7S) for support and updates.
|
|
39
39
|
|
|
40
|
-
Offsets are sourced from [imtheo.lol](https://imtheo.lol/
|
|
40
|
+
Offsets are sourced from [imtheo.lol](https://offsets.imtheo.lol/). This project is not affiliated with imtheo.lol in any way.
|
|
41
41
|
|
|
42
42
|
## Installation
|
|
43
43
|
|
|
@@ -6,7 +6,7 @@ This was made by [upio](https://github.com/notpoiu), [mstudio45](https://github.
|
|
|
6
6
|
|
|
7
7
|
Join our [Discord](https://discord.gg/FJcJMuze7S) for support and updates.
|
|
8
8
|
|
|
9
|
-
Offsets are sourced from [imtheo.lol](https://imtheo.lol/
|
|
9
|
+
Offsets are sourced from [imtheo.lol](https://offsets.imtheo.lol/). This project is not affiliated with imtheo.lol in any way.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "robloxmemoryapi"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Python Library that abstracts reading and writing data from the Roblox DataModel"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -2,6 +2,7 @@ from ..offsets import *
|
|
|
2
2
|
import time, math
|
|
3
3
|
import threading
|
|
4
4
|
import inspect
|
|
5
|
+
import struct
|
|
5
6
|
from .datastructures import *
|
|
6
7
|
from .bytecode import decryptor, encryptor
|
|
7
8
|
|
|
@@ -5065,6 +5066,147 @@ class MeshData:
|
|
|
5065
5066
|
def FaceEnd(self):
|
|
5066
5067
|
return self.memory_module.get_pointer(self.raw_address, self.offset_base["FaceEnd"])
|
|
5067
5068
|
|
|
5069
|
+
class Head:
|
|
5070
|
+
def __init__(self, raw_address: int, memory_module):
|
|
5071
|
+
self.raw_address = raw_address
|
|
5072
|
+
self.memory_module = memory_module
|
|
5073
|
+
self.offset_base = meshcontentprovider_offsets
|
|
5074
|
+
self.Node = raw_address
|
|
5075
|
+
if self.Node:
|
|
5076
|
+
self.NextNode()
|
|
5077
|
+
|
|
5078
|
+
def NextNode(self):
|
|
5079
|
+
if not self.Node:
|
|
5080
|
+
return None
|
|
5081
|
+
|
|
5082
|
+
Node = self.memory_module.get_pointer(self.Node)
|
|
5083
|
+
if Node and Node != self.raw_address:
|
|
5084
|
+
self.Node = Node
|
|
5085
|
+
return self.Node
|
|
5086
|
+
|
|
5087
|
+
self.Node = None
|
|
5088
|
+
return None
|
|
5089
|
+
|
|
5090
|
+
@property
|
|
5091
|
+
def ToMeshData(self):
|
|
5092
|
+
if not self.Node:
|
|
5093
|
+
return 0
|
|
5094
|
+
return self.memory_module.get_pointer(self.Node, self.offset_base["ToMeshData"])
|
|
5095
|
+
|
|
5096
|
+
@property
|
|
5097
|
+
def MeshData(self):
|
|
5098
|
+
to_mesh_data = self.ToMeshData
|
|
5099
|
+
if not to_mesh_data:
|
|
5100
|
+
return None
|
|
5101
|
+
|
|
5102
|
+
ptr = self.memory_module.get_pointer(to_mesh_data, self.offset_base["MeshData"])
|
|
5103
|
+
return MeshData(ptr, self.memory_module) if ptr != 0 else None
|
|
5104
|
+
|
|
5105
|
+
def GetMeshesIds(self):
|
|
5106
|
+
ids = {}
|
|
5107
|
+
while self.Node:
|
|
5108
|
+
raw_id = self.AssetID
|
|
5109
|
+
clean_id = raw_id[raw_id.rfind("=") + 1:] if raw_id and "=" in raw_id else raw_id
|
|
5110
|
+
ids[raw_id] = clean_id
|
|
5111
|
+
self.NextNode()
|
|
5112
|
+
return ids
|
|
5113
|
+
|
|
5114
|
+
def GetMeshData(self, id: str | tuple = None, max_nodes: int = 100_000) -> dict[str, dict[str]]:
|
|
5115
|
+
"""
|
|
5116
|
+
Extract meshes.
|
|
5117
|
+
Args:
|
|
5118
|
+
id (str): If an ID is provided, the search returns when the corresponding mesh is found.
|
|
5119
|
+
id (tuple): If a tuple of IDs is provided, the search returns once all corresponding meshes are found.
|
|
5120
|
+
max_nodes: The maximum number of nodes to search through.
|
|
5121
|
+
|
|
5122
|
+
Returns:
|
|
5123
|
+
dict: A dictionary mapping mesh IDs to their extracted data.
|
|
5124
|
+
Each mesh data dictionary contains:
|
|
5125
|
+
id (str)
|
|
5126
|
+
rawId (str)
|
|
5127
|
+
vertices (list)
|
|
5128
|
+
faces (list)
|
|
5129
|
+
vertexCount (int)
|
|
5130
|
+
faceCount (int)
|
|
5131
|
+
"""
|
|
5132
|
+
if isinstance(id, str):
|
|
5133
|
+
id = (id, )
|
|
5134
|
+
|
|
5135
|
+
VERTEX_SIZE = 40
|
|
5136
|
+
FACE_SIZE = 12
|
|
5137
|
+
|
|
5138
|
+
meshes = {}
|
|
5139
|
+
visited = 0
|
|
5140
|
+
while self.Node and visited < max_nodes:
|
|
5141
|
+
visited += 1
|
|
5142
|
+
raw_id = self.AssetID
|
|
5143
|
+
clean_id = raw_id[raw_id.rfind("=") + 1:] if raw_id and "=" in raw_id else raw_id
|
|
5144
|
+
|
|
5145
|
+
mesh = self.MeshData
|
|
5146
|
+
|
|
5147
|
+
if id:
|
|
5148
|
+
flag = clean_id in id
|
|
5149
|
+
else:
|
|
5150
|
+
flag = True
|
|
5151
|
+
|
|
5152
|
+
if mesh and flag:
|
|
5153
|
+
vertex_start = mesh.VertexStart
|
|
5154
|
+
vertex_end = mesh.VertexEnd
|
|
5155
|
+
face_start = mesh.FaceStart
|
|
5156
|
+
face_end = mesh.FaceEnd
|
|
5157
|
+
|
|
5158
|
+
if (
|
|
5159
|
+
vertex_start
|
|
5160
|
+
and vertex_end
|
|
5161
|
+
and face_start
|
|
5162
|
+
and face_end
|
|
5163
|
+
and vertex_end > vertex_start
|
|
5164
|
+
and face_end > face_start
|
|
5165
|
+
):
|
|
5166
|
+
vertex_count = (vertex_end - vertex_start) // VERTEX_SIZE
|
|
5167
|
+
face_count = (face_end - face_start) // FACE_SIZE
|
|
5168
|
+
|
|
5169
|
+
if 0 < vertex_count < 5_000_000 and 0 < face_count < 5_000_000:
|
|
5170
|
+
vertices = []
|
|
5171
|
+
for i in range(vertex_count):
|
|
5172
|
+
data = bytes(self.memory_module.read(vertex_start + i * VERTEX_SIZE, VERTEX_SIZE))
|
|
5173
|
+
pos = struct.unpack_from("<3f", data, 0x00)
|
|
5174
|
+
normal = struct.unpack_from("<3f", data, 0x0C)
|
|
5175
|
+
uv = struct.unpack_from("<2f", data, 0x18)
|
|
5176
|
+
vertices.append({
|
|
5177
|
+
"position": [pos[0], pos[1], pos[2]],
|
|
5178
|
+
"normal": [normal[0], normal[1], normal[2]],
|
|
5179
|
+
"uv": [uv[0], 1.0 - uv[1]]
|
|
5180
|
+
})
|
|
5181
|
+
|
|
5182
|
+
faces = []
|
|
5183
|
+
for i in range(face_count):
|
|
5184
|
+
data = bytes(self.memory_module.read(face_start + i * FACE_SIZE, FACE_SIZE))
|
|
5185
|
+
i1, i2, i3 = struct.unpack_from("<3I", data, 0x00)
|
|
5186
|
+
if i1 < len(vertices) and i2 < len(vertices) and i3 < len(vertices):
|
|
5187
|
+
faces.append([int(i1), int(i2), int(i3)])
|
|
5188
|
+
|
|
5189
|
+
meshes[clean_id] = {
|
|
5190
|
+
"id": clean_id,
|
|
5191
|
+
"rawId": raw_id,
|
|
5192
|
+
"vertices": vertices or [],
|
|
5193
|
+
"faces": faces or [],
|
|
5194
|
+
"vertexCount": vertex_count,
|
|
5195
|
+
"faceCount": face_count,
|
|
5196
|
+
}
|
|
5197
|
+
|
|
5198
|
+
if id and set(id).issubset(meshes):
|
|
5199
|
+
return meshes
|
|
5200
|
+
|
|
5201
|
+
self.NextNode()
|
|
5202
|
+
return meshes
|
|
5203
|
+
|
|
5204
|
+
@property
|
|
5205
|
+
def AssetID(self):
|
|
5206
|
+
if not self.Node:
|
|
5207
|
+
return ""
|
|
5208
|
+
return self.memory_module.read_string(self.Node, self.offset_base["AssetID"])
|
|
5209
|
+
|
|
5068
5210
|
class MeshContentProviderService(ServiceBase):
|
|
5069
5211
|
def __init__(self, memory_module, game: DataModel):
|
|
5070
5212
|
super().__init__()
|
|
@@ -5079,18 +5221,22 @@ class MeshContentProviderService(ServiceBase):
|
|
|
5079
5221
|
except (KeyError, OSError):
|
|
5080
5222
|
self.failed = True
|
|
5081
5223
|
|
|
5082
|
-
def _ptr(self, offset_name):
|
|
5083
|
-
if self.failed:
|
|
5224
|
+
def _ptr(self, address, offset_name=0):
|
|
5225
|
+
if self.failed or not address:
|
|
5084
5226
|
return 0
|
|
5085
|
-
|
|
5227
|
+
offset = self.offset_base[offset_name] if isinstance(offset_name, str) else offset_name
|
|
5228
|
+
return self.memory_module.get_pointer(address, offset)
|
|
5086
5229
|
|
|
5087
5230
|
@property
|
|
5088
5231
|
def Cache(self):
|
|
5089
|
-
|
|
5232
|
+
if self.failed:
|
|
5233
|
+
return 0
|
|
5234
|
+
return self._ptr(self.instance.raw_address, self.offset_base.get("Cache", 0xF0))
|
|
5090
5235
|
|
|
5091
5236
|
@property
|
|
5092
5237
|
def LRUCache(self):
|
|
5093
|
-
|
|
5238
|
+
cache = self.Cache
|
|
5239
|
+
return self._ptr(cache, "LRUCache") if cache else 0
|
|
5094
5240
|
|
|
5095
5241
|
@property
|
|
5096
5242
|
def AssetID(self):
|
|
@@ -5099,14 +5245,10 @@ class MeshContentProviderService(ServiceBase):
|
|
|
5099
5245
|
return self.memory_module.read_long(self.instance.raw_address, self.offset_base["AssetID"])
|
|
5100
5246
|
|
|
5101
5247
|
@property
|
|
5102
|
-
def
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
@property
|
|
5107
|
-
def ToMeshData(self):
|
|
5108
|
-
ptr = self._ptr("ToMeshData")
|
|
5109
|
-
return MeshData(ptr, self.memory_module) if ptr != 0 else None
|
|
5248
|
+
def Head(self):
|
|
5249
|
+
lru_cache = self.LRUCache
|
|
5250
|
+
ptr = self._ptr(lru_cache, 0x08) if lru_cache else 0
|
|
5251
|
+
return Head(ptr, self.memory_module) if ptr != 0 else None
|
|
5110
5252
|
|
|
5111
5253
|
class PlayerConfigurer:
|
|
5112
5254
|
def __init__(self, memory_module, raw_address: int | None = None):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robloxmemoryapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python Library that abstracts reading and writing data from the Roblox DataModel
|
|
5
5
|
Author-email: upio <notpoiu@users.noreply.github.com>, mstudio45 <mstudio45@users.noreply.github.com>, ActualMasterOogway <ActualMasterOogway@users.noreply.github.com>
|
|
6
6
|
License: Copyright 2025 upio, mstudio45, master oogway
|
|
@@ -37,7 +37,7 @@ This was made by [upio](https://github.com/notpoiu), [mstudio45](https://github.
|
|
|
37
37
|
|
|
38
38
|
Join our [Discord](https://discord.gg/FJcJMuze7S) for support and updates.
|
|
39
39
|
|
|
40
|
-
Offsets are sourced from [imtheo.lol](https://imtheo.lol/
|
|
40
|
+
Offsets are sourced from [imtheo.lol](https://offsets.imtheo.lol/). This project is not affiliated with imtheo.lol in any way.
|
|
41
41
|
|
|
42
42
|
## Installation
|
|
43
43
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/luau/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/datastructures.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/top_level.txt
RENAMED
|
File without changes
|