【Bukkit】【Spigot】スピードハック対策の方法

スピードハックは最もよく知られているハックであり、一番対策がしやすいのかなとも思います。

 

プレイヤーの動きを検知する

Bukkit プラグインは

イベントの発火

プラグイン側で処理

という流れとなっており、プレイヤーが動いた時の専用のイベントがあります。

そのイベントを使用してハックかどうかの検査を行います。

@EventHandler
public void onMove(PlayerMoveEvent event){
// ここで処理を行います
}

 

しかしこのままだと顔が動いただけでもイベントが発火するため移動していなくても処理が行われてしまいます。

それを防ぐために

if (event.getFrom().getBlockX() != event.getTo().getBlockX()
|| event.getFrom().getBlockY() != event.getTo().getBlockY()
|| event.getFrom().getBlockZ() != event.getTo().getBlockZ()){
// ここで処理を行う
}

↑のコードを追加することで、X、Y、Zのいずれかが動いた時(移動したとき)に処理を行うことができるので、多少ラグを軽減できると思います。

※重い処理を行う際は非同期で処理しましょう

 

さて本題の処理の部分です。

初めにプレイヤーのダッシュ時の速度を変数として保存しておきます。

※ないと思いますが、バージョンアップで移動速度が変わるかもしれないので

public static double final MAX_SPEED = 0.666D;

次にプレイヤーの移動距離を計算し、ダッシュ時の速度を超えている場合はロールバック処理を行います。

// 移動距離の計算
if (event.getFrom().distance(event.getTo()) > MAX_SPEED){
// ダッシュ時の速度を超えているので
// ロールバック処理を行う
event.setCancelled(true);
// ※イベントをキャンセルすることで移動できなくなる
}

最後に全体のソースコードになります。

public static double final MAX_SPEED = 0.666D;
@EventHandler
public void onMove(PlayerMoveEvent event){
if (event.getFrom().getBlockX() != event.getTo().getBlockX()
|| event.getFrom().getBlockY() != event.getTo().getBlockY()
|| event.getFrom().getBlockZ() != event.getTo().getBlockZ()){
if (event.getFrom().distance(event.getTo()) > MAX_SPEED){
event.setCancelled(true);
}
}
}

 

このコードは完全ではないです。

例えば、シフトをしているときやクモの巣、水の中にいるとき、など細かく条件を加えていくことでより詳細にハックかどうかを確認しなければいけません。

また、PVPサーバーでこのコードを使うと、ロールバックを沢山して動けなくなる可能性があります。

なぜなら殴られた時のノックバックによって移動速度(ベクトル)が加算され、MAX_SPEEDを超えてしまうためです。

このコードは改良の余地がたくさんあります。

ぜひこのコードを参考にして独自の対ハックプラグインを作ってみてください。

プログラミングを始めようと思ってる人へ

プログラミングを始めようと思っている人向けの記事になります。

雑談混じってます。

プログラミングは意外と簡単

プログラミングは口で説明するとめっちゃ簡単です。

テキストエディタでもなんでもいいからコードを書いてコンパイル、実行すればいいだけです。(コードを書いて即実行タイプもあります)

これだけです。とっても簡単ですね。

 

動画を見るだけより手を動かすべき

チュートリアル動画を見るだけよりも、実際に手を動かして自分でプログラムを組んでみる方がいいです。

なぜなら、自分で作ることによって、手順や仕組みを覚える機会にもなりますし、達成感も得ることができます。

達成感はプログラミングをやるうえでとても大事です。

もしもプログラムがうまく動かなくても達成感があれば乗り越えれるときもあるからです。

 

難しいことをいきなりはやるな

当たり前ですが、難しいことにいきなり初心者が挑戦しても失敗して挫折するだけです。

少しずつ簡単なものから確実にやっていき、段々と難しいものに挑戦していくことがベストです!

何か大きなものを作りたいのであれば確実に基礎を積むことが大切です。急がば回れ!

 

自分のやりたいように

人それぞれ好みや趣向は違うわけですから開発環境など自分の好きなようにセットアップすればいいと思います。

人に合わせる必要はないと思います。

 

プログラミングをする目的はなにか

プログラミングをする目的や目標を明確にしておくと、モチベーションにもつながりますし、成し遂げたときには大きな達成感があります。

また、目的にあったプログラミングを学習する方が楽だと思いますし、効率的だと私は思います。

 

まとめ

・プログラミングは意外と簡単

・基礎を固めることが大事

・急がば回れ

・目的や目標を明確にする

【Bukkit】【Spigot】めっちゃ便利!インベントリをファイルに保存して活用する方法【プラグイン開発】

簡単にインベントリをファイルに保存する方法です。

拡張インベントリを作るときに便利だと思います!

組み込み型なので自作プラグインに埋め込んでください!

 

※お借りしたコード

https://jyn.jp/ – CustomConfig 

 

1.完成例

完成して実際に動かしたものの動画があります!

 

2.制作環境について

IDE Eclipse 

Java java7

Spigot 1.14.4

 

3.保存形式

YAMLにて保存しました

 

4.コード

とってもシンプルです。

※プラグインの無効化時にクリーン処理を挟んでください。 InventorySQL.clean();

※プレイヤーが退出したときにクリーン処理を挟んでください。 InventorySQL.clean(Player#getUniqueId());

※インベントリをそのまま保存しておくとメモリリークが心配なので毎回作成していますが、必要に応じて変更してください。

※ファイル名、フォルダを追加する場合は必要に応じて引数を変更してください。


import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;

import CustomConfig;

public class InventorySQL{
private static HashMap<UUID, InventorySQL> datas = new HashMap<>();
public static InventorySQL getData(UUID key) {
if (!datas.containsKey(key)) {
return new InventorySQL(key);
}
return datas.get(key);
}

public static void clean() {
for (UUID key : datas.keySet()) {
clean(key);
}
}
public static void clean(UUID key) {
if (datas.containsKey(key)) {
datas.get(key).save();
datas.remove(key);
}
}

private UUID key;
private ItemStack[] contents;
public InventorySQL(UUID key) {
this.key = key;

reload();


datas.put(key, this);
}

public void reload() {
contents = new ItemStack[9 * 6];
try {
CustomConfig CC = new CustomConfig(key.toString() + ".inv.yml");
FileConfiguration config = CC.getConfig();

if (config.contains("inventory")) {
List<?> list = config.getList("inventory");
int max = list.size();
for (int cur = 0; cur < max; cur++) {
Object obj = list.get(cur);
if (obj instanceof ItemStack) {
contents[cur] = (ItemStack) obj;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

public void open(Player p) {
Inventory inv = Bukkit.createInventory(null, 9 * 6, "§eBackPack");
inv.setContents(contents);
p.openInventory(inv);
}

public void closeInventory(Player p, Inventory inv) {
contents = inv.getContents();
}

public void save() {
CustomConfig CC = new CustomConfig(key.toString() + ".inv.yml");
FileConfiguration config = CC.getConfig();

/**
* Save as list type
*/
List<ItemStack> list = new ArrayList<>(Arrays.asList(contents));

config.set("inventory", list);
CC.saveConfig();
}
}

 

今回はやりませんでしたが、Blob形式に変換できればSQLにも保存できると思います。