robloxmemoryapi 0.2.6__tar.gz → 0.2.8__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.6/src/robloxmemoryapi.egg-info → robloxmemoryapi-0.2.8}/PKG-INFO +4 -2
  2. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/README.md +3 -1
  3. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/pyproject.toml +1 -1
  4. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/rbx/datastructures.py +23 -0
  5. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/rbx/instance.py +790 -14
  6. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8/src/robloxmemoryapi.egg-info}/PKG-INFO +4 -2
  7. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/LICENSE.md +0 -0
  8. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/setup.cfg +0 -0
  9. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/__init__.py +0 -0
  10. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/__init__.py +0 -0
  11. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/luau/__init__.py +0 -0
  12. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/luau/parser.py +0 -0
  13. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/memory.py +0 -0
  14. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/offsets.py +0 -0
  15. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/rbx/__init__.py +0 -0
  16. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/rbx/bytecode/decryptor.py +0 -0
  17. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/rbx/bytecode/encryptor.py +0 -0
  18. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi/utils/rbx/fflags.py +0 -0
  19. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi.egg-info/SOURCES.txt +0 -0
  20. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi.egg-info/dependency_links.txt +0 -0
  21. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/src/robloxmemoryapi.egg-info/requires.txt +0 -0
  22. {robloxmemoryapi-0.2.6 → robloxmemoryapi-0.2.8}/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.6
3
+ Version: 0.2.8
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
@@ -35,7 +35,9 @@ Dynamic: license-file
35
35
 
