Terraria:またはゲームを正しく書く





こんにちは、habrapuser様!



誰もが少なくとも一度はTerrariaのような素晴らしいおもちゃをプレイしたことを願っています。なぜなら、今日はそれについて、そしてセキュリティの観点からゲームを書く価値がない方法について話すからです。 興味があれば-habrakatへようこそ!





エントリー



Terrariaとは何か、どのように表示されるかから始めましょう。



Minecraftの驚異的な成功は、常にサンドボックスの開発にありましたが、すでにマーカスペルソナを何百万人ももたらしましたが、気付かれることはありませんでした。 そして、それが起こった、すぐにテラリアが生まれました。 開発に携わっているユニークな人物は、チーフデザイナーであり、少なくともチーフプログラマーであるアンドリュースピンクスです。



地元の「8ビット」の風景を見ると、役に立つ潜在意識はすぐに「Minecraft in 2D」というラベルを付けようとします。 そして何? バックパック-つるはしとa、周り-ランダムに生成されたスペース。 目標は、掘り、造り、殺し、掘り起こすことです。



このゲームに関する特別な記事を読むと、さらに学ぶことができます。 さて、Habrには技術情報が必要です。



どのように機能しますか?



ゲームは、XNAフレームワークを使用してC#(.NET 4.0)で記述されています。これについては、Habrについて多くのことを書きました。たとえば、 hereherehereです。



おもちゃ自体を学ぶ



ゲームを購入して、友人と約2週間プレイしました。少し退屈しました。その構造をさらに詳しく調べることにしました。 構造の特徴として-独自の目的に使用できます。



ゲームはXNAと.NETを使用して記述されています。つまり、すべてのバイナリファイルとライブラリファイルは、リフレクター(たとえば.NET Reflector)で見ることができます。



Terraria.exeを開き、メイン(プログラム)エントリポイントを探します。





面白い行が表示されます。

Steam.Init(); if (Steam.SteamInit) { main.Run(); } else { MessageBox.Show("Please launch the game from your Steam client.", "Error"); }
      
      







つまり 通常のユーザーがSteamフォルダーからゲームファイルを取得し、このSteamを持っていない友人にそれらを与えると、ゲームはエラーを出して開始を拒否します。



この「セキュリティ」を回避するには、 steam_api.dll (関数のインポート元)を置き換えるだけで十分です。または、対応する行をコメント化してアプリケーションを再構築できます。 結局のところ、Steam自体は、レイアウトを追加することを除いて、ゲームにいかなる影響も及ぼしません。 しかし、私たちはもっと面白い方法で、ゲーム自体に影響を与えようとさえします。



ゲームはXNAを使用して作成されたことを思い出してください。これは、Microsoft.XNA.Framework.Gameから継承されたゲームのメインクラスを持っている必要があることを意味します。これはメインクラスです。



XNAで記述されたゲームには、そこに追加できるいわゆる「コンポーネント」があります。 コンポーネントは、通常(論理)またはグラフィカル(描画可能)のいずれかです。



では、何ができるのか考えてみましょう。



メインクラスはMainであり、 パブリック修飾子(パブリッククラスMain:Game {...})があります!

これは何を脅かすのですか? Terraria.exeをライブラリとしてインポートして起動する新しいアプリケーションを作成してから、独自のコンポーネントをゲームに追加すると、このコンポーネントがゲームにほぼ完全にアクセスできるようになります。



あらゆる種類のクラスを調べた後、これらのクラスの主なアイデアは、 シングルトン静的アクセスのインド版であることがわかります。



すべてが失敗するため、パブリックとは異なるアクセス修飾子をメインクラスに与える価値があります。



さらにすべてが非常に簡単で、コンポーネントを作成してmain.Componentsに追加します 。 しかし、私はspriteBatchでテラリアを描きたかったのです。 DrawableCompontentには次のような困難がありました。 DrawOrderをどのように使用しても、 Mainクラスのメイン描画の前に描画されます。



次に、 メインクラスをもう一度見てみましたが、これには封印された修飾子がありませんでした。 アイデアはずっとシンプルになりました。Mainから継承するだけです。



