「プライベート」カテゴリーアーカイブ

【GAME】ARMA3 EXILE MODサーバの旅その90

image

追記:サーバOSアップデート更新@4/19 AM11から稼働

追記:ガソスタでの自動給油無し?!

追記:サーバに強い味方参上!(物理)

追記:ゾンビ感染するらしいので注意@世界保険機関WHO

追記:凄すぎるArma3のムービー動画

追記:北国のまだ咲いてない桜

追記:ヘリパトロールを改良

追記:昨日のテストプレー

追記:今後の追加要素予定まとめ

追記:サーバ微調整しましたx2

さらにパワーアップしました。

鯖味噌サーバの密告書(SabamisoLeaks)

拠点と車両のデータを追加しました。

車両が盗難やイタズラにあったり、拠点が抜かれたり、家賃支払忘れなど・・・どこからでもスマホで確認できます。

(;^ω^)

ページがでかくなってしまったので、画面下部にリンクを設けてます。

追記:サーバ微調整しました

全域に渡り、僅かぁ~に微調整しました。難易度変わらず(若干、バンビ寄りに)PM7から適用。

良いの見っけた。

( ゚д゚)!

ハンドガンサプ増殖バグの対策、町AIの若干の調整、車両パトロールの調整(プレーヤー要望、不平不満はgさんへ)、アイテム価格の誤り修正

総じて、難易度アップとなります。

4/17 PM19頃のリスタートで適用です。

m9( ゚д゚)!

追記:今後の追加要素予定まとめ

image

昨夜のDiscordのボードにて、色々と情報を頂きました。

やるか、やらないか?はさておき、まとめておきます。

オーバーデス対策(要調査、DB重複登録バグ)

パトロール車両搭乗者を増やせよ。コラ(プレーヤーさん要望)済み

バスに20人位AI乗せたらどうよ

ゾンビ感染と治療

ガソリンスタンドでの給油を無効にする(原油をクラフト?)(ヘリ運用が地獄になる)

以下は、勝手に導入しようとしてるリスタートタイミングの新要素(鯖味噌オリジナル)

古くなった車両は壊れやすくなる(どこかが20%程度壊れる)

ガソリンが自然に減っていく(気化する)

生もの食品が腐って消える

アヒル人形が何かに変身する

アヒル人形が現れる(服・車両)※条件:前回稼働時にイン

ポップタブが少し無くなる※ポッケに穴が開いてる

追記:昨日のテストプレー

20190415214300_1

何かで使えるかもと、ナイスなシーンを撮り溜めていってます。砂嵐の中、薄っすら見える人影がいい感じ。

20190417211516_1

箱、あんな所にあるよ・・w

20190417212002_1

パトロールヘリをスコープでズームしてみた。

20190417212158_1

音がした方に行ったら、プレーヤーさんの車両を見つけた。

ガチ勢やん。

(;^ω^)

後を追い掛けて、IEDでも仕掛けたくなる。

追記:ヘリパトロールを改良

image

ヘリパトロールは、ランダムでどこかの町が選ばれて、適当に飛んでるだけなのですが。。

イマイチ、”脅威”じゃないんですよね。

これを大きく改造しました!

(;^ω^)

マップを所狭しと、滑空しながら要所をパトロールするようにしました。

まだ、動作未確認ですけども。

追記:北国のまだ咲いてない桜

P_20190418_132106

どうでしょ、今週末くらいかな。。

追記:凄すぎるArma3のムービー動画

クオリティ高すぎ。

追記:ゾンビ感染するらしいので注意@世界保険機関WHO

ゾンビに攻撃されると、まれに感染してしまう場合があるようです。まだ治療方法が無いので、注意です。

:(;゙゚’ω゚’):

追記:サーバに強い味方参上!(物理)

P_20190418_164337

最近暑くなってきたからね・・ケースに風当ててますが。

(;´Д`)

追記:ガソスタでの自動給油無し?!

20190418181727_1

以前からやりたかった事のひとつ・・、ガソリンスタンドで自動給油できなく、したい。

だが、なかなか仕組みが分からなくて、諦めてたんですが。

先程、テストで成功した。

(;´∀`)

死ぬほど簡単やった。発想の転換が必要だったようです。

{
_x enableSimulation false;
}foreach nearestTerrainObjects [this, [“Fuelstation”], 100];

テストしたコードがこれ。

MAPのオブジェクトのシミュレートを無効にするだけ、という。実際に組み込むには、MAP全域でサーチを掛けなきゃいけませんでどもね(あと、enableSimulationGlobalの方で無効にせにゃあかん)

追記:サーバOSアップデート更新@AM11から稼働

image

OS更新が溜まりまくっていたので、まとめて更新掛けてます。

サーバをネットに公開すると、何気に、外から結構な数の攻撃をされてます・・。

(;^ω^)しょーない

開けてるポートは、Arma3のみなので、心配無用ですが、万一に備えて、OSの更新も忘れず実施します。

P_20190419_110530

みんな、すまぬ・・。プリンを食させていただく。

【Arma3】スコアをウェブ公開する方法@Exileサーバ

image

動作サンプルはこちら(鯖味噌サーバ密告書)

ゲーム動作時でもリアルタイムのプレーヤースコア公開が可能です。

Exile ModによるArma3  Dedicated Serverでサーバ運用されてる管理者さんの参考にさればと、公開してます。

なお、こちらで公開しているのは、Arma3側もウェブサーバ側もLinuxですので、Windowsの場合は、適宜書き換えてください。

また、動けばOKッ!というスタイルで短時間で書いた代物ですので、小汚く低品質コードなのは了承ください。

(;^ω^)参考程度に・・

分からないという方は、ご連絡ください。

動作仕組み

Arma3サーバ側

Cronにて、以下を定期的に実行するようにします。当方では1時間毎。

MySQLデータベースから必要なデータを取り込み、JSONファイルを複数生成します。

SCP(秘密鍵)にて、Webサーバへコピーします。念の為、ユーザーのホームへコピーします。

ウェブサーバ側

コピーされたJSONファイルへ、ウェブ公開ホルダーにリンクを貼っておきます。

ここから先は、HTMLのお話なので、割愛しますが、当方では、eisenbraun-columnsで、そのままJSONデータを表示しています。とっても楽です。

SQLコード

まずは、欲しいデータの要求が正常に行えるようSQLコードを作ります。

image

使い慣れたDBユーティリティで、SQL文を用意します。Exileのデータベースはとてもシンプルなので、見るだけで分かるはずです。

注意するのは、余計なデータまで入れ込んでしまうと、(知ってる人が)JSONファイルに直接アクセスして、表示外のデータまで見られてしまいます。

データ転送量も鑑みて、ミニマムにするべきです。

リスペクト上位5名をランダム順(鯖缶除く)

SELECT * FROM
(SELECT a.name/*,a.score*/ FROM exile.account as a WHERE a.name <> “nabe” ORDER BY a.score DESC LIMIT 5) as rank
ORDER BY RAND();

キル数上位5名をランダム順(鯖缶除く)

SELECT * FROM
(SELECT a.name/*,a.kills*/ FROM exile.account as a WHERE a.name <> “nabe” ORDER BY a.kills DESC LIMIT 5) as rank
ORDER BY RAND();

最近50件のデスリスト(鯖缶除く)

SELECT
h.name,
h.died_at,
cast(round(h.position_x,0) as unsigned) as x,
cast(round(h.position_y) as unsigned) as y
FROM exile.player_history as h
WHERE name <> ‘nabe’
ORDER BY died_at DESC
LIMIT 50;

全プレーヤーの詳細リスト(名前無し)

SELECT
/*a.uid,a.name,*/
cast(round(p.damage*100,0) as unsigned) as damage,
cast(truncate(p.hunger,0) as unsigned) as hunger,
cast(truncate(p.thirst,0) as unsigned) as thirst,
p.money,
cast(round(p.position_x,0) as unsigned) as x,
cast(round(p.position_y,0) as unsigned) as y,
p.primary_weapon as w,
p.spawned_at as sp,
datediff(now(),p.spawned_at) as alive,
a.deaths,a.kills,a.score,
a.total_connections as tc,
last_disconnect_at as ld,
datediff(now(),a.last_disconnect_at) as last,
a.first_connect_at as fc,
datediff(now(),a.first_connect_at) as days
FROM exile.account as a LEFT JOIN exile.player as p ON a.uid = p.account_uid
WHERE a.name <> ‘DMS_PersistentVehicle’
ORDER BY a.last_disconnect_at DESC;

所有ポップタブのランキング上位10名

SELECT rank.name,CAST(rank.poptabs as UNSIGNED) as money FROM
     (SELECT a.uid,a.name,
     (IFNULL((SELECT SUM(p.money) FROM exile.player as p WHERE p.account_uid = a.uid),0)+
     IFNULL((SELECT SUM(v.money) FROM exile.vehicle as v WHERE v.account_uid = a.uid),0)+
     IFNULL((SELECT SUM(c.money) FROM exile.container as c WHERE c.account_uid = a.uid),0)) as poptabs
     FROM exile.account as a WHERE NOT a.name in (‘nabe’,’DMS_PersistentVehicle’) ORDER BY poptabs DESC LIMIT 10) as rank
ORDER BY money DESC;

所有エロ本のランキング上位10名

SELECT /*a.uid,*/a.name,
     CAST(
         IFNULL((SELECT
         TRUNCATE((LENGTH(CONCAT(p.backpack_magazines,p.uniform_magazines,p.vest_magazines))-LENGTH(REPLACE(CONCAT(p.backpack_magazines,p.uniform_magazines,p.vest_magazines),’Exile_Item_Magazine0′,”)))/LENGTH(‘Exile_Item_Magazine0’),0) as cnt1
         FROM exile.player as p
         WHERE p.account_uid = a.uid),0)+
         IFNULL((SELECT SUM(TRUNCATE((LENGTH(v.cargo_magazines)-LENGTH(REPLACE(v.cargo_magazines,’Exile_Item_Magazine0′,”)))/LENGTH(‘Exile_Item_Magazine0’),0)) as cnt2
         FROM exile.vehicle as v
         WHERE v.account_uid = a.uid),0)+
         IFNULL((SELECT SUM(TRUNCATE((LENGTH(c.cargo_magazines)-LENGTH(REPLACE(c.cargo_magazines,’Exile_Item_Magazine0′,”)))/LENGTH(‘Exile_Item_Magazine0’),0)) as cnt3
         FROM exile.container as c
         WHERE c.account_uid = a.uid),0)
     AS SIGNED) as books
FROM exile.account as a WHERE NOT a.name in (‘DMS_PersistentVehicle’) ORDER BY books DESC LIMIT 10;

現在の接続数と更新時間が欲しいので・・

SELECT CAST(COUNT(a.uid) as UNSIGNED) as connected,NOW() as tm FROM exile.account as a WHERE a.last_connect_at > a.last_disconnect_at;

当方で利用してるSQLは、こんな感じです。

お好きな、欲しいデータを出力するSQLを書いてそれぞれに用意します。

JSONを解釈するJavaScript側で、Decimal型をうまく扱えないようで、結構面倒です。なので、実数だけならSQL内でUNSIGNED型に変換しています。

Arma3サーバ側コード

CRONでの設定(定期的実行)

30 * * * * /home/****/arma3/getExileDB.sh

Windowsだと、タスクスケジューラとかかな?

ファイルを送信するシェルスクリプト

Arma3サーバが起動していれば、実行したいSQLをファイルにして、JSONファイルを生成して、まとめてウェブサーバへコピーするだけです。

Windowsだと、PowerShellやBATファイルでの記述になります。中身は結構変わりますが、やる事はシンプルなので。SCPの部分は、別途Termソフトで実現できるかと思います。

下記、青文字部分がCron内で動いてくれない様子なので、緑色文字のようにして、動作確認しました。こっちの方がシンプルw

■getExileDB.sh

#!/bin/sh

count=`ps -e|grep -v grep arma3server|wc -l`
if [ $count -ge 1 ]; then

count=`pgrep arma3`
if [ -n $count ]; then

     cd /home/****/arma3

    cat list_death.sql|python3 get_ExileDB.py > d.json
     cat list_players.sql|python3 get_ExileDB.py > p.json
     cat rank10_death.sql|python3 get_ExileDB.py > rd.json
     cat rank10_kill.sql|python3 get_ExileDB.py > rk.json
     cat rank10_score.sql|python3 get_ExileDB.py > rs.json
     cat rank10_money.sql|python3 get_ExileDB.py > rm.json
     cat rank10_books.sql|python3 get_ExileDB.py > rb.json
     cat connected.sql|python3 get_ExileDB.py > cn.json

    scp -i ~/.ssh/id_rsa /home/****/arma3/*.json (ユーザーID)@(Webサーバ):/(ウェブサーバ側コピー先
fi

SQL結果からJSONファイルを生成するPythonコード

Python3用なので、古いシステムなら注意。必要なら、pipでmysql.connectorをインストールします。

丸っとDBのパスワードが書かれるので、パーミッション設定は確実に(または他の方法で隠してください)

Windowsも、Pythonを別途インストールすればそのまま利用できます(別にPython経由しなくても、MySQLユーティリティ単体で出力できる・・かもしれない、未調査)

■get_ExileDB.py

import sys
import mysql.connector
import json
from datetime import date, datetime
import codecs

input_sql = sys.stdin.readlines()
# db
data = “”
conn = mysql.connector.connect(host=’DBサーバアドレス‘,port=’3306′,user=’DBユーザー‘,password=’DBパスワード‘,database=’exile’)
cursor = conn.cursor(dictionary=True)
try:
     cursor.execute(“”.join(input_sql))
     data = cursor.fetchall()
finally:
     cursor.close()
     conn.close()
def json_serial(obj):
     if isinstance(obj, (datetime, date)):
         return obj.isoformat()
     raise TypeError (“Type %s not serializable” % type(obj))
# convert
#print(data)
print(json.dumps(data, default=json_serial))

ウェブサーバ側コード

image

ウェブ公開ホルダーではなく、ユーザーホームのsabamisoにコピーするようにしてますので、事前に、リンクファイルをウェブ公開ホルダーに生成しておきます。

無事コピーされてるようでしたら、後は簡単です。JSONとJavascriptは相性バツグンです。

ウェブサーバ側にデータがあるので、クロスドメインも気にする事もありません。

HTMLコードは、ブラウザから見れるので、ここで紹介する事もないですけども。

var URL_DATA_PLAYER = ‘p.json’;
var URL_DATA_DEATH = ‘d.json’;
var URL_RANK_BOOK = ‘rb.json’;
var URL_RANK_DEATH = ‘rd.json’;
var URL_RANK_KILL = ‘rk.json’;
var URL_RANK_MONEY = ‘rm.json’;
var URL_RANK_SCORE = ‘rs.json’;
var URL_CONNECTED = ‘cn.json’;
function getJSON(urlServer,fncCall){
     var req = new XMLHttpRequest();
     req.onreadystatechange = function() {
         if(req.readyState == 4 && req.status == 200){
             var data = JSON.parse(req.responseText);
             fncCall(data);
         }
     };
     req.open(“GET”,urlServer,false);
     req.send(null);
}

お約束のコードを書いたら。後は、受信後の部分。

ある程度の加工は、このタイミングで実施します。

$(document).ready(function(){
     getJSON(URL_DATA_PLAYER,
     function(res){
     // Modify data
     res.forEach(function(obj){
         if(obj[‘alive’] == null){obj[‘alive’]=””;}
         else{obj[‘alive’]=obj[‘alive’]-obj[‘last’]+1;};
         var str = obj[‘w’];
         if(str == null){str=””;};
         str = str.replace(/^Exile_Weapon_/,”);
         str = str.replace(/^gac_JSDF_W_R_/,”);
         str = str.replace(/^srifle_/,”);
         str = str.replace(/^arifle_/,”);
         str = str.replace(/_F$/,”);
         obj[‘w’] = str;
         if(obj[‘damage’] == 0){obj[‘damage’]=”無”;};
     });

マップ上に、マッピングする方法も簡単に実装してます。

res.forEach(function(obj){
     var x = obj[‘x’];
     var y = obj[‘y’];
     if(x!=null && y!=null){
         // Marker
         $(‘#s_map’).append(
             “<div style=’position:absolute;left:”+(x/40-12)+”px;bottom:”+(y/40-12)+”px;’><img src=’images/duck.png’><div>”
             );
     };
});

プレーヤーの情報リストはこんな感じで書いてます。Microsoft .Netのデータバインディングの感じで、簡単に設定できます。なお、この段階まで来ると値の加工は出来ません(フィルターは可能)

※eisenbraun-columns

    // Update Player Deail List
     $(‘#columns’).columns({
         data:res,
         schema: [
         {“header”:”武器”, “key”:”w”,”template”:”{{#w}}<strong>{{w}}</strong>{{/w}}”},
         {“header”:”生存”, “key”:”alive”,”template”:”{{#alive}}{{alive}}{{/alive}}”},
         {“header”:”デス数”, “key”:”deaths”},
         {“header”:”キル数”, “key”:”kills”},
         {“header”:”リスペクト”, “key”:”score”},
         {“header”:”負傷”,”key”:”damage”,”template”:”{{#damage}}{{damage}}{{/damage}}”},
         {“header”:”空腹”, “key”:”hunger”,”template”:”{{#hunger}}{{hunger}}{{/hunger}}”},
         {“header”:”水”, “key”:”thirst”,”template”:”{{#thirst}}{{thirst}}{{/thirst}}”},
         {“header”:”所持金”, “key”:”money”,”template”:”{{#money}}{{money}}{{/money}}”},
         {“header”:”接続数”, “key”:”tc”},
         {“header”:”最近”, “key”:”last”}
         ]
     })
     });

なお、JSON結果をそのまんま貼り付けるだけなら、これで結構です。

    getJSON(’JSONファイル’,
     function(res){
         $(‘どこかのDIV‘).columns({data:res})
     });

データの塊だけでなく、以下は、任意のデータを出力したい場合などの例。

現在「接続してるプレーヤー」、「更新時間」の表示を行ってます。

    getJSON(URL_CONNECTED,
     function(res){
         var dt = new Date(res[0][‘tm’]);
         $(‘#apply_time’).text((dt.getMonth()+1)+”/”+dt.getDate()+” “+dt.getHours()+”:”+dt.getMinutes());
         $(‘#connected’).text(res[0][‘connected’]);
     });

量的に全てを公開できないので、分からない方はぜひともご連絡ください。

【見】鯖缶が現物を見に行く@自衛隊まつり

P1130090

陸自第6師団のお祭り(創立記念)に、現物を見に行ってみました。

凄い混みようで、長蛇の渋滞に巻き込まれ、手荷物検査を受け、やっと会場の駐屯地内部に潜入できた。

P1130038

こんな用紙が渡される。メインイベントがそろそろ始まってしまう。

P1130020

良い場所は全て取られてしまってる。

(;´Д`)

P1130014

ちょっとだけ時間があったので、売店へ。

自衛隊関連の土産が凄い事になってたw

P1130015

サバゲーショップ顔負けの品揃えです。5mm・7.62mm小銃クリーニングキットとか平然と売ってましたが・・、誰が買うんですか?w

(;・∀・)

P1130079

FaminyMartではなく、FamilyMartの方がありましたw

(;^ω^)

P1130016

メインイベントが始まったようなので、急いで会場に向かいます。

P1130018

UH-1の編隊飛行っす。こちらのUH-1のプロペラはしっかり回ってました。

P1130021

はい、現物の89式です。ご苦労さまです。

P1130023

ドゥンドゥンいらっしゃいます。福島の方からも来てるそうです。

P1130026

我がサーバにも登場するカワサキバイクカワサキです。

P1130032

榴弾砲ぇ・・

P1130028

(見切れてしまった)16式かな?(あんまり詳しくないので)

P1130033

対空のやつとか(後ほど近影)

P1130036

ショベルカーも迷彩。

P1130039

かっちょええ。

P1130041

この辺から戦闘車両が続きます。

P1130042

これが96式かな・・。

P1130043

やっべ(声が漏れる)かっちょ良すぎる。

P1130044

上空には、AH-1戦闘ヘリが。

P1130037

旭日旗が映えております。ここで、訓練展示の準備で、しばらく待ちます。

P1130045

屋台が恐ろしい程に乱立しております。

P1130046

隊員クラブはなの舞・・駐屯地内のくつろぎの場なんでしょうか。

P1130047

体験搭乗できるらしいんですが・・、周りには子供が沢山いるんですよね・・。乗ってみたいけど・・将来を担うお子様達に譲る事にしましょう。

P1130049

16式が整然と並んでる。先程のナレーションでは、MCVと呼んでました。

P1130050

さて、訓練展示の開始です!架空のストーリーで進んでいきます。

UH-1からのラペリング(懸垂下降)でスタート。しかし、ヘリの操縦が上手い、キレイにホバーして無駄なく飛び去っていきます。

P1130052

AH-1の援護で、陣地確保の様子。

P1130055

きた、120mmと80mmの迫撃砲。

(゚∀゚)特科ッ

P1130057

大きな音がする時は、目の前の隊員がこんなプラカードを上げます。

(#゚Д゚)!「大きな音がします

無論、空砲ですので、イメージで、向こう側で煙が炊かれる。

P1130058

ドゥン!ドゥン!地面が揺れる程の爆音です。

16式の空砲よりも、榴弾砲の方がめっちゃ凄い音です。

P1130059

最終局面の突撃ッ!の様子。

P1130061

一斉掃射!

P1130062

・・と、怪しげな一台が観客席の前に停車。

(゚Д゚)!「急募!自衛官

の文字が・・。ここでも人手不足らしい。

P1130065

演習が終わったので、展示を見に行きます。

81式地対空誘導弾車両。やべー

P1130066

このレールの上にミサイルを乗っけるようです。

P1130067

ミサイルはこれ。一発、いくらするんでしょうか。

((((;゚Д゚))))

P1130068

これも93式地対空誘導弾車両

P1130069

何を隠そう、なんと、東芝製!?

P1130070

ミサイルポッドの背面部分から。

P1130071

運転席はこんなです。車両の方はトヨタ製なんですね。ATなんだw

いずれも特殊なタイヤは全てブリジストン製です。全てが国産なんですね。

P1130072

軽装甲車両LAV・ラブ。

P1130073

中はメチャメチャ狭かった。ギリギリ6人乗れるかどーか、な感じ。

P1130074

こちらは、あのコマツ。

ヽ(;゚д゚)ノ 国産すげー

P1130075

87式偵察車両。25mmと、7.62mmが装備されてるようです。

7.62mm砲はどこに付いてるんですか?と隊員さんに聞いたら・・

P1130076

あ・・主砲の横に付いてたw

(;^ω^)

P1130077

カワサキのバイクです。

P1130080

榴弾砲、軽く30-40Kmは飛ぶらしい。おとろしい

P1130081

UH-1とAH-1が、体験搭乗の準備に入ってるようです。

P1130085

Σ(゚∀゚ノ)ノ

P1130086

Σ(゚∀゚ノ)ノ

P1130087

先程の榴弾砲、自走出来たんだ・・w

P1130088

名前失念。

P1130089

74式かな?

ずっと前に来た時は、確か小銃の展示もあったような気がしたんだが、どこを探しても無かった。

小型火器も観察したくて来たので、残念やった・・。

。゚(゚´Д`゚)゚。

足が棒になりそうやったので、ここらへんで帰りました。駐車場まで、軽く1Kmはあるのだ。

※鯖缶:Arma3というゲームのサーバ(≒鯖)を管理してるので、こういうタイトルになった

大人向け硬派過ぎるPCゲーム「Arma3」を超オススメします。ぜひとも、うちのサーバに来てくんなまし。

ARMA3 EXILE 鯖味噌サーバ 89式小銃や三菱・カワサキも乗れる超過酷系サバイバル