robloxmemoryapi 0.2.2__tar.gz → 0.2.3__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.2/src/robloxmemoryapi.egg-info → robloxmemoryapi-0.2.3}/PKG-INFO +1 -1
  2. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/pyproject.toml +1 -1
  3. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/rbx/datastructures.py +25 -1
  4. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/rbx/fflags.py +23 -29
  5. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/rbx/instance.py +379 -22
  6. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3/src/robloxmemoryapi.egg-info}/PKG-INFO +1 -1
  7. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/LICENSE.md +0 -0
  8. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/README.md +0 -0
  9. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/setup.cfg +0 -0
  10. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/__init__.py +0 -0
  11. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/__init__.py +0 -0
  12. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/luau/__init__.py +0 -0
  13. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/luau/parser.py +0 -0
  14. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/memory.py +0 -0
  15. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/offsets.py +0 -0
  16. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/rbx/__init__.py +0 -0
  17. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/rbx/bytecode/decryptor.py +0 -0
  18. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi/utils/rbx/bytecode/encryptor.py +0 -0
  19. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi.egg-info/SOURCES.txt +0 -0
  20. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi.egg-info/dependency_links.txt +0 -0
  21. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/src/robloxmemoryapi.egg-info/requires.txt +0 -0
  22. {robloxmemoryapi-0.2.2 → robloxmemoryapi-0.2.3}/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.2
3
+ Version: 0.2.3
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "robloxmemoryapi"
7
- version = "0.2.2"
7
+ version = "0.2.3"
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"
@@ -389,4 +389,28 @@ class AnimationTrack:
389
389
 
390
390
  @property
391
391
  def IsPlaying(self):
392
- return self.memory_module.read_bool(self.raw_address, self._offsets["IsPlaying"])
392
+ return self.memory_module.read_bool(self.raw_address, self._offsets["IsPlaying"])
393
+
394
+ class FFlag:
395
+ __slots__ = ("name", "type", "_value", "offset", "_manager")
396
+
397
+ def __init__(self, name: str, flag_type: str, value, offset: int, manager=None):
398
+ self.name = name
399
+ self.type = flag_type
400
+ self._value = value
401
+ self.offset = offset
402
+ self._manager = manager
403
+
404
+ @property
405
+ def value(self):
406
+ return self._value
407
+
408
+ @value.setter
409
+ def value(self, new_value):
410
+ if self._manager is None:
411
+ raise RuntimeError("Cannot set value: FFlag not bound to an FFlagManager")
412
+ result = self._manager.set(self.name, new_value)
413
+ self._value = result._value
414
+
415
+ def __repr__(self):
416
+ return f"FFlag(name={self.name!r}, type={self.type!r}, value={self._value!r})"
@@ -1,18 +1,20 @@
1
1
  from ..offsets import get_fflag_offsets
2
+ from .datastructures import FFlag
2
3
 
3
4
  _MODULE_SIZE_LIMIT = 0x20000000
4
5
 
5
6
  # FLog level byte → display name.
6
7
  _FLOG_LEVELS = {
7
- 0: "None",
8
- 1: "Trace",
9
- 2: "Info",
8
+ 2: "Error",
10
9
  3: "Warning",
11
- 4: "Error",
12
- 5: "Assert",
13
- 6: "Fatal",
10
+ 4: "Info",
11
+ 5: "Debug",
12
+ 6: "Verbose",
13
+ 255: "None",
14
14
  }
15
15
 
16
+ _VALID_FLOG_LEVELS = set(_FLOG_LEVELS.keys())
17
+
16
18
  _FLOG_LEVELS_REV = {v: k for k, v in _FLOG_LEVELS.items()}
17
19
 
18
20
  def _decode_flog(raw_int: int) -> str:
@@ -32,17 +34,6 @@ def _encode_flog(value: str) -> int:
32
34
  return (level_byte << 8) | (param & 0xFF)
33
35
 
34
36
 
