Загрузка данных


import pymem
import time
import json
import os
import psutil
from tkinter import Tk, Label, Entry, Button, StringVar, messagebox

CONFIG_FILE = "config.json"
DEFAULT_CONFIG = {
    "old_skin_id": 33602,
    "new_skin_id": 97100,
    "process_name": "HD-Player.exe",
    "scan_delay": 1.5
}

class Standoff2SkinChanger:
    def __init__(self):
        self.pm = None
        self.config = self.load_config()
        self.old_id = self.config["old_skin_id"]
        self.new_id = self.config["new_skin_id"]
        self.process_name = self.config["process_name"]
        
    def load_config(self):
        if os.path.exists(CONFIG_FILE):
            with open(CONFIG_FILE, 'r') as f:
                return json.load(f)
        else:
            with open(CONFIG_FILE, 'w') as f:
                json.dump(DEFAULT_CONFIG, f, indent=4)
            return DEFAULT_CONFIG.copy()
    
    def find_bluestacks_pid(self):
        for proc in psutil.process_iter(['pid', 'name']):
            if proc.info['name'] == self.process_name:
                return proc.info['pid']
        return None
    
    def attach_to_process(self):
        pid = self.find_bluestacks_pid()
        if not pid:
            return False, "Bluestacks не запущен или процесс не найден"
        try:
            self.pm = pymem.Pymem(pid)
            return True, "Подключено к Bluestacks"
        except Exception as e:
            return False, f"Ошибка подключения: {e}"
    
    def find_skin_addresses(self):
        if not self.pm:
            return []
        addresses = []
        old_id_bytes = self.old_id.to_bytes(4, 'little')
        start_addr = 0x01000000
        end_addr = 0x7FFFFFFF
        chunk_size = 0x100000
        
        for current_addr in range(start_addr, end_addr, chunk_size):
            try:
                chunk = self.pm.read_bytes(current_addr, chunk_size)
                pos = chunk.find(old_id_bytes)
                while pos != -1:
                    addr = current_addr + pos
                    try:
                        value = self.pm.read_int(addr)
                        if value == self.old_id:
                            addresses.append(addr)
                    except:
                        pass
                    pos = chunk.find(old_id_bytes, pos + 1)
            except:
                continue
        return addresses
    
    def replace_skins(self):
        if not self.pm:
            return False, "Не подключено к процессу"
        addresses = self.find_skin_addresses()
        if not addresses:
            return False, "Скины не найдены в памяти"
        replaced = 0
        for addr in addresses:
            try:
                self.pm.write_int(addr, self.new_id)
                replaced += 1
            except:
                continue
        return True, f"Заменено {replaced} скинов"
    
    def run(self, status_callback=None):
        if status_callback:
            status_callback("Поиск процесса Bluestacks...")
        success, msg = self.attach_to_process()
        if not success:
            return False, msg
        if status_callback:
            status_callback("Поиск скинов в памяти...")
        time.sleep(self.config["scan_delay"])
        success, msg = self.replace_skins()
        return success, msg

class SkinChangerGUI:
    def __init__(self):
        self.root = Tk()
        self.root.title("Standoff 2 Skin Changer v1.0")
        self.root.geometry("400x250")
        self.root.resizable(False, False)
        self.changer = Standoff2SkinChanger()
        self.status_var = StringVar()
        self.status_var.set("Готов к работе")
        self.create_widgets()
        
    def create_widgets(self):
        Label(self.root, text="Standoff 2 Skin Changer", font=("Arial", 14, "bold")).pack(pady=10)
        Label(self.root, text=f"Замена: {self.changer.old_id} → {self.changer.new_id}", font=("Arial", 10)).pack()
        Label(self.root, text="Старый ID:").pack()
        self.old_entry = Entry(self.root, width=15)
        self.old_entry.insert(0, str(self.changer.old_id))
        self.old_entry.pack()
        Label(self.root, text="Новый ID:").pack()
        self.new_entry = Entry(self.root, width=15)
        self.new_entry.insert(0, str(self.changer.new_id))
        self.new_entry.pack()
        Button(self.root, text="Обновить настройки", command=self.update_config).pack(pady=5)
        Button(self.root, text="ЗАМЕНИТЬ СКИНЫ", command=self.execute, bg="green", fg="white", font=("Arial", 12, "bold")).pack(pady=10)
        Label(self.root, textvariable=self.status_var, fg="blue").pack(pady=5)
        
    def update_config(self):
        try:
            old = int(self.old_entry.get())
            new = int(self.new_entry.get())
            self.changer.old_id = old
            self.changer.new_id = new
            self.changer.config["old_skin_id"] = old
            self.changer.config["new_skin_id"] = new
            with open(CONFIG_FILE, 'w') as f:
                json.dump(self.changer.config, f, indent=4)
            self.status_var.set(f"Обновлено: {old} → {new}")
        except:
            self.status_var.set("Ошибка: введите числа")
    
    def execute(self):
        self.status_var.set("Идет замена...")
        self.root.update()
        success, msg = self.changer.run(lambda s: self.status_var.set(s))
        if success:
            messagebox.showinfo("Успешно", msg)
            self.status_var.set(f"Готово! {msg}")
        else:
            messagebox.showerror("Ошибка", msg)
            self.status_var.set("Ошибка выполнения")
    
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    app = SkinChangerGUI()
    app.run()