2

私は MMORPG プライベート サーバーの開発者であり、手動でダウンロードしなければならないパッチを使用するのは非常に面倒で不便なので、ユーザーのクライアント用のオールインワン アップデーターを作成することを楽しみにしています。

私は C# を初めて使用しますが、独自のインターフェイスと基本的なゲームの開始/オプション ボタンを備えた独自のランチャーを作成し、それを Web サーバーから読み取ることに既に成功しています。

今、私はそのための統合された更新機能を作りたいのですが、かなり迷っています。どこから始めればいいのかわかりません。これは、それがどのように見えるかです、それは単なる概念です

ここに画像の説明を入力

ゲームを開始して更新するために使用されるメインボタンがあり、基本的にプログラムを開くと、ボタンに「UPDATE」と書かれ、無効になり(新しい更新を検索している間)、見つかった場合はクリック可能なボタンに変更すると、更新がダウンロードされた後、「ゲームの開始」に変わります。

全体的な更新の進行状況バーと、ダウンロード中の現在のファイルのみの進行状況を確認するための進行状況バー。パーセンテージやダウンロードする必要があるファイルの量などの基本的な情報がすべて表示されます。

ランチャーが Web サーバー上のファイルを HTTP メソッドでチェックし、クライアントと同じか新しいファイルかをチェックする方法を見つける必要があります。そのため、常に同じバージョンのファイルを再ダウンロードすることはなく、アップデーターがファイルをダウンロードする方法も必要です。圧縮アーカイブとして更新し、ダウンロードが完了すると既存のファイルを自動抽出して上書きします。

注: 更新されるファイルは .exe ではなく、ほとんどが textures/config files/maps/images/etc... です。

4

2 に答える 2

4

このシステムの可能なアーキテクチャをスケッチします。これは不完全です。前半は詳細な疑似 C# コードの形式であり、後半は一連のヒントと提案であると考えてください。

これには 2 つのアプリケーションが必要になると思います。

  • AC# WinForms クライアント。
  • AC# サーバー側アプリケーション、おそらく Web サービス。

この回答ではセキュリティの問題には焦点を当てませんが、明らかに非常に重要です。おそらくSSLを使用して、より高いレベルでセキュリティを実装できると思います。Web サービスは IIS 内で実行され、何らかの形式のセキュリティを実装するには、主に構成の問題が必要です。

特に圧縮が必要ない場合は、サーバー側の部分は厳密には必要ありません。おそらく、 website.com /updaterで HTTP リクエストが行われたときに簡単に解析できるファイルのリストを返すようにサーバーを構成する方法があります。ただし、Web サービスを使用する方がより柔軟であり、おそらく実装がさらに簡単です。まず、この MSDN の記事 を参照してください。圧縮が必要な場合は、個々のファイルを透過的に圧縮するようにサーバーを構成できます。考えられるすべてのバリエーションをスケッチしてみます。

1 つの更新 ZIP ファイルの場合、基本的にアップデータ Web サービスは 2 つの異なる要求に応答できる必要があります。まず、サーバー ディレクトリwebsite.com/updaterに関連するすべてのゲーム ファイルのリストを、それらの最終書き込みタイムスタンプ ( GetUpdateInfo ) と共に返すことができます。メソッド)。クライアントは、このリストをローカル ファイルと比較します。一部のファイルはサーバー上にもう存在しない可能性があり (おそらくクライアントはローカル コピーを削除する必要があります)、一部はクライアント上に存在しない可能性があり (完全に新しいコンテンツです)、その他のファイルはクライアントとサーバーの両方に存在する可能性があります。その場合、クライアントは最終書き込み時刻をチェックして、更新されたバージョンが必要かどうかを判断する必要があります。クライアントは、ゲーム コンテンツ ディレクトリを基準にして、これらのファイルのパスのリストを作成します。ゲーム コンテンツ ディレクトリは、サーバーのwebsite.com/updaterディレクトリをミラーリングする必要があります。

次に、クライアントはこのリストをサーバーに送信します ( Web サービスのGetUpdateURL )。サーバーは更新を含む ZIP を作成し、その URL で応答します。

[ServiceContract]
public interface IUpdater
{
    [OperationContract]
    public FileModified[] GetUpdateInfo();

    [OperationContract]
    public string GetUpdateURL();
}

[DataContract]
public class FileModified
{
    [DataMember]
    public string Path;

    [DataMember]
    public DateTime Modified;
}

public class Updater : IUpdater
{
    public FileModified[] GetUpdateInfo()
    {
        // Get the physical directory
        string updateDir = HostingEnvironment.MapPath("website.com/updater");

        IList<FileModified> updateInfo = new List<FileModified>();

        foreach (string path in Directory.GetFiles(updateDir))
        {
            FileModified fm = new FileModified();
            fm.Path = // You may need to adjust path so that it is local with respect to updateDir
            fm.Modified = new FileInfo(path).LastWriteTime;
            updateInfo.Add(fm);
        }

        return updateInfo.ToArray();
    }

    [OperationContract]
    public string GetUpdateURL(string[] files)
    {
        // You could use System.IO.Compression.ZipArchive and its
        // method CreateEntryFromFile. You create a ZipArchive by
        // calling ZipFile.Open. The name of the file should probably
        // be unique for the update session, to avoid that two concurrent
        // updates from different clients will conflict. You could also
        // cache the ZIP packages you create, in a way that if a future
        // update requires the same exact file you would return the same
        // ZIP.

        // You have to return the URL of the ZIP, not its local path on the
        // server. There may be several ways to do this, and they tend to
        // depend on the server configuration.

        return urlOfTheUpdate;
    }
}

クライアントは、 HttpWebRequestおよびHttpWebResponseオブジェクトを使用して ZIP ファイルをダウンロードします。プログレス バーを更新するには (この設定ではプログレス バーが 1 つしかありません。質問に対する私のコメントを確認してください)、BackgroundWorkerを作成する必要があります。この記事この別の記事では、関連する側面について説明します (残念ながら、この例は VB.NET で書かれていますが、C# の場合と非常によく似ています)。プログレス バーを進めるには、受信したバイト数を追跡​​する必要があります。

int nTotalRead = 0;
HttpWebRequest theRequest;
HttpWebResponse theResponse;

...

byte[] readBytes = new byte[1024];
int bytesRead = theResponse.GetResponseStream.Read(readBytes, 0, 4096);

nTotalRead += bytesread;
int percent = (int)((nTotalRead * 100.0) / length);

ファイルを受け取ったら、System.IO.Compression.ZipArchive.ExtractToDirectoryを使用してゲームを更新できます。

ファイルを .NET で明示的に圧縮したくない場合でも、Web サービスの最初の方法を使用して更新されたファイルのリストを取得し、HttpWebRequest/HttpWebResponseペアを使用して必要なファイルをクライアントにコピーできます。各。このようにして、実際には 2 つのプログレス バーを表示できます。ファイルをカウントするものは、次のようなパーセンテージに単純に設定されます。

int filesPercent = (int)((nCurrentFile * 100.0) / nTotalFiles);

リストを取得する別の方法がある場合は、Web サービスも必要ありません。

ファイルを個別に圧縮したいが、この機能をサーバーによって自動的に実装できない場合は、次のインターフェイスを使用して Web サービスを定義する必要があります。

[ServiceContract]
public interface IUpdater
{
    [OperationContract]
    public FileModified[] GetUpdateInfo();

    [OperationContract]
    public string CompressFileAndGetURL(string path);
}

サーバーに特定のファイルを圧縮し、圧縮された単一ファイルのアーカイブの URL を返すように要求できます。

編集 - 重要

特に更新頻度が非常に高い場合は、タイム ゾーンに特に注意する必要があります。

編集 - 代替案

ここでの主な問題の 1 つは、現在のリリースのファイルのリストをサーバーから取得することです。このファイルには、各ファイルの最終書き込み時刻が含まれている必要があります。Apache のようなサーバーは、そのようなリストを無料で提供できますが、通常は人間が使用することを目的としていますが、それでもプログラムで簡単に解析できます。そのリストをさらにマシンフレンドリーな方法でフォーマットするには、何らかのスクリプト/拡張機能が必要だと確信しています。

そのリストを取得する別の方法があります。サーバー上に、すべてのゲーム コンテンツファイルの最終書き込み時刻、またはプログレッシブ リリース番号を格納するテキスト ファイルを配置することもできます。日付ではなくリリース番号を比較して、必要なファイルを確認します。これにより、タイムゾーンの問題から身を守ることができます. ただし、この場合、ファイルにはリリース番号のようなものはなく、名前と一連の日付しかないため、このリストのローカル コピーを維持する必要があります。

于 2013-02-15T05:06:00.983 に答える
1

これは広範かつ多様な質問であり、さまざまな実装要件に応じて「正しい」と言える答えがいくつかあります。ここにいくつかのアイデアがあります...

  1. 私のアプローチはSystem.Security.Cryptography.SHA1、各ゲーム アセットのハッシュ コードのリストを生成するために使用することです。その後、アップデーターはリストをダウンロードし、それをローカル ファイル システムと比較し (効率のためにローカルで生成されたハッシュをキャッシュします)、ダウンロードする新しい/変更されたファイルのリストを作成します。

  2. ゲーム データがアーカイブを使用している場合、内部の小さなファイルが 1 つだけ変更されている可能性がある場合に巨大なアーカイブをダウンロードしたくないため、プロセスはもう少し複雑になります。この場合、アーカイブ内の各ファイルをハッシュし、含まれているファイルをダウンロードする方法を提供してから、サーバーからダウンロードしたファイルを使用してアーカイブを更新します。

  3. 最後に、Binary Diff/Patch アルゴリズムを使用して、可能な場合はより小さいパッチ ファイルをダウンロードして帯域幅の要件を減らすことを検討してください。この場合、クライアントはファイルの現在のバージョンから最新バージョンに更新するパッチを要求し、ローカル ファイルのハッシュを送信して、サーバーが送信するパッチを認識できるようにします。これには、パッチを適用できるようにしたい以前のバージョンごとにサーバー上にパッチのスタックを維持する必要があり、これはあなたが興味を持っている以上のものかもしれません.

関連する可能性のあるリンクを次に示します。

  • SHA1 クラス- SHA1 ハッシュ クラスに関する Microsoft ドキュメント
  • SevenZipSharp - C# で 7Zip を使用する
  • bsdiff.net - bsdiff を実装する .NET ライブラリ

ああ、マルチパート ダウンローダーを使用して、クライアント エンドで利用可能な帯域幅をより適切に飽和させることを検討してください。これにより、サーバーの負荷が高くなりますが、クライアント側のエクスペリエンスが大幅に向上します。

于 2013-02-15T03:54:39.410 に答える