35
- class FFlag:
36
- __slots__ = ("name", "type", "value", "offset")
37
-
38
- def __init__(self, name: str, flag_type: str, value, offset: int):
39
- self.name = name
40
- self.type = flag_type # "bool", "int", or "string"
41
- self.value = value
42
- self.offset = offset
43
-
44
- def __repr__(self):
45
- return f"FFlag(name={self.name!r}, type={self.type!r}, value={self.value!r})"
46
37
 
47
38
  class FFlagManager:
48
39
  def __init__(self, memory_module):
@@ -77,7 +68,11 @@ class FFlagManager:
77
68
  return "bool", bool(raw[0])
78
69
  else:
79
70
  raw_int = int.from_bytes(raw[0:4], "little")
80
- return "string", _decode_flog(raw_int)
71
+ level_byte = (raw_int >> 8) & 0xFF
72
+ if level_byte in _VALID_FLOG_LEVELS:
73
+ return "flog", _decode_flog(raw_int)
74
+ else:
75
+ return "int", int.from_bytes(raw[0:4], "little", signed=True)
81
76
  else:
82
77
  str_len = int.from_bytes(raw[16:24], "little")
83
78
  str_cap = int.from_bytes(raw[24:32], "little")
@@ -104,7 +99,7 @@ class FFlagManager:
104
99
  if offset is None:
105
100
  return None
106
101
  flag_type, value = self._reflect(name, offset)
107
- return FFlag(name, flag_type, value, offset)
102
+ return FFlag(name, flag_type, value, offset, manager=self)
108
103
 
109
104
  def get_many(self, *names: str) -> dict[str, FFlag]:
110
105
  self._ensure_offsets()
@@ -121,7 +116,7 @@ class FFlagManager:
121
116
  for name, offset in self._offsets.items():
122
117
  try:
123
118
  flag_type, value = self._reflect(name, offset)
124
- out[name] = FFlag(name, flag_type, value, offset)
119
+ out[name] = FFlag(name, flag_type, value, offset, manager=self)
125
120
  except OSError:
126
121
  pass
127
122
  return out
@@ -146,22 +141,21 @@ class FFlagManager:
146
141
  self._mem.write_int(addr, value)
147
142
 
148
143
  elif flag_type == "string":
149
- if not isinstance(value, (str, int)):
150
- raise TypeError(f"Expected str or int for flag '{name}', got {type(value).__name__}")
144
+ if not isinstance(value, str):
145
+ raise TypeError(f"Expected str for flag '{name}', got {type(value).__name__}")
151
146
 
152
- _, current = self._reflect(name, offset)
153
- is_flog = isinstance(current, str) and "," in current
147
+ self._mem.write_string(addr, str(value))
154
148
 
155
- if is_flog:
156
- self._mem.write_int(addr, _encode_flog(str(value)) if isinstance(value, str) else value)
157
- else:
158
- self._mem.write_string(addr, str(value))
149
+ elif flag_type == "flog":
150
+ if not isinstance(value, (str, int)):
151
+ raise TypeError(f"Expected str or int for flag '{name}', got {type(value).__name__}")
159
152
 
153
+ self._mem.write_int(addr, _encode_flog(str(value)) if isinstance(value, str) else value)
160
154
  else:
161
155
  raise RuntimeError(f"Cannot write to flag with unknown type '{flag_type}'")
162
156
 
163
157
  new_type, new_value = self._reflect(name, offset)
164
- return FFlag(name, new_type, new_value, offset)
158
+ return FFlag(name, new_type, new_value, offset, manager=self)
165
159
 
166
160
  def __getitem__(self, name: str) -> FFlag:
167
161
  flag = self.get(name)
@@ -7,6 +7,7 @@ from .bytecode import decryptor, encryptor
7
7
 
8
8
  instance_offsets = Offsets["Instance"]
9
9
  basepart_offsets = Offsets["BasePart"]
10
+ primitive_offsets = Offsets["Primitive"]
10
11
  camera_offsets = Offsets["Camera"]
