﻿--------------------------------------------------------------
---立体コメント落下VCI
---
---機能
---わんコメプラグインより、画像URLがOSCにて送信されると、コメントの内容を立体コメントとして落下する
---
---機能詳細
--- ●本VCIはわんコメプラグイン（Ver.1.2.0以上）と連携して動作するVCIである
---     ●自分自身のわんコメのOSCと、自身のVCIの組み合わせのみ動作する
---     ●OSCにてコメント情報を受信すると立体コメントを落下させる
---     ●落下させる立体コメントの寿命は15秒
---     ●立体コメントの色は、選択されたカラーパレットによって決まる
--- ●プレーン君を操作することで、立体コメントの落下位置を調整することができる
---     ●プレーン君の数値操作は、アイテムオーナーのみが可能
---     ●オーナー以外は、設定値（吹き出し）は非アクティブ
---     ●1秒以上のUSEで、落下基準点の切り替え（「プレイヤー中心」と「スイッチ中心」）
---     ●1秒未満のUSEで、落下位置操作切り替え（「範囲」と「オフセット」）
---     ●プレーン君の拡縮操作で、「範囲」または「オフセット」の数値操作
---     ●上記の位置は、ローカルストリームカメラ、または、モニタ、の方向を向くような基準となる
---     ●上記の向きの基準は、ローカルストリームカメラが出ている場合はそちらを基準に、出てない場合はモニタが基準となる
--- ●設定吹き出しのパレットマークをUseすると、カラーパレットの選択画面のON/OFFが操作できる
---     ●表示された選択画面の、カラーパレットをUseすると、そのカラーパレットを選択できる
--------------------------------------------------------------

local displayModule = require("planeKunDisplay")
local solidComment = require("SolidComment")

local myId
local ownerId

local switchFlag = false
local switchUseFlag = false
local switchGrabFlag = false
local switchUseStartTime = 0
local switchIntervalTime = 1
local dropRange = {"2.00","0.00","0.50"}
local dropOffset = {"0.00","3.00","0.00"}
local preScl = Vector3.one
local switchFase = 1
local nxtState = {0,0,0}
local switchCollider = vci.assets.GetTransform("ButtonRootCollider")
local switch = vci.assets.GetTransform("ButtonRoot")


local queueMax = 15
local queueOutInterval = 0.3            --キューチェックのインターバル
local queueOutPreTime = 0               --前回のキューチェックの時間
local commentQueueTbl = {}              --キューテーブル

local heightOffset = 0


---OSCアドレス
local commonAdress = "/vc-official/onecomme/common"
--- ---------------------------------------------------------
--- OSC受信時の処理
--- ---------------------------------------------------------
--- OSC受信データをバッファ用テーブルに保存する。
--- メッセージの流量を制限するため、バッファを設けている。
--- 保存時、設定した保存限界を超えたデータは、古いものから削除する。
--- @param content table @OSCからの取得データ
local function commentDrop(content)
    if ownerId ~= nil then
        if ownerId == myId then
            local oscData = json.parse(content)
            --文字数制限処理
            if #oscData.comment > 15 then
                oscData.comment = oscData.comment:sub(1, 15)
            end
            table.insert(commentQueueTbl, oscData.comment)
            --キューに貯まりすぎないよう、上限を超えたら古いコメントを削除
            while #commentQueueTbl > queueMax do
                table.remove(commentQueueTbl, 1)
                print("キュー上限を超えたので、キュー内の古いコメントを削除しました")
            end
        end
    end
end
vci.osc.RegisterMethod(commonAdress, commentDrop, {ExportOscType.BlobAsUtf8})


--- キューから、立体コメントを生成する処理
local function outputFromQueue()
    if #commentQueueTbl ~= 0 and os.time() - queueOutPreTime > queueOutInterval then
        local spawnPos = switch.GetPosition()
        --スイッチがオーナー基準の場合、オーナーの位置を取得
        if not(switchFlag) then
            spawnPos = vci.vc.room.GetLocalPlayer().GetPosition()
        end
        --ランダム化の位置設定
        local randomPos = Vector3.__new(
                (math.random()-0.5)*2*dropRange[1] + dropOffset[1],
                (math.random()-0.5)*2*dropRange[2] + dropOffset[2],
                (math.random()-0.5)*2*dropRange[3] + dropOffset[3]
            )
        --基準向きの取得
        local spawnRot = Quaternion.identity
        --ローカルストリームカメラの有無のチェック
        local camera = vci.vc.room.streamCamera.GetLocalStreamCameraByPlayerId(ownerId)
        local monitor = vci.vc.room.monitorCamera
        if camera.IsAvailable() then
            local tempRot = camera.GetRotation().eulerAngles
            tempRot.x = 0
            tempRot.z = 0
            spawnRot = Quaternion.Euler(tempRot)*Quaternion.Euler(0,180,0)
        elseif monitor.GetRotation() ~= nil then
            local tempRot = monitor.GetRotation().eulerAngles
            tempRot.x = 0
            tempRot.z = 0
            spawnRot = Quaternion.Euler(tempRot)*Quaternion.Euler(0,180,0)
        end
        --コメント落下位置の、カメラの向き基準でのランダム化処理
        spawnPos = spawnPos + spawnRot*randomPos
        --コメントのスケールのランダム設定
        local solidScl = 0.2*(math.random()-0.5) + 0.35
        --コメントの生成処理
        solidComment.commentDrop(spawnPos, spawnRot, solidScl, commentQueueTbl[1])
        --生成したコメントの、キューからの削除
        table.remove(commentQueueTbl, 1)
        queueOutPreTime = os.time()
    end
end

------------------------------------------------------------
---Initialize処理
------------------------------------------------------------
--- スタジオでは、オブジェクトを非アクティブに
local function initialize()
    --ルームの識別
    if vci.vc.GetSpaceType() == ExportVcSpaceType.Studio then
        vci.assets.GetTransform("/ButtonRoot/FukidashiObj").SetActive(false)
        vci.assets.GetTransform("Yajirushi").SetActive(false)
        vci.assets.GetTransform("planekun").GetSkinnedMeshRenderer().SetBlendShapeWeight(7, 100)
        --パレットオブジェクトの非アクティブ化
        solidComment.inactive()
    elseif vci.vc.GetSpaceType() == ExportVcSpaceType.Room then
        myId = vci.vc.room.GetLocalPlayer().GetId()
        --パレットオブジェクトの非アクティブ化
        solidComment.inactive()
        if vci.assets.IsMine then
            if vci.state.Get("OwnerID") == nil then
                --stateの初期化処理
                vci.state.Set("OwnerID", myId)
                vci.state.Set("Range", dropRange)
                vci.state.Set("Offset", dropOffset)
                vci.state.Set("Switch", false)
                displayModule.textUpdate(switchFase, switchFlag, true)
                ownerId = myId
                --カラーパレット用のスイッチのアクティブ化
                solidComment.paletteSwitchActive(true)
            elseif vci.state.Get("OwnerID") == myId then
                switchFlag = vci.state.Get("Switch")
                dropRange = vci.state.Get("Range")
                dropOffset = vci.state.Get("Offset")
                displayModule.textUpdate(switchFase, switchFlag, true)
                ownerId = myId
                --カラーパレット用のスイッチのアクティブ化
                solidComment.paletteSwitchActive(true)
                --カラーパレットの番号の読み出し処理
                solidComment.readState()
            else
                vci.assets.GetTransform("/ButtonRoot/FukidashiObj").SetActive(false)
                vci.assets.GetTransform("Yajirushi").SetActive(false)
            end
        else
            vci.assets.GetTransform("/ButtonRoot/FukidashiObj").SetActive(false)
            vci.assets.GetTransform("Yajirushi").SetActive(false)
        end
        --プレーン君の表情切り替え
        vci.assets.GetTransform("planekun").GetSkinnedMeshRenderer().SetBlendShapeWeight(0, 100)
    end
end
initialize()


function updateAll()
    --スイッチのコライダーの追従処理
    if switchCollider.IsMine then
        switch.SetPosition(switchCollider.GetPosition())
        switch.SetRotation(switchCollider.GetRotation())
    end

    --スイッチ操作
    if ownerId == myId then
        outputFromQueue()
        if switchGrabFlag then
            nxtState = displayModule.textUpdateGrabbing(switchFase, preScl)
        end
    end

    solidComment.updateAll()
end


function onGrab(item)
    if ownerId ~= nil then
        --プレーン君の操作
        if item == "ButtonRootCollider" and ownerId == myId then
            switchGrabFlag = true
            --数値操作用のスケールの用意
            preScl = {
                switchCollider.GetLocalScale().x,
                switchCollider.GetLocalScale().y,
                switchCollider.GetLocalScale().z
            }
        end
    end
end


function onUngrab(item)
    if ownerId ~= nil then
        --プレーン君の操作
        if item == "ButtonRootCollider" and ownerId == myId then
            switchGrabFlag = false
            --数値操作用のコライダーリセット
            switchCollider.SetLocalScale(Vector3.one)
            --範囲・オフセットの上書き処理
            if switchFase == 1 then
                dropRange = nxtState
                vci.state.Set("Range", dropRange)
                vci.message.EmitToSelf("ThumbnailDropRangeSend", dropRange)
            else
                dropOffset = nxtState
                vci.state.Set("Offset", dropOffset)
                vci.message.EmitToSelf("ThumbnailDropOffsetSend", dropOffset)
            end
        end
    end
end



function onUse(use)
    if ownerId ~= nil then
        --プレーン君の操作
        --長押し・短押しの判定用のカウント開始
        if use == "ButtonRootCollider" and ownerId == myId then
            if not(switchUseFlag) then
                switchUseFlag = true
                switchUseStartTime = os.time()
            end
        end
        solidComment.onUse(use)
    end
end



function onUnuse(use)
    if ownerId ~= nil then
        --プレーン君の操作
        --1秒以上「USE」長押し：基準の切り替え
        --1秒未満「USE」：範囲とオフセットの切り替え
        if use == "ButtonRootCollider" and ownerId == myId then
            if switchUseFlag and os.time() - switchUseStartTime >= switchIntervalTime then
                switchFlag = not(switchFlag)
                if switchFlag then
                    heightOffset = switch.GetPosition().y - vci.vc.room.GetLocalPlayer().GetPosition().y
                    if heightOffset < 0 then
                        heightOffset = 0
                    end
                end
                dropOffset[2] = displayModule.baseSwitchHeightAdjust(switchFlag, switchFase, heightOffset)
                vci.state.Set("Offset", dropOffset)
                vci.state.Set("Switch", switchFlag)
                vci.message.EmitToSelf("ThumbnailSwitchChange", {switchFlag, dropOffset})
                displayModule.textUpdate(switchFase, switchFlag, false)
            else
                if switchFase == 1 then
                    switchFase = 2
                else
                    switchFase = 1
                end
                displayModule.textUpdate(switchFase, switchFlag, false)
            end
            switchUseFlag = false
        end
    end
end


function onTriggerEnter(item, collider)
    if ownerId ~= nil then
        solidComment.onTriggerEnter(item, collider)
    end
end


function onTriggerExit(item, collider)
    if ownerId ~= nil then
        solidComment.onTriggerExit(item, collider)
    end
end

