ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

python语言GTA SA 固定地址修改器 v1.0 - 完整版代码QZQ

python语言GTA SA 固定地址修改器 v1.0 - 完整版代码QZQ import pymem import pymem.process import tkinter as tk from tkinter import ttk, messagebox import threading import psutil import time # GTA SA v1.0 固定地址表 # 数据来源GTAMods Wiki / SDA Knowledge Base / 社区公认文档 # 适用范围GTA SA v1.0 US (模块基址 0x400000) # FIXED_ADDRESSES { # ---- 核心属性 ---- 当前金钱: {addr: 0xB7CE50, type: int, desc: 玩家现金}, 生命上限: {addr: 0xB793E0, type: float, desc: Max Health}, 肌肉: {addr: 0xB793DC, type: float, desc: Muscle}, 体力: {addr: 0xB793D8, type: float, desc: Stamina}, 肥胖度: {addr: 0xB793D4, type: float, desc: Fat}, 性吸引力: {addr: 0xB793E4, type: float, desc: Sex Appeal}, 肺活量: {addr: 0xB791A4, type: float, desc: Lung Capacity}, # ---- 技能/熟练度 ---- 自行车技能: {addr: 0xB791B8, type: float, desc: Bike Skill}, 摩托车技能: {addr: 0xB791B4, type: float, desc: Cycle Skill}, 飞行技能: {addr: 0xB7919C, type: float, desc: Flying Skill}, 驾驶技能: {addr: 0xB790A0, type: float, desc: Driving Skill}, # ---- 游戏统计 ---- 游戏时长(ms): {addr: 0xB7CB84, type: int, desc: Playing Time}, 步行距离: {addr: 0xB7938C, type: float, desc: Distance on foot}, 驾驶距离: {addr: 0xB79390, type: float, desc: Distance in car}, 骑行距离: {addr: 0xB793EC, type: float, desc: Distance on bicycle}, # ---- 通缉等级 ---- 通缉等级: {addr: 0xBAA420, type: int, desc: Wanted Level 0-6}, # ---- 游戏时间/天气 ---- 游戏小时: {addr: 0xB7014C, type: int, desc: 0-23}, 游戏分钟: {addr: 0xB70150, type: int, desc: 0-59}, 天气: {addr: 0xC81320, type: int, desc: 0-20}, } # 动态属性通过玩家指针偏移计算 # 玩家指针固定地址0xB6F5F0 # 读取方式CPed [0xB6F5F0]然后 CPed 偏移 # PLAYER_POINTER 0xB6F5F0 # 玩家 CPed 指针 PLAYER_OFFSETS { 当前生命: 0x540, # Float 当前护甲: 0x548, # Float } # 玩家坐标指针链 # CPed - 0x14 坐标结构 - 0x30/0x34/0x38 X/Y/Z # COORD_PTR_OFFSET 0x14 COORD_X_OFFSET 0x30 COORD_Y_OFFSET 0x34 COORD_Z_OFFSET 0x38 class GTASAFixedEditor: def __init__(self, root): self.root root self.root.title(GTA SA 固定地址修改器 v1.0 - 完整版) self.root.geometry(680x700) self.root.resizable(True, True) self.pm None self.process_id None self.player_ptr None # CPed 指针值 self.entries {} # 名称 - 输入框 self.locks {} # 名称 - 是否锁定 self.lock_threads {} # 名称 - 线程 self.create_widgets() self.detect_game() # UI def create_widgets(self): # 顶部进程状态 top ttk.LabelFrame(self.root, text进程) top.pack(fillx, padx10, pady5) self.proc_var tk.StringVar(value未连接) ttk.Label(top, textvariableself.proc_var, width55).pack(sideleft, padx5) ttk.Button(top, text刷新检测, commandself.detect_game).pack(sideright, padx5) # 玩家指针状态 ptr_frame ttk.LabelFrame(self.root, text玩家指针 (CPed)) ptr_frame.pack(fillx, padx10, pady5) self.ptr_var tk.StringVar(value未获取) ttk.Label(ptr_frame, textvariableself.ptr_var, font(Consolas, 10)).pack(sideleft, padx5) ttk.Button(ptr_frame, text刷新指针, commandself.update_player_ptr).pack(sideright, padx5) # 中部固定地址属性列表 mid ttk.LabelFrame(self.root, text属性列表v1.0 固定地址) mid.pack(fillboth, expandTrue, padx10, pady5) canvas tk.Canvas(mid, height350) scrollbar ttk.Scrollbar(mid, orientvertical, commandcanvas.yview) self.scrollable_frame ttk.Frame(canvas) self.scrollable_frame.bind( Configure, lambda e: canvas.configure(scrollregioncanvas.bbox(all)) ) canvas.create_window((0, 0), windowself.scrollable_frame, anchornw) canvas.configure(yscrollcommandscrollbar.set) canvas.pack(sideleft, fillboth, expandTrue) scrollbar.pack(sideright, filly) # 表头 header ttk.Frame(self.scrollable_frame) header.grid(row0, column0, columnspan7, stickyew, pady2) ttk.Label(header, text属性, width12, font(, 9, bold)).pack(sideleft, padx3) ttk.Label(header, text地址, width12, font(, 9, bold)).pack(sideleft, padx3) ttk.Label(header, text类型, width6, font(, 9, bold)).pack(sideleft, padx3) ttk.Label(header, text值, width15, font(, 9, bold)).pack(sideleft, padx3) ttk.Label(header, text操作, width20, font(, 9, bold)).pack(sideleft, padx3) # 生成所有属性行固定 动态 all_attrs list(FIXED_ADDRESSES.items()) [ (当前生命, {addr: 动态, type: float, desc: CPed0x540}), (当前护甲, {addr: 动态, type: float, desc: CPed0x548}), ] for i, (name, info) in enumerate(all_attrs, start1): self.create_attr_row(i, name, info) # 底部操作按钮 bot ttk.Frame(self.root) bot.pack(fillx, padx10, pady5) ttk.Button(bot, text读取全部, commandself.read_all).pack(sideleft, padx3) ttk.Button(bot, text一键满血满甲, commandself.max_hp_armor).pack(sideleft, padx3) ttk.Button(bot, text金钱9999999, commandlambda: self.quick_set(当前金钱, 9999999)).pack(sideleft, padx3) ttk.Button(bot, text通缉0, commandlambda: self.quick_set(通缉等级, 0)).pack(sideleft, padx3) # 坐标显示 coord_frame ttk.LabelFrame(self.root, text玩家坐标) coord_frame.pack(fillx, padx10, pady5) self.coord_var tk.StringVar(valueX?, Y?, Z?) ttk.Label(coord_frame, textvariableself.coord_var, font(Consolas, 10)).pack(sideleft, padx5) ttk.Button(coord_frame, text读取坐标, commandself.read_coords).pack(sideright, padx5) # 状态栏 self.status_var tk.StringVar(value就绪) ttk.Label(self.root, textvariableself.status_var, reliefsunken, anchorw).pack(fillx, sidebottom) def create_attr_row(self, row, name, info): 创建一行属性 ttk.Label(self.scrollable_frame, textname, width12).grid( rowrow, column0, padx3, pady2, stickyw) addr info[addr] addr_text f0x{addr:08X} if isinstance(addr, int) else str(addr) ttk.Label(self.scrollable_frame, textaddr_text, font(Consolas, 9), width12).grid( rowrow, column1, padx3, pady2) ttk.Label(self.scrollable_frame, textinfo[type], width6).grid( rowrow, column2, padx3, pady2) entry ttk.Entry(self.scrollable_frame, width15) entry.grid(rowrow, column3, padx3, pady2) self.entries[name] entry # 按钮组 btn_frame ttk.Frame(self.scrollable_frame) btn_frame.grid(rowrow, column4, padx3, pady2) ttk.Button(btn_frame, text读, width3, commandlambda nname: self.read_value(n)).pack(sideleft, padx1) ttk.Button(btn_frame, text写, width3, commandlambda nname: self.write_value(n)).pack(sideleft, padx1) ttk.Button(btn_frame, text锁, width3, commandlambda nname: self.toggle_lock(n)).pack(sideleft, padx1) # 进程操作 def detect_game(self): try: found None for p in psutil.process_iter([pid, name]): if gta_sa in (p.info[name] or ).lower(): found p.info break if not found: self.proc_var.set(未检测到 gta_sa.exe) self.pm None return self.process_id found[pid] self.pm pymem.Pymem(self.process_id) self.proc_var.set(f已连接 {found[name]} (PID {self.process_id})) self.status_var.set(连接成功点“读取全部”刷新数值) self.update_player_ptr() except Exception as e: self.pm None self.proc_var.set(f连接失败: {e}) def update_player_ptr(self): 读取玩家指针 if self.pm is None: messagebox.showinfo(提示, 未连接游戏进程) return try: self.player_ptr self.pm.read_int(PLAYER_POINTER) self.ptr_var.set(fCPed 0x{self.player_ptr:08X}) self.status_var.set(f玩家指针更新: 0x{self.player_ptr:08X}) except Exception as e: self.player_ptr None self.ptr_var.set(读取失败) self.status_var.set(f玩家指针读取失败: {e}) # 读取/写入 def resolve_address(self, name): 解析地址固定地址直接返回动态属性需要 player_ptr # 动态属性 if name in PLAYER_OFFSETS: if self.player_ptr is None: self.update_player_ptr() if self.player_ptr is None: return None return self.player_ptr PLAYER_OFFSETS[name] # 固定属性 if name in FIXED_ADDRESSES: return FIXED_ADDRESSES[name][addr] return None def get_type(self, name): 获取属性类型 if name in PLAYER_OFFSETS: return float if name in FIXED_ADDRESSES: return FIXED_ADDRESSES[name][type] return int def read_value(self, name): if self.pm is None: messagebox.showinfo(提示, 未连接游戏进程) return addr self.resolve_address(name) if addr is None: self.status_var.set(f{name} 地址无效需要玩家指针) return try: t self.get_type(name) if t float: val self.pm.read_float(addr) disp f{val:.2f} else: val self.pm.read_int(addr) disp str(val) self.entries[name].delete(0, tk.END) self.entries[name].insert(0, disp) self.status_var.set(f{name} {disp}) except Exception as e: self.status_var.set(f读取 {name} 失败: {e}) def write_value(self, name): if self.pm is None: messagebox.showinfo(提示, 未连接游戏进程) return addr self.resolve_address(name) if addr is None: self.status_var.set(f{name} 地址无效需要玩家指针) return try: txt self.entries[name].get().strip() t self.get_type(name) if t float: self.pm.write_float(addr, float(txt)) else: self.pm.write_int(addr, int(txt)) self.status_var.set(f{name} 已写入: {txt}) except ValueError: messagebox.showerror(错误, 请输入有效数字) except Exception as e: self.status_var.set(f写入 {name} 失败: {e}) def quick_set(self, name, value): 快捷设置 if name not in self.entries: return self.entries[name].delete(0, tk.END) self.entries[name].insert(0, str(value)) self.write_value(name) def max_hp_armor(self): 一键满血满甲 if self.pm is None: messagebox.showinfo(提示, 未连接游戏进程) return self.quick_set(当前生命, 100) self.quick_set(当前护甲, 100) self.status_var.set(生命和护甲已设为 100) def read_all(self): for name in list(FIXED_ADDRESSES.keys()) list(PLAYER_OFFSETS.keys()): self.read_value(name) def read_coords(self): 读取玩家坐标 if self.pm is None: messagebox.showinfo(提示, 未连接游戏进程) return if self.player_ptr is None: self.update_player_ptr() if self.player_ptr is None: return try: coord_ptr self.pm.read_int(self.player_ptr COORD_PTR_OFFSET) x self.pm.read_float(coord_ptr COORD_X_OFFSET) y self.pm.read_float(coord_ptr COORD_Y_OFFSET) z self.pm.read_float(coord_ptr COORD_Z_OFFSET) self.coord_var.set(fX{x:.2f}, Y{y:.2f}, Z{z:.2f}) self.status_var.set(f坐标: X{x:.2f}, Y{y:.2f}, Z{z:.2f}) except Exception as e: self.coord_var.set(读取失败) self.status_var.set(f读取坐标失败: {e}) # 锁定 def toggle_lock(self, name): if self.locks.get(name): self.locks[name] False self.status_var.set(f{name} 锁定已关闭) else: self.locks[name] True t threading.Thread(targetself.lock_worker, args(name,), daemonTrue) self.lock_threads[name] t t.start() self.status_var.set(f{name} 锁定中...) def lock_worker(self, name): while self.locks.get(name): try: if self.pm is not None: addr self.resolve_address(name) if addr is not None: txt self.entries[name].get().strip() if txt: t self.get_type(name) if t float: self.pm.write_float(addr, float(txt)) else: self.pm.write_int(addr, int(txt)) except Exception: pass time.sleep(0.3) if __name__ __main__: root tk.Tk() app GTASAFixedEditor(root) root.mainloop()
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表