11
12
  gui_offsets = Offsets["GuiObject"]
12
13
  misc_offsets = Offsets["Misc"]
@@ -18,6 +19,8 @@ statsitem_offsets = Offsets["StatsItem"]
18
19
  inputobject_offsets = Offsets["MouseService"] # InputObject uses MouseService offsets
19
20
  animator_offsets = Offsets["Animator"]
20
21
  animationtrack_offsets = Offsets["AnimationTrack"]
22
+ tool_offsets = Offsets["Tool"]
23
+ world_offsets = Offsets["World"]
21
24
 
22
25
  ROTATION_MATRIX_FLOATS = 9
23
26
 
@@ -141,6 +144,11 @@ class RBXInstance:
141
144
  else:
142
145
  raise TypeError("Parent must be set to an RBXInstance, int address, or None.")
143
146
  self._ensure_writable()
147
+
148
+ current_parent = self.Parent
149
+ if current_parent is not None:
150
+ current_parent.Children.remove(self)
151
+
144
152
  self.memory_module.write_long(
145
153
  self.raw_address + instance_offsets["Parent"],
146
154
  target
@@ -181,11 +189,11 @@ class RBXInstance:
181
189
 
182
190
  if "part" in className.lower():
183
191
  CFrameRotation = self.memory_module.read_floats(
184
- self.primitive_address + basepart_offsets["Rotation"],
192
+ self.primitive_address + primitive_offsets["Rotation"],
185
193
  ROTATION_MATRIX_FLOATS
186
194
  )
187
195
  PositionData = self.memory_module.read_floats(
188
- self.primitive_address + basepart_offsets["Position"],
196
+ self.primitive_address + primitive_offsets["Position"],
189
197
  3
190
198
  )
191
199
  elif className == "Camera":
@@ -226,8 +234,8 @@ class RBXInstance:
226
234
 
227
235
  className = self.ClassName
228
236
  if "part" in className.lower():
229
- rotation_address = self.primitive_address + basepart_offsets["Rotation"]
230
- position_address = self.primitive_address + basepart_offsets["Position"]
237
+ rotation_address = self.primitive_address + primitive_offsets["Rotation"]
238
+ position_address = self.primitive_address + primitive_offsets["Position"]
231
239
  elif className == "Camera":
232
240
  rotation_address = self.raw_address + camera_offsets["Rotation"]
233
241
  position_address = self.raw_address + camera_offsets["Position"]
@@ -242,7 +250,7 @@ class RBXInstance:
242
250
  className = self.ClassName.lower()
243
251
  if "part" in className:
244
252
  position_vector3 = self.memory_module.read_floats(
245
- self.primitive_address + basepart_offsets["Position"],
253
+ self.primitive_address + primitive_offsets["Position"],
246
254
  3
247
255
  )
248
256
  return Vector3(*position_vector3)
@@ -263,7 +271,7 @@ class RBXInstance:
263
271
  if "part" in className:
264
272
  vec = self._as_vector3(value, "Position")
265
273
  self.memory_module.write_floats(
266
- self.primitive_address + basepart_offsets["Position"],
274
+ self.primitive_address + primitive_offsets["Position"],
267
275
  (vec.X, vec.Y, vec.Z)
268
276
  )
269
277
 
@@ -284,7 +292,7 @@ class RBXInstance:
284
292
 
285
293
  if "part" in className.lower():
286
294
  velocity_vector3 = self.memory_module.read_floats(
287
- self.primitive_address + basepart_offsets["AssemblyLinearVelocity"],
295
+ self.primitive_address + primitive_offsets["AssemblyLinearVelocity"],
288
296
  3
289
297
  )
290
298
  return Vector3(*velocity_vector3)
@@ -301,7 +309,7 @@ class RBXInstance:
301
309
 
302
310
  self._ensure_writable()
303
311
  self.memory_module.write_floats(
304
- self.primitive_address + basepart_offsets["AssemblyLinearVelocity"],
312
+ self.primitive_address + primitive_offsets["AssemblyLinearVelocity"],
305
313
  (vec.X, vec.Y, vec.Z)
306
314
  )
307
315
 
@@ -311,7 +319,7 @@ class RBXInstance:
311
319
 
312
320
  if "part" in className.lower():
313
321
  velocity_vector3 = self.memory_module.read_floats(
314
- self.primitive_address + basepart_offsets["AssemblyAngularVelocity"],
322
+ self.primitive_address + primitive_offsets["AssemblyAngularVelocity"],
315
323
  3
316
324
  )
317
325
  return Vector3(*velocity_vector3)
@@ -328,7 +336,7 @@ class RBXInstance:
328
336
 
329
337
  self._ensure_writable()
330
338
  self.memory_module.write_floats(
331
- self.primitive_address + basepart_offsets["AssemblyAngularVelocity"],
339
+ self.primitive_address + primitive_offsets["AssemblyAngularVelocity"],
332
340
  (vec.X, vec.Y, vec.Z)
333
341
  )
334
342
 
@@ -367,6 +375,16 @@ class RBXInstance:
367
375
  self.raw_address,
368
376
  proximityprompt_offsets["Enabled"]
369
377
  )
