Untitled
import tkinter as tk from tkinter import ttk import pymem import pymem.process import time from flask import Flask, jsonify from threading import Thread app = Flask(__name__) # Zmienne globalne (value_1, value_2, value_3, value_4, value_5, value_6, value_7, value_8, value_9, value_10, value_11, value_12, value_13, value_14, value_15, value_16, value_17, value_18, value_19, value_20, value_21, value_22, value_23) = \ (None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None) # Funkcja do odczytu pamięci z gry def read_memory(): global value_1, value_2, value_3, value_4, value_5, value_6, value_7, value_8, value_9, value_10,\ value_11, value_12, value_13, value_14, value_15, value_16, value_17, value_18, value_19,\ value_20, value_21, value_22, value_23 try: attempt = 1 # Licznik prób połączeń do SimRail.exe while True: try: pm = pymem.Pymem("SimRail.exe") module = pymem.process.module_from_name(pm.process_handle, "GameAssembly.dll") module_base = module.lpBaseOfDll break except Exception as _: print(f"Nie znaleziono procesu. Ponawiam próbę za 3 sekundy... (próba {attempt})") attempt += 1 time.sleep(3) # Definicja adresów bazowych i offsetów dla każdej wartości addresses_config = { "value_1": [ {"base_offset": 0x067EC8D0, "offsets": [0x48, 0xB8, 0x10, 0x78, 0x80, 0x88, 0x48], "type": float}, {"base_offset": 0x067F1D70, "offsets": [0x80, 0x50, 0xB8, 0x50, 0x80, 0x118, 0x48], "type": float}, ], "value_2": [ {"base_offset": 0x067CBAA0, "offsets": [0x70, 0xB8, 0x20, 0x78, 0x248, 0x20, 0XC0], "type": float}, {"base_offset": 0x067EC8D0, "offsets": [0x48, 0xB8, 0x10, 0x78, 0x248, 0x20, 0XC0], "type": float}, ], "value_3": [ {"base_offset": 0x067EF930, "offsets": [0x48, 0xB8, 0x0, 0x78, 0x248, 0x20, 0xBC], "type": float}, {"base_offset": 0x067DC4D8, "offsets": [0xB8, 0x10, 0x60, 0x88, 0x208, 0x20, 0xBC], "type": float}, ], "value_4": [ {"base_offset": 0x067DC628, "offsets": [0xB8, 0x20, 0x60, 0x90, 0x208, 0x20, 0x94], "type": float}, {"base_offset": 0x068662B0, "offsets": [0xB8, 0x0, 0x60, 0x88, 0x208, 0x20, 0x94], "type": float}, ], "value_5": [ {"base_offset": 0x067F1D70, "offsets": [0xB8, 0x50, 0x80, 0x248, 0x20, 0xA0], "type": float}, {"base_offset": 0x067CBAA0, "offsets": [0x70, 0xB8, 0x20, 0x78, 0x248, 0x20, 0xA0], "type": float}, ], "value_6": [ {"base_offset": 0x067DC628, "offsets": [0xB8, 0x20, 0xA0, 0x80, 0x248, 0x20, 0x50], "type": float}, {"base_offset": 0x067DC4D8, "offsets": [0xB8, 0x10, 0x60, 0x88, 0x118, 0x20, 0x50], "type": float}, ], "value_7": [ {"base_offset": 0x067F1D70, "offsets": [0xB8, 0x50, 0x298, 0x20, 0x38, 0x20, 0x4C], "type": float}, {"base_offset": 0x067CBA38, "offsets": [0x48, 0xB8, 0x20, 0x78, 0x248, 0x20, 0x4C], "type": float}, ], "value_8": [ {"base_offset": 0x067DC4D8, "offsets": [0x80, 0x50, 0xB8, 0x10, 0x40, 0x88, 0x38], "type": float}, {"base_offset": 0x067EFE00, "offsets": [0x78, 0xC0, 0xE8, 0xB8, 0x10, 0x88, 0x38], "type": float}, ], "value_9": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_10": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_11": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_12": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_13": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_14": [ {"base_offset": 0x0687B948, "offsets": [0xB8, 0x10, 0x80, 0x440, 0x10, 0x70, 0x40], "type": int}, {"base_offset": 0x0682CBD8, "offsets": [0x48, 0xB8, 0x20, 0x68, 0x918, 0x11C], "type": int}, ], "value_15": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_16": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_17": [ {"base_offset": 0x067EFD80, "offsets": [0x30, 0x48, 0x78, 0xB8, 0x30, 0x80, 0x860], "type": int}, {"base_offset": 0x067EC8D0, "offsets": [0x90, 0x28, 0x40, 0xB8, 0x10, 0x78, 0x860], "type": int}, ], "value_18": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_19": [ {"base_offset": 0x067F1D70, "offsets": [0xB8, 0x50, 0x80, 0x418], "type": int}, {"base_offset": 0x0687B948, "offsets": [0xB8, 0x10, 0x80, 0x418], "type": int}, ], "value_20": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_21": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, ], "value_22": [ {"base_offset": 0x068662B0, "offsets": [0xB8, 0x0, 0x60, 0x88, 0x208, 0x20, 0xC4], "type": float}, {"base_offset": 0x067F1D90, "offsets": [0x20, 0xB8, 0x50, 0x80, 0x248, 0x20, 0xC4], "type": float}, ], "value_23": [ {"base_offset": 0x00, "offsets": [0xB8, 0x10, 0x60, 0x120, 0x84], "type": int}, {"base_offset": 0x067F1D90, "offsets": [0x20, 0xB8, 0x50, 0x80, 0x248, 0x20, 0xC4], "type": float}, ], } # Funkcja pomocnicza do odczytu wartości float/int def read_value(config_list): for config in config_list: try: address = module_base + config["base_offset"] for offset in config["offsets"]: address = pm.read_longlong(address) + offset value = pm.read_float(address) if config["type"] == float else pm.read_int(address) return value except Exception: continue return None # Aktualizacja wartości value_1 = read_value(addresses_config["value_1"]) value_2 = read_value(addresses_config["value_2"]) value_3 = read_value(addresses_config["value_3"]) value_4 = read_value(addresses_config["value_4"]) value_5 = read_value(addresses_config["value_5"]) value_6 = read_value(addresses_config["value_6"]) value_7 = read_value(addresses_config["value_7"]) value_8 = read_value(addresses_config["value_8"]) value_9 = read_value(addresses_config["value_9"]) value_10 = read_value(addresses_config["value_10"]) value_11 = read_value(addresses_config["value_11"]) value_12 = read_value(addresses_config["value_12"]) value_13 = read_value(addresses_config["value_13"]) value_14 = read_value(addresses_config["value_14"]) value_15 = read_value(addresses_config["value_15"]) value_16 = read_value(addresses_config["value_16"]) value_17 = read_value(addresses_config["value_17"]) value_18 = read_value(addresses_config["value_18"]) value_19 = read_value(addresses_config["value_19"]) value_20 = read_value(addresses_config["value_20"]) value_21 = read_value(addresses_config["value_21"]) value_22 = read_value(addresses_config["value_22"]) value_23 = read_value(addresses_config["value_23"]) except Exception as e: print(f"Błąd odczytu pamięci: {e}") # Funkcja do odczytu pamięci co 150 ms def continuous_read(): while True: read_memory() time.sleep(0.15) # 150 ms # Endpoint Flask do przesyłania danych @app.route('/api/receive_data', methods=['GET']) def get_data(): # Zwrócenie danych w formacie JSON return jsonify({ "value_1": round(value_1 or 0, 2), "value_2": round(value_2 or 0, 2), "value_3": round(value_3 or 0, 2), "value_4": round(value_4 or 0, 2), "value_5": round(value_5 or 0, 2), "value_6": round(value_6 or 0, 2), "value_7": round(value_7 or 0, 2), "value_8": round(value_8 or 0, 2), "value_9": int(value_9 or 0), "value_10": int(value_10 or 0), "value_11": int(value_11 or 0), "value_12": int(value_12 or 0), "value_13": int(value_13 or 0), "value_14": int(value_14 or 0), "value_15": int(value_15 or 0), "value_16": int(value_16 or 0), "value_17": int(value_17 or 0), "value_18": int(value_18 or 0), "value_19": int(value_19 or 0), "value_20": int(value_20 or 0), "value_21": int(value_21 or 0), "value_22": round(value_8 or 0, 2), "value_23": int(value_23 or 0), }) # GUI za pomocą tkinter def create_gui(): root = tk.Tk() root.title("EU07 API - Stan manometrów i lampek") root.geometry("500x700") # Pola dla wyników fields = [tk.StringVar(value="---") for _ in range(23)] labels = [] # Listy nazw dla każdego pola names = ["1. Woltomierz WN sieci trakcyjnej","2. Amperomierz WN2 ","3. Amperomierz WN1 ", "4. Woltomierz NN", "5. Amperomierz NN", "6. Manometr cylindrów hamulcowych", "7. Manometr przewodu głównego","8. Manometr zbiornika głównego","9. Przek.nadmiar.sprężarek", "10. Przek.nadmiar.wentylatorów", "11. Załączony wyłącznik szybki", "12. Przek.nadmiar.silników trakcyjnych", "13. Przek.Różnicowy", "14. Przek.nadmiar.przetw.i ogrzewania.", "15. Styczniki liniowe", "16. Poślizg", "17. Sygnał wys.rozruchu", "18. Jazda na oporach", "19. Ogrzewanie pociągu", "20. Czuwak aktywny", "21. Samoczynne hamowanie pociągu", "22. Aktualna prędkość", "23. Pole testowe"] # etykiety i pól tekstowych for i, (field, name) in enumerate(zip(fields, names)): label = ttk.Label(root, text=name, font=("Arial", 10)) label.grid(row=i, column=0, sticky="w", padx=10, pady=5) labels.append(label) value_label = ttk.Label(root, textvariable=field, font=("Arial", 10), width=30, relief="sunken") value_label.grid(row=i, column=1, padx=10, pady=5) # Funkcja do formatowania wartości def format_value(value, is_float): if value is None: return "Brak danych" if is_float: # Zaokrąglenie przed formatowaniem do dwóch miejsc po przecinku value = round(value, 2) return f"{value:.2f}" # Zwrócenie wartości z dwoma miejscami po przecinku return str(value) # Zwróć wartość całkowitą # Aktualizacja GUI def interpret_light_status(value): if value == 1: return "1 - Zapalona" elif value == 0: return "0 - Zgaszona" else: return "Stan nieznany" def update_gui(): while True: fields[0].set(f"{'Połączono' if value_1 is not None else 'Brak połączenia'}: {format_value(value_1, True)}") fields[1].set(f"{'Połączono' if value_2 is not None else 'Brak połączenia'}: {format_value(value_2, True)}") fields[2].set(f"{'Połączono' if value_3 is not None else 'Brak połączenia'}: {format_value(value_3, True)}") fields[3].set(f"{'Połączono' if value_4 is not None else 'Brak połączenia'}: {format_value(value_4, True)}") fields[4].set(f"{'Połączono' if value_5 is not None else 'Brak połączenia'}: {format_value(value_5, True)}") fields[5].set(f"{'Połączono' if value_6 is not None else 'Brak połączenia'}: {format_value(value_6, True)}") fields[6].set(f"{'Połączono' if value_7 is not None else 'Brak połączenia'}: {format_value(value_7, True)}") fields[7].set(f"{'Połączono' if value_8 is not None else 'Brak połączenia'}: {format_value(value_8, True)}") fields[8].set(f"{'Połączono' if value_9 is not None else 'Brak połączenia'}: {format_value(value_9, True)}") fields[9].set(f"{'Połączono' if value_10 is not None else 'Brak połączenia'}: {format_value(value_10, True)}") fields[10].set(f"{'Połączono' if value_11 is not None else 'Brak połączenia'}: {format_value(value_11, True)}") fields[11].set(f"{'Połączono' if value_12 is not None else 'Brak połączenia'}: {format_value(value_12, True)}") fields[12].set(f"{'Połączono' if value_13 is not None else 'Brak połączenia'}: {format_value(value_13, True)}") fields[13].set(f"{'Połączono' if value_14 is not None else 'Brak połączenia'}: {interpret_light_status(value_14)}") fields[14].set(f"{'Połączono' if value_15 is not None else 'Brak połączenia'}: {format_value(value_15, True)}") fields[15].set(f"{'Połączono' if value_16 is not None else 'Brak połączenia'}: {format_value(value_16, True)}") fields[16].set(f"{'Połączono' if value_17 is not None else 'Brak połączenia'}: {interpret_light_status(value_17)}") fields[17].set(f"{'Połączono' if value_18 is not None else 'Brak połączenia'}: {format_value(value_18, False)}") fields[18].set(f"{'Połączono' if value_19 is not None else 'Brak połączenia'}: {interpret_light_status(value_19)}") fields[19].set(f"{'Połączono' if value_20 is not None else 'Brak połączenia'}: {format_value(value_20, True)}") fields[20].set(f"{'Połączono' if value_21 is not None else 'Brak połączenia'}: {format_value(value_21, True)}") fields[21].set(f"{'Połączono' if value_22 is not None else 'Brak połączenia'}: {format_value(value_22, True)}") fields[22].set(f"{'Połączono' if value_23 is not None else 'Brak połączenia'}: {format_value(value_23, True)}") time.sleep(0.5) Thread(target=update_gui, daemon=True).start() root.mainloop() # Funkcja do uruchomienia serwera Flask def run_flask(): app.run(host="0.0.0.0", port=5000, debug=False) if __name__ == "__main__": # Uruchomienie odczytu pamięci w osobnym wątku read_thread = Thread(target=continuous_read, daemon=True) read_thread.start() # Uruchomienie serwera Flask w osobnym wątku flask_thread = Thread(target=run_flask, daemon=True) flask_thread.start() # Uruchomienie interfejsu GUI try: create_gui() except KeyboardInterrupt: print("Program został przerwany przez użytkownika.")
Leave a Comment