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.
Files changed (22) hide show
  1. {robloxmemoryapi-0.2.9.1/src/robloxmemoryapi.egg-info → robloxmemoryapi-0.3.0}/PKG-INFO +2 -2
  2. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/README.md +1 -1
  3. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/pyproject.toml +1 -1
  4. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/instance.py +155 -13
  5. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0/src/robloxmemoryapi.egg-info}/PKG-INFO +2 -2
  6. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/LICENSE.md +0 -0
  7. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/setup.cfg +0 -0
  8. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/__init__.py +0 -0
  9. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/__init__.py +0 -0
  10. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/luau/__init__.py +0 -0
  11. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/luau/parser.py +0 -0
  12. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/memory.py +0 -0
  13. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/offsets.py +0 -0
  14. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/__init__.py +0 -0
  15. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/bytecode/decryptor.py +0 -0
  16. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/bytecode/encryptor.py +0 -0
  17. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/datastructures.py +0 -0
  18. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi/utils/rbx/fflags.py +0 -0
  19. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/SOURCES.txt +0 -0
  20. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/dependency_links.txt +0 -0
  21. {robloxmemoryapi-0.2.9.1 → robloxmemoryapi-0.3.0}/src/robloxmemoryapi.egg-info/requires.txt +0 -0
  22. {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.2.9.1
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/Offsets). This project is not affiliated with imtheo.lol in any way.
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/Offsets). This project is not affiliated with imtheo.lol in any way.
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.2.9.1"
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
- return self.memory_module.get_pointer(self.instance.raw_address, self.offset_base[offset_name])
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
- return self._ptr("Cache")
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
- return self._ptr("LRUCache")
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 MeshData(self):
5103
- ptr = self._ptr("MeshData")
5104
- return MeshData(ptr, self.memory_module) if ptr != 0 else None
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.2.9.1
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/Offsets). This project is not affiliated with imtheo.lol in any way.
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