5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Minecraft CommandAdvent Calendar 2024

Day 2

データパックとリソースパックでプレイヤーの名前を変更する(ように見せる)

Last updated at Posted at 2024-12-08

この記事は JavaEdition 1.21 にて動作確認を行っています
データパック及びコマンドにある程度の知識があることを前提としています。

追記: defaultフォントであることを前提としています。
それ以外のフォント(uniformなど)については 6. 追記

1. はじめに

今回こんなものを作ってみます。

サイドバーだけでなく、チャットまで名前が変わっていますね。

ここからは説明や過程が多くなります。
出来上がったものが見たい方は 5. おわりに まで飛んでください

2. 簡易的な説明

String Parsing(文字列解析)について調べていたときに見つけた、これが説明であり発端です 1
Minecraft-String-Utilities のリポジトリ (https://github.com/McTsts/Minecraft-String-Utilities)

Getting Width

Getting the length of a non-JSON string is just a matter of parsing it and then using a look-up table for all characters you want to support. You then add up the widths of all characters (while respecting that the gap between characters is 1 pixel).

You can for example use this to determine the length of a player name, then using negative spaces in team prefix/suffixes to replace the player name with a different text.

Getting the length of a JSON string is a fairly convoluted process. You first need to string parse the string, then JSON parse it, then extract all characters from the JSON, while separating bold and non-bold characters. You use the same look-up table process as for normal strings, with the exception, that all bold characters are 1 pixel wider than the non-bold variant.

何言ってるのかわからないので簡単に日本語訳

文字列の長さ(ピクセル)を取得するには、一文字ずつに分解して、それぞれの文字のピクセル数を記録し、そこから参照すればいい。あとはそれを合計するだけ。(文字と文字の間隔が1ピクセルであることを尊重しながら)
例えば、プレイヤー名の長さを取得して、teamコマンドのprefix/suffixで負のスペースを使えばプレイヤー名を変えられる。

コマンドを結構やっている方なら、もうここで何をすればいいのかわかったかも...?

負のスペースとは?

上の文章において、「負のスペース」という単語が出てきました。
これは一体何でしょうか?

結論から言いますと、原文にある通り negative space (以降 ネガティブスペース)
というカスタムフォントの要素です。

ネガティブスペース、及びカスタムフォントについては、まっしゅ さんの この動画 (https://www.youtube.com/watch?v=w0Zraz-o8yE)
ネガティブスペースフォントのリポジトリ (https://github.com/AmberWat/NegativeSpaceFont) にてわかりやすく解説されているので見ていただきたいのですが、簡単に説明すると...


スペースなし

no_space.png

普通のスペース

normal_space.png

ネガティブスペース

negative_space_-1.png

のように、普通のスペースを「正のスペース」「プラス方向に広がるスペース」と考えると、
ネガティブスペースは 「負のスペース」「マイナス方向に広がるスペース」 と捉えられます。

なのでネガティブスペースを大きくすると...

negative_space_-15.png

このように前後関係が反対になったりもします。

プレイヤー名変更データパックではこれが最重要要素になります。

3. 本格的な説明

2. 簡易的な説明負のスペースとは? の内容を組み合わせて考えます。

まずhogeというプレイヤーがtestとチャットをしたという過程で話します
Slide1.jpg

プレイヤーが所属しているteamprefixにネガティブスペースを入れ、画面外に飛ばします
Slide2.jpg

その後suffixに変更後の名前を入れます。(ここではfugaとしています)
Slide3.jpg

変更後の名前の前に普通のスペースを挿入することで画面内に戻します。
スペースの長さは、prefixに入れたネガティブスペースの長さと同じにします。
Slide5.jpg

プレイヤー名の長さ(合計ピクセル数)分だけ(今回の場合はhogeの長さ)、スペースの後にネガティブスペースを入れ、位置を調整します。
Slide6.jpg

つまり、本来の名前を画面外に飛ばし、文字を同じ場所に出すことで名前を変更したように見せることができる ということです。

理論はこれで終わりです。あとはコマンドを書きましょう。

4. 作成手順

  1. プレイヤー名の取得
  2. プレイヤー名の合計ピクセル数を計算
  3. teamの作成と加入
  4. prefixsuffixを変更

4-1. プレイヤー名の取得

loot_tablefill_player_headでプレイヤー名を取得します。

function: cnn:core/main/
summon minecraft:item_frame ~ ~500 ~ {Invisible:true,Fixed:true,Tags:[cnn.head_frame]}

execute positioned ~ ~500 ~ align xyz run loot replace entity @e[dx=0,type=item_frame,tag=cnn.head_frame,limit=1] container.0 loot cnn:head

execute positioned ~ ~500 ~ align xyz as @e[dx=0,type=item_frame,tag=cnn.head_frame,limit=1] run function cnn:core/main/head
loot_table: cnn:head
{
  "type": "minecraft:entity",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "name": "minecraft:player_head",
          "functions": [
            {
              "function": "minecraft:fill_player_head",
              "entity": "this"
            }
          ]
        }
      ]
    }
  ]
}

loot_table: cnn:core/main/head
# player_headからplayer_nameを取り出し
data modify storage custom_nick_name:_ player_name set from entity @s Item.components."minecraft:profile".name

# 用済み
kill @s

4-2. プレイヤー名の合計ピクセル数を計算

そして一文字あたりのピクセル数を調べます。
これはゲーム内で人力でやります。

ネガティブスペースなし
0.png

-3だと...
-3.png

-6で完全に重なりました。
-6.png

さらに 2. 簡易的な説明 で書いていた通り、文字と文字の間は1ピクセルなので、
実際の一文字のピクセル数は5となります。

では、一文字分のピクセル数を5としてテストしてみましょう。

zure.png

...ズレてしまいました。
おそらくプレイヤー名の長さの計算がおかしいのでしょう。調べてみます。

(前後関係がわかりやすいように文字に色を付けています)
ネガティブスペースなし
i_no.png

ネガティブスペースを-6だけ入れたもの
i_-6.png

おかしいですね
aの場合-6でちょうど重なったのにもかかわらず、iでは通り越してしまっています。

つまり文字の種類ごとにピクセル数が変わるということです。
なので、面倒くさいですが、プレイヤー名に使える文字すべてのピクセル数を調べました。

1px 2px 3px 4px 5px
i l (小文字のL I (大文字のi f _ (アンダーバー) を含むその他のアルファベットと数字
t k

これを元に場合分けして計算します。

function: cnn:core/main/
# 処理用に一時的に移動&文字間の1ピクセルを計算にいれるために、player_nameの長さをスコアに代入
data modify storage custom_nick_name:_ __temp__.name set from storage custom_nick_name:_ player_name
execute store result score $total_pixel cnn.main run data get storage custom_nick_name:_ player_name

# プレイヤーの名前の合計ピクセル数を計算
function cnn:core/pixel/loop
function: cnn:core/pixel/loop
# 保存しておいて、後で同じかチェックする
scoreboard players operation $else cnn.main = $total_pixel cnn.main

# player_nameの一文字目をwordに入れる
data modify storage custom_nick_name:_ word set string storage custom_nick_name:_ __temp__.name 0 1

# 文字幅が特殊なものはここで処理
execute if data storage custom_nick_name:_ {word:"i"} run scoreboard players add $total_pixel cnn.main 1
execute if data storage custom_nick_name:_ {word:"l"} run scoreboard players add $total_pixel cnn.main 2
execute if data storage custom_nick_name:_ {word:"I"} run scoreboard players add $total_pixel cnn.main 3
execute if data storage custom_nick_name:_ {word:"t"} run scoreboard players add $total_pixel cnn.main 3
execute if data storage custom_nick_name:_ {word:"f"} run scoreboard players add $total_pixel cnn.main 4
execute if data storage custom_nick_name:_ {word:"k"} run scoreboard players add $total_pixel cnn.main 4

# 保存されていたものと値が同じ = 特殊処理の際に数値が追加されていない = 文字幅が特殊ではないので5を追加
execute if score $else cnn.main = $total_pixel cnn.main run scoreboard players add $total_pixel cnn.main 5

# player_nameの一文字目を消す
data modify storage custom_nick_name:_ __temp__.name set string storage custom_nick_name:_ __temp__.name 1

# player_nameがなくなるまで再帰
execute unless data storage custom_nick_name:_ {__temp__:{name: ""}} run function cnn:core/pixel/loop

これで大丈夫です。

4-3. teamの作成と加入

マクロを使って、名前を変更するプレイヤー専用のteamを作ります

function: cnn:core/main/
# 名前変更用teamを作成し加入
# マクロ用に移動
data modify storage custom_nick_name:_ macro.nick_name set from storage custom_nick_name: input
data modify storage custom_nick_name:_ macro.player_name set from storage custom_nick_name:_ player_name
execute store result storage custom_nick_name:_ macro.total_pixel int 1 run scoreboard players get $total_pixel cnn.main

function cnn:core/team/macro with storage custom_nick_name:_ macro
function: cnn:core/team/macro
$team add cnn_$(player_name)

$team join cnn_$(player_name) $(player_name)

4-4. prefixsuffixを変更

作成したteamprefixにネガティブスペースを入れ、
suffixにスペースと変更後の名前を入れます。

function: cnn:core/team/macro
# ネガティブスペースで画面外へぶっ飛ばす
$team modify cnn_$(player_name) prefix {"translate":"space.-max"}

# ただのスペースで画面内へ戻し、位置調整後、偽の名前をセット
$team modify cnn_$(player_name) suffix [{"translate":"space.max"},{"translate":"space.-$(total_pixel)"},{"text":"$(nick_name)"}]

今までのものを合わせてテストすると...
result.png
できました!完璧です!

本当にできてるかのテスト

Aは普通にチャットしたもの。Bは「hikoma0000」と名前変更してみたもの
A.png
B.png

全く同じになっていますね。

5. おわりに

今回作ったデータパックに、機能を少し付け加えたものを ここ (https://github.com/hikoma0000/CustomNickName) に公開しました。
ぜひお使いください。

初めてQiitaの記事を書いてみました。至らぬところがございましたら、ぜひコメントしていただければ幸いです。

ご清覧ありがとうございました。

6. 追記

完っ全にuniformフォントについて忘れていました...

2024-12-09_11.43.36.png

その内対応します...

  1. つまりアイデア自体は自分じゃないってこと

5
0
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
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?