378
+ elif self.ClassName == "Tool":
379
+ return self.memory_module.read_bool(
380
+ self.raw_address,
381
+ tool_offsets["Enabled"]
382
+ )
383
+ elif self.ClassName == "ColorCorrectionEffect":
384
+ return self.memory_module.read_bool(
385
+ self.raw_address,
386
+ Offsets["ColorCorrectionEffect"]["Enabled"]
387
+ )
370
388
  return None
371
389
 
372
390
  @Enabled.setter
@@ -383,8 +401,20 @@ class RBXInstance:
383
401
  self.raw_address + proximityprompt_offsets["Enabled"],
384
402
  value
385
403
  )
404
+ elif self.ClassName == "Tool":
405
+ self._ensure_writable()
406
+ self.memory_module.write_bool(
407
+ self.raw_address + tool_offsets["Enabled"],
408
+ bool(value)
409
+ )
410
+ elif self.ClassName == "ColorCorrectionEffect":
411
+ self._ensure_writable()
412
+ self.memory_module.write_bool(
413
+ self.raw_address + Offsets["ColorCorrectionEffect"]["Enabled"],
414
+ bool(value)
415
+ )
386
416
  else:
387
- raise AttributeError("Enabled is only available on ScreenGui or ProximityPrompt instances.")
417
+ raise AttributeError("Enabled is only available on ScreenGui, ProximityPrompt, Tool, or ColorCorrectionEffect instances.")
388
418
 
389
419
  @property
390
420
  def Visible(self):
@@ -420,7 +450,7 @@ class RBXInstance:
420
450
  def Size(self):
421
451
  if "part" in self.ClassName.lower():
422
452
  size_vector3 = self.memory_module.read_floats(
423
- self.primitive_address + basepart_offsets["Size"],
453
+ self.primitive_address + primitive_offsets["Size"],
424
454
  3
425
455
  )
426
456
  return Vector3(*size_vector3)
@@ -433,7 +463,7 @@ class RBXInstance:
433
463
  if "part" in self.ClassName.lower():
434
464
  vec = self._as_vector3(value, "Size")
435
465
  self.memory_module.write_floats(
436
- self.primitive_address + basepart_offsets["Size"],
466
+ self.primitive_address + primitive_offsets["Size"],
437
467
  (vec.X, vec.Y, vec.Z)
438
468
  )
439
469
  else:
@@ -486,7 +516,7 @@ class RBXInstance:
486
516
 
487
517
  def _read_primitive_flags(self):
488
518
  data = self.memory_module.read(
489
- self.primitive_address + basepart_offsets["PrimitiveFlags"],
519
+ self.primitive_address + primitive_offsets["Flags"],
490
520
  1
491
521
  )