36
36
  This was made by [upio](https://github.com/notpoiu), [mstudio45](https://github.com/mstudio45), and [Master Oogway](https://github.com/ActualMasterOogway) and created for the [Dig Macro](https://github.com/mstudio45/digmacro) project (external mode and not the computer vision mode).
37
37
 
38
- Offsets are sourced from [imtheo.lol](https://imtheo.lol/Offsets). This project is not affilated with imtheo.lol in any way.
38
+ Join our [Discord](https://discord.gg/FJcJMuze7S) for support and updates.
39
+
40
+ Offsets are sourced from [imtheo.lol](https://imtheo.lol/Offsets). This project is not affiliated with imtheo.lol in any way.
39
41
 
40
42
  ## Installation
41
43
 
@@ -4,7 +4,9 @@
4
4
 
5
5
  This was made by [upio](https://github.com/notpoiu), [mstudio45](https://github.com/mstudio45), and [Master Oogway](https://github.com/ActualMasterOogway) and created for the [Dig Macro](https://github.com/mstudio45/digmacro) project (external mode and not the computer vision mode).
6
6
 
7
- Offsets are sourced from [imtheo.lol](https://imtheo.lol/Offsets). This project is not affilated with imtheo.lol in any way.
7
+ Join our [Discord](https://discord.gg/FJcJMuze7S) for support and updates.
8
+
9
+ Offsets are sourced from [imtheo.lol](https://imtheo.lol/Offsets). This project is not affiliated with imtheo.lol in any way.
8
10
 
9
11
  ## Installation
10
12
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "robloxmemoryapi"
7
- version = "0.2.6"
7
+ version = "0.2.8"
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"
@@ -47,6 +47,21 @@ class Vector2:
47
47
  and self.Y == other.Y
48
48
  )
49
49
 
50
+ class NumberRange:
51
+ def __init__(self, min_val=0, max_val=None):
52
+ self.Min = float(min_val)
53
+ self.Max = float(max_val if max_val is not None else min_val)
54
+
55
+ def __repr__(self):
56
+ return f"{self.Min}, {self.Max}"
57
+
58
+ def __eq__(self, other):
59
+ return (
60
+ isinstance(other, NumberRange)
61
+ and self.Min == other.Min
62
+ and self.Max == other.Max
63
+ )
64
+
50
65
  class Color3:
51
66
  def __init__(self, r=0, g=0, b=0):
52
67
  self.R = float(r)
@@ -391,6 +406,14 @@ class AnimationTrack:
391
406
  def IsPlaying(self):
392
407
  return self.memory_module.read_bool(self.raw_address, self._offsets["IsPlaying"])
393
408
 
409
+ @property
410
+ def TimePosition(self):
411
+ return self.memory_module.read_float(self.raw_address, self._offsets["TimePosition"])
412
+
413
+ @TimePosition.setter
414
+ def TimePosition(self, value: float):
415
+ self.memory_module.write_float(self.raw_address + self._offsets["TimePosition"], float(value))
416
+
394
417
  class FFlag:
395
418
  __slots__ = ("name", "type", "_value", "offset", "_manager")
396
419
 
@@ -29,6 +29,15 @@ charactermesh_offsets = Offsets["CharacterMesh"]
29
29
  attachment_offsets = Offsets["Attachment"]
30
30
  air_properties_offsets = Offsets["AirProperties"]
31
31
  seat_offsets = Offsets["Seat"]
32
+ meshpart_offsets = Offsets["MeshPart"]
33
+ textures_offsets = Offsets["Textures"]
34
+ beam_offsets = Offsets["Beam"]
35
+ particleemitter_offsets = Offsets["ParticleEmitter"]
36
+ vehicleseat_offsets = Offsets["VehicleSeat"]
37
+ weld_offsets = Offsets["Weld"]
38
+ weldconstraint_offsets = Offsets["WeldConstraint"]
39
+ surfaceappearance_offsets = Offsets["SurfaceAppearance"]
40
+ script_offsets = Offsets["Script"]
32
41
 
33
42
  ROTATION_MATRIX_FLOATS = 9
34
43
 
@@ -612,6 +621,69 @@ class RBXInstance:
612
621
  bytes([r & 0xFF, g & 0xFF, b & 0xFF])
613
622
  )
614
623
 
624
+ @property
625
+ def Reflectance(self):
626
+ if "part" not in self.ClassName.lower():
627
+ return None
628
+
629
+ return self.memory_module.read_float(
630
+ self.raw_address,
631
+ basepart_offsets["Reflectance"]
632
+ )
633
+
634
+ @Reflectance.setter
635
+ def Reflectance(self, value: float):
636
+ if "part" not in self.ClassName.lower():
637
+ raise AttributeError("Reflectance is only available on BasePart-derived instances.")
638
+ self._ensure_writable()
639
+
640
+ self.memory_module.write_float(
641
+ self.raw_address + basepart_offsets["Reflectance"],
642
+ float(value)
643
+ )
644
+
645
+ @property
646
+ def Locked(self):
647
+ if "part" not in self.ClassName.lower():
648
+ return None
649
+
650
+ return self.memory_module.read_bool(
651
+ self.raw_address,
652
+ basepart_offsets["Locked"]
653
+ )
654
+
655
+ @Locked.setter
656
+ def Locked(self, value: bool):
657
+ if "part" not in self.ClassName.lower():
658
+ raise AttributeError("Locked is only available on BasePart-derived instances.")
659
+ self._ensure_writable()
660
+
661
+ self.memory_module.write_bool(
662
+ self.raw_address + basepart_offsets["Locked"],
663
+ bool(value)
664
+ )
665
+
666
+ @property
667
+ def Massless(self):
668
+ if "part" not in self.ClassName.lower():
669
+ return None
670
+
671
+ return self.memory_module.read_bool(
672
+ self.raw_address,
673
+ basepart_offsets["Massless"]
674
+ )
675
+
676
+ @Massless.setter
677
+ def Massless(self, value: bool):
678
+ if "part" not in self.ClassName.lower():
679
+ raise AttributeError("Massless is only available on BasePart-derived instances.")
680
+ self._ensure_writable()
681
+
682
+ self.memory_module.write_bool(
683
+ self.raw_address + basepart_offsets["Massless"],
684
+ bool(value)
685
+ )
686
+
615
687
  def _read_primitive_flags(self):
616
688
  data = self.memory_module.read(
617
689
  self.primitive_address + primitive_offsets["Flags"],
@@ -686,6 +758,26 @@ class RBXInstance:
686
758
  flags &= ~Offsets["PrimitiveFlags"]["CanTouch"]
687
759
  self._write_primitive_flags(flags)
688
760
 
761
+ @property
762
+ def CanQuery(self):
763
+ if "part" not in self.ClassName.lower():
764
+ return None
765
+
766
+ flags = self._read_primitive_flags()
767
+ return bool(flags & Offsets["PrimitiveFlags"]["CanQuery"])
768
+
769
+ @CanQuery.setter
770
+ def CanQuery(self, value: bool):
771
+ if "part" not in self.ClassName.lower():
772
+ raise AttributeError("CanQuery is only available on BasePart-derived instances.")
773
+
774
+ flags = self._read_primitive_flags()
775
+ if value:
776
+ flags |= Offsets["PrimitiveFlags"]["CanQuery"]
777
+ else:
778
+ flags &= ~Offsets["PrimitiveFlags"]["CanQuery"]
779
+ self._write_primitive_flags(flags)
780
+
689
781
  # Animator props #
690
782
  def GetPlayingAnimationTracks(self):
691
783
  if self.ClassName != "Animator":
@@ -1132,20 +1224,72 @@ class RBXInstance:
1132
1224
 
1133
1225
  @property
1134
1226
  def TextureId(self):
1135
- if self.ClassName != "Tool":
1227
+ className = self.ClassName
1228
+ if className == "Tool":
1229
+ return self.memory_module.read_string(
1230
+ self.raw_address,
1231
+ tool_offsets["TextureId"]
1232
+ )
1233
+ elif className == "MeshPart":
1234
+ return self.memory_module.read_string(
1235
+ self.raw_address,
1236
+ meshpart_offsets["Texture"]
1237
+ )
1238
+ elif className == "Decal":
1239
+ return self.memory_module.read_string(
1240
+ self.raw_address,
1241
+ textures_offsets["Decal_Texture"]
1242
+ )
1243
+ elif className == "Texture":
1244
+ return self.memory_module.read_string(
1245
+ self.raw_address,
1246
+ textures_offsets["Texture_Texture"]
1247
+ )
1248
+ return None
1249
+
1250
+ @TextureId.setter
1251
+ def TextureId(self, value: str):
1252
+ className = self.ClassName
1253
+ self._ensure_writable()
1254
+ if className == "Tool":
1255
+ self.memory_module.write_string(
1256
+ self.raw_address + tool_offsets["TextureId"],
1257
+ str(value)
1258
+ )
1259
+ elif className == "MeshPart":
1260
+ self.memory_module.write_string(
1261
+ self.raw_address + meshpart_offsets["Texture"],
1262
+ str(value)
1263
+ )
1264
+ elif className == "Decal":
1265
+ self.memory_module.write_string(
1266
+ self.raw_address + textures_offsets["Decal_Texture"],
1267
+ str(value)
1268
+ )
1269
+ elif className == "Texture":
1270
+ self.memory_module.write_string(
1271
+ self.raw_address + textures_offsets["Texture_Texture"],
1272
+ str(value)
1273
+ )
1274
+ else:
1275
+ raise AttributeError("TextureId is only available on Tool, MeshPart, Decal, or Texture instances.")
1276
+
1277
+ @property
1278
+ def MeshId(self):
1279
+ if self.ClassName != "MeshPart":
1136
1280
  return None
1137
1281
  return self.memory_module.read_string(
1138
1282
  self.raw_address,
1139
- tool_offsets["TextureId"]
1283
+ meshpart_offsets["MeshId"]
1140
1284
  )
1141
1285
 
1142
- @TextureId.setter
1143
- def TextureId(self, value: str):
1144
- if self.ClassName != "Tool":
1145
- raise AttributeError("TextureId is only available on Tool instances.")
1286
+ @MeshId.setter
1287
+ def MeshId(self, value: str):
1288
+ if self.ClassName != "MeshPart":
1289
+ raise AttributeError("MeshId is only available on MeshPart instances.")
1146
1290
  self._ensure_writable()
1147
1291
  self.memory_module.write_string(
1148
- self.raw_address + tool_offsets["TextureId"],
1292
+ self.raw_address + meshpart_offsets["MeshId"],
1149
1293
  str(value)
1150
1294
  )
1151
1295
 
@@ -1171,23 +1315,33 @@ class RBXInstance:
1171
1315
  # colorcorrection props #
1172
1316
  @property
1173
1317
  def Brightness(self):
1174
- if self.ClassName == "ColorCorrectionEffect":
1318
+ cn = self.ClassName
1319
+ if cn == "ColorCorrectionEffect":
1175
1320
  return self.memory_module.read_float(
1176
1321
  self.raw_address,
1177
1322
  Offsets["ColorCorrectionEffect"]["Brightness"]
1178
1323
  )
1324
+ elif cn == "Beam":
1325
+ return self.memory_module.read_float(self.raw_address, beam_offsets["Brightness"])
1326
+ elif cn == "ParticleEmitter":
1327
+ return self.memory_module.read_float(self.raw_address, particleemitter_offsets["Brightness"])
1179
1328
  return None
1180
1329
 
1181
1330
  @Brightness.setter
1182
1331
  def Brightness(self, value: float):
1183
- if self.ClassName == "ColorCorrectionEffect":
1184
- self._ensure_writable()
1332
+ cn = self.ClassName
1333
+ self._ensure_writable()
1334
+ if cn == "ColorCorrectionEffect":
1185
1335
  self.memory_module.write_float(
1186
1336
  self.raw_address + Offsets["ColorCorrectionEffect"]["Brightness"],
1187
1337
  float(value)
1188
1338
  )
1339
+ elif cn == "Beam":
1340
+ self.memory_module.write_float(self.raw_address + beam_offsets["Brightness"], float(value))
1341
+ elif cn == "ParticleEmitter":
1342
+ self.memory_module.write_float(self.raw_address + particleemitter_offsets["Brightness"], float(value))
1189
1343
  else:
1190
- raise AttributeError("Brightness is only available on ColorCorrectionEffect instances (use LightingService.Brightness for Lighting).")
1344
+ raise AttributeError("Brightness is only available on ColorCorrectionEffect, Beam, or ParticleEmitter instances.")
1191
1345
 
1192
1346
  @property
1193
1347
  def Contrast(self):
@@ -2172,6 +2326,62 @@ class RBXInstance:
2172
2326
  else:
2173
2327
  threading.Thread(target=execute_move, daemon=True).start()
2174
2328
 
2329
+ @property
2330
+ def AutomaticScalingEnabled(self):
2331
+ if self.ClassName != "Humanoid":
2332
+ return None
2333
+ return self.memory_module.read_bool(
2334
+ self.raw_address,
2335
+ humanoid_offsets["AutomaticScalingEnabled"]
2336
+ )
2337
+
2338
+ @AutomaticScalingEnabled.setter
2339
+ def AutomaticScalingEnabled(self, value: bool):
2340
+ if self.ClassName != "Humanoid":
2341
+ raise AttributeError("AutomaticScalingEnabled is only available on Humanoid instances.")
2342
+ self._ensure_writable()
2343
+ self.memory_module.write_bool(
2344
+ self.raw_address + humanoid_offsets["AutomaticScalingEnabled"],
2345
+ bool(value)
2346
+ )
2347
+
2348
+ @property
2349
+ def UseJumpPower(self):
2350
+ if self.ClassName != "Humanoid":
2351
+ return None
2352
+ return self.memory_module.read_bool(
2353
+ self.raw_address,
2354
+ humanoid_offsets["UseJumpPower"]
2355
+ )
2356
+
2357
+ @UseJumpPower.setter
2358
+ def UseJumpPower(self, value: bool):
2359
+ if self.ClassName != "Humanoid":
2360
+ raise AttributeError("UseJumpPower is only available on Humanoid instances.")
2361
+ self._ensure_writable()
2362
+ self.memory_module.write_bool(
2363
+ self.raw_address + humanoid_offsets["UseJumpPower"],
2364
+ bool(value)
2365
+ )
2366
+
2367
+ @property
2368
+ def WalkTimer(self):
2369
+ if self.ClassName != "Humanoid":
2370
+ return None
2371
+ return self.memory_module.read_double(
2372
+ self.raw_address + humanoid_offsets["WalkTimer"]
2373
+ )
2374
+
2375
+ @WalkTimer.setter
2376
+ def WalkTimer(self, value: float):
2377
+ if self.ClassName != "Humanoid":
2378
+ raise AttributeError("WalkTimer is only available on Humanoid instances.")
2379
+ self._ensure_writable()
2380
+ self.memory_module.write_double(
2381
+ self.raw_address + humanoid_offsets["WalkTimer"],
2382
+ float(value)
2383
+ )
2384
+
2175
2385
  # adornee / animation props #
2176
2386
  @property
2177
2387
  def Adornee(self):
@@ -2267,6 +2477,8 @@ class RBXInstance:
2267
2477
  bytecode_offset = Offsets["LocalScript"]["ByteCode"]
2268
2478
  elif classname == "ModuleScript":
2269
2479
  bytecode_offset = Offsets["ModuleScript"]["ByteCode"]
2480
+ elif classname == "Script":
2481
+ bytecode_offset = script_offsets["ByteCode"]
2270
2482
  else:
2271
2483
  return None
2272
2484
 
@@ -2289,8 +2501,10 @@ class RBXInstance:
2289
2501
  bytecode_offset = Offsets["LocalScript"]["ByteCode"]
2290
2502
  elif classname == "ModuleScript":
2291
2503
  bytecode_offset = Offsets["ModuleScript"]["ByteCode"]
2504
+ elif classname == "Script":
2505
+ bytecode_offset = script_offsets["ByteCode"]
2292
2506
  else:
2293
- raise AttributeError("Bytecode can only be written for LocalScript or ModuleScript.")
2507
+ raise AttributeError("Bytecode can only be written for LocalScript, ModuleScript, or Script.")
2294
2508
 
2295
2509
  encoded_data = encryptor.encode_roblox(value)
2296
2510
  new_size = len(encoded_data)
@@ -2314,6 +2528,8 @@ class RBXInstance:
2314
2528
  guid_offset = Offsets["LocalScript"]["GUID"]
2315
2529
  elif classname == "ModuleScript":
2316
2530
  guid_offset = Offsets["ModuleScript"]["GUID"]
2531
+ elif classname == "Script":
2532
+ guid_offset = script_offsets["GUID"]
2317
2533
  else:
2318
2534
  return None
2319
2535
  return self.memory_module.read_string(
@@ -2328,6 +2544,8 @@ class RBXInstance:
2328
2544
  hash_offset = Offsets["LocalScript"]["Hash"]
2329
2545
  elif classname == "ModuleScript":
2330
2546
  hash_offset = Offsets["ModuleScript"]["Hash"]
2547
+ elif classname == "Script":
2548
+ hash_offset = script_offsets["Hash"]
2331
2549
  else:
2332
2550
  return None
2333
2551
  return self.memory_module.read_string(
@@ -2482,6 +2700,471 @@ class RBXInstance:
2482
2700
  except: pass
2483
2701
  return "Unknown"
2484
2702
 
2703
+ # modulescript props #
2704
+ @property
2705
+ def IsCoreScript(self):
2706
+ if self.ClassName != "ModuleScript":
2707
+ return None
2708
+ return self.memory_module.read_bool(
2709
+ self.raw_address,
2710
+ Offsets["ModuleScript"]["IsCoreScript"]
2711
+ )
2712
+
2713
+ # beam props #
2714
+ @property
2715
+ def Attachment0(self):
2716
+ cn = self.ClassName
2717
+ if cn == "Beam":
2718
+ ptr = self.memory_module.get_pointer(self.raw_address, beam_offsets["Attachment0"])
2719
+ return RBXInstance(ptr, self.memory_module) if ptr != 0 else None
2720
+ return None
2721
+
2722
+ @property
2723
+ def Attachment1(self):
2724
+ cn = self.ClassName
2725
+ if cn == "Beam":
2726
+ ptr = self.memory_module.get_pointer(self.raw_address, beam_offsets["Attachment1"])
2727
+ return RBXInstance(ptr, self.memory_module) if ptr != 0 else None
2728
+ return None
2729
+
2730
+ @property
2731
+ def CurveSize0(self):
2732
+ if self.ClassName != "Beam":
2733
+ return None
2734
+ return self.memory_module.read_float(self.raw_address, beam_offsets["CurveSize0"])
2735
+
2736
+ @CurveSize0.setter
2737
+ def CurveSize0(self, value: float):
2738
+ if self.ClassName != "Beam":
2739
+ raise AttributeError("CurveSize0 is only available on Beam instances.")
2740
+ self._ensure_writable()
2741
+ self.memory_module.write_float(self.raw_address + beam_offsets["CurveSize0"], float(value))
2742
+
2743
+ @property
2744
+ def CurveSize1(self):
2745
+ if self.ClassName != "Beam":
2746
+ return None
2747
+ return self.memory_module.read_float(self.raw_address, beam_offsets["CurveSize1"])
2748
+
2749
+ @CurveSize1.setter
2750
+ def CurveSize1(self, value: float):
2751
+ if self.ClassName != "Beam":
2752
+ raise AttributeError("CurveSize1 is only available on Beam instances.")
2753
+ self._ensure_writable()
2754
+ self.memory_module.write_float(self.raw_address + beam_offsets["CurveSize1"], float(value))
2755
+
2756
+ @property
2757
+ def LightEmission(self):
2758
+ cn = self.ClassName
2759
+ if cn == "Beam":
2760
+ return self.memory_module.read_float(self.raw_address, beam_offsets["LightEmission"])
2761
+ elif cn == "ParticleEmitter":
2762
+ return self.memory_module.read_float(self.raw_address, particleemitter_offsets["LightEmission"])
2763
+ return None
2764
+
2765
+ @LightEmission.setter
2766
+ def LightEmission(self, value: float):
2767
+ cn = self.ClassName
2768
+ self._ensure_writable()
2769
+ if cn == "Beam":
2770
+ self.memory_module.write_float(self.raw_address + beam_offsets["LightEmission"], float(value))
2771
+ elif cn == "ParticleEmitter":
2772
+ self.memory_module.write_float(self.raw_address + particleemitter_offsets["LightEmission"], float(value))
2773
+ else:
2774
+ raise AttributeError("LightEmission is only available on Beam or ParticleEmitter instances.")
2775
+
2776
+ @property
2777
+ def LightInfluence(self):
2778
+ cn = self.ClassName
2779
+ if cn == "Beam":
2780
+ return self.memory_module.read_float(self.raw_address, beam_offsets["LightInfluence"])
2781
+ elif cn == "ParticleEmitter":
2782
+ return self.memory_module.read_float(self.raw_address, particleemitter_offsets["LightInfluence"])
2783
+ return None
2784
+
2785
+ @LightInfluence.setter
2786
+ def LightInfluence(self, value: float):
2787
+ cn = self.ClassName
2788
+ self._ensure_writable()
2789
+ if cn == "Beam":
2790
+ self.memory_module.write_float(self.raw_address + beam_offsets["LightInfluence"], float(value))
2791
+ elif cn == "ParticleEmitter":
2792
+ self.memory_module.write_float(self.raw_address + particleemitter_offsets["LightInfluence"], float(value))
2793
+ else:
2794
+ raise AttributeError("LightInfluence is only available on Beam or ParticleEmitter instances.")
2795
+
2796
+ @property
2797
+ def TextureLength(self):
2798
+ if self.ClassName != "Beam":
2799
+ return None
2800
+ return self.memory_module.read_float(self.raw_address, beam_offsets["TextureLength"])
2801
+
2802
+ @TextureLength.setter
2803
+ def TextureLength(self, value: float):
2804
+ if self.ClassName != "Beam":
2805
+ raise AttributeError("TextureLength is only available on Beam instances.")
2806
+ self._ensure_writable()
2807
+ self.memory_module.write_float(self.raw_address + beam_offsets["TextureLength"], float(value))
2808
+
2809
+ @property
2810
+ def TextureSpeed(self):
2811
+ if self.ClassName != "Beam":
2812
+ return None
2813
+ return self.memory_module.read_float(self.raw_address, beam_offsets["TextureSpeed"])
2814
+
2815
+ @TextureSpeed.setter
2816
+ def TextureSpeed(self, value: float):
2817
+ if self.ClassName != "Beam":
2818
+ raise AttributeError("TextureSpeed is only available on Beam instances.")
2819
+ self._ensure_writable()
2820
+ self.memory_module.write_float(self.raw_address + beam_offsets["TextureSpeed"], float(value))
2821
+
2822
+ @property
2823
+ def Width0(self):
2824
+ if self.ClassName != "Beam":
2825
+ return None
2826
+ return self.memory_module.read_float(self.raw_address, beam_offsets["Width0"])
2827
+
2828
+ @Width0.setter
2829
+ def Width0(self, value: float):
2830
+ if self.ClassName != "Beam":
2831
+ raise AttributeError("Width0 is only available on Beam instances.")
2832
+ self._ensure_writable()
2833
+ self.memory_module.write_float(self.raw_address + beam_offsets["Width0"], float(value))
2834
+
2835
+ @property
2836
+ def Width1(self):
2837
+ if self.ClassName != "Beam":
2838
+ return None
2839
+ return self.memory_module.read_float(self.raw_address, beam_offsets["Width1"])
2840
+
2841
+ @Width1.setter
2842
+ def Width1(self, value: float):
2843
+ if self.ClassName != "Beam":
2844
+ raise AttributeError("Width1 is only available on Beam instances.")
2845
+ self._ensure_writable()
2846
+ self.memory_module.write_float(self.raw_address + beam_offsets["Width1"], float(value))
2847
+
2848
+ @property
2849
+ def ZOffset(self):
2850
+ cn = self.ClassName
2851
+ if cn == "Beam":
2852
+ return self.memory_module.read_float(self.raw_address, beam_offsets["ZOffset"])
2853
+ elif cn == "ParticleEmitter":
2854
+ return self.memory_module.read_float(self.raw_address, particleemitter_offsets["ZOffset"])
2855
+ return None
2856
+
2857
+ @ZOffset.setter
2858
+ def ZOffset(self, value: float):
2859
+ cn = self.ClassName
2860
+ self._ensure_writable()
2861
+ if cn == "Beam":
2862
+ self.memory_module.write_float(self.raw_address + beam_offsets["ZOffset"], float(value))
2863
+ elif cn == "ParticleEmitter":
2864
+ self.memory_module.write_float(self.raw_address + particleemitter_offsets["ZOffset"], float(value))
2865
+ else:
2866
+ raise AttributeError("ZOffset is only available on Beam or ParticleEmitter instances.")
2867
+
2868
+ # particleemitter props #
2869
+ @property
2870
+ def Acceleration(self):
2871
+ if self.ClassName != "ParticleEmitter":
2872
+ return None
2873
+ data = self.memory_module.read_floats(
2874
+ self.raw_address + particleemitter_offsets["Acceleration"], 3
2875
+ )
2876
+ return Vector3(*data)
2877
+
2878
+ @Acceleration.setter
2879
+ def Acceleration(self, value):
2880
+ if self.ClassName != "ParticleEmitter":
2881
+ raise AttributeError("Acceleration is only available on ParticleEmitter instances.")
2882
+ self._ensure_writable()
2883
+ vec = self._as_vector3(value, "Acceleration")
2884
+ self.memory_module.write_floats(
2885
+ self.raw_address + particleemitter_offsets["Acceleration"],
2886
+ (vec.X, vec.Y, vec.Z)
2887
+ )
2888
+
2889
+ @property
2890
+ def Drag(self):
2891
+ if self.ClassName != "ParticleEmitter":
2892
+ return None
2893
+ return self.memory_module.read_float(self.raw_address, particleemitter_offsets["Drag"])
2894
+
2895
+ @Drag.setter
2896
+ def Drag(self, value: float):
2897
+ if self.ClassName != "ParticleEmitter":
2898
+ raise AttributeError("Drag is only available on ParticleEmitter instances.")
2899
+ self._ensure_writable()
2900
+ self.memory_module.write_float(self.raw_address + particleemitter_offsets["Drag"], float(value))
2901
+
2902
+ @property
2903
+ def Lifetime(self):
2904
+ if self.ClassName != "ParticleEmitter":
2905
+ return None
2906
+ data = self.memory_module.read_floats(
2907
+ self.raw_address + particleemitter_offsets["Lifetime"], 2
2908
+ )
2909
+ return NumberRange(*data)
2910
+
2911
+ @property
2912
+ def Rate(self):
2913
+ if self.ClassName != "ParticleEmitter":
2914
+ return None
2915
+ return self.memory_module.read_float(self.raw_address, particleemitter_offsets["Rate"])
2916
+
2917
+ @Rate.setter
2918
+ def Rate(self, value: float):
2919
+ if self.ClassName != "ParticleEmitter":
2920
+ raise AttributeError("Rate is only available on ParticleEmitter instances.")
2921
+ self._ensure_writable()
2922
+ self.memory_module.write_float(self.raw_address + particleemitter_offsets["Rate"], float(value))
2923
+
2924
+ @property
2925
+ def RotSpeed(self):
2926
+ if self.ClassName != "ParticleEmitter":
2927
+ return None
2928
+ data = self.memory_module.read_floats(
2929
+ self.raw_address + particleemitter_offsets["RotSpeed"], 2
2930
+ )
2931
+ return NumberRange(*data)
2932
+
2933
+ @RotSpeed.setter
2934
+ def RotSpeed(self, value):
2935
+ if self.ClassName != "ParticleEmitter":
2936
+ raise AttributeError("RotSpeed is only available on ParticleEmitter instances.")
2937
+ self._ensure_writable()
2938
+ if isinstance(value, NumberRange):
2939
+ vals = (value.Min, value.Max)
2940
+ elif isinstance(value, (tuple, list)) and len(value) == 2:
2941
+ vals = (float(value[0]), float(value[1]))
2942
+ else:
2943
+ v = float(value)
2944
+ vals = (v, v)
2945
+ self.memory_module.write_floats(
2946
+ self.raw_address + particleemitter_offsets["RotSpeed"], vals
2947
+ )
2948
+
2949
+ @property
2950
+ def ParticleSpeed(self):
2951
+ """Speed property for ParticleEmitter (named ParticleSpeed to avoid conflict with AnimationTrack.Speed)."""
2952
+ if self.ClassName != "ParticleEmitter":
2953
+ return None
2954
+ data = self.memory_module.read_floats(
2955
+ self.raw_address + particleemitter_offsets["Speed"], 2
2956
+ )
2957
+ return NumberRange(*data)
2958
+
2959
+ @ParticleSpeed.setter
2960
+ def ParticleSpeed(self, value):
2961
+ if self.ClassName != "ParticleEmitter":
2962
+ raise AttributeError("ParticleSpeed is only available on ParticleEmitter instances.")
2963
+ self._ensure_writable()
2964
+ if isinstance(value, NumberRange):
2965
+ vals = (value.Min, value.Max)
2966
+ elif isinstance(value, (tuple, list)) and len(value) == 2:
2967
+ vals = (float(value[0]), float(value[1]))
2968
+ else:
2969
+ v = float(value)
2970
+ vals = (v, v)
2971
+ self.memory_module.write_floats(
2972
+ self.raw_address + particleemitter_offsets["Speed"], vals
2973
+ )
2974
+
2975
+ @property
2976
+ def SpreadAngle(self):
2977
+ if self.ClassName != "ParticleEmitter":
2978
+ return None
2979
+ data = self.memory_module.read_floats(
2980
+ self.raw_address + particleemitter_offsets["SpreadAngle"], 2
2981
+ )
2982
+ return Vector2(*data)
2983
+
2984
+ @property
2985
+ def TimeScale(self):
2986
+ if self.ClassName != "ParticleEmitter":
2987
+ return None
2988
+ return self.memory_module.read_float(self.raw_address, particleemitter_offsets["TimeScale"])
2989
+
2990
+ @TimeScale.setter
2991
+ def TimeScale(self, value: float):
2992
+ if self.ClassName != "ParticleEmitter":
2993
+ raise AttributeError("TimeScale is only available on ParticleEmitter instances.")
2994
+ self._ensure_writable()
2995
+ self.memory_module.write_float(self.raw_address + particleemitter_offsets["TimeScale"], float(value))
2996
+
2997
+ @property
2998
+ def VelocityInheritance(self):
2999
+ if self.ClassName != "ParticleEmitter":
3000
+ return None
3001
+ return self.memory_module.read_float(self.raw_address, particleemitter_offsets["VelocityInheritance"])
3002
+
3003
+ @VelocityInheritance.setter
3004
+ def VelocityInheritance(self, value: float):
3005
+ if self.ClassName != "ParticleEmitter":
3006
+ raise AttributeError("VelocityInheritance is only available on ParticleEmitter instances.")
3007
+ self._ensure_writable()
3008
+ self.memory_module.write_float(self.raw_address + particleemitter_offsets["VelocityInheritance"], float(value))
3009
+
3010
+ # vehicleseat props #
3011
+ @property
3012
+ def MaxSpeed(self):
3013
+ if self.ClassName != "VehicleSeat":
3014
+ return None
3015
+ return self.memory_module.read_float(self.raw_address, vehicleseat_offsets["MaxSpeed"])
3016
+
3017
+ @MaxSpeed.setter
3018
+ def MaxSpeed(self, value: float):
3019
+ if self.ClassName != "VehicleSeat":
3020
+ raise AttributeError("MaxSpeed is only available on VehicleSeat instances.")
3021
+ self._ensure_writable()
3022
+ self.memory_module.write_float(self.raw_address + vehicleseat_offsets["MaxSpeed"], float(value))
3023
+
3024
+ @property
3025
+ def SteerFloat(self):
3026
+ if self.ClassName != "VehicleSeat":
3027
+ return None
3028
+ return self.memory_module.read_float(self.raw_address, vehicleseat_offsets["SteerFloat"])
3029
+
3030
+ @SteerFloat.setter
3031
+ def SteerFloat(self, value: float):
3032
+ if self.ClassName != "VehicleSeat":
3033
+ raise AttributeError("SteerFloat is only available on VehicleSeat instances.")
3034
+ self._ensure_writable()
3035
+ self.memory_module.write_float(self.raw_address + vehicleseat_offsets["SteerFloat"], float(value))
3036
+
3037
+ @property
3038
+ def ThrottleFloat(self):
3039
+ if self.ClassName != "VehicleSeat":
3040
+ return None
3041
+ return self.memory_module.read_float(self.raw_address, vehicleseat_offsets["ThrottleFloat"])
3042
+
3043
+ @ThrottleFloat.setter
3044
+ def ThrottleFloat(self, value: float):
3045
+ if self.ClassName != "VehicleSeat":
3046
+ raise AttributeError("ThrottleFloat is only available on VehicleSeat instances.")
3047
+ self._ensure_writable()
3048
+ self.memory_module.write_float(self.raw_address + vehicleseat_offsets["ThrottleFloat"], float(value))
3049
+
3050
+ @property
3051
+ def Torque(self):
3052
+ if self.ClassName != "VehicleSeat":
3053
+ return None
3054
+ return self.memory_module.read_float(self.raw_address, vehicleseat_offsets["Torque"])
3055
+
3056
+ @Torque.setter
3057
+ def Torque(self, value: float):
3058
+ if self.ClassName != "VehicleSeat":
3059
+ raise AttributeError("Torque is only available on VehicleSeat instances.")
3060
+ self._ensure_writable()
3061
+ self.memory_module.write_float(self.raw_address + vehicleseat_offsets["Torque"], float(value))
3062
+
3063
+ @property
3064
+ def TurnSpeed(self):
3065
+ if self.ClassName != "VehicleSeat":
3066
+ return None
3067
+ return self.memory_module.read_float(self.raw_address, vehicleseat_offsets["TurnSpeed"])
3068
+
3069
+ @TurnSpeed.setter
3070
+ def TurnSpeed(self, value: float):
3071
+ if self.ClassName != "VehicleSeat":
3072
+ raise AttributeError("TurnSpeed is only available on VehicleSeat instances.")
3073
+ self._ensure_writable()
3074
+ self.memory_module.write_float(self.raw_address + vehicleseat_offsets["TurnSpeed"], float(value))
3075
+
3076
+ # weld / weldconstraint props #
3077
+ @property
3078
+ def Part0(self):
3079
+ cn = self.ClassName
3080
+ if cn == "Weld":
3081
+ ptr = self.memory_module.get_pointer(self.raw_address, weld_offsets["Part0"])
3082
+ elif cn == "WeldConstraint":
3083
+ ptr = self.memory_module.get_pointer(self.raw_address, weldconstraint_offsets["Part0"])
3084
+ else:
3085
+ return None
3086
+ return RBXInstance(ptr, self.memory_module) if ptr != 0 else None
3087
+
3088
+ @Part0.setter
3089
+ def Part0(self, value):
3090
+ cn = self.ClassName
3091
+ if cn != "Weld" and cn != "WeldConstraint":
3092
+ raise AttributeError("Part0 is only available on Weld or WeldConstraint instances.")
3093
+ self._ensure_writable()
3094
+ if value is None:
3095
+ target = 0
3096
+ elif isinstance(value, RBXInstance):
3097
+ target = value.raw_address
3098
+ elif isinstance(value, int):
3099
+ target = value
3100
+ else:
3101
+ raise TypeError("Part0 must be set to an RBXInstance, int address, or None.")
3102
+ offset = weld_offsets["Part0"] if cn == "Weld" else weldconstraint_offsets["Part0"]
3103
+ self.memory_module.write_long(self.raw_address + offset, target)
3104
+
3105
+ @property
3106
+ def Part1(self):
3107
+ cn = self.ClassName
3108
+ if cn == "Weld":
3109
+ ptr = self.memory_module.get_pointer(self.raw_address, weld_offsets["Part1"])
3110
+ elif cn == "WeldConstraint":
3111
+ ptr = self.memory_module.get_pointer(self.raw_address, weldconstraint_offsets["Part1"])
3112
+ else:
3113
+ return None
3114
+ return RBXInstance(ptr, self.memory_module) if ptr != 0 else None
3115
+
3116
+ @Part1.setter
3117
+ def Part1(self, value):
3118
+ cn = self.ClassName
3119
+ if cn != "Weld" and cn != "WeldConstraint":
3120
+ raise AttributeError("Part1 is only available on Weld or WeldConstraint instances.")
3121
+ self._ensure_writable()
3122
+ if value is None:
3123
+ target = 0
3124
+ elif isinstance(value, RBXInstance):
3125
+ target = value.raw_address
3126
+ elif isinstance(value, int):
3127
+ target = value
3128
+ else:
3129
+ raise TypeError("Part1 must be set to an RBXInstance, int address, or None.")
3130
+ offset = weld_offsets["Part1"] if cn == "Weld" else weldconstraint_offsets["Part1"]
3131
+ self.memory_module.write_long(self.raw_address + offset, target)
3132
+
3133
+ # surfaceappearance props #
3134
+ @property
3135
+ def AlphaMode(self):
3136
+ if self.ClassName != "SurfaceAppearance":
3137
+ return None
3138
+ return self.memory_module.read_int(
3139
+ self.raw_address, surfaceappearance_offsets["AlphaMode"]
3140
+ )
3141
+
3142
+ @AlphaMode.setter
3143
+ def AlphaMode(self, value: int):
3144
+ if self.ClassName != "SurfaceAppearance":
3145
+ raise AttributeError("AlphaMode is only available on SurfaceAppearance instances.")
3146
+ self._ensure_writable()
3147
+ self.memory_module.write_int(
3148
+ self.raw_address + surfaceappearance_offsets["AlphaMode"], int(value)
3149
+ )
3150
+
3151
+ @property
3152
+ def EmissiveStrength(self):
3153
+ if self.ClassName != "SurfaceAppearance":
3154
+ return None
3155
+ return self.memory_module.read_float(
3156
+ self.raw_address, surfaceappearance_offsets["EmissiveStrength"]
3157
+ )
3158
+
3159
+ @EmissiveStrength.setter
3160
+ def EmissiveStrength(self, value: float):
3161
+ if self.ClassName != "SurfaceAppearance":
3162
+ raise AttributeError("EmissiveStrength is only available on SurfaceAppearance instances.")
3163
+ self._ensure_writable()
3164
+ self.memory_module.write_float(
3165
+ self.raw_address + surfaceappearance_offsets["EmissiveStrength"], float(value)
3166
+ )
3167
+
2485
3168
  class AttributeValue:
2486
3169
  def __init__(self, address, name, type_name, memory_module):
2487
3170
  self.address = address
@@ -2655,10 +3338,37 @@ class PlayerClass(RBXInstance):
2655
3338
  return RBXInstance(TeamAddress, self.memory_module)
2656
3339
 
2657
3340
  @property
2658
- def Country(self):
3341
+ def LocaleId(self):
2659
3342
  return self.memory_module.read_string(
2660
3343
  self.raw_address,
2661
- self.offset_base["Country"]
3344
+ self.offset_base["LocaleId"]
3345
+ )
3346
+
3347
+ @property
3348
+ def Country(self):
3349
+ """Deprecated: Use LocaleId instead. Renamed in V2.1.4."""
3350
+ return self.LocaleId
3351
+
3352
+ @property
3353
+ def TeamColor(self):
3354
+ return self.memory_module.read_int(
3355
+ self.raw_address,
3356
+ self.offset_base["TeamColor"]
3357
+ )
3358
+
3359
+ @TeamColor.setter
3360
+ def TeamColor(self, value: int):
3361
+ self._ensure_writable()
3362
+ self.memory_module.write_int(
3363
+ self.raw_address + self.offset_base["TeamColor"],
3364
+ int(value)
3365
+ )
3366
+
3367
+ @property
3368
+ def AccountAge(self):
3369
+ return self.memory_module.read_int(
3370
+ self.raw_address,
3371
+ self.offset_base["AccountAge"]
2662
3372
  )
2663
3373
 
2664
3374
  @property
@@ -3753,3 +4463,69 @@ class MouseService(ServiceBase):
3753
4463
  if input_obj is None:
3754
4464
  return
3755
4465
  input_obj.MousePosition = value
4466
+
4467
+ @property
4468
+ def InputObject2(self):
4469
+ if self.failed:
4470
+ return None
4471
+ try:
4472
+ input_ptr = self.memory_module.get_pointer(
4473
+ self.instance.raw_address,
4474
+ self.offset_base["InputObject2"]
4475
+ )
4476
+ if input_ptr == 0:
4477
+ return None
4478
+ return InputObject(input_ptr, self.memory_module)
4479
+ except (KeyError, OSError):
4480
+ return None
4481
+
4482
+ class UserInputService(ServiceBase):
4483
+ def __init__(self, memory_module, game: DataModel):
4484
+ super().__init__()
4485
+ self.memory_module = memory_module
4486
+ self.offset_base = Offsets["UserInputService"]
4487
+ try:
4488
+ uis_instance: RBXInstance = game.GetRawService("UserInputService")
4489
+ if uis_instance is None or uis_instance.ClassName != "UserInputService":
4490
+ self.failed = True
4491
+ else:
4492
+ self.instance = uis_instance
4493
+ except (KeyError, OSError):
4494
+ self.failed = True
4495
+
4496
+ @property
4497
+ def WindowInputState(self):
4498
+ if self.failed:
4499
+ return None
4500
+ try:
4501
+ ptr = self.memory_module.get_pointer(
4502
+ self.instance.raw_address,
4503
+ self.offset_base["WindowInputState"]
4504
+ )
4505
+ if ptr == 0:
4506
+ return None
4507
+ return WindowInputState(ptr, self.memory_module)
4508
+ except (KeyError, OSError):
4509
+ return None
4510
+
4511
+ class WindowInputState(RBXInstance):
4512
+ def __init__(self, raw_address: int, memory_module):
4513
+ super().__init__(raw_address, memory_module)
4514
+ self._wis_offsets = Offsets["WindowInputState"]
4515
+
4516
+ @property
4517
+ def CapsLock(self):
4518
+ return self.memory_module.read_bool(
4519
+ self.raw_address,
4520
+ self._wis_offsets["CapsLock"]
4521
+ )
4522
+
4523
+ @property
4524
+ def CurrentTextBox(self):
4525
+ ptr = self.memory_module.get_pointer(
4526
+ self.raw_address,
4527
+ self._wis_offsets["CurrentTextBox"]
4528
+ )
4529
+ if ptr == 0:
4530
+ return None
4531
+ return RBXInstance(ptr, self.memory_module)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: robloxmemoryapi
3
- Version: 0.2.6
3
+ Version: 0.2.8
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
@@ -35,7 +35,9 @@ Dynamic: license-file
35
35
 
36
36
  This was made by [upio](https://github.com/notpoiu), [mstudio45](https://github.com/mstudio45), and [Master Oogway](https://github.com/ActualMasterOogway) and created for the [Dig Macro](https://github.com/mstudio45/digmacro) project (external mode and not the computer vision mode).
37
37
 
38
- Offsets are sourced from [imtheo.lol](https://imtheo.lol/Offsets). This project is not affilated with imtheo.lol in any way.
38
+ Join our [Discord](https://discord.gg/FJcJMuze7S) for support and updates.
39
+
40
+ Offsets are sourced from [imtheo.lol](https://imtheo.lol/Offsets). This project is not affiliated with imtheo.lol in any way.
39
41
 
40
42
  ## Installation
41
43