返信機能付きの一行掲示板を作成する

返信機能付きの一行掲示板を今回は作成しようと思うのですが、まず始めに基本となる一行掲示板を作成してから追加機能として返信機能を付けたいと思います。

ですので既存のツールに組み込むことができるかもしれません。よかったら参考にしてみてください。

 

一行掲示板

初めにデータベースの設計を考えます。

データベースの設計は重要です。再構築するとなると全データを移動させる必要があるので面倒になります。先にしっかりと考えましょう。

今回は以下のような構造体にします。

id int not null auto_increment primary key
user varchar(30) not null
message text not null
reply tinyint(1) default 0
replyId int
date datetime default current_timestamp

解説をすると、

id はそのデータの固有IDとなります。

返信をする際に必要となります。

user は投稿主の名前です。

message は投稿内容です。

reply は 0 か 1 によって、返信かどうかを見分けるためのフラグです。

replyId は返信先の固有IDです。

date は投稿された日時です。自動的にMYSQLサーバーのタイムスタンプを割り当てています。

 

フォームの宛先を雑ですが書くと

<?php

$pdo = new PDO(/* あらかじめ作成しておく */);
$user = filter_input(INPUT_POST, "user");
$message = filter_input(INPUT_POST, "message");
$isReply = filter_input(INPUT_POST, "reply") == null ? 0 : 1;
$repId = filter_input(INPUT_POST, "replyId");

if ($isReply) {
$sql = "insert into bbs(user, message, reply, replyId) values(:user, :message, 1, :replyId)";
} else {
$sql = "insert into bbs(user, message) values(:user, :message)";
}

$smt = $pdo->prepare($sql);
$smt->execute(/* 必要な値を配列で渡す */);

のような形になります(雑だけど)。

※受け取った値は必ず 「htmlspecialchars」などの関数を使用してパースしてください。

※本番環境ではNULLチェックだとか、TRY CATCH とかしてね☆

 

トップページ用のSQLは

select * from bbs where reply=0;

返信表示用のページ(SNS風にするのであれば)は

select * from bbs where reply=1 replyId={$ID};

のようにすればOKだと思います!

 

以上で一行掲示板返信機能付きの解説(じゃないですねすいません)でした

このままだと認証(アカウント機能)やスパム対策がないので追加していかなければいけませんね。

ffmpeg による動画の圧縮処理

今回、とあるウェブサービスを実装するにあたり動画を圧縮する必要が出てきた。

圧縮すると画質は劣化するけど、容量を抑えるためには必須だよね。

 

それで

・サーバー上で実行できること

・コマンドラインで実行できること

・情報が豊富であること

の3拍子揃ったFFMPEGを使うことにした。

使い方はとってもシンプルだった。

mp4 から webm への変換は

$ ffmpeg -i input.mp4 output.webm

これだけ少し待てば output.webm が生成される。

容量はテスト動画だと2分の1になった。

画質は少し文字が見にくくなっている(ぼやけてる)

人によっては嫌う。

 

この処理をバックグラウンドで非同期に行うには

$ nohup ffmpeg -i input.mp4 output.webm > /dev/null &

でOK

> /dev/null はログを捨てていて

& で非同期にさせている

 

【Minecraft】UHCを作ろう!#2

前回の続きとなるので前回を見てから読むことを推奨する。

前回はプラグインの基盤を作成したところで終わった。

今回は基本的なイベントリスナーを実装し、ワールドの自動生成を行うクラスを作成する。

イベントリスナーの実装

必要となるイベントを先に考えておこう。

・BlockBreak BlockPlace

・PlayerDeath

・PlayerJoin PlayerQuit

・EntityDamageByEntity

 

BlockBreak BlockPlace

ロビーでブロック設置、破壊を無効にする必要があると思うので実装する必要があります。

PlayerDeath

プレイヤーが死亡したときにヘッドをドロップする処理や、プレイヤーのキル数を加算する処理が必要なので実装します。

PlayerJoin PlayerQuit

プレイヤーがログインしたときにリセットしたり、スコアを取得する必要があるので実装します。

EntityDamageByEntity

PVPが無効の時にPVPができないようにする必要があるので実装します。

 

UHCの仕様を踏まえると、最低限以下のイベントも必要となりますね。

FoodLevelChange

体力ゲージの調整

EntityRegainHealth

資源回復の無効化

 

現時点で作成可能なイベントリスナーをさくっと作ってしまいましょう。

@EventHandler
public void onBreak(BlockBreakEvent e){
if (e.getPlayer().getWorld().getName().equals("lobby")){
e.setCancelled(true);
}
}
@EventHandler
public void onPlace(BlockPlaceEvent e){
if (e.getPlayer().getWorld().getName().equals("lobby")){
e.setCancelled(true);
}
}
@EventHandler
public void onFood(FoodLevelChangeEvent e){
e.setFoodLevel(e.getFoodLevel() - 1); // sorry no debug this code
}
@EventHandler
public void onRegain(EntityRegainHealthEvent e){
if (e.getRegainReason().equals(RegainReason.SATIATED)){
e.setCancelled(true);
}
}

 

次にワールドの自動生成用のクラスを作成します。

Bukkitでワールドを作成するには

WorldCreator というクラスを作成してそれを Bukkit#createWorld に渡す必要があります。

public World Create(String worldName){
WorldCreator wc = new WorldCreator(worldName);
// wc.seed(long) seed 値の設定などができます。
World w = Bukkit.createWorld(wc);
return w;
}

 

ワールドをアンロードするには

public void Unload(String worldName, boolean save){
Bukkit.unloadWorld(worldName, save);
}

です。とても分かりやすく簡単ですね。

 

このままでは、サーバーを再起動した際に、ワールドが読み込まれておらず手動で読み込む必要があるうえに読み込んだ際は前回作成したデータが引き継がれてしまいます(新規に作成されない)

そのため、生成する前に一度ワールドを削除する必要があります。

public void Remove(String worldName){
File f = new File(Bukkit.getWorldContainer(), worldName);
if (f.exists()){
IODelete(f);
}
}
public void IODelete(File file){
if (file.isFile()){
file.delete();
}else {
File[] files = file.listFiles();
for (File f : files){
IODelete(f);
}

file.delete();
}
}

 

「Remove();」を呼び出せば削除することができます(削除する前にワールドをアンロードする必要がありますよ!)

ここまでのコードを一つのクラスにまとめれば使いやすく便利なクラスの誕生です。

UHC以外でも使い道はありますね。