492
522
  return int.from_bytes(data, 'little') if data else 0
@@ -494,7 +524,7 @@ class RBXInstance:
494
524
  def _write_primitive_flags(self, flags: int):
495
525
  self._ensure_writable()
496
526
  self.memory_module.write(
497
- self.primitive_address + basepart_offsets["PrimitiveFlags"],
527
+ self.primitive_address + primitive_offsets["Flags"],
498
528
  (flags & 0xFF).to_bytes(1, 'little')
499
529
  )
500
530
 
@@ -907,6 +937,203 @@ class RBXInstance:
907
937
  float(value)
908
938
  )
909
939
 
940
+ @property
941
+ def BackgroundTransparency(self):
942
+ return self.memory_module.read_float(
943
+ self.raw_address,
944
+ gui_offsets["BackgroundTransparency"]
945
+ )
946
+
947
+ @BackgroundTransparency.setter
948
+ def BackgroundTransparency(self, value: float):
949
+ self._ensure_writable()
950
+ self.memory_module.write_float(
951
+ self.raw_address + gui_offsets["BackgroundTransparency"],
952
+ float(value)
953
+ )
954
+
955
+ @property
956
+ def ZIndex(self):
957
+ return self.memory_module.read_int(
958
+ self.raw_address,
959
+ gui_offsets["ZIndex"]
960
+ )
961
+
962
+ @ZIndex.setter
963
+ def ZIndex(self, value: int):
964
+ self._ensure_writable()
965
+ self.memory_module.write_int(
966
+ self.raw_address + gui_offsets["ZIndex"],
967
+ int(value)
968
+ )
969
+
970
+ # tool props #
971
+ @property
972
+ def CanBeDropped(self):
973
+ if self.ClassName != "Tool":
974
+ return None
975
+ return self.memory_module.read_bool(
976
+ self.raw_address,
977
+ tool_offsets["CanBeDropped"]
978
+ )
979
+
980
+ @CanBeDropped.setter
981
+ def CanBeDropped(self, value: bool):
982
+ if self.ClassName != "Tool":
983
+ raise AttributeError("CanBeDropped is only available on Tool instances.")
984
+ self._ensure_writable()
985
+ self.memory_module.write_bool(
986
+ self.raw_address + tool_offsets["CanBeDropped"],
987
+ bool(value)
988
+ )
989
+
990
+ @property
991
+ def Grip(self):
992
+ if self.ClassName != "Tool":
993
+ return None
994
+ grip_data = self.memory_module.read_floats(
995
+ self.raw_address + tool_offsets["Grip"],
996
+ 12 # CFrame: 9 rotation + 3 position
997
+ )
998
+ return grip_data
999
+
1000
+ @property
1001
+ def ManualActivationOnly(self):
1002
+ if self.ClassName != "Tool":
1003
+ return None
1004
+ return self.memory_module.read_bool(
1005
+ self.raw_address,
1006
+ tool_offsets["ManualActivationOnly"]
1007
+ )
1008
+
1009
+ @ManualActivationOnly.setter
1010
+ def ManualActivationOnly(self, value: bool):
1011
+ if self.ClassName != "Tool":
1012
+ raise AttributeError("ManualActivationOnly is only available on Tool instances.")
1013
+ self._ensure_writable()
1014
+ self.memory_module.write_bool(
1015
+ self.raw_address + tool_offsets["ManualActivationOnly"],
1016
+ bool(value)
1017
+ )
1018
+
1019
+ @property
1020
+ def RequiresHandle(self):
1021
+ if self.ClassName != "Tool":
1022
+ return None
1023
+ return self.memory_module.read_bool(
1024
+ self.raw_address,
1025
+ tool_offsets["RequiresHandle"]
1026
+ )
1027
+
1028
+ @RequiresHandle.setter
1029
+ def RequiresHandle(self, value: bool):
1030
+ if self.ClassName != "Tool":
1031
+ raise AttributeError("RequiresHandle is only available on Tool instances.")
1032
+ self._ensure_writable()
1033
+ self.memory_module.write_bool(
1034
+ self.raw_address + tool_offsets["RequiresHandle"],
1035
+ bool(value)
1036
+ )
1037
+
1038
+ @property
1039
+ def TextureId(self):
1040
+ if self.ClassName != "Tool":
1041
+ return None
1042
+ return self.memory_module.read_string(
1043
+ self.raw_address,
1044
+ tool_offsets["TextureId"]
1045
+ )
1046
+
1047
+ @TextureId.setter
1048
+ def TextureId(self, value: str):
1049
+ if self.ClassName != "Tool":
1050
+ raise AttributeError("TextureId is only available on Tool instances.")
1051
+ self._ensure_writable()
1052
+ self.memory_module.write_string(
1053
+ self.raw_address + tool_offsets["TextureId"],
1054
+ str(value)
1055
+ )
1056
+
1057
+ @property
1058
+ def Tooltip(self):
1059
+ if self.ClassName != "Tool":
1060
+ return None
1061
+ return self.memory_module.read_string(
1062
+ self.raw_address,
1063
+ tool_offsets["Tooltip"]
1064
+ )
1065
+
1066
+ @Tooltip.setter
1067
+ def Tooltip(self, value: str):
1068
+ if self.ClassName != "Tool":
1069
+ raise AttributeError("Tooltip is only available on Tool instances.")
1070
+ self._ensure_writable()
1071
+ self.memory_module.write_string(
1072
+ self.raw_address + tool_offsets["Tooltip"],
1073
+ str(value)
1074
+ )
1075
+
1076
+ # colorcorrection props #
1077
+ @property
1078
+ def Brightness(self):
1079
+ if self.ClassName == "ColorCorrectionEffect":
1080
+ return self.memory_module.read_float(
1081
+ self.raw_address,
1082
+ Offsets["ColorCorrectionEffect"]["Brightness"]
1083
+ )
1084
+ return None
1085
+
1086
+ @Brightness.setter
1087
+ def Brightness(self, value: float):
1088
+ if self.ClassName == "ColorCorrectionEffect":
1089
+ self._ensure_writable()
1090
+ self.memory_module.write_float(
1091
+ self.raw_address + Offsets["ColorCorrectionEffect"]["Brightness"],
1092
+ float(value)
1093
+ )
1094
+ else:
1095
+ raise AttributeError("Brightness is only available on ColorCorrectionEffect instances (use LightingService.Brightness for Lighting).")
1096
+
1097
+ @property
1098
+ def Contrast(self):
1099
+ if self.ClassName != "ColorCorrectionEffect":
1100
+ return None
1101
+ return self.memory_module.read_float(
1102
+ self.raw_address,
1103
+ Offsets["ColorCorrectionEffect"]["Contrast"]
1104
+ )
1105
+
1106
+ @Contrast.setter
1107
+ def Contrast(self, value: float):
1108
+ if self.ClassName != "ColorCorrectionEffect":
1109
+ raise AttributeError("Contrast is only available on ColorCorrectionEffect instances.")
1110
+ self._ensure_writable()
1111
+ self.memory_module.write_float(
1112
+ self.raw_address + Offsets["ColorCorrectionEffect"]["Contrast"],
1113
+ float(value)
1114
+ )
1115
+
1116
+ @property
1117
+ def TintColor(self):
1118
+ if self.ClassName != "ColorCorrectionEffect":
1119
+ return None
1120
+ color_data = self.memory_module.read_floats(
1121
+ self.raw_address + Offsets["ColorCorrectionEffect"]["TintColor"],
1122
+ 3
1123
+ )
1124
+ return Color3(*color_data)
1125
+
1126
+ @TintColor.setter
1127
+ def TintColor(self, value):
1128
+ if self.ClassName != "ColorCorrectionEffect":
1129
+ raise AttributeError("TintColor is only available on ColorCorrectionEffect instances.")
1130
+ self._ensure_writable()
1131
+ vec = self._as_color3(value, "TintColor")
1132
+ self.memory_module.write_floats(
1133
+ self.raw_address + Offsets["ColorCorrectionEffect"]["TintColor"],
1134
+ (vec.X, vec.Y, vec.Z)
1135
+ )
1136
+
910
1137
  # humanoid props #
