「BCDice/TRPGツールからの呼び出し方/どどんとふ」の版間の差分
Ochaochaocha3 (トーク | 投稿記録) (サーバー本体:見出しにクラス名を追加する) |
タグ: 取り消し |
(他の1人の利用者による、間の1版が非表示) | |
(相違点なし)
|
2020年8月25日 (火) 07:43時点における最新版
どどんとふからのBCDiceの呼び出し方。このページでは、Rubyで書かれたどどんとふのサーバのダイス関連の処理を扱う。v1.49.04.01のソースコードを参考にしている。
各ファイルの役割
どどんとふのサーバでは、ダイスボットとの通信の処理は以下のファイルに記述されている。
- src_ruby/dodontof/dice_adapter.rb:BCDiceとのアダプタ
- src_ruby/diceBotInfos.rb:ダイスボットの情報を取得する処理
- DodontoFServer.rb:サーバ本体
src_ruby/dodontof/dice_adapter.rb:BCDiceとのアダプタ
ダイスロールと関係していることがすぐに分かるファイル名だが、実は大部分は独自の表からの情報の読み出しやファイル管理の処理となっている。
L7-L10:DiceAdapter#initialize
アダプタを初期化する。
@dir
:部屋固有のデータ保存ディレクトリが設定される。詳細は「#L164-L185:@dice_adapter の初期化」で解説する。@diceBotTablePrefix
:必ず'diceBotTable_'
が設定される。
def initialize(dir, prefix)
@logger = DodontoF::Logger.instance
@dir = dir
@diceBotTablePrefix = prefix
end
L13-L34:DiceAdapter#rollDice
ダイスロールを行う。メッセージ、ゲームシステム、出目を返すかが指定できる。結果のメッセージ、シークレットダイスかどうか、出目が返る。結果のメッセージの '>'
は '→'
に置換され、末尾の改行コードは削除される。
def rollDice(params)
require 'cgiDiceBot.rb'
message = params['message']
gameType = params['gameType']
isNeedResult = params['isNeedResult']
@logger.debug(message, 'rollDice message')
@logger.debug(gameType, 'rollDice gameType')
bot = CgiDiceBot.new
result, randResults = bot.roll(message, gameType, @dir, @diceBotTablePrefix, isNeedResult)
result.gsub!(/>/, '→')
result.sub!(/\r?\n?\Z/m, '')
@logger.debug(result, 'rollDice result')
@logger.debug(randResults, 'rollDice randResults')
return result, bot.isSecret, randResults
end
L36-L45:DiceAdapter#getGameCommandInfos
独自の表について、ゲームタイプ(ゲームの識別子)および含まれるコマンドの情報を返す。CgiDiceBot#getGameCommandInfos
を経由して TableFileData#getGameCommandInfos
を呼び出している。
def getGameCommandInfos
require 'cgiDiceBot.rb'
bot = CgiDiceBot.new
@logger.debug(@dir, 'dir')
commandInfos = bot.getGameCommandInfos(@dir, @diceBotTablePrefix)
@logger.debug(commandInfos, "getGameCommandInfos End commandInfos")
return commandInfos
end
L47-L63:DiceAdapter#getBotTableInfosFromDir
独自の表についての情報を取得する。getGameCommandInfos
と似ているが、こちらの方が返される情報が詳しい?
def getBotTableInfosFromDir
@logger.debug(@dir, 'getBotTableInfosFromDir dir')
require 'TableFileData'
isLoadCommonTable = false
tableFileData = TableFileData.new( isLoadCommonTable )
tableFileData.setDir(@dir, @diceBotTablePrefix)
tableInfos = tableFileData.getAllTableInfo
@logger.debug(tableInfos, "getBotTableInfosFromDir tableInfos")
tableInfos.sort!{|a, b| a["command"].to_i <=> b["command"].to_i}
@logger.debug(tableInfos, 'getBotTableInfosFromDir result tableInfos')
return tableInfos
end
L65-L84:DiceAdapter#addBotTableMain
独自の表のファイルを保存する。
def addBotTableMain(params)
@logger.debug("addBotTableMain Begin")
DodontoF::Utils.makeDir(@dir)
require 'TableFileData'
resultText = 'OK'
begin
creator = TableFileCreator.new(@dir, @diceBotTablePrefix, params)
creator.execute
rescue Exception => e
@logger.exception(e)
resultText = getLanguageKey( e.to_s )
end
@logger.debug(resultText, "addBotTableMain End resultText")
return resultText
end
L86-L103:DiceAdapter#changeBotTableMain
独自の表のファイルを更新する。
def changeBotTableMain(params)
@logger.debug("changeBotTableMain Begin")
require 'TableFileData'
resultText = 'OK'
begin
creator = TableFileEditer.new(@dir, @diceBotTablePrefix, params)
creator.execute
rescue Exception => e
@logger.exception(e)
resultText = getLanguageKey( e.to_s )
end
@logger.debug(resultText, "changeBotTableMain End resultText")
return resultText
end
L105-L135:DiceAdapter#removeBotTableMain
独自の表のファイルを削除する。
def removeBotTableMain(params)
@logger.debug("removeBotTableMain Begin")
command = params["command"]
require 'TableFileData'
isLoadCommonTable = false
tableFileData = TableFileData.new( isLoadCommonTable )
tableFileData.setDir(@dir, @diceBotTablePrefix)
tableInfos = tableFileData.getAllTableInfo
tableInfo = tableInfos.find{|i| i["command"] == command}
@logger.debug(tableInfo, "tableInfo")
return if( tableInfo.nil? )
fileName = tableInfo["fileName"]
@logger.debug(fileName, "fileName")
return if( fileName.nil? )
@logger.debug("isFile exist?")
return unless( File.exist?(fileName) )
begin
File.delete(fileName)
rescue Exception => e
@logger.exception(e)
end
@logger.debug("removeBotTableMain End")
end
src_ruby/diceBotInfos.rb:ダイスボットの情報を取得する処理
L69-L102:DiceBotInfos.get
# ダイスボットの情報の一覧を取得する
# @param [Array<String>] orderedGameNames 順序付けられたゲーム名の配列
# @param [Boolean] showAllDiceBots すべてのダイスボットを表示するか
# @return [Array<Hash>]
def self.get(orderedGameNames, showAllDiceBots)
diceBots = DiceBotLoader.collectDiceBots
# ゲーム名 => ダイスボットの対応を作る
diceBotFor = Hash[
diceBots.map { |diceBot| [diceBot.gameName, diceBot] }
]
toDiceBot = lambda { |gameName| diceBotFor[gameName] }
orderedEnabledDiceBots = orderedGameNames.
map(&toDiceBot).
# ゲーム名が誤記されていた場合nilになるので除く
compact
orderedDiceBots =
if showAllDiceBots
disabledGameNames = diceBotFor.keys - orderedGameNames
orderedDisabledDiceBots = disabledGameNames.
sort.
map(&toDiceBot)
# 一覧に記載されていたゲーム→記載されていなかったゲームの順
orderedEnabledDiceBots + orderedDisabledDiceBots
else
orderedEnabledDiceBots
end
# 指定なし→各ゲーム→基本の順で返す
[NONE_DICE_BOT_INFO] + orderedDiceBots.map(&:info) + [BASE_DICE_BOT_INFO]
end
L104-150:DiceBotInfos.withTableCommands
# テーブルのコマンドも加えたダイスボットの情報の一覧を取得する
# @param [Array<String>] orderedGameNames 順序付けられたゲーム名の配列
# @param [Boolean] showAllDiceBots すべてのダイスボットを表示するか
# @param [Array<Hash>] commandInfos テーブルのコマンドの情報の配列
# @return [Array<Hash>]
#
# このメソッドは、ダイスボットから返された情報を破壊しない。
def self.withTableCommands(orderedGameNames, showAllDiceBots, commandInfos)
diceBotInfos = self.get(orderedGameNames, showAllDiceBots)
# ゲームタイプ => ダイスボット情報のインデックスの対応を作る
diceBotInfoIndexFor = Hash[
diceBotInfos.each_with_index.map { |info, i| [info[KEY_GAME_TYPE], i] }
]
allGameTypes = diceBotInfoIndexFor.keys
# ゲームタイプ => 追加するコマンドの一覧の対応を作る
commandsToAdd = commandInfos.reduce({}) { |acc, commandInfo|
gameType = commandInfo[KEY_GAME_TYPE]
command = commandInfo[KEY_COMMAND]
# ゲームタイプ未指定ならすべてのゲームタイプに追加する
targetGameTypes = gameType.empty? ? allGameTypes : [gameType]
targetGameTypes.each do |targetGameType|
acc[targetGameType] ||= []
acc[targetGameType] << command
end
acc
}
commandsToAdd.each do |gameType, commands|
diceBotInfoIndex = diceBotInfoIndexFor[gameType]
next unless diceBotInfoIndex
originalInfo = diceBotInfos[diceBotInfoIndex]
# ダイスボットから返された情報を破壊しないようにして更新する
diceBotInfos[diceBotInfoIndex] = originalInfo.merge({
KEY_PREFIXS => originalInfo[KEY_PREFIXS] + commands
})
end
diceBotInfos
end
DodontoFServer.rb:サーバ本体
L164-L185:@dice_adapter
の初期化
def initialize(saveDirInfo, cgiParams)
@cgiParams = cgiParams
@saveDirInfo = saveDirInfo
@logger = DodontoF::Logger.instance
@cgi = nil
@jsonpCallBack = nil
@isWebIf = false
@isRecordEmpty = false
initSaveFiles(getRequestData('room'))
@dice_adapter = DodontoF::DiceAdapter.new(getDiceBotExtraTableDirName, 'diceBotTable_')
@fullBackupFileBaseName = "DodontoFFullBackup"
@allSaveDataFileExt = '.tar.gz'
@defaultAllSaveData = 'default.sav'
@defaultChatPallete = 'default.cpd'
@card = nil
end
getDiceBotExtraTableDirName
(L3727-L3729)では、getRoomLocalSpaceDirName
(L3262-L3265)、getRoomLocalSpaceDirNameByRoomNo
(L3267-L3273)を経由して、$imageUploadDir
の中の部屋固有のディレクトリを返す。
L1193-L1210:DodontoFServer#getWebIfServerInfo
Webインターフェースのサーバ情報を返すコマンド。getDiceBotInfos
でダイスボットの情報を取得する。
def getWebIfServerInfo()
jsonData = {
"maxRoom" => ($saveDataMaxCount - 1),
'isNeedCreatePassword' => (not $createPlayRoomPassword.empty?),
'result' => 'OK',
}
if( getWebIfRequestBoolean("card", false) )
cardInfos = getCardsInfo.collectCardTypeAndTypeName($cardOrder)
jsonData["cardInfos"] = cardInfos
end
if( getWebIfRequestBoolean("dice", false) )
jsonData['diceBotInfos'] = getDiceBotInfos()
end
return jsonData
end
L2090:DodontoFServer#getLoginInfo
ダイスボット情報の取得を行う。
diceBotInfos = getDiceBotInfos()
L2266-L2280:DodontoFServer#getDiceBotInfos
ダイスボット情報取得処理の実装。部屋に入っているかどうかで、テーブルのコマンドも含めた情報を返すかどうかを決定している。
def getDiceBotInfos
@logger.debug("getDiceBotInfos() Begin")
require 'diceBotInfos'
orderedGameNames = $diceBotOrder.split("\n")
if @saveDirInfo.getSaveDataDirIndex != -1
DiceBotInfos.withTableCommands(orderedGameNames,
$isDisplayAllDice,
@dice_adapter.getGameCommandInfos)
else
DiceBotInfos.get(orderedGameNames, $isDisplayAllDice)
end
end
L2542-2556:DodontoFServer#save
, getDiceTableData
部屋のデータの保存時に、独自の表についての情報を取得する。
def save()
isAddPlayRoomInfo = true
extension = @@saveFileExtension
addInfos = {}
addInfos[$diceBotTableSaveKey] = getDiceTableData()
saveSelectFiles($saveFiles.keys, extension, isAddPlayRoomInfo, addInfos)
end
def getDiceTableData()
tableInfos = @dice_adapter.getBotTableInfosFromDir
tableInfos.each{|i| i.delete('fileName') }
return tableInfos
end
L2806-L2817:DodontoFServer#getBotTableInfos
独自の表についての情報を取得する。
def getBotTableInfos()
@logger.debug("getBotTableInfos Begin")
result = {
"resultText"=> "OK",
}
result["tableInfos"] = @dice_adapter.getBotTableInfosFromDir
@logger.debug(result, "result")
@logger.debug("getBotTableInfos End")
return result
end
L2819-L2835:DodontoFServer#addBotTable
独自の表を追加する。
def addBotTable()
result = {}
params = getParamsFromRequestData()
result['resultText'] = @dice_adapter.addBotTableMain(params)
if( result['resultText'] != "OK" )
return result
end
@logger.debug("addBotTableMain called")
result = getBotTableInfos()
@logger.debug(result, "addBotTable result")
return result
end
L2837-L2849:DodontoFServer#changeBotTable
独自の表を変更する。
def changeBotTable()
params = getParamsFromRequestData()
result = {}
result['resultText'] = @dice_adapter.changeBotTableMain(params)
if( result['resultText'] != "OK" )
return result
end
result = getBotTableInfos()
return result
end
L2851-L2855:DodontoFServer#removeBotTable
独自の表を削除する。
def removeBotTable()
params = getParamsFromRequestData()
@dice_adapter.removeBotTableMain(params)
return getBotTableInfos()
end
L3458-L3459:DodontoFServer#loadSaveFileDataFilterByTargets
セーブデータの部分読み込み処理の一部。独自の表を読み込む。
when "diceBotTable"
loadDiceBotTable(jsonData)
L3511-L3531:DodontoFServer#loadDiceBotTable
, DodontoFServer#getDiceBotTableString
独自の表を読み込む。
def loadDiceBotTable(jsonData)
data = jsonData[$diceBotTableSaveKey]
return if( data.nil? )
data.each do |info|
info['table'] = getDiceBotTableString(info['table'])
@dice_adapter.addBotTableMain(info)
end
end
def getDiceBotTableString(table)
lines = []
table.each do |line|
lines << line.join(":")
end
return lines.join("\n")
end
L3632-L3657:DodontoFServer#sendDiceBotChatMessage
BCDiceにコマンドを送る処理。回数 コマンド
という形で送信回数が指定されていた場合は、指定された回数だけコマンドをBCDiceに送る。
def sendDiceBotChatMessage
@logger.debug('sendDiceBotChatMessage')
params = getParamsFromRequestData()
repeatCount = getDiceBotRepeatCount(params)
results = []
repeatCount.times do |i|
paramsClone = params.clone
paramsClone['message'] += " \##{ i + 1 }" if( repeatCount > 1 )
result = sendDiceBotChatMessageOnece( paramsClone )
@logger.debug(result, "sendDiceBotChatMessageOnece result")
next if( result.nil? )
results << result
end
@logger.debug(results, "sendDiceBotChatMessage results")
return results
end
L3659-L3669:DodontoFServer#getDiceBotRepeatCount
コマンド送信回数を1〜20回に制限する。最近のRubyでは (params['repeatCount'] || 1).clamp(1, 20)
と簡潔に書ける。
def getDiceBotRepeatCount(params)
repeatCountLimit = 20
repeatCount = params['repeatCount']
repeatCount ||= 1
repeatCount = 1 if( repeatCount < 1 )
repeatCount = repeatCountLimit if( repeatCount > repeatCountLimit )
return repeatCount
end
L3672-L3709:DodontoFServer#sendDiceBotChatMessageOnece
BCDiceに1回分(おそらく Onece
は once
のスペルミス)のコマンドを送る処理。getRollDiceResult
でダイスロールした結果を取得する。sendChatMessageByChatData
(L3817-3839)で、その結果を含むメッセージを送信する。
def sendDiceBotChatMessageOnece(params)
rolledMessage, isSecret, secretMessage = getRollDiceResult( params )
senderName = params['name']
unless /\t/ === senderName
state = params['state']
senderName += ("\t" + state) unless( state.empty? )
end
chatData = {
"senderName" => senderName,
"message" => rolledMessage,
"color" => params['color'],
"uniqueId" => '0',
"channel" => params['channel']
}
sendto = params['sendto']
unless( sendto.nil? )
chatData['sendto'] = sendto
chatData['sendtoName'] = sendtoName
end
@logger.debug(chatData, 'sendDiceBotChatMessageOnece chatData')
sendChatMessageByChatData(chatData)
result = nil
if( isSecret )
params['isSecret'] = isSecret
params['message'] = secretMessage
result = params
end
return result
end
L3672-L3725:DodontoFServer#getRollDiceResult
BCDiceでダイスを振る。シークレットダイスかどうかも考慮してメッセージを加工し、返す。
def getRollDiceResult( params )
params['originalMessage'] = params['message']
rollResult, isSecret, randResults = @dice_adapter.rollDice(params)
secretMessage = ""
if( isSecret )
secretMessage = params['message'] + rollResult
else
params['message'] += rollResult
end
rolledMessage = getRolledMessage(params, isSecret, randResults)
return rolledMessage, isSecret, secretMessage
end
L3732-L3762:DodontoFServer#getRolledMessage
ダイスロールの結果を入力として、どどんとふクライアントでの表示に必要な情報を付加する。シークレットダイスの場合に結果を隠すことと、「!」の数でサイコロを強調できるようにすることが目的のようだ。
def getRolledMessage(params, isSecret, randResults)
@logger.debug("getRolledMessage Begin")
@logger.debug(isSecret, "isSecret")
@logger.debug(randResults, "randResults")
if( isSecret )
params['message'] = getLanguageKey('secretDice')
randResults = randResults.collect{|value, max| [0, 0] }
end
message = params['message']
if( randResults.nil? )
@logger.debug("randResults is nil")
return message
end
data = {
"chatMessage" => message,
"randResults" => randResults,
"uniqueId" => params['uniqueId'],
"power" => getDiceBotPower(params),
}
text = "###CutInCommand:rollVisualDice###" + getJsonString(data)
@logger.debug(text, "getRolledMessage End text")
return text
end