minecraft吧 关注:2,568,787贴子:32,084,099

回复:我的世界启动器制作教程

只看楼主收藏回复

下面上修改的Launcher.cs代码:
using System;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;
using System.Collections.Generic;
namespace JuicyLauncher
{
class LauncherReturn//返回的公共类
{
public String rtv;//子值,返回字符串
public String[] rtvs;//子值,返回字符串数组,在正版登陆时有用
public List<string> DUList = new List<string>();//子值,返回下载列表
}
class Launcher
{
private List<string> URLList = new List<string>();//声明总列表
/// <summary>
/// 启动主方法
/// </summary>
/// <param name="MaxMem">最大内存</param>
/// <param name="JavaPath">Javaw.exe路径</param>
/// <param name="UserName">用户名</param>
/// <param name="VerName">版本名</param>
/// <param name="returnvalue">返回值的指定。0为不返回,直接执行;1为返回库的完整字符串;2为返回完整的启动命令。默认为0。</param>
/// <param name="dc">指示是否下载文件。</param>
public LauncherReturn Launch(string MaxMem, string JavaPath, string UserName, string VerName, int returnvalue = 0, bool dc = false)
{
string rtxt = "";//声明
int tmp = 0;//声明
rtxt = File.ReadAllText(Application.StartupPath + "\\.minecraft\\versions\\" + VerName + "\\" + VerName + ".json").Replace(" ", "").Replace("\n", "");//读取内容
tmp = rtxt.IndexOf("mainClass") + "mainClass".Length + 3;//取名称起始位置并赋值到tmp
String mainClass = rtxt.Substring(tmp, rtxt.IndexOf("\"", tmp) - tmp);//截取值
tmp = rtxt.IndexOf("minecraftArguments") + "minecraftArguments".Length + 3;//json读取部分,同上
String minecraftArguments = rtxt.Substring(tmp, rtxt.IndexOf("\"", tmp) - tmp).Replace("${", " ${").Replace("}", "} ").Replace("cpw", " cpw");//json读取部分,同上
tmp = rtxt.IndexOf("libraries") + "libraries".Length + 3;//json读取部分,同上
String libraries = rtxt.Substring(tmp + 1, rtxt.LastIndexOf("]") - tmp);//json读取部分,同上
String natives = Application.StartupPath + "\\.minecraft\\versions\\" + VerName + "\\" + VerName + "-natives";//设置natives路径
if (!Directory.Exists(natives))//目录不存在
{
Directory.CreateDirectory(natives);//创建
}
String[] libs = libraries.Replace("${arch}", "32").Replace("},{", "^").Split("^".ToCharArray());//将},{替换为^然后以^进行分割,顺便决定32位系统
String libp = "";//声明libp
for (int i = 0; i < libs.Length; i++)//为数组内容循环,也可以考虑foreach
{
if (libs[i].IndexOf("name") == -1)//如果没有name值
{
continue;//跳过
}
String tml = libs[i];//声明临时字符串变量tml
if (tml.IndexOf("{") != -1)//如果含有子json对象,则去掉子项
{
do//循环
{
try//捕获错误
{
tml = tml.Replace(tml.Substring(tml.LastIndexOf("{") - 1, tml.IndexOf("}", tml.LastIndexOf("{")) - tml.LastIndexOf("{") + 1), "");//去掉子项
}
catch (ArgumentOutOfRangeException)//如果是干扰的
{
tml = tml + "," + libs[i + 1];//追加
tml = tml.Replace(tml.Substring(tml.LastIndexOf("{") - 1, tml.IndexOf("}", tml.LastIndexOf("{")) - tml.LastIndexOf("{") + 1), "");//再去掉子项
}
} while (tml.IndexOf("{") != -1);//有子项则仍然循环
tml = tml.Replace("{", "").Replace("}", "");//去掉干扰的{}
}
tmp = tml.IndexOf("name") + "name".Length + 3;//json读取部分,同上
String libn = tml.Substring(tmp, tml.IndexOf("\"", tmp) - tmp);//json读取部分,同上
if (libn.IndexOf(":") == -1)//如果name的值不合法
{
continue;//跳过
}
String[] tlib = new String[] { libn.Substring(0, libn.IndexOf(":")).Replace(":", ""), libn.Substring(libn.IndexOf(":") + 1, libn.IndexOf(":", libn.IndexOf(":") + 1) - libn.IndexOf(":")).Replace(":", ""), libn.Substring(libn.IndexOf(":", libn.IndexOf(":") + 1)).Replace(":", "") };//将读取的name值转成路径
String tpath = Application.StartupPath + "\\.minecraft\\libraries\\" + tlib[0].Replace(".", "\\") + "\\" + tlib[1] + "\\" + tlib[2] + "\\" + tlib[1] + "-" + tlib[2] + ".jar";//同上
if (libs[i].IndexOf("natives") != -1 && libs[i].IndexOf("windows") != -1)//如果有natives指定
{
tmp = libs[i].IndexOf("windows") + "windows".Length + 3;//json读取部分,同上
tpath = tpath.Replace(".jar", "") + "-" + libs[i].Substring(tmp, libs[i].IndexOf("\"", tmp) - tmp) + ".jar";//json读取部分,同上
}
if (File.Exists(tpath))//检查文件是否存在
{
libp = libp + tpath + ";";//存在就加录
}
else//如果不存在
{
if (libs[i].IndexOf("url") == -1)//判断是否存在url
{//不存在


260楼2016-07-11 16:13
回复
    URLList.Add("htt删ps:/掉/libraries.中minecraft.n文et" + tpath.Replace(Application.StartupPath + "\\.minecraft\\libraries", "").Replace("\\", "/") + ":::" + tpath);//加入到下载列表
    }
    else//存在
    {
    tmp = libs[i].IndexOf("url") + "url".Length + 3;//json读取部分,同上
    String du = libs[i].Substring(tmp, libs[i].IndexOf("\"", tmp) - tmp);//读取到url
    if (du == "ht删tp://fi掉les.minecraft中forge.n文et/maven/")//如果是forge的
    {
    String tmpp = tpath;//声明临时url
    if (tpath.IndexOf(@"net\minecraftforge\forge\") != -1)//如果是forge主文件
    {
    tmpp = tpath.Replace(".jar", "") + "-universal.jar";//加上universal后缀
    }
    URLList.Add(du.Substring(0, du.Length - 1) + tmpp.Replace(Application.StartupPath + "\\.minecraft\\libraries", "").Replace("\\", "/") + ":::" + tpath);//加入到下载列表
    }
    else//不是Forge的
    {
    URLList.Add("ht删tps://libr掉aries.mine中craft.n文et" + tpath.Replace(Application.StartupPath + "\\.minecraft\\libraries", "").Replace("\\", "/") + ":::" + tpath);//加入到下载列表
    }
    }


    261楼2016-07-11 16:15
    回复
      2026-01-14 08:14:34
      广告
      不感兴趣
      开通SVIP免广告
      }
      if (libs[i].IndexOf("extract") != -1)//如果要提取natives
      {
      decompress(tpath, natives);//提取
      }
      }
      String oldVerName = VerName;//转储版本号
      String recallar = MaxMem + ",%,%," + JavaPath + ",%,%," + UserName + ",%,%," + oldVerName;
      if (rtxt.IndexOf("inheritsFrom\":") != -1)//如果是继承的json数据
      {
      tmp = rtxt.IndexOf("inheritsFrom\":") + "inheritsFrom".Length + 3;//json读取部分,同上
      String newVerName = rtxt.Substring(tmp, rtxt.IndexOf("\"", tmp) - tmp);//json读取部分,同上
      libp += Launch("", "", "", newVerName, 1).rtv;//读入父json数据生成的库,解压父json数据要求的natives
      tmp = rtxt.IndexOf("jar\":") + "jar".Length + 3;//json读取部分,同上
      VerName = newVerName;//转储
      natives = Application.StartupPath + "\\.minecraft\\versions\\" + newVerName + "\\" + newVerName + "-natives";//重新指定natives文件夹
      }
      String assets = Application.StartupPath + "\\.minecraft\\assets";//设置资源文件夹路径
      if (rtxt.IndexOf("assetIndex\":") != -1)
      {
      tmp = rtxt.IndexOf("assetIndex\":") + "assetIndex".Length + 3;//json读取部分,同上
      String ajrurl = rtxt.Substring(tmp, rtxt.IndexOf("}", tmp) - tmp);//json读取部分,同上
      tmp = ajrurl.IndexOf("url\":") + "url".Length + 3;//json读取部分,同上
      String ajurl = ajrurl.Substring(tmp, ajrurl.IndexOf("\"", tmp) - tmp);//json读取部分,同上
      tmp = ajrurl.IndexOf("id\":") + "id".Length + 3;//json读取部分,同上
      String ai = ajrurl.Substring(tmp, ajrurl.IndexOf("\"", tmp) - tmp);//json读取部分,同上
      if (dealWithAssets(ai, ajurl, 1).rtv == "资源文件不完整!" & dc == false)//如果资源不完整且尚未执行下载
      {
      if (MessageBox.Show("资源文件不完整,是否补全?", "提示", MessageBoxButtons.YesNo) == DialogResult.Yes)//弹窗提示用户
      {//如果用户选择“是”
      dealWithAssets(ai, ajurl);//添加要下载的资源文件
      }
      }
      if (dealWithAssets(ai, ajurl, 1).rtv == "资源文件完整!" & File.ReadAllText(Application.StartupPath + "\\.minecraft\\assets\\indexes\\" + ai + ".json").Replace(" ", "").IndexOf("\"virtual\":true") != -1)//如果json文件要求virtual为真
      {
      if (Directory.Exists(Application.StartupPath + "\\.minecraft\\assets\\virtual\\" + ai) == false)//虚拟文件夹不存在
      {
      Directory.CreateDirectory(Application.StartupPath + "\\.minecraft\\assets\\virtual\\" + ai);//为游戏创建虚拟文件夹
      dealWithAssets(ai, ajurl, 2);//执行复制操作
      }
      assets = Application.StartupPath + "\\.minecraft\\assets\\virtual\\" + ai;//重设资源文件夹路径
      }
      }
      if (returnvalue == 1)//如果要返回库路径
      {
      LauncherReturn lr = new LauncherReturn();
      lr.rtv = libp;
      return lr;//返回并退出方法
      }
      if (URLList.Count != 0 && dc == false)//如果下载列表不为空且尚未执行下载
      {
      ShowDownload sd = new ShowDownload();//引用下载进度窗体到实例
      sd.Show();//显示该窗体
      sd.DownloadBL(URLList, recallar);//调用窗体中的下载方法并传参,但使用的是原版本号
      return null;//返回空值
      }
      libp = libp + Application.StartupPath + "\\.minecraft\\versions\\" + VerName + "\\" + VerName + ".jar";//整合字符串
      tmp = rtxt.IndexOf("assets\":") + "assets".Length + 3;//json读取部分,同上
      String assetIndex = rtxt.Substring(tmp, rtxt.IndexOf("\"", tmp) - tmp);//json读取部分,同上
      String gameDir = Application.StartupPath + "\\.minecraft";//设置游戏路径
      if (Application.StartupPath.IndexOf(" ") != -1)//如果路径有空格
      {
      natives = "\"" + natives + "\"";//加上引号
      libp = "\"" + libp + "\"";//加上引号
      assets = "\"" + assets + "\"";//加上引号
      gameDir = "\"" + gameDir + "\"";//加上引号
      }
      minecraftArguments = minecraftArguments.Replace("${auth_player_name}", UserName).Replace("${version_name}", "JuicyLauncher_1.0").Replace("${game_directory}", gameDir).Replace("${game_assets}", assets).Replace("${assets_root}", assets).Replace("${assets_index_name}", assetIndex).Replace("${user_properties}", "{}").Replace("${user_type}", "Legacy");//读取额外参数
      //启动参数拼接
      String RunComm = "";//声明RunComm
      RunComm = "-Xmx" + MaxMem + "m -Djava.library.path=" + natives + " -Dfml.ignoreInvalidMinecraftCertificates=true -Dfml.ignorePatchDiscrepancies=true -cp " + libp + " " + mainClass + " " + minecraftArguments;//拼接参数
      if (returnvalue == 2)//如果要返回完整的启动命令
      {
      LauncherReturn lr = new LauncherReturn();
      lr.rtv = RunComm;
      return lr;//返回并退出
      }
      Process mjp = new Process();//运行部分
      ProcessStartInfo psi = new ProcessStartInfo(JavaPath, RunComm);//运行部分
      psi.UseShellExecute = false;//运行部分
      mjp.StartInfo = psi;//运行部分
      mjp.Start();//运行部分
      Application.Exit();//退出
      return null;//最终返回空值
      }
      (此处省略decompress方法)


      262楼2016-07-11 16:16
      回复
        public LauncherReturn dealWithAssets(String AssetIndex, String JSONDownloadURL, int dealWay = 0)//声明资源文件处理公共函数过程
        {
        LauncherReturn lr = new LauncherReturn();//声明返回值
        String asset_JSON = Application.StartupPath + "\\.minecraft\\assets\\indexes\\" + AssetIndex + ".json";//准备json文件路径
        if (File.Exists(asset_JSON) == false && SystemInformation.Network == true)//如果数据文件不存在且连接到网络
        {
        new System.Net.WebClient().DownloadFile(JSONDownloadURL, asset_JSON);//下载数据资源文件
        do//反复等待
        {
        System.Threading.Thread.Sleep(10);//等待10毫秒
        } while (!File.Exists(asset_JSON));//直到数据文件下载完成
        }
        string rtxt = "";//声明
        int tmp = 0;//声明
        rtxt = File.ReadAllText(asset_JSON).Replace(" ", "");//读取内容
        tmp = rtxt.IndexOf("objects") + "objects".Length + 3;//读取objects数组数据
        String objects_S = rtxt.Substring(tmp, rtxt.LastIndexOf("}", rtxt.Length - 1) - tmp);//同上
        String[] objects = objects_S.Replace("},", "$").Split("$".ToCharArray());//分割数组
        String tmu = "";//声明并初始化tmu
        switch (dealWay)//判断处理方式
        {
        case 0://为零
        foreach (string oi in objects)//为每个项循环
        {
        tmp = oi.IndexOf("hash") + "hash".Length + 3;//读取hash值
        tmu = oi.Substring(tmp, oi.IndexOf("\"", tmp) - tmp);//同上
        tmu = Application.StartupPath + "\\.minecraft\\assets\\objects\\" + tmu.Substring(0, 2) + "\\" + tmu;//生成完整路径
        tmp = oi.IndexOf("size") + "size".Length + 2;//读取文件大小
        if ((!File.Exists(tmu)) || new FileInfo(tmu).Length < int.Parse(oi.Substring(tmp, oi.IndexOf("\n", tmp) - tmp)))//如果发现文件不完整
        {
        URLList.Add(tmu.Replace(Application.StartupPath + "\\.minecraft\\assets\\objects\\", "ht删tp://reso掉urces.download中.minecraft.n文et/").Replace("\\", "/") + ":::" + tmu);//添加下载地址到列表备用
        }
        }
        lr.rtv = "下载完成!";//返回
        return lr;//返回
        case 1:
        foreach (string oi in objects)//为每个项循环
        {
        tmp = oi.IndexOf("hash") + "hash".Length + 3;//读取hash值
        tmu = oi.Substring(tmp, oi.IndexOf("\"", tmp) - tmp);//同上
        tmu = Application.StartupPath + "\\.minecraft\\assets\\objects\\" + tmu.Substring(0, 2) + "\\" + tmu;//生成完整路径
        tmp = oi.IndexOf("size") + "size".Length + 2;//读取文件大小
        if ((!File.Exists(tmu)) || new FileInfo(tmu).Length < int.Parse(oi.Substring(tmp, oi.IndexOf("\n", tmp) - tmp)))//如果发现文件不完整
        {
        lr.rtv = "资源文件不完整!";//返回
        return lr;//返回
        }
        }
        lr.rtv = "资源文件完整!";//返回
        return lr;//返回
        case 2:
        foreach (string oi in objects)//为每个项循环
        {
        tmp = oi.IndexOf("hash") + "hash".Length + 3;//读取hash值
        tmu = oi.Substring(tmp, oi.IndexOf("\"", tmp) - tmp);//同上
        tmu = Application.StartupPath + "\\.minecraft\\assets\\objects\\" + tmu.Substring(0, 2) + "\\" + tmu;//生成完整路径
        String fp = Application.StartupPath + "\\.minecraft\\assets\\virtual\\" + AssetIndex + "\\" + oi.Substring(2, oi.IndexOf("\"", 2) - 2).Replace("/", "\\");//生成目标文件完整路径
        if (!Directory.Exists(fp.Replace(Path.GetFileName(fp), "")))//如果目标文件所在文件夹不存在
        {
        Directory.CreateDirectory(fp.Replace(Path.GetFileName(fp), ""));//创建
        }
        File.Copy(tmu, fp);//复制文件
        }
        return lr;//返回
        }
        return null;//返回空值
        }
        }
        }