911
1138
  @property
912
1139
  def WalkSpeed(self):
@@ -1353,6 +1580,35 @@ class RBXInstance:
1353
1580
 
1354
1581
  self.memory_module.write_long(bytecode_ptr + Offsets["ByteCode"]["Pointer"], new_content_ptr)
1355
1582
  self.memory_module.write_int(bytecode_ptr + Offsets["ByteCode"]["Size"], new_size)
1583
+
1584
+ # script identification #
1585
+ @property
1586
+ def GUID(self):
1587
+ classname = self.ClassName
1588
+ if classname == "LocalScript":
1589
+ guid_offset = Offsets["LocalScript"]["GUID"]
1590
+ elif classname == "ModuleScript":
1591
+ guid_offset = Offsets["ModuleScript"]["GUID"]
1592
+ else:
1593
+ return None
1594
+ return self.memory_module.read_string(
1595
+ self.raw_address,
1596
+ guid_offset
1597
+ )
1598
+
1599
+ @property
1600
+ def Hash(self):
1601
+ classname = self.ClassName
1602
+ if classname == "LocalScript":
1603
+ hash_offset = Offsets["LocalScript"]["Hash"]
1604
+ elif classname == "ModuleScript":
1605
+ hash_offset = Offsets["ModuleScript"]["Hash"]
1606
+ else:
1607
+ return None
1608
+ return self.memory_module.read_string(
1609
+ self.raw_address,
1610
+ hash_offset
1611
+ )
1356
1612
 
