Factorio Locale File Comparison Tool

Enhance your gameplay with these tools. This category is also the right place for tools useful for modders.
Mod databases, calculators, cheatsheets, multiplayer, scripts, libs and other useful stuff that is not strictly in-game mods.
plexpt
Long Handed Inserter
Long Handed Inserter
Posts: 60
Joined: Mon Feb 07, 2022 2:32 am
Contact:

Factorio Locale File Comparison Tool

Post by plexpt »

Code: Select all

import tkinter as tk
from tkinter import ttk
import re
from tkinterdnd2 import DND_FILES, TkinterDnD
import os


class FactorioConfigComparer(TkinterDnD.Tk):
    def __init__(self):
        super().__init__()

        self.title("Factorio Config Comparer")
        self.geometry("1000x600")

        # 创建主框架
        self.main_frame = ttk.Frame(self)
        self.main_frame.pack(expand=True, fill='both', padx=10, pady=10)

        # 创建左右两栏
        self.create_panels()

        # 创建对比结果区域
        self.create_result_area()

        # 存储当前加载的配置
        self.left_config = None
        self.right_config = None

    def create_panels(self):
        # 创建左右面板容器
        panels_frame = ttk.Frame(self.main_frame)
        panels_frame.pack(expand=True, fill='both')

        # 左面板
        left_frame = ttk.LabelFrame(panels_frame, text="Left Config File")
        left_frame.pack(side='left', expand=True, fill='both', padx=5)

        self.left_text = tk.Text(left_frame, height=10, wrap=tk.WORD)
        self.left_text.pack(expand=True, fill='both', padx=5, pady=5)
        self.left_text.insert('1.0', "Drop .cfg file here")

        # 配置拖放
        self.left_text.drop_target_register(DND_FILES)
        self.left_text.dnd_bind('<<Drop>>', lambda e: self.on_drop(e, 'left'))

        # 右面板
        right_frame = ttk.LabelFrame(panels_frame, text="Right Config File")
        right_frame.pack(side='left', expand=True, fill='both', padx=5)

        self.right_text = tk.Text(right_frame, height=10, wrap=tk.WORD)
        self.right_text.pack(expand=True, fill='both', padx=5, pady=5)
        self.right_text.insert('1.0', "Drop .cfg file here")

        # 配置拖放
        self.right_text.drop_target_register(DND_FILES)
        self.right_text.dnd_bind('<<Drop>>', lambda e: self.on_drop(e, 'right'))

    def create_result_area(self):
        # 创建结果显示区域
        result_frame = ttk.LabelFrame(self.main_frame, text="Comparison Results")
        result_frame.pack(expand=True, fill='both', pady=10)

        # 创建两个子区域用于显示缺失的键
        results_container = ttk.Frame(result_frame)
        results_container.pack(expand=True, fill='both')

        # 左侧缺失的键
        left_missing_frame = ttk.LabelFrame(results_container, text="Keys missing in Left file")
        left_missing_frame.pack(side='left', expand=True, fill='both', padx=5, pady=5)

        self.left_missing_text = tk.Text(left_missing_frame, height=10, wrap=tk.WORD)
        self.left_missing_text.pack(expand=True, fill='both', padx=5, pady=5)

        # 右侧缺失的键
        right_missing_frame = ttk.LabelFrame(results_container, text="Keys missing in Right file")
        right_missing_frame.pack(side='left', expand=True, fill='both', padx=5, pady=5)

        self.right_missing_text = tk.Text(right_missing_frame, height=10, wrap=tk.WORD)
        self.right_missing_text.pack(expand=True, fill='both', padx=5, pady=5)

    def parse_factorio_cfg(self, file_path):
        """解析 Factorio 配置文件,返回键值对字典"""
        config_dict = {}
        current_key = None

        with open(file_path, 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()

                # 跳过空行和注释
                if not line or line.startswith('#') or line.startswith('_'):
                    continue

                # 检查是否是键值对
                if '=' in line:
                    key, value = line.split('=', 1)
                    key = key.strip()
                    value = value.strip()

                    # 去掉值的引号(如果存在)
                    value = value.strip('"').strip("'")

                    config_dict[key] = value

        return config_dict

    def on_drop(self, event, side):
        # 获取拖放的文件路径
        file_path = event.data
        # 移除可能的大括号和引号
        file_path = file_path.strip('{}').strip('"')

        # 检查文件是否存在且是.cfg文件
        if not os.path.exists(file_path) or not file_path.lower().endswith('.cfg'):
            self.show_error("Please drop a valid .cfg file")
            return

        # 读取配置文件
        try:
            config_dict = self.parse_factorio_cfg(file_path)

            # 更新相应的文本框和存储的配置
            if side == 'left':
                self.left_text.delete('1.0', tk.END)
                self.left_text.insert('1.0', f"Loaded: {os.path.basename(file_path)}\n")
                self.left_text.insert(tk.END, f"Found {len(config_dict)} keys")
                self.left_config = config_dict
            else:
                self.right_text.delete('1.0', tk.END)
                self.right_text.insert('1.0', f"Loaded: {os.path.basename(file_path)}\n")
                self.right_text.insert(tk.END, f"Found {len(config_dict)} keys")
                self.right_config = config_dict

            # 如果两个配置文件都已加载,则进行比较
            if self.left_config and self.right_config:
                self.compare_configs()

        except Exception as e:
            self.show_error(f"Error reading config file: {str(e)}")

    def compare_configs(self):
        # 清空结果区域
        self.left_missing_text.delete('1.0', tk.END)
        self.right_missing_text.delete('1.0', tk.END)

        # 获取所有键
        left_keys = set(self.left_config.keys())
        right_keys = set(self.right_config.keys())

        # 找出缺失的键
        missing_in_left = right_keys - left_keys
        missing_in_right = left_keys - right_keys

        # 显示结果
        if missing_in_left:
            for key in sorted(missing_in_left):
                self.left_missing_text.insert(tk.END, f"{key}={self.right_config[key]}\n")
        else:
            self.left_missing_text.insert('1.0', "No missing keys")

        if missing_in_right:
            for key in sorted(missing_in_right):
                self.right_missing_text.insert(tk.END, f"{key}={self.left_config[key]}\n")
        else:
            self.right_missing_text.insert('1.0', "No missing keys")

    def show_error(self, message):
        """显示错误消息"""
        import tkinter.messagebox as messagebox
        messagebox.showerror("Error", message)


if __name__ == "__main__":
    app = FactorioConfigComparer()
    app.mainloop()
Post Reply

Return to “Tools”