Untitled

 avatar
unknown
python
22 days ago
16 kB
16
Indexable
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