1357
1613
  # functions #
1358
1614
  def GetChildren(self):
@@ -1725,6 +1981,36 @@ class PlayerClass(RBXInstance):
1725
1981
  int(value)
1726
1982
  )
1727
1983
 
1984
+ @property
1985
+ def HealthDisplayDistance(self):
1986
+ return self.memory_module.read_float(
1987
+ self.raw_address,
1988
+ self.offset_base["HealthDisplayDistance"]
1989
+ )
1990
+
1991
+ @HealthDisplayDistance.setter
1992
+ def HealthDisplayDistance(self, value: float):
1993
+ self._ensure_writable()
1994
+ self.memory_module.write_float(
1995
+ self.raw_address + self.offset_base["HealthDisplayDistance"],
1996
+ float(value)
1997
+ )
1998
+
1999
+ @property
2000
+ def NameDisplayDistance(self):
2001
+ return self.memory_module.read_float(
2002
+ self.raw_address,
2003
+ self.offset_base["NameDisplayDistance"]
2004
+ )
2005
+
2006
+ @NameDisplayDistance.setter
2007
+ def NameDisplayDistance(self, value: float):
2008
+ self._ensure_writable()
2009
+ self.memory_module.write_float(
2010
+ self.raw_address + self.offset_base["NameDisplayDistance"],
2011
+ float(value)
2012
+ )
2013
+
1728
2014
  class CameraClass(RBXInstance):
1729
2015
  def __init__(self, memory_module, camera: RBXInstance):
1730
2016
  super().__init__(camera.raw_address, memory_module)
@@ -2235,27 +2521,27 @@ class WorkspaceService(ServiceBase):
2235
2521
 
2236
2522
  @property
2237
2523
  def Gravity(self):