        263楼2016-07-11 16:18
        回复
          棒棒哒!


          IP属地:河南264楼2016-07-11 16:19
          回复
            效果图:


            265楼2016-07-11 16:22
            回复
              进阶七:纯净版json和jar主文件的下载


              267楼2016-07-11 16:43
              回复
                https://www.github.com
                以后吧代码放在这里吧,贴吧没有代码缩进和高亮感觉很别扭。


                268楼2016-07-11 19:02
                收起回复
                  2026-01-14 08:08:34
                  广告
                  不感兴趣
                  开通SVIP免广告
                  纯净版json和jar主文件下载的工作原理就是下载并解析https://launchermeta.mojang.com/mc/game/version_manifest.json这个文件,然后下载文件中给出的对应版本下载地址。


                  269楼2016-07-12 16:52
                  回复
                    内容如下:{"latest":{"snapshot":"1.10.2","release":"1.10.2"},"versions":[{"id":"1.10.2","type":"release","time":"2016-06-23T09:45:47+00:00","releaseTime":"2016-06-23T09:17:32+00:00","url":"https://launchermeta.mojang.com/mc/game/1920a2b4e996bae0af1a67d38d63706bac10ac47/1.10.2.json"},{"id":"1.10.1","type":"release","time":"2016-06-22T10:14:48+00:00","releaseTime":"2016-06-22T10:13:22+00:00","url":"https://launchermeta.mojang.com/mc/game/62653674ee595442f842934eb57078b7aa8d0742/1.10.1.json"},{"id":"1.10","type":"release","time":"2016-06-20T15:31:06+00:00","releaseTime":"2016-06-08T13:06:18+00:00","url":"https://launchermeta.mojang.com/mc/game/281697b6f88d757066b5f0427b40ffabc50e79b9/1.10.json"},{"id":"1.10-pre2","type":"snapshot","time":"2016-06-15T13:36:22+00:00","releaseTime":"2016-06-07T14:56:34+00:00","url":"https://launchermeta.mojang.com/mc/game/53b005912a758e30d94eaff7676a84005ae1ea1b/1.10-pre2.json"},{"id":"1.10-pre1","type":"snapshot","time":"2016-06-08T13:48:15+00:00","releaseTime":"2016-06-02T14:45:16+00:00","url":"https://launchermeta.mojang.com/mc/game/11795dfbb4715f345a5a99cd8e7278161bd4c306/1.10-pre1.json"},{"id":"16w21b","type":"snapshot","time":"2016-06-01T11:45:48+00:00","releaseTime":"2016-05-26T12:47:22+00:00","url":"https://launchermeta.mojang.com/mc/game/746adc2f6244d1f4ea5f654ebb4038c56b7ce503/16w21b.json"},{"id":"16w20a","type":"snapshot","time":"2016-06-01T11:45:48+00:00","releaseTime":"2016-05-18T12:45:14+00:00","url":"https://launchermeta.mojang.com/mc/game/36e5b5b5516089a314cee1fa6165cc1e075416b1/16w20a.json"},{"id":"1.9.4","type":"release","time":"2016-06-01T11:45:48+00:00","releaseTime":"2016-05-10T10:17:16+00:00","url":"https://launchermeta.mojang.com/mc/game/cdcd308b7cbd15bc595850ce6557d4ade48cee7a/1.9.4.json"},{"id":"1.9.3","type":"release","time":"2016-06-01T11:45:48+00:00","releaseTime":"2016-05-10T08:33:35+00:00","url":"https://launchermeta.mojang.com/mc/game/566def4133157888f4b2d1832951d78ebd328840/1.9.3.json"},{"id":"16w15b","type":"snapshot","time":"2016-06-01T11:45:48+00:00","releaseTime":"2016-04-13T13:56:41+00:00","url":"https://launchermeta.mojang.com/mc/game/5d3c577c06255bec1a3577d00d441368e2cd5c1d/16w15b.json"},{"id":"16w14a","type":"snapshot","time":"2016-06-01T11:45:48+00:00","releaseTime":"2016-04-07T12:47:51+00:00","url":"https://launchermeta.mojang.com/mc/game/1d94fd994824c4b24453d28bc04e04d7e4c70730/16w14a.json"}(此处省略)]}


                    270楼2016-07-12 16:54
                    回复
                      可以看得出楼主真的十分用心,所有代码都贴出来而且还配上了注释。


                      IP属地:浙江来自Android客户端271楼2016-07-12 19:40
                      回复
                        问一下楼主这些知识都是哪里学来的呢


                        IP属地:浙江来自Android客户端272楼2016-07-12 19:40
                        收起回复
                          我们在“设置“窗体中添加一个listBox和两个按钮,分别修改它们的Text属性。添加顺序是先添加“下载”按钮再添加“获取纯净版列表”按钮。


                          273楼2016-07-12 20:40
                          回复
                            我们双击“下载”按钮,键入代码到private void button3_Click(object sender, EventArgs e):


                            279楼2016-07-12 20:47
                            回复
                              2026-01-14 08:02:34
                              广告
                              不感兴趣
                              开通SVIP免广告
                              if (listBox1.SelectedIndex == -1)//如果用户没选
                              {
                              return;//返回
                              }


                              280楼2016-07-12 20:47
                              回复