10
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Modding】Minecraftで重要なSideの概念

Last updated at Posted at 2019-08-04

はまったこと

world.createExplosion()を実行したときに、表示されていないが当たり判定だけが残っている、いわゆるゴーストブロック現象が発生してしまった。いろいろ調べたところ、ServerClientという、サイドの概念がForgeには存在しているらしい。で、それぞれのサイドでプログラムが実行されていることが分かった。こちらのリファレンスを参考にした。

サイドの種類について

大体の認識だと、クライアントというものはプレーヤーに影響するもので、サーバーというものはマルチプレイをするときに接続するものだという認識だろう。

さてここで、この二つのサイドのあいまいな点を解説していこう。

物理サーバー

物理サーバーというのは、よくdedicated server(専用サーバー)といわれるものだ。専用サーバーはminecraft_server.jarのような種類のプログラム全体のことで、操作できる画面を持たない。

物理クライアント

物理クライアントというのは、Minecraftをランチャーから起動するプログラム全体のことだ。ゲームの描画や画面操作などを担っているすべてのスレッドやプロセス、そしてサービスは物理クライアントの一部だといえる。

論理サーバー

論理サーバーはゲームの統括をする。モブのスポーン、天候、インベントリの更新、モブの知能など、ゲームの仕組みすべてを担っている。論理サーバーは物理サーバーの中にあるものだが、シングルプレイのときは物理クライアントの中で論理クライアントと一緒に実行することができる。これはServer Threadという名前で実行される。

論理クライアント

論理クライアントはプレーヤーからの入力を受け取って、それを論理サーバーに送信する役目を持っている。加えて論理クライアントは論理サーバーから情報を受け取り、その情報をプレーヤーが見えるように画面に表示する。これは、Client Threadという名前で実行される。

サイドに合わせたプログラムの実行

world.isRemote

この真偽値はどちらのサイドでプログラムが実行されているかを調べるものである。この真偽値で調べられるのは、論理サーバーか論理クライアントかどうかだ。論理クライアントだったらtrueを返し、論理サーバーだったらfalseを返す。これは、物理サーバーでは常にfalseを返すため、物理クライアントの論理サーバーと値が被っている。原則、それが物理サーバーか論理サーバーか、この値からではわからない。
この真偽値の使いどころは、ゲームのルールやそのほかの仕組みを実行したいときである。例えば、

  • あるブロックに触れている間は、ずっとダメージを受け続ける
  • ある機械に土を入れると、それをダイヤモンドに変える

などである。これらはworld.isRemoteの値がfalseの時に実行するべきだ。これらを論理クライアントで実行してしまうと、論理サーバーとの整合性が取れなくなり、軽いバグの場合、モブのゴースト現象や体力の不一致などが発生する。重いバグの場合はゲームがクラッシュしてしまうこともある。

getEffectiveSide

FMLCommonHandler.getEffectiveSide()は何らかの理由によって、world.isRemoteが使えない時に使われる。これはどっちのサイドかを、推測する。なぜ推測かというと、これはスレッドの名前(Server ThreadもしくはClient Thread)から、どちらのサイドかを判断するからだ。worldが使用可能の時は、できるだけworld.isRemoteを使うようにして、これはその方法が使えないときの代替手段として使うべきだ。

解決

なるほど、どうやらワールドのブロックなどの管理をしているのは論理サーバーらしいから、論理クライアントと論理サーバーでworld.createExplosion()を実行してしまうと、サーバーにあるブロック情報とクライアントにあるブロック情報が食い違ってしまうから、ゴーストブロック現象が起こるらしい。爆発で破壊するブロックはランダムで決めているから、クライアントでは破壊したことになっているブロックもサーバーでは爆発を免れているかもしれない。ここで、存在しないブロックに対する当たり判定が発生していたのだ。よって、この問題の解決方法は、

if (!world.isRemote)
    world.createExplosion(...);

となる。当たり判定やゴーストエンティティで悩んでいるModderは論理サーバーのみ、論理クライアントのみでの実行を一回試してみたら幸せになれるだろう。

10
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?