2238
- GravityContainer = self.memory_module.get_pointer(
2524
+ World = self.memory_module.get_pointer(
2239
2525
  self.instance.raw_address,
2240
- self.offset_base["GravityContainer"]
2526
+ self.offset_base["World"]
2241
2527
  )
2242
2528
 
2243
2529
  return self.memory_module.read_float(
2244
- GravityContainer,
2245
- self.offset_base["Gravity"]
2530
+ World,
2531
+ world_offsets["Gravity"]
2246
2532
  )
2247
2533
 
2248
2534
  @Gravity.setter
2249
2535
  def Gravity(self, value: float):
2250
2536
  self._ensure_writable()
2251
2537
 
2252
- GravityContainer = self.memory_module.get_pointer(
2538
+ World = self.memory_module.get_pointer(
2253
2539
  self.instance.raw_address,
2254
- self.offset_base["GravityContainer"]
2540
+ self.offset_base["World"]
2255
2541
  )
2256
2542
 
2257
2543
  self.memory_module.write_float(
2258
- GravityContainer + self.offset_base["Gravity"],
2544
+ World + world_offsets["Gravity"],
2259
2545
  float(value)
2260
2546
  )
2261
2547
 
@@ -2469,6 +2755,77 @@ class LightingService(ServiceBase):
2469
2755
  float(value)
2470
2756
  )
2471
2757
 
2758
+ @property
2759
+ def Sky(self):
2760
+ if self.failed: return None
2761
+ sky_ptr = self.memory_module.get_pointer(
2762
+ self.instance.raw_address,
2763
+ self.offset_base["Sky"]
2764
+ )
2765
+ if sky_ptr == 0:
2766
+ return None
2767
+ return RBXInstance(sky_ptr, self.memory_module)
2768
+
2769
+ @property
2770
+ def Source(self):
2771
+ if self.failed: return None
2772
+ return self.memory_module.read_int(
2773
+ self.instance.raw_address,
2774
+ self.offset_base["Source"]
2775
+ )
2776
+
2777
+ @property
2778
+ def SunPosition(self):
2779
+ if self.failed: return None
2780
+ pos_data = self.memory_module.read_floats(
2781
+ self.instance.raw_address + self.offset_base["SunPosition"],
2782
+ 3
2783
+ )
2784
+ return Vector3(*pos_data)
2785
+
2786
+ @property
2787
+ def MoonPosition(self):
2788
+ if self.failed: return None
2789
+ pos_data = self.memory_module.read_floats(
2790
+ self.instance.raw_address + self.offset_base["MoonPosition"],
2791
+ 3
2792
+ )
2793
+ return Vector3(*pos_data)
2794
+
2795
+ @property
2796
+ def EnvironmentDiffuseScale(self):
2797
+ if self.failed: return 0.0
2798
+ return self.memory_module.read_float(
2799
+ self.instance.raw_address,
2800
+ self.offset_base["EnvironmentDiffuseScale"]
2801
+ )
2802
+
2803
+ @EnvironmentDiffuseScale.setter
2804
+ def EnvironmentDiffuseScale(self, value: float):
2805
+ if self.failed: return
2806
+ self._ensure_writable()
2807
+ self.memory_module.write_float(
2808
+ self.instance.raw_address + self.offset_base["EnvironmentDiffuseScale"],
2809
+ float(value)
2810
+ )
2811
+
2812
+ @property
2813
+ def EnvironmentSpecularScale(self):
2814
+ if self.failed: return 0.0
2815
+ return self.memory_module.read_float(
2816
+ self.instance.raw_address,
2817
+ self.offset_base["EnvironmentSpecularScale"]
2818
+ )
2819
+
2820
+ @EnvironmentSpecularScale.setter
2821
+ def EnvironmentSpecularScale(self, value: float):
2822
+ if self.failed: return
2823
+ self._ensure_writable()
2824
+ self.memory_module.write_float(
2825
+ self.instance.raw_address + self.offset_base["EnvironmentSpecularScale"],
2826
+ float(value)
2827
+ )
2828
+
2472
2829
  class InputObject(RBXInstance):
2473
2830
  def __init__(self, raw_address: int, memory_module):
2474
2831
  super().__init__(raw_address, memory_module)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: robloxmemoryapi
3
- Version: 0.2.2
3
+ Version: 0.2.3
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