結果だけでなく過程も見てください

たい焼きさんの日々の奮闘を綴る日記です。

Excel VBAでセルを操作する関数等リファレンス 個人的メモ

今更こんなものまとめるのは大変遺憾なのですが、色々なサイトを巡るのが面倒なため個人的に必要な情報だけまとめます。
必要に応じて拡張していきます。

Excel VBAには初めて触れるため、間違いがあればご指摘ください。

前提知識いろいろ

  • Excel上でAlt + F11を押すとコードエディタが開く
  • デバッグ時 ステップインはF8、ステップアウトはShift+F8、ステップオーバーはCtrl + Shift + F8
  • Debug.Print関数の出力先は、コードエディタの[表示]→イミディエイトウィンドウで開ける

文法やら細かいところ

ループ文
Dim i As Long
For i = 0 To 3
 処理
 Exit For ←break相当
Next i

Do
 処理
 Exit Do ←break相当
Loop Until 式
条件式
If a = b Then
ElseIf c <> d Then
Else
End If

式を評価してtrueの場合に返る値と、falseの時に返る値を指定したいときはIIfを使う。
以下はa=bのとき10が返り、そうでないときは5が返る例。

IIf(a=b,10,5)
演算子
比較演算子 < <= >= > = <> <>は等しくない(!=)の意
論理演算子 And Or Not
関数

Subは戻り値を扱えない。Functionは戻り値を扱うことができる。

Sub func()
  ExitSub  ←return相当
End Sub
Function func()
  func = 10   ←プロシージャ―名に値を入れることが戻り値を設定することに相当する。
  Exit Function  ←return相当
End Function

関数の呼び出し方。
Callステートメントで関数をコールする場合と、Callを省略する場合で引数の渡し方が異なるので注意!
参考:
Office TANAKA - VBAのステートメント[Call]


Callステートメントをつける場合は引数を()で囲って呼び出す。()をつけないとエラーになる。

Call func(a, b)

Callを省略する場合は引数を()で囲わずに呼び出す。()をつけるとエラーになることがある

func a,b

またいくつか注意点が。

  • 配列を引数として渡すときはCallをつけて呼び出す必要がある(これ本当?)
  • 戻り値を受け取る場合はCallを省略し、()をつけて引数を渡さなければならない

疑問点。
↑が本当なら引数で配列を受け取り、戻り値を返す関数が作れないということになるのですが…。
動作させてみると上記のようになっているのですが、どなたか解決法知りませんか?

配列周り

配列の定義は以下。
他言語と違い、配列サイズを渡すのではなく配列に格納できる最大インデックスを渡す点に注意すること
つまり以下の例ではvalueArray(5)としているが、これはインデックス0, 1, 2, 3, 4, 5が格納可能なサイズ6の配列を定義していることになる。
また、変数定義時に配列のサイズを指定しない場合は、後にReDimで配列サイズを拡張する必要がある。

Dim valueArray(5) As Long
Dim emptyArray() As Long

配列に値が格納されている最も小さいインデックスおよび、値を入れることができる最大インデックスはそれぞれLBound,UBound関数で求められる。
これは配列のサイズや要素数ではなく、インデックスが返ってきている点に注意。
なお変数定義時にサイズを指定していないものをLBoundおよびUBoundに渡すと「インデックスが有効範囲にありません。」エラーになる。

Dim valueArray(5) As Long
valueArray(0) = 10

LBound(valueArray) → 0が返る
UBound(valueArray) → 5が返る
Dim emptyArray() As Long

LBound(valueArray) → 「インデックスが有効範囲にありません。」エラー
UBound(valueArray) → 「インデックスが有効範囲にありません。」エラー
Dim emptyArray() As Long

ReDim emptyArray(2)
emptyArray(0) = 10
emptyArray(1) = 11

LBound(valueArray) → 0が返る
UBound(valueArray) → 2が返る

配列がサイズが0(初期化されていない状態)かどうかを判定する方法。
ネットで調べるとSgn関数で判定可能とありますが、この関数は使うべきではないと思います。理由は以下。

<理由>
本来Sgn関数は渡された数値の符号を判定して正なら1、0なら0、負なら-1を返す関数であり、配列は渡せないはずです。
しかしSgn関数に配列を渡すと、初期化されていないと0、初期化されていると-16064を返す動作をします。
しかし環境によっては「エラーコード51の内部エラー」になることから、おそらくバグでたまたまこのような動作をしているものと考えられます。

というわけで、配列サイズが0かどうか判定するときは、以下のような関数を作って判定しましょう。

'配列arrが初期化されていない(配列サイズが0)場合:0を返す
'配列arrが初期化されている(配列サイズが1以上)の場合:1を返す
'arrが配列でない等予期せぬエラーの場合:-1を返す
Public Function IsArrayEmpty(arr As Variant) As Integer
On Error GoTo ERR_CATCH

    IsArrayEmpty = -1

    Dim tmp As Integer
    tmp = UBound(arr)
    If tmp < 0 Then
        ' ユーザー定義型の場合は例外は発生せず-1が返ってくるため、ここで空として判断する
        IsArrayEmpty = 0
        Exit Function
    End If
    
    IsArrayEmpty = 1
    Exit Function

ERR_CATCH:
    If Err.Number = 9 Then
        IsArrayEmpty = 0
    End If
End Function

呼び出し方は以下。
aは初期化済(サイズが0でない)配列、bが初期化されてない(サイズが0の)配列、cは配列でない変数です。

  Dim a(5) As Long
  Dim b() As Long
  Dim c As Long
    
  If IsArrayEmpty(a) > 0 Then
      Debug.Print ("UBound(a)=" & UBound(a))
  End If
  
  If IsArrayEmpty(b) = 0 Then
      Debug.Print ("bは初期化されていない(サイズが0の)配列です")
  End If
  
  If IsArrayEmpty(c) = -1 Then
      Debug.Print ("予期せぬエラー(cが配列かどうか確認してください)")
  End If

メッセージ出力

メッセージウィンドウに出力
MsgBox 文字列
デバッグウィンドウに出力

コードエディタの[表示]→イミディエイトウィンドウに出力される。

Debug.Print(文字列)

エラー

事象 対処
メッセージボックス「400」とだけ表示される 400は「アプリケーション定義またはオブジェクト定義のエラーです。」の意味。識別子のタイプミス等。xlToRightをxlRightと書いてしまう等。
Setで変数を更新するとコンパイルエラーと言われる Setで更新するのはSheetなどのオブジェクトだけ。Long型やString型などプリミティブな?型はSetを使わずに代入しなければならない

x列目y行目のセルの値を取得・値を設定

取得
Dim cell As Range
cell = Cells(1,1)
Debug.Print(cell.Value)

なお「A1」のような名前でセルを指定することも可能。

Dim cell As Range
cell = Range("A1")
Debug.Print(cell.Value)
設定

セル操作をするには、まず書き込むシートをアクティブ化する必要がある。

以下は書き込み対象とは別のシート(例:def)から書き込みをする例。
シートdefの関数から別シート(xyz)を用意する場合は、別シート(xyz)をアクティブ化した後、アクティブ化したシートを指定してセルに値を入れる必要がある。
ここをActiveSheet.をつけずに単にCells(1,1)としてしまうと、元のシート(def)に書き込まれてしまうので注意。
(Cells単体の場合Me.(C++でいうthisポインタのようなもの)が省略されているためと思われる)

以下は"xyz"というシートの左上に値10を設定する例。

Worksheets("xyz").Activate
ActiveSheet.Cells(1, 1) = 10

何度もActiveSheet.とつけるのが面倒な場合はWithステートメントを使って省略することができる。
ただし省略する場合は以下例のように頭に「.」をつけること。

Worksheets("xyz").Activate
With ActiveSheet
    .Cells(1, 1) = 10
    .Cells(1, 2) = 20
    :
End With

アクティブなセルを取得

Dim cell As Range
cell = ActiveCell
Debug.Print(cell.Value)

選択しているセル(複数選択可)を取得

Dim cells As Range
cells = Selection

以下のようなセルを選択していた場合。

1 2 3
4 5 6
7 8 9

Selection(x)のxに渡す数値と、取得できる値は以下の通り。

Selection(1) 1
Selection(2) 2
Selection(3) 3
Selection(4) 4
Selection(5) 5
Selection(6) 6
Selection(7) 7
Selection(8) 8
Selection(9) 9

選択範囲の行と列の数の取得方法は以下。

行数を取得 Selection.Rows.Count
列数を取得 Selection.Columns.Count

ここで例。二次元配列っぽく全データを巡回したいときはこう。

Dim x,y As Long
Dim data As Range
Set data = Selection
For y = 1 To data.Rows.Count
  For x = 1 To data.Columns.Count
    Debug.Print( data(x + (y-1)*data.Columns.Count).Value )
  Next x
Next y

1つ隣のセルを取得する

これはセル上でTabやShift+Tabを押したときに選択されるセルを取得する

1つ前のセル(Shift+Tab相当) ActiveCell.Previous
1つ次のセル(Tab相当) ActiveCell.Next

特定のセルから辿った終端セルを取得する

これはCtrl+矢印で取得できるセルに相当する。
以下は左上(1,1)のセルから辿った終端セルを取得するコード。

Dim cell As Range
cell = Cells(1,1).End(方向)

方向については以下の通り。

上(Ctrl+↑相当) xlUp
下(Ctrl+↓相当) xlDown
左(Ctrl+←相当) xlToLeft
右(Ctrl+→相当) xlToRight

終端セルが何番目か、数値で取得するには以下の通り。

Cells(1,1).End(xlToRight).Column 列が4つなら「4」が返ってくる
Cells(1,1).End(xlDown).Row 行が4つなら「4」が返ってくる

変数の型を判定する

式を評価し、その型を数値で返す。
数値はこのあたりを参照のこと。
Office TANAKA - Excel VBA関数[VarType]
VarType 関数 (Visual Basic for Applications) | Microsoft Docs

VarType(式)

セルが空かどうかを返す

IsEmpty(Cells(1,1))

可変配列(もどき)

以下は配列arrayを定義し、ReDimを使って配列サイズを1つ拡張している。
Preserveをつけると配列のデータを保持したままサイズを拡張する

Dim array() As String
処理
ReDim Preserve array(UBound(array) + 1)

セルをクリア(空にする)・削除

左上のセルをクリアする
Cells(1,1).Clear
範囲指定してクリアする

以下どちらでもよい。

Range("A1:B2").Clear
Range(Cells(1,1), Cells(2,2)).Clear
列全体をクリアする

以下どちらでもよい。

Range("A1").EntireColumn.Clear
Cells(1,1).EntireColumn.Clear
行全体をクリアする

以下どちらでもよい。

Range("A1").EntireRow.Clear
Cells(1,1).EntireRow.Clear
列・行を削除する

見ればわかると思うので説明は省略。

Range("A1").EntireColumn.Delete
or
Cells(1,1).EntireColumn.Delete

Range("A1").EntireRow.Delete
or
Cells(1,1).EntireRow.Delete

構造体

Excel VBAにもC言語の構造体(struct)相当の仕組みが存在します。
以下は名前、年齢、コメントを持つStudent構造体の宣言方法です。

Private Type TStudent
    name As String
    age As Long
    comment As String
End Type

使用するときは、通常の型と同様以下のように変数定義します。

Dim student1 As TStudent

student1.name = "FUFUFU.T"
student1.age = 18
student1.comment = "good"

なお、構造体のスコープにはPublicとPrivateがありますが、標準モジュールなどに定義するときにはPublicが使えますが、Sheet1などのシートモジュールに定義する際はPrivateにする必要があります。
※ちなみに元々1つあるThisWorkbookはブックモジュールである。

サンプルプログラム 1行1レコードから日付ごとのレコード数を数える

サンプルデータ

日付 名前 点数 コメント
2020/6/1 TANAKA 80 aaaaa
2020/6/2 MAMADA 100 bbbbb
2020/6/3 HAKAMA 50 ccccc
2020/6/3 AYAYA 77 ddddd
2020/6/5 MOMOMO 99 eeeee

プログラム
以下は"def"というシートに定義するものとします。
"def"シートにボタン等を配置し、ボタンが押されたらこの関数がコールされるようにしてください。

Option Explicit

Private Type TRecord
    date As Date
    count As Long
End Type

Sub defFunc()
    Dim records() As TRecord
    ReDim records(0)
    
    ' データが1つもなければ何もせず帰る
    If IsEmpty(Cells(2, 1)) Then
        Exit Sub
    End If
    
    Dim LineNum As Long
    LineNum = Cells(1, 1).End(xlDown).Row
    
    
    ' めんどくせーけどy=2(最初のデータ)だけ特別扱いする。可変配列はReDim xxx(0)で
    ' 最低1つ分のデータを持たせておかないとUBound関数でエラーになるため。
    
    records(0).date = Cells(2, 1)
    records(0).count = 1
        
        
    ' 3行目(2つ目のデータ)からはループで処理する
    Dim y As Long
    For y = 3 To LineNum
        
        Dim bFoundSameDate As Boolean
        bFoundSameDate = False
        
        ' すでに同じ日付がないか、日付配列から検索する
        Dim indexForFind As Long
        For indexForFind = 0 To UBound(records)
            If records(indexForFind).date = Cells(y, 1) Then
                bFoundSameDate = True
                Exit For
            End If
        Next indexForFind
        
        If bFoundSameDate = True Then
            'すでに一回以上出てきている日付。そしてそのインデックスはindexForFind。
            records(indexForFind).count = records(indexForFind).count + 1
        Else
            '初めて出てきた日付なので、配列を+1してカウントは1としておく。
            ReDim Preserve records(UBound(records) + 1)
            records(UBound(records)).date = Cells(y, 1)
            records(UBound(records)).count = 1
        End If
        
    Next y
    
    
    ' コンソールに結果表示
    Dim c As Long
    For c = 0 To UBound(records)
        Debug.Print ("date=" & records(c).date & "  count=" & records(c).count)
    Next c
    
    
    ' "xyz"というシート(事前に作成しておく)に結果を書き込む
    Worksheets("xyz").Activate
    ActiveSheet.Cells(1, 1).EntireColumn.Clear
    ActiveSheet.Cells(1, 2).EntireColumn.Clear
    
    Dim i As Long
    For i = 0 To UBound(records)
        ActiveSheet.Cells(i + 1, 1) = records(i).date
        ActiveSheet.Cells(i + 1, 2) = records(i).count
    Next i

    ' 累計も出してみる
    ActiveSheet.Cells(1, 3).Value = "=B1"
    ActiveSheet.Cells(2, 3).Value = "=B2+C1"
    ' ここからオートフィルで埋める
    ActiveSheet.Range("C2").AutoFill Destination:=ActiveSheet.Range("C2:C" & ActiveSheet.Cells(1, 2).End(xlDown).Row)

End Sub

結果はこのように出力される。

date=2020/06/01  count=1
date=2020/06/02  count=1
date=2020/06/03  count=2
date=2020/06/05  count=1

さらに別シートxyzに以下のデータが書き込まれる。

2020/6/1 1 1
2020/6/2 1 2
2020/6/3 2 4
2020/6/5 1 5

個人的なメモ

abcというシートに目標件数を入れる場合の例。
abcシートの内容は以下の通り。カラムは日付、目標件数である。

2020/6/1 1
2020/6/2 1
2020/6/3 2
2020/6/4 3
2020/6/5 1
Option Explicit

Private Type TRecord
    date As Date
    bugCount As Long      '実績件数
    expectCount As Long   '目標件数(こっちは累計)
End Type

Sub defFunc()
    Dim records() As TRecord
    ReDim records(0)
    
    ' データが1つもなければ何もせず帰る
    If IsEmpty(Cells(2, 1)) Then
        Exit Sub
    End If
    
    Dim LineNum As Long
    LineNum = Cells(1, 1).End(xlDown).Row
    
    
    ' まず実績を読む
    ' めんどくせーけどy=2(最初のデータ)だけ特別扱いする。可変配列はReDim xxx(0)で
    ' 最低1つ分のデータを持たせておかないとUBound関数でエラーになるため。
    
    records(0).date = Cells(2, 1)
    records(0).bugCount = 1
    records(0).expectCount = 0
        
        
    ' 3行目(2つ目のデータ)からはループで処理する
    Dim y As Long
    For y = 3 To LineNum
        
        Dim bFoundSameDate As Boolean
        bFoundSameDate = False
        
        ' すでに同じ日付がないか、日付配列から検索する
        Dim indexForFind As Long
        For indexForFind = 0 To UBound(records)
            If records(indexForFind).date = Cells(y, 1) Then
                bFoundSameDate = True
                Exit For
            End If
        Next indexForFind
        
        If bFoundSameDate = True Then
            'すでに一回以上出てきている日付。そしてそのインデックスはindexForFind。
            records(indexForFind).bugCount = records(indexForFind).bugCount + 1
        Else
            '初めて出てきた日付なので、配列を+1してカウントは1としておく。
            ReDim Preserve records(UBound(records) + 1)
            records(UBound(records)).date = Cells(y, 1)
            records(UBound(records)).bugCount = 1
            records(UBound(records)).expectCount = -1
        End If
        
    Next y
    
    
    ' 続いて、目標件数を読む
    Worksheets("abc").Activate
        
    ' 目標件数の累計を出す。目標件数は面倒なんで累計で読んじゃう。
    ActiveSheet.Cells(1, 3).Value = "=B1"
    ActiveSheet.Cells(2, 3).Value = "=B2+C1"
    ' ここからオートフィルで埋める
    ActiveSheet.Range("C2").AutoFill Destination:=ActiveSheet.Range("C2:C" & ActiveSheet.Cells(1, 1).End(xlDown).Row)
        
    ' ヘッダがないので最初の行から読む
    LineNum = ActiveSheet.Cells(1, 1).End(xlDown).Row
'    Dim y As Long
    For y = 1 To LineNum

        'Dim bFoundSameDate As Boolean
        bFoundSameDate = False

        ' すでに同じ日付がないか、日付配列から検索する
        'Dim indexForFind As Long
        For indexForFind = 0 To UBound(records)
            If records(indexForFind).date = ActiveSheet.Cells(y, 1) Then
                bFoundSameDate = True
                Exit For
            End If
        Next indexForFind
        
        If bFoundSameDate = True Then
            'すでに一回以上出てきている日付。そしてそのインデックスはindexForFind。
            records(indexForFind).expectCount = ActiveSheet.Cells(y, 3)
        Else
            '初めて出てきた日付なので、配列サイズを+1して値を入れる
            ReDim Preserve records(UBound(records) + 1)
            records(UBound(records)).date = ActiveSheet.Cells(y, 1)
            records(UBound(records)).bugCount = 0
            records(UBound(records)).expectCount = ActiveSheet.Cells(y, 3)
        End If

    Next y

        
    ' コンソールに結果表示
    'Dim c As Long
    'For c = 0 To UBound(records)
    '    Debug.Print ("date=" & records(c).date & "  bugCount=" & records(c).bugCount)
    'Next c
    
    
    ' "xyz"というシート(事前に作成しておく)に結果を書き込む
    Worksheets("xyz").Activate
    ActiveSheet.Cells(1, 1).EntireColumn.Clear
    ActiveSheet.Cells(1, 2).EntireColumn.Clear
    ActiveSheet.Cells(1, 3).EntireColumn.Clear
    ActiveSheet.Cells(1, 4).EntireColumn.Clear
    
    ActiveSheet.Cells(1, 1) = "日付"
    ActiveSheet.Cells(1, 2) = "目標件数(累計)"
    ActiveSheet.Cells(1, 3) = "実績件数(累計)"
    ActiveSheet.Cells(1, 4) = "実績件数(日毎)"
    
    Dim i As Long
    For i = 0 To UBound(records)
        ActiveSheet.Cells(i + 2, 1) = records(i).date
        ActiveSheet.Cells(i + 2, 2) = records(i).expectCount  '目標件数(累計)
        ActiveSheet.Cells(i + 2, 4) = records(i).bugCount     '実績件数
    Next i
    
    
    ' 日付順にソート
    Call ActiveSheet.Range("A2:D" & ActiveSheet.Cells(2, 1).End(xlDown).Row).Sort(Key1:=ActiveSheet.Range("A2"))
    
    
    ' 目標件数の累計は、目標の入力データがない場合-1になっているので、その日付の時点で最も大きい件数を入れて補完する
    Dim expectMaxCount As Long
    expectMaxCount = 0
    For y = 2 To ActiveSheet.Cells(2, 1).End(xlDown).Row
        If ActiveSheet.Cells(y, 2) = -1 Then
            ActiveSheet.Cells(y, 2) = expectMaxCount
        Else
            expectMaxCount = ActiveSheet.Cells(y, 2)
        End If
    Next y
    
    
    ' 実績の累計も出してみる
    ActiveSheet.Cells(2, 3).Value = "=D2"
    ActiveSheet.Cells(3, 3).Value = "=D3+C2"
    ' ここからオートフィルで埋める
    ActiveSheet.Range("C3").AutoFill Destination:=ActiveSheet.Range("C3:C" & ActiveSheet.Cells(2, 1).End(xlDown).Row)
    
End Sub

結果は以下のようになる。

日付 目標件数(累計) 実績件数(累計) 実績件数(日毎)
2020/6/1 1 1 1
2020/6/2 2 2 1
2020/6/3 4 4 2
2020/6/4 7 4 0
2020/6/5 8 5 1

Linux(CentOS)でRAID1運用しているディスクにエラーが発生したときメール通知させる方法

方法自体は大したことやってないのですが、備忘録として書いておきます。

メールの通知先がGmailの場合は、先日書いた以下の記事も参考にしてください!
taiyakisun.hatenablog.com

手順

RAIDシステム状態を確認するスクリプト

以下のperlスクリプトを、メールアドレス部分を自身のものに書き換えてから任意のファイルに保存します。
なお、perlが入ってない人はyum等でインストールしてください。

#!/bin/perl
use strict;

my @mdstat_lines = `cat /proc/mdstat`;
my $mdstat_len   = @mdstat_lines;
my $mail_msg;

for ( my $i=1; $i < $mdstat_len;  )
{
    if ( ($mdstat_lines[$i] eq "") or ($mdstat_lines[$i] =~ /Personalities/) )
    {
       ++$i;
       next;
    }

    if ( $mdstat_lines[$i] =~ /unused devices/ )
    {
       # The last line of the mdstat output.
       last;
    }

    if ( !($mdstat_lines[$i] =~ /([a-zA-Z0-9]+) : .+/g) or !defined($1) )
    {
       ++$i;
       next;
    }

    my $id = $1;

    # Going to next line.
    ++$i;

    if ( !($mdstat_lines[$i] =~ /blocks .+ \[([U_][U_])\]/g) or !defined($1) )
    {
       ++$i;
       next;
    }

    my $status = $1;

    if ( $status ne "UU" )
    {
       $mail_msg .= "Warning. RAID1 disks(" . $id . ") may have some errors(" . $status . ").\n";
    }

    ++$i;
}

if ( $mail_msg ne "" )
{
    open FH,'|mail -s "[Warning] Home server RAID system errors have been detected." mygmailaddress@gmail.com' or die;
    print FH $mail_msg;
    close FH;
}
cronで定期的にスクリプトを実行させる

ここでは例として一日に一回実行させてみることにします。

crontab -e

perlスクリプトを/usr/local/bin/chkmdstat.plとして保存していて、毎日午前0時に実行する場合の例は以下です。

0 0 * * * /usr/local/bin/chkmdstat.pl

念のためですが、以下も忘れないようにしておいてください。

chmod +x /usr/local/bin/chkmdstat.pl

参考サイト

rfs.jp

PostfixからGmail宛へのメール送信で550-5.7.1エラーやポート25番Connection refusedエラーになるときの対処法

自分は携帯電話の写真や動画を自宅サーバーのRAID1で運用しているのですが、冗長化したディスクの一部にエラーが発生した場合等、メールで通知してほしい場合があります。

で、手軽に扱えるGmailを使いたいわけですが、何も考えずにmailコマンドなどでGmailにメールを送ろうとすると題名にあるエラーになってしまいます。今回はこのエラーを回避して自宅サーバーやAWS等のサーバーからGmail宛にメールを送れるようにする方法をご紹介します。

根本的な対処方法(今回これはやりません)

以下の公式のガイドにもあるように、Gmailは不正なメールを検知するためにIPアドレスの逆引きを行います。そのため自宅サーバーからメールを送る場合は、インターネット上でドメイン名を取得し、ポインタ(PTR)レコードを正確に設定して逆引きが行えるようにしておく必要があります。
https://support.google.com/mail/answer/81126?hl=ja

自分の自宅サーバーはドメインは取得していないため、根本的な対策は行いません。
今回は、PostfixからGmailにメールを転送してGmailSMTPサーバーとして利用してメール送信する方法を取ります。

前提パッケージのインストール

Postfix, mailx(mailコマンド), SMTP認証を行うためのライブラリをインストールします。

yum -y install postfix
yum -y install mailx
yum -y cyrus-sasl cyrus-sasl-plain

以下を実行して起動/自動起動を設定しておきます。

systemctl start postfix
systemctl enable postfix
systemctl start saslauthd
systemctl enable saslauthd

手順

ホストの名前解決

/etc/hostsやDNSでホスト名が名前解決できるようにしておきます。
今回自分はサーバーではドメイン名は設定していません。以下は例です。

192.168.2.5  myserver
メールの転送設定

/etc/postfix/main.cfの末尾に以下の二行を追加します。
これはgmail宛のメールだけ、GmailSMTPサーバーへ転送するための設定です。

gmail.com  smtp:[smtp.gmail.com]:587
*          :

その後、postmapコマンドを使って↑で作成したファイルの情報をPostfixのDBにします。

postmap /etc/postfix/transport

/etc/postfix/transport.dbが作成されていることを確認してください。

サーバーをIPv6で運用していない場合の設定

この設定をしないとPostfixIPv6を優先的に使おうとしてエラーになることがあります。
/etc/postfix/main.cfを以下のように書き換えます。

inet_protocols = all
↓
inet_protocols = ipv4
Postfixの色々な設定

これも/etc/postfix/main.cfを編集します。以下のパラメーター部分を編集してください。
IPアドレスの部分はご自分の環境に合わせてください。

myhostname = myserver
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
mynetworks = 127.0.0.0/8 192.168.2.0/24
home_mailbox = Maildir/
SMTP認証の設定

これも/etc/postfix/main.cfを編集します。末尾に以下を追加してください。

# smtp-auth
relayhost = [smtp.gmail.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/relay_password
smtp_sasl_security_options = noanonymous

# starttls
smtp_tls_security_level = may
smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt

上で記載したパスワードファイルを作成していきます。
/etc/postfix/relay_passwordを作成して、以下のようにGmailアドレスとそのパスワードを入力してください。

[smtp.gmail.com]:587 mygmailaddress@gmail.com:mygmailpassword

その後以下のコマンドを実行します。

chmod 600 /etc/postfix/relay_password
postmap hash:/etc/postfix/relay_password
Postfixに設定を反映する

サービスを再起動して設定を反映しましょう。

systemctl restart postfix
Gmail側の設定

セキュリティの観点から、Gmailは信頼性の低いクライアントからメールの受信を許可していません。
今回はこの設定を許可するように変更して、自宅サーバーからのメールを受信できるようにします。
https://myaccount.google.com/lesssecureapps

テストメールを送ってみる

以下のコマンドを実行してメールを送ってください。

echo "test from myserver" | mail -s "test mail" mygmailaddress@gmail.com

サマータイム(夏時間)について勉強する

※整理しきれていないため、修正・加筆予定です。

サマータイム(夏時間、Daylight saving time)は、日本ではあまり馴染みがありませんが、欧米で採用されている仕組みです。

簡単に言うと、地域全体で時計をずらし、太陽が出ている時間帯を有効に使おうというものです。

この仕組み自体はコンピューターの仕組みというわけではなく、地域全体で時計をずらすため、その地域で動作するコンピューターでもその仕組みに合わせて時計を動かさなきゃね、というものになります。

ここにものすごくわかりやすい説明がありましたのでリンクを貼っておきます。
http://gakusyu.shizuoka-c.ed.jp/shakai/jisa/009%20sama-taimutte.htm

さらに詳細を知りたい方はWikipediaなんかを参照してください。

OSの夏時間の設定

Windowsでの夏時間の設定方法

コントロールパネルで「日付と時刻」→「タイム ゾーンの設定」と選択します。

日本に住んでいる人は、地域が「東京、大阪」などになると思いますが、ここを、サマータイムを採用している国に変更します。イギリスや、アメリカの特定に地域等ですね。

ここでは「(UTC+00:00) ダブリン、エジンバラリスボン、ロンドン」とします。
また「自動的に夏時間の調整をする」といった設定にはチェックを入れます。

Linuxでの夏時間の設定方法

環境変数TZを設定します。あとで書きます。

プログラム(C/C++)で夏時間を扱う

ここでは年月日や時刻(YYYYMMDD等)、人が通常使う表記のことをISO 8601形式と呼ぶことにします。

UNIX時間からISO 8601形式への変換

注意書きだらけですみません。

UNIX時間(UNIX時刻,POSIX時刻)というのは1970年1月1日午前0時0分0秒からの経過秒数です。
うるう秒は加味せず、8時59分59秒→8時59分60秒といった瞬間も+1されています。
現在時刻から、UNIX時間を算出してくれるWebシステムがありますが、
そのWebシステムが「現在時刻」をローカル時刻とみなすかどうかを意識してください。

例えば
https://url-c.com/tc/
こちらのサイトでは、現在時刻がローカル時刻になっています。

https://www.epochconverter.com/
こちらのサイトでは、現在時刻をGMTかLocal timeから選択できるようになっています。

ここを間違えると、日本の場合9時間分がズレてしまいますのでご注意ください。
夏時間がいつから開始(時計が一定時間スキップされます0:59:59→2:00:00)され、
終了(時計が一定時間同じ時間を繰り返します1:59:59→1:00:00)するかは、地域によって異なります。
2019年の「(UTC+00:00) ダブリン、エジンバラ、リスボン、ロンドン」では以下の通り。

開始:2019/03/31(日) 02:00 (OS上は03/31 0:59:59→1秒後 03/31 2:00:00)
終了:2019/10/27(日) 01:00 (OS上は10/27 1:59:59→1秒後 10/27 1:00:00)

このあたりから確認できます。
https://www.jisakeisan.com/summertime/london/

以下のようなソースコードで検証を行ってみます。
夏時間が有効な地域かどうかわからないため、夏時間フラグは手動で入力しています。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>

void settm(struct tm* ptm, int year, int mon, int day, int hour, int min, int sec, int isdst)
{
	ptm->tm_year = year - 1900;
	ptm->tm_mon = mon - 1;
	ptm->tm_mday = day;
	ptm->tm_hour = hour;
	ptm->tm_min = min;
	ptm->tm_sec = sec;
	ptm->tm_isdst = isdst;
}

int main()
{
    struct tm  tmp = {0};
    time_t     tt  = 0;

    // TODO:ここでtmpに年月日と時刻を入れます。夏時間が有効であればisdstに1、そうでなければ0を入れます。
    // 例 settm(&tmp, 2019, 12, 15, 3, 0, 0, 1);

    tt = mktime(&tmp);
    printf("%lld  %d/%d/%d %d:%d:%d\n", tt, tmp.tm_year + 1900, tmp.tm_mon + 1, tmp.tm_mday, tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
}

自分が検証したかったのは、OSの「自動的に夏時間を調整する」の設定有無と、プログラム上のtm_isdstフラグの組み合わせで、サマータイム開始・終了時間帯を指定した場合どういう結果になるのか?ということです。

今回の入力は「2019/03/31 01:30(UNIX時間:1553995800)」です。
この2019/03/31 01:30は日本時間(ローカル時刻)ではなく、GMTであることを意識してください。
間違えると日本時間はGMTから+9時間のズレがあるので、その分UNIX時間もズレてしまいます。

結果。

# OSの夏時間設定 struct tmのtm_isdst mktimeの結果 mktimeの結果のISO 8601形式表記
なし 0 1553995800 2019/03/31 01:30:00
あり 0 1553995800 2019/03/31 02:30:00
なし 1 1553995800 2019/03/31 01:30:00
あり 1 1553992200 2019/03/31 00:30:00

で、なぜこの結果になるのかを考えてみました。

①のケース(OSの夏時間設定:なし tm_isdst:0)

夏時間に合わせて時刻を合わせないし、サマータイム影響中でもない。つまり渡された時刻をそのまま処理する。だから結果は3/31 1:30のままとなる。

②のケース(OSの夏時間設定:あり tm_isdst:0)

このケースは、OSは夏時間に合わせて時刻をずらす気まんまんだが、tm_isdstではサマータイム影響中でないことになっている。
そう言われたらOSはそれを信じるしかないので、純粋に3/31 1:30を処理しようとする。
しかし夏時間としては、3/31 1:30は存在しない時刻なので、夏時間の定義に従って2:30に補正する。
重要なのは見た目の時間が変わっているだけであって、通算秒は変わっていない点。

③のケース(OSの夏時間設定:なし tm_isdst:1)

3/31 1:30はサマータイム影響中と主張しているが、OSとしては夏時間に合わせて時刻をずらさないので、渡されたものをそのまま処理する。夏時間影響であれば本当は存在しない時間だが、OSは夏時間を認識してないので、そのまま表示できる。ということで3/31 1:30のまま処理をしている。

④のケース(OSの夏時間設定:あり tm_isdst:1)

このケースは時刻がすでにサマータイム影響下である。
OSは夏時間に合わせて時刻を調整しなければならないので、3/31 1:30は1時間進められた時間と認識するため、(ここの理解が曖昧です…)まず時間を1時間戻す。
戻した時間が本来の時間であり、ここは実際に1時間前の時刻としてみなされるので、実際にUNIX時間が1時間ずれる。
3/31 0:30は、夏時間としてはそのまま表示できる時間なので、そのまま出力されている。


ちなみに、2019/03/31 2:30(UNIX時間:1553999400)で、上記④のケースを適用してみると、結果はUNIX時間1553995800、ISO 8601形式では2019/03/31 02:30:00だった。
動作としては、まず03/31 2:30が渡される。これはサマータイム影響中であり本当の時間は1時間前である。だから1時間ずらす(3/31 1:30)。実際UNIX時間が戻されている。
3/31 1:30は夏時間としては存在しない時間であり、夏時間表示としては2:30になる。

ドラゴンクエストウォーク(DQW)の情報メモ

ドラゴンクエストウォークを始めました。
個人的に疑問に思ったことをどんどんメモしていきたいと思います(情報が分散してわかりづらいので…)

モンスターについて

モンスターの頭に出るビックリマークの数

モンスターの総合戦力を表しており、ビックリマークの数が多いほど強敵ということになります。

これは相対的な戦力を表しており、例えば全員LV30のパーティならビックリマーク1つの場合でも、転職してLV1のキャラクターがいるとビックリマークの数が3つになったりします。

キラキラ光っているモンスターは何?

倒すと宝箱を確定で落とします。

「かくてい」とふきだしがあるモンスターは何?

倒すと確定で「こころ」を落とします。
はぐれメタルなどのモンスターにも「かくてい」が出ることがあるようですが、逃げられると入手できないので注意です。

丸いマーク(こころ)のふきだしがあるモンスターは何?

倒すと高確率(約50%とのウワサ)で「こころ」を落とします。

範囲外に出現したモンスターと戦いたい

タップするとこちらに寄ってきてくれます

モンスターの強さはどうやって決まる?図鑑を埋めるときなど、弱いモンスターと戦いたいのだが。

現在進行中のクエストに依存するようです。
ですのでクリア済の昔のクエストを開始すれば、弱い敵と戦うことができます。

※つまりいつでも弱い(昔の)モンスターと戦うことはできるので、こころの所持上限などに到達してしまった方はばんばん弱いものから処分していって問題ないと思われます。

メガモンスターは離れていても戦える?

戦えません。
離れていると「近くへ移動してください」的なメッセージが出て、戦闘から離脱するか、近づいて再開するまで戦うことができなくなります。

戦闘から離脱すると、手形は無くなりますので注意してください。

目的地周辺のモンスターにメタル系のモンスターが現れた!今すぐ行けないんだけど、消えたりしないかな?

先日8時間程度放置しましたが、消えませんでした。
日付が変わったりするとどうなのかわかりませんが、短時間なら焦らなくて大丈夫みたいですよ!

4章10話のアームライオンが倒せない!

ラリホーがめっちゃ効きます!ずっと寝てましたw

ウォークモード

範囲内に敵がいるのに戦ってくれない
  • 移動していないと自動で戦ってくれません
  • 瀕死やピンチの状態だと戦ってくれません
範囲内に複数の敵や回復スポットがある場合の優先順位

優先順はないようです。つまりランダムということになります。
ちなみにウォークモード中でも目標物に対するタップは有効なので、優先的に回復スポットに触りたい等の場合はタップを活用すると良いでしょう。

マップについて

クリアした目的地周辺に、新たに「どこでも目的地」を置くことができないのだけど…クリア済の目的地が邪魔!

クリアしたクエストを、別の場所で再度クリアすればクリア済の目的地が移動するようです。
これ改善してほしいですねぇ…。

回復スポットをずらす方法

「どこでも目的地」機能で、回復スポットに被るように目的地を設定するとズレることがあるようです。
裏技の部類なので、修正される可能性があります。

よく行く目的地を記憶しておき、一発で目的地を設定する方法 (iPhone限定)
  1. 目的地を選ぶ画面で、右上の「登録リスト」アイコン→「外部マップへ」の順にタップ。
  2. マップから住所を入れたり、目的地を直接選んだりします。
  3. 画面下から出てきた画面から「共有」→「DQウォーク」を選ぶ。

これでドラクエウォーク内に位置が登録されます。10個まで登録できます。これは便利ですねぇ。

アイテム

アクセサリの入手方法
  • メガモンスター討伐時にランダムで入手(まだドロップしたことない…)
  • サブクエストクリア時の報酬
  • イベントの報酬

HP・MPの回復手段

  • 回復スポット(同じ箇所は30分程度に1回)
  • 自宅で休む (1時間に1回)
  • 各クエストの初回クリア時 (クリア済のクエストをもう一度クリアしても、回復しないようです)
  • スラミチにたのむ(HP/MP全回復。1日1回まで無料。以降は50ジェムかかります)
  • レベルアップ時
  • ドラクエウォークを一定時間操作しない(休憩)
  • 回復アイテム・呪文
ドラクエウォークを一定時間操作しない(休憩)

10分以上操作をしなかった場合だけ、回復します。
回復量は、10分なら最大HPMPの10%、30分なら30%といった具合でした。つまり100分操作しなければ全快するということですね。

それから注意点として、フィールド画面にしたままホームに戻るなどしてアプリから離れると、なぜか回復できない場合があります(休憩開始時間がちゃんと記録されてない予感)。じゅんび画面などに切り替えてからアプリを切り替えましょう!


全滅のペナルティ

特にありません。その場で全員HP1で復活します。
つまり、ウォークモードで放置してもデメリットはないということですね!

フレンドになるとどんな良いことがあるの?フレンドになる意味は?

おみやげをあげられる

東京タワーなどのランドマークを訪れるとお土産を入手できますが、それをフレンドに渡すことができます。フレンド同士連携しておみやげ図鑑を効率的に埋めることができるのですね。

フレンドごとに自宅の公開範囲を設定できる

特定のフレンドにだけ自宅の正確の位置を教え、あとの人はぼかして公開したりできます。
設定方法は以下の通り。

メニュー→その他・設定→設定→プライバシー→フレンドごとに設定

(※2019/09/16現在、ちゃんと反映されていない気がします…)

ゴールドパスを買ったら、スタンダードパスから勝手に切り替わるの?

いいえ。ゴールドパスに切り替わるのではなく、ゴールドパスとスタンダードパス同時にマイルが入るようになります

スタンダードパスを使い切ってからゴールドパスを買う…とかそういう面倒なことは考えなくて良さそう。

ドラクエウォークアプリを起動していなくても歩数カウントさせたい場合は?

ゲーム内の設定が必要です。
またiOSの場合、OSの設定も必要です。(Androidの場合不要…?)
バッテリー消費量が上がるかもしれません。ご注意を。

ゲーム内の設定

メニュー→その他・設定→設定→システム→いつでも歩数カウントを「ON」にします

iOSの場合は、OSの設定も必要!

「設定」アプリ→プライバシー→位置情報サービス→DQウォーク→常に許可

モンスターのこころ

ドラクエウォークはこころゲーと言われるほど、こころは重要な要素です。
武器防具はガチャでしか手に入らないためカネと運の要素が強いですが、こちらはコツコツと続ければ誰でもいつかは強いこころが手に入るという安心感がありますね。

色の意味

装備する色をそろえるとステータスにボーナスが付きます。
こころは3か所装備する部分があり、上はどんな色でもよいです。左と右は職業によって色が変わる。

戦士 黄色
僧侶
武闘家
魔法使い
盗賊
メガモンスターのこころ

倒すと確定でドロップします。

キャラクターの名前はどこから変えられる?

じゅんび→名前を変えたいキャラクターの顔をタップする→左上あたりにある、現在のキャラクター名表示の隣にある羽ペンアイコンをタップ

こころチャンス(こころかくてい、こころ高確率)の法則

自分の経験や集めた情報から記載していきます。

  • こころチャンスが出現している場所(スポット)は、全ユーザーで同じ
  • こころチャンスで出現するモンスターは、進行中のクエスト、またはパーティの平均レベルで決まる。どちらで決まるかは事前にはわからない(スポットによって決まっているのかな?)
  • こころチャンスの出現位置・モンスターは午前3時にリセットされる
  • 一度表示されたこころチャンスのモンスターはリセットまで変わらない!(ここ重要。目当てのモンスターが出るクエストを受注して移動した方がいいということ!
  • こころチャンス(高確率)の確率は約50%
  • こころチャンスのレア度(よくみかける、めったにみかけない等)は全スポットで共通。ツイッターなどを使って「めったにみかけない」巡りをすることも可能ですね!
  • パーティの平均レベルで出現モンスターが変わるようなので、ツイッターの情報は、投稿者のレベルも確認すること。いざ現地に行ったら違うモンスターがいるなんて可能性もあるので…。

一度表示されたモンスターはリセットまで24時間変わらないので(途中でレベルアップしたら変わるのかも?)、
午前3時になる前にクエストを受注して寝た方がいいですね!
朝起きてからクエスト受ければいいや~とか考えていると、自分の家の周辺のこころチャンスのモンスターが確定してしまう可能性があるのです…。

パーティの平均レベルで出現するモンスターが変わるこころチャンススポットのレベル帯

ちょっとこれは正確な調査をしたわけではありません。
なんとなく、各クエストの推奨レベル帯にいるレアリティのモンスターが出現すると感じているので、整理したいと思います。
あと自分の経験上のデータがあれば、それも反映しますね。
推奨レベルの隙間など、間違いがあるかもしれませんので、ご注意ください。

モンスター名 レアリティ PT平均レベル帯 エスト帯 備考
キングスライム あまり見かけない 48~55 5-9~5-10
ヒイラギどうじ あまり見かけない 43~47 5-5~5-8
ボーンナイト あまり見かけない 40~42 4-10~5-4
ベビル あまり見かけない 35~39 4-7~4-9
よろいのきし あまり見かけない 31~35 4-1~4-7
キラーマシン めったに見かけない 48~55 5-9~5-10
ホークブリザード めったに見かけない 43~47 5-5~5-8
あくま神官 めったに見かけない 38~42 4-9~5-4
ホークマン めったに見かけない 33~37 4-5~4-8
はぐれメタル めったに見かけない 31~48 4-1~5-9

■あまり見かけない(パーティ平均レベル帯)

f:id:taiyakisun:20191026035723p:plain

■めったに見かけない(パーティ平均レベル帯)

f:id:taiyakisun:20191026035806p:plain

■あまり見かけない(クエスト帯)

f:id:taiyakisun:20191026040918p:plain

■めったに見かけない(クエスト帯)

f:id:taiyakisun:20191026041118p:plain

こころのドロップ率
項目 おおよその確率
こころ自体のドロップ率 4%
Sのドロップ率 3%
Aのドロップ率 7%
Bのドロップ率 15%
Cのドロップ率 35%
Dのドロップ率 45%

レアリティ別モンスター出現率

最初に断っておきますが、おそらくクエストによって(モンスターによって?)、同じレアリティでも出現率が違います。
今回はクエスト5-8で超適当に実測したものを共有しておきます(気が向いたら更新します)。

■クエスト5-8

レアリティ 出現率(%) 出現モンスター
とてもよく見かける 297 80.054% ベホイミスライムとかパペットマンとかいろいろ
よく見かける 37 9.973% ミニデーモン, キラーパンサー
ときどき見かける 27 7.278% ドラゴスライム, つむりんママ(雨/水辺限定)
あまり見かけない 6 1.617% ヒイラギどうじ
めったに見かけない 4 1.078% はぐれメタル, ホークブリザード

ときどき見かけるの確率が思ったより高かったです。そのほかは予想通りですね~。
4-9でひとつめピエロを狙ったときはぜんっぜんでないイメージだったので意外です。
4-9はメタルライダーハートナイト(関東限定)がいるので、ときどき自体の確率はこの通りでも、
そのうちのモンスター一点狙いだと当然確率は下がってしまうので、出ないと感じていたのかもしれません。
4-9も出現率調査したいっす。

■参考情報
においぶくろ1個で37体くらいのモンスターを倒すことができました。
レベル上げパーティなので盗LV48 僧LV44 魔LV31 魔LV30です。ガチパーティならもっと速くなりそうですね。

倒したモンスター数 単位時間
37体 /5分
7.4体 /1分

ということになります。
ここからどれだけ時間をかければモンスターにどれだけ会うことができて、こころドロップまでにかかる時間(期待値)も出せそうですね。

例えば、ヒイラギどうじの場合、1分間に1体以上出会える確率はだいたい11%程度(1-(0.984^7))。
こころドロップ率が4%なので、1分間にヒイラギどうじのこころを1つ以上入手できる確率は0.44%。
で、例えば80%の確率でヒイラギどうじのこころを入手したければ1-0.9956^366=0.199978...ということで366分このペースでモンスターを倒し続ければ、10人に8人はヒイラギどうじのこころが最低1つは手に入るということですね!
うーん、あってますかね?この計算…確率苦手です。これは…確定スポット巡りますわ…!

ケース かかる時間 備考
80%の確率で最低1つ以上こころ入手 366分 1-0.9956^366
90%の確率で最低1つ以上こころ入手 523分 1-0.9956^523
95%の確率で最低1つ以上こころ入手 680分 1-0.9956^680
99%の確率で最低1つ以上こころ入手 1047分 1-0.9956^1047

各スポットの復活時間

自宅で休める間隔 1時間
回復スポット たぶん15分程度
他人の家のアイテム たぶん24時間程度

経験値(EXP)テーブル

わかったところ(実経験)から記載します。それぞれだいたいの数値ですよ~。
LV21~27はメモし忘れました…LV39も怪しいです…_(´ཀ`」 ∠)_
ウワサには聞いてましたが、LV50から経験値がハネ上がりますね…LV51が55までの折り返しと聞いたこともあります…。

このLVになるまで 必要な経験値 累計
1から11まで 6,000 6,000
12 2,600
13 3,600
14 4,900
15 6,400
16 8,400
17 10,600
18 13,700
19 16,700
20 19,700
21 23,300
22 27,229 144,276
23 31,674 175,950
24 36,570 212,520
25
26 47,824 303,153
27 54,540 356,829
28 61,861 418,690
29 69,822
30 78,459
31 88,198
32 98,738
33 110,123
34 122,000
35 135,500
36 150,861
37 166,718
38 183,000
39 202,000
40 222,153
41 243,755
42 266,857 2,558,591
43 291,535 2,850,126
44 318,675 3,168,801
45 347,641 3,516,442
46 378,530 3,894,972
47 412,543 4,307,515
48 447,454 4,754,969
49 485,797 5,240,766
50 526,592 5,767,358
51 845,922 6,613,280
52 1,265,137 7,877,316
53 1,811,064 9,688,380
54 2,519,375 12,207,755
55 3,441,626 15,649,381

リセット時間

ログインボーナス・スラミチの無料全回復・一日一回のサブクエス

夜中の午前3:00です。

とうばつ手形

こちらは午後3:00だそうです!

バグ?(不具合)

止まっているのに、「移動速度が速いためプレイを制限しています。」「あなたは運転者ではありませんか?」と聞かれる。

自分もスマホの位置を取得するアプリを使ったことがありますが、けっこうずれます。
特に位置計測直後はむちゃくちゃずれるので、このせいで表示されている可能性があります。
実害はない(し、けっこうどうしようもない側面もある)ので、対応優先度は低そうです。

戦闘終了後にフリーズする

発生条件がよくわかりませんが、けっこう固まります…。
タップしても無反応。いくらまっても動きません。アプリをKILLして対応しましょ。

要望メモ

個人的に要望が出せれば出そうと思っていることをメモしておきます。

  • モンスター図鑑の報酬で、いちいちモンスターを選ばせるのはやめてほしい。けっこうストレスです。
  • ほぼまんたん(ドラクエ11であったやつ)がほしい
  • ウォークモード時、一戦ごとにほぼまんたんする仕掛けがほしい
  • まんたんはメイン画面(マップ画面)からワンタップで使えるようにしてほしい。「まんたんにしました」のような確認メッセージも不要。
  • AIの強化もしくは、AIが使っていいスキルをユーザーが選べるようにしてほしい。
  • 転職の演出が長い。カットしてほしい。
  • というか、歩きながらやるゲームなのに、数秒操作できない演出(クエストクリアや冒険者ランクアップ)が多すぎる。表示しないオプションが欲しい。
  • クリア済の目的地周辺に「どこでも目的地」が置けない問題。仕様だとしても不便すぎます。
  • こころや図鑑などのページのスワイプの感度がおかしい。どうやらモンスターの絵の部分を触ってスワイプすると正常に動作するけど、モンスターとモンスターの間などを触るとスクロールしないみたい。なんでこんなことに???携帯2台で確認済。
  • スキルの位置を移動させてほしい。特にスキルが2ページ目になると戦闘中、いちいちページ移動→スキル選択しなければならず、ストレスです。
  • フィールド画面のままアプリを切り替えたりすると、その後ドラクエウォークに戻っても正しく休憩時間とカウントされずHPMPが回復しないときがある。(朝起きてアプリを起動したら、MPがほぼ0のままなんてこともありました)
  • クリア済みの目的地が邪魔で敵をタップできない。レアモンスターが出た時とかほんと〜〜〜〜に腹が立ちます。携帯投げつけて割りそう。なんとかしてほしいです。

ノートンアンチウィルス(Norton Antivirus)でスケジュール実行されたスキャンのキャンセル方法

マニュアル読んだけどわかりませんでしたーッ!ということで備忘録としてメモしておきます。
ノートン アンチウィルスのバージョンは22.18.0.213です。

バージョンはメインウィンドウ→[ヘルプ]→[バージョン情報]から確認できます。

キャンセル手順

  1. ノートンアンチウィルスのメインウィンドウから[セキュリティ]→[スキャン]を選びます
  2. [スキャンとタスク]の項目から[カスタムスキャン]ラジオボタンを選択し、[実行する]ボタンを押します
  3. スキャンウィンドウで実行中のスキャン名(例:システムの完全スキャン)の横にある「X」チェックマークを外します。
  4. チェックを外した行の[実行する]ボタンを押すと、スキャンが開始するのですぐにキャンセルします

現在進行中のスキャンを確認するのにスキャンを実行しなきゃいけないなんて気づかないよッ!
あれやこれやと探して無駄な時間を過ごしてしまいました。。。

Minecraft(マインクラフト)のクリエイティブモードで建築を始める前に、最低限覚えておいた方がいい知識

いまさらですがSwitch版のマイクラをちょこちょこ触ってます。
先日クリエイティブモードを遊んでみましたが、色々と前提知識がなく四苦八苦したので、
最低限まぁこれは知っといたほうがいいか、と思った知識をメモしておきます。個人的な備忘録です

エディションの整理

エディション 2019/8/13時点での最新バージョン 説明
Java 1.14.4 PC版。一番何でもできるエディションで、Modは使用可だが、クロスプラットフォームでのマルチプレイ不可
統合版(BE(Bedrock)版) 1.12.0 PC版(こちらはWindows 10版という名前がついている)、XBox One版、Switch版、スマホタブレット版はすべてこれ。一部は昔ポケットエディション(PE版)という名前だった。Mod不可だがクロスプラットフォームでプレイ可能
PS4 1.90 BE版が先にアップデートされてから、後を追ってアップデートされるサイクルになっている。クロスプラットフォームでのプレイ不可
XBox 360番・Wii U版・PS3版・PS Vita版 ? PS4版と同じアップデート方式。ただ現在はアップデート終了している?クロスプラットフォームでのプレイ不可

※PCでプレイできるマイクラには、Java版とWindows 10版の二種類があります。

まぁ普通に考えて、Java版か統合版(BE版)のどちらかを選ぶことになると思います!
マルチプラットフォームで遊ぶなら統合版(BE版)一択かと思います。

前提とか注意点

  • 当方SwitchなのでBE版を使用しています。2019/8/13現在、バージョンは1.12.0でした。
  • fillコマンドやsetblockコマンドはやり直し(Ctrl+zのような機能)がない。つまり一度fillコマンドでブロックが配置されてしまったら、上書きした既存のブロック等は元に戻せないので注意が必要。

用語

用語 意味
コマンドブロック 起動すると、任意のコマンドを実行することができるブロック。giveコマンドでアイテム名を「command_block」とすることで入手可。(コマンド実行例:/give @s command_block 2)
NBT Named Binary Tagの略。コマンドブロック等は任意のコマンドを設定できるが、これを記憶しておく領域というかフォーマットがNBTである。中身は拡張されたXML?マイクラオリジナルのフォーマットらしい。

細かい知識

  • 座標系は右手座標系であり、相対座標によるコマンドを使用する場合は向きを気にする必要があるかもしれない?
  • fillコマンド等で同時に処理できるブロック数は32,768個(2^15)である

Java版で出来て、BE版で出来ないこと

  • giveコマンドで、Java版のNBTは使用できない→コマンドブロック生成時にBlockEntityTagを指定できない→コマンドブロックの配置でまとめて複数のブロックを配置したりできない

設定

  • 「座標を表示」をONにしましょう
  • 「チートの実行」をONにしましょう
  • 「コマンドブロックが有効」をONにしましょう
  • 純粋に建築だけが目的なら「常に昼間」「モブの出現」「モブによる妨害」をOFFにしましょう
  • マルチプレイで全員にコマンドを実行できる権限を持たせるなら、「招待から参加した場合のプレイヤー権限」を「オペレーター」にしましょう

飛行(浮遊)モード

ジャンプボタン(Switch版ならAボタン)を素早く二回押すことで、飛行モードと通常モードが交互に切り替わる。空中で通常モードに切り替えると落下するので注意。

飛行モード中は、ジャンプボタンで上(+y方向)へ移動し、しゃがみボタン(Switch版ならBボタン)で下(-y方向)へ移動する。

整地方法

何はともあれまずはコレ。ここから整地したいな~と思った座標を決めます。
ここでは例として(10, 10, 20)に決め、100x100を同じブロックで整地します。(座標は(x座標, y座標, z座標)と記載しています)

/fill 10 10 20 110 10 120 concrete
/fill 10 11 20 110 13 120 air
/fill 10 14 20 110 16 120 air
/fill 10 17 20 110 19 120 air

2行目以降は、整地した範囲の上(+y座標方向、空の方向)のブロックを排除するために実行してます。
必要に応じて実行してください。fillコマンドで同時に処理できるブロック数が32,768個のため複数回実行してます。

ぼやき

  • こりゃキーボード必須ですね…。なんとSwitch版はbluetoothキーボードが使用できないという…クソクソクソ(>_<)
  • イクラ、遊んでいて大変面白いのですが、普段からプログラムを組んでいると、直感的にやりたいことができなくてかなりストレスが溜まりますね〜。純粋に強化版レゴのソフトウェア版!と割り切った方がよさそうです。
プライバシーポリシー お問い合わせ