C# 使用WinForm写的一个魔兽世界单机版T端修改Boss掉落数量的小工具

发布时间 2023-10-19 10:26:57作者: WmW

单机版的掉落机制比较复杂,一般大家修改掉落数量都是简单粗暴的把所有分组取消但是这样就完全依赖掉率了

我之前研究了一段时间的T端掉落,写了个小工具,具体的原理就是增加掉落分组的数量,实际使用时发现除了部分掉落套装的箱子外,基本都起作用了

源码如下

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace LootChange {
    public partial class MainForm : Form {
        string connString;
        public MainForm() {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e) {
            TxtMsg.AppendText("1.执行操作前请做好数据备份,避免数据损坏" + Environment.NewLine);
            TxtMsg.AppendText("2.执行操作可能很慢并且界面卡住,请耐心等待" + Environment.NewLine);
            TxtMsg.AppendText("3.每次只能执行一次操作,再次执行需要重启程序" + Environment.NewLine);
            TxtMsg.AppendText("4.每成功执行一次,掉落数量翻一倍" + Environment.NewLine);
        }

        private void BtnOK_Click(object sender, EventArgs e) {
            if (txtPid.Text == "" || txtPwd.Text == "") {
                MessageBox.Show("请输入必要信息!");
                return;
            }
            connString = $"Database=world;Data Source=127.0.0.1;User Id={txtPid.Text};Password={txtPwd.Text};port=3306;SslMode=None";
            txtPid.Enabled = false;
            txtPwd.Enabled = false;
            btnOK.Enabled = false;
            Task.Run(ProgressAsync);
        }
        /// <summary>
        /// 异步执行操作,避免业务逻辑导致界面卡死
        /// </summary>
        void ProgressAsync() {
            string tableNames = "creature_loot_template,item_loot_template,reference_loot_template"; //3个掉落相关的表
            try {
                HashSet<int> items = GetItems(connString);
                ShowMsg("查询物品" + items.Count);
                foreach (var tableName in tableNames.Split(',')) {
                    try {
                        var dict = GetAllGroup(tableName);
                        ShowMsg($"{tableName} 查询分组信息" + dict.Count);
                        ShowMsg($"{tableName} 更新分组完毕,执行" + UpdateGroupid(tableName, dict, items));
                    } catch (Exception ex) {
                        MessageBox.Show($"tableName表更新异常:{ex.Message}");
                        break;
                    }
                }
                MessageBox.Show("执行成功!");
            } catch (Exception ex) {
                MessageBox.Show("失败!" + ex.Message);
            }
        }
        /// <summary>
        /// 得到允许调整的item集合,避免不必要的调整
        /// </summary>
        HashSet<int> GetItems(string connString) {
            HashSet<int> hs = new HashSet<int>();
            var sql = "select entry from item_template where class in (2,4) and Quality>=3;"; //现在武器装备以及皮质大于绿色,避免出现大量垃圾物品
            using (var dr = new MySqlDBHelper(connString).GetDataReader(sql)) {
                while (dr.Read()) {
                    hs.Add(Convert.ToInt32(dr["entry"]));
                }
            }
            return hs;
        }
        /// <summary>
        /// 得到掉落信息
        /// </summary>
        Dictionary<int, List<Model>> GetAllGroup(string tableName) {
            Dictionary<int, List<Model>> dict_entry_loots = new Dictionary<int, List<Model>>();
            string sql = $"select entry,item,groupid,mincountOrRef from {tableName} where groupid>0;";
            using (var dr = new MySqlDBHelper(connString).GetDataReader(sql)) {
                while (dr.Read()) {
                    int entry = Convert.ToInt32(dr["entry"]); //以掉落id为键
                    if (!dict_entry_loots.TryGetValue(entry, out List<Model> list)) {
                        list = new List<Model>();
                        dict_entry_loots.Add(entry, list);
                    }
                    list.Add(new Model() {
                        entry = entry,
                        item = Convert.ToInt32(dr["item"]),
                        groupId = Convert.ToInt32(dr["groupid"]),
                        mincountOrRef = Convert.ToInt32(dr["mincountOrRef"]),
                    });
                }
            }
            return dict_entry_loots;
        }
        /// <summary>
        /// 更新分组
        /// </summary>
        int UpdateGroupid(string tableName, Dictionary<int, List<Model>> dict, HashSet<int> items) {
            StringBuilder sql = new StringBuilder();
            sql.Append("start transaction;");
            int counter = 0;
            foreach (var kv in dict) { //循环每个掉落
                Dictionary<int, List<Model>> kv_groupId_loots = new Dictionary<int, List<Model>>();  //记录分组
                foreach (var p in kv.Value) {
                    if (!kv_groupId_loots.TryGetValue(p.groupId, out List<Model> list)) {
                        list = new List<Model>();
                        kv_groupId_loots.Add(p.groupId, list); //记录所有分组,避免分组id冲突
                    }
                    if (p.mincountOrRef > 0 && items.Contains(p.item)) { //但是只保存符合条件的,即不是引用列且物品符合条件
                        list.Add(p);
                    }
                }
                int groupId = kv_groupId_loots.Keys.Max() + 1; //新编groupId的值  
                foreach (var loots in kv_groupId_loots.Values) { //循环每个组,最多新增一倍的组
                    if (loots.Count > 1) { //如果该组数量大于1
                        foreach (var loot in loots.Skip(loots.Count / 2)) { //就将后一半数据的groupId更新成新的
                            sql.Append($"update {tableName} set groupid={groupId} where entry={loot.entry} and item={loot.item};");
                        }
                        groupId++;
                        counter++;
                    }
                }
            }
            sql.Append("commit;");
            ShowMsg($"{tableName} 新建分组{counter},开始执行sql,字符{sql.Length}");
            Stopwatch sw = new Stopwatch();
            sw.Start();
            int rs = new MySqlDBHelper(connString).ExecuteCommand(sql.ToString(), 300);
            sw.Stop();
            ShowMsg($"{tableName} 执行sql完毕,耗时:{sw.ElapsedMilliseconds / 1000}秒");
            return rs;
        }
        void ShowMsg(string msg) {
            TxtMsg.Invoke((Action)(() => TxtMsg.AppendText(msg + Environment.NewLine)));
        }
    }
}
View Code
namespace LootChange {
    internal class Model {
        public int entry;
        public int item;
        public int groupId;
        public int mincountOrRef;
    }
}
View Code