コード作成の練習



新しいコンソールアプリケーションを作成し、 Microsoft.Xna.Framework。*Terraria.exeをライブラリとして接続します。



次に、 Mainを継承するクラスを作成します。

 sealed class InjectedMain : Terraria.Main { private SpriteFont font; private SpriteBatch spriteBatch; internal InjectedMain() : base() { } protected override void LoadContent() { base.LoadContent(); font = Terraria.Main.fontMouseText; //  -  spriteBatch = new SpriteBatch(GraphicsDevice); } protected override void Update(GameTime gameTime) { base.Update(gameTime); } protected override void Draw(GameTime gameTime) { base.Draw(gameTime); } }
      
      







次に、エントリポイントに移動して、ゲームクラスを開始します。

 static void Main(string[] args) { try { Program.game = new InjectedMain(); } catch { Console.WriteLine("fail, sorry :("); Console.ReadKey(); return; } Program.game.Run(); }
      
      







さて、何かを描いて、再定義されたDrawに追加しましょう:



 spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied); spriteBatch.DrawString(font, "Hello habrahabr!", new Vector2(5f, 5f), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f); spriteBatch.End();
      
      







結果:





これは機能します。つまり、ロジックへのすべてのアクセス権があるため、 海賊宝物のある胸の場所など、何らかの種類のデータを描画できます。



そして最後に、何か壮大な、ある種のハックを行います。



テラリウムプレーヤーには興味深い特性が1つあります。 ゴーストは、プレーヤーをキャスパーキャストに変え、壁を通り抜けて世界中を飛び回ることを可能にします(もちろん、開発者向けのチップ)。 だから、 左シフトを押したままにすると、プレイヤーは怒って危険にさらされるようにしましょう。



Updateメソッドに移動します



 KeyboardState state = Keyboard.GetState(); Player local = Main.player[Main.myPlayer]; //    local.ghost = state.IsKeyDown(Keys.LeftShift); if (local.ghost) { local.Ghost(); } //    if (state.IsKeyDown(Keys.LeftShift) && oldKeyboardState.IsKeyUp(Keys.LeftShift)) { Terraria.Main.NewText("Ghost activated!", 200, 200, 255); } if (state.IsKeyUp(Keys.LeftShift) && oldKeyboardState.IsKeyDown(Keys.LeftShift)) { Terraria.Main.NewText("Ghost deactivaed!", 200, 200, 255); } oldKeyboardState = state;
      
      







ゲームを開始し、シフトをクリックしてキャストになります。





あなたが理解しているように、テキストやその他の設定を描く-問題はこれに限定されず、ゲームにほぼ完全に影響を与えることができます、マルチプレイヤー同期の曲がり具合について別々に言う必要があります-これらの変更はすべて停止されず、これらのハックでサーバーでプレイすることが許可されます



また、 プレイヤークラスについても言いたいと思います。保存/読み込み関数を使用すると、それに応じてプレイヤーを保存および読み込むことができ、プレイヤープレイヤークラス自体を受け入れて提供します。 つまり プレーヤーを完全に少し変更するだけで、保存してゲームで使用できます。 または、たとえば、サーバー上のすべてのプレーヤーをファイルに保存し、それらをプレーヤーフォルダーにドロップして再生します。



道徳



必要に応じて常にアクセス修飾子を使用し、有限のクラスは封印されます (継承を禁止します)。 パラノイア忠実度から丸薬については、コードを難読化することもできます。



また、マルチプレーヤーを実装している場合は、サーバーですべてのロジックがチェックされるように適切な同期を行い、不一致が激しい場合はプレーヤーをオフにします。 たとえば、プレーヤーが1秒未満でマップ上のあるポイントから別のポイントに瞬時に移動するにはどうすればよいですか? 残念ながら、テラリウムサーバーはこれを正常と見なします。



この記事は、教育目的のみのために書かれました:単純な修飾子の例として-あなたは強力なハックを書くことができます。



残念ながら、私は記事のソースコードを適用しません、アイデアは明確です。



じゃあね!



All Articles