/* * Class: MusicBox * Author: sphereii * Category: Entity * Description: * This script allows the attached block to play music, videos and do animations. * * Music Player: * The music player will read the sounds.xml and play SoundDataNode. The music players are all loot containers; this means you can add an item that contains a "SoundDataNode" that * points to an entry in the sounds.xml. Multiple music items can be added to the loot container, and it will randomly play from them. * * Rather than items in the slots, you can also add the to the block, which will allow it to play without an extra item. * * Animation Player: * When the music box is attached, it will check the Model to find an Animator at the top level. An animator SetBool is called on "IsOn" to turn it on. * * Video Player: * The video player works like the music player, and will play videos listed in the . * This assumes that the Squeeze.mp4 video is inside of the MyVideos.unity3d bundle. As in the Music Player, multiple items can be added to the container slots to play from. */ using System.Collections.Generic; using UnityEngine; using UnityEngine.Video; public class BlockMusicBox : BlockLoot { private readonly BlockActivationCommand[] cmds = { new BlockActivationCommand("light", "electric_switch", true), new BlockActivationCommand("search", "search", true), new BlockActivationCommand("take", "hand", false) }; private readonly float TakeDelay = 5f; // The AudioSource is a reference to the SoundDataNode's AudioSource. private string strAudioSource; // This is the SoundDataNode, if configured through the block private string strSoundSource; // Video Source contains the asset bundle where the video is stored, if configured through the block. private string strVideoSource; private Vector2i vLootContainerSize; public BlockMusicBox() { HasTileEntity = true; } public override void Init() { base.Init(); // SoundSource is the referenced SoundDataNode if (Properties.Values.ContainsKey("SoundDataNode")) strSoundSource = Properties.Values["SoundDataNode"]; // Audio Source is the prefab name, without the asset bundle reference. // This is used to keep track of which audio source is actually playing, so we can turn it on and off. if (Properties.Values.ContainsKey("AudioSource")) strAudioSource = Properties.Values["AudioSource"]; // The VideoSource can be an asset bundle or URL. If there is an embedded clip on the Video Player, it'll play that in preference to the URL, but // a video in the asset bundle will over-ride if (Properties.Values.ContainsKey("VideoSource")) strVideoSource = Properties.Values["VideoSource"]; if (Properties.Values.ContainsKey("LootContainerSize")) vLootContainerSize = StringParsers.ParseVector2i(Properties.Values["LootContainerSize"]); else vLootContainerSize = new Vector2i(2, 3); } // We want to set down the file if it doesn't already exist, but we don't want to do the Loot container check // We want it to only have a 1,1 slot, but don't want to waste a loot container id for it. public override void OnBlockAdded(WorldBase world, Chunk _chunk, Vector3i _blockPos, BlockValue _blockValue) { #region OnBlockAdded if (_blockValue.ischild) return; shape.OnBlockAdded(world, _chunk, _blockPos, _blockValue); if (isMultiBlock) multiBlockPos.AddChilds(world, _chunk, _blockPos, _blockValue); if (!(world.GetTileEntity(_chunk.ClrIdx, _blockPos) is TileEntitySecureLootContainer)) { var tileEntityLootContainer = new TileEntityLootContainer(_chunk); tileEntityLootContainer.localChunkPos = World.toBlock(_blockPos); tileEntityLootContainer.lootListName = "cntDropBag"; tileEntityLootContainer.SetContainerSize(vLootContainerSize); _chunk.AddTileEntity(tileEntityLootContainer); } _chunk.AddEntityBlockStub(new BlockEntityData(_blockValue, _blockPos) { bNeedsTemperature = true }); #endregion } // Display custom messages for turning on and off the music box, based on the block's name. public override string GetActivationText(WorldBase _world, BlockValue _blockValue, int _clrIdx, Vector3i _blockPos, EntityAlive _entityFocusing) { #region GetActivationText var playerInput = ((EntityPlayerLocal)_entityFocusing).playerInput; var keybindString = playerInput.Activate.GetBindingXuiMarkupString() + playerInput.PermanentActions.Activate.GetBindingXuiMarkupString(); //string keybindString = UIUtils.GetKeybindString(playerInput.Activate, playerInput.PermanentActions.Activate); var block = list[_blockValue.type]; var blockName = block.GetBlockName(); var strReturn = string.Format(Localization.Get("pickupPrompt"), Localization.Get(blockName)); var _ebcd = _world.GetChunkFromWorldPos(_blockPos).GetBlockEntity(_blockPos); if (_ebcd == null || !_ebcd.transform) return strReturn; var myMusicBoxScript = _ebcd.transform.GetComponent(); if (myMusicBoxScript == null) { myMusicBoxScript = _ebcd.transform.gameObject.AddComponent(); myMusicBoxScript.enabled = false; } if (!myMusicBoxScript) return strReturn; if (myMusicBoxScript.enabled) return $"{Localization.Get("musicbox_turnOff")} {GetBlockName()}"; else return $"{Localization.Get("musicbox_turnOn")} {GetBlockName()}"; #endregion } public override BlockActivationCommand[] GetBlockActivationCommands(WorldBase _world, BlockValue _blockValue, int _clrIdx, Vector3i _blockPos, EntityAlive _entityFocusing) { cmds[0].enabled = true; cmds[1].enabled = true; cmds[2].enabled = TakeDelay > 0f; return cmds; } // Handles what happens to the contents of the box when you pick up the block. private void EventData_Event(TimerEventData timerData) { #region EventData_Event var world = GameManager.Instance.World; var array = (object[])timerData.Data; var clrIdx = (int)array[0]; var blockValue = (BlockValue)array[1]; var vector3i = (Vector3i)array[2]; var block = world.GetBlock(vector3i); var entityPlayerLocal = array[3] as EntityPlayerLocal; var tileEntityLootContainer = world.GetTileEntity(clrIdx, vector3i) as TileEntityLootContainer; if (tileEntityLootContainer == null) world.GetGameManager() .DropContentOfLootContainerServer(blockValue, vector3i, tileEntityLootContainer.entityId); // Pick up the item and put it inyor your inventory. var uiforPlayer = LocalPlayerUI.GetUIForPlayer(entityPlayerLocal); var itemStack = new ItemStack(block.ToItemValue(), 1); if (!uiforPlayer.xui.PlayerInventory.AddItem(itemStack, true)) uiforPlayer.xui.PlayerInventory.DropItem(itemStack); world.SetBlockRPC(clrIdx, vector3i, BlockValue.Air); #endregion } // We want to give the user the ability to pick up the blocks too, but the loot containers don't support that directly. public void TakeItemWithTimer(int _cIdx, Vector3i _blockPos, BlockValue _blockValue, EntityAlive _player) { #region TakeItemWithTimer if (_blockValue.damage > 0) { GameManager.ShowTooltip(_player as EntityPlayerLocal, Localization.Get("ttRepairBeforePickup"), "ui_denied"); return; } var playerUI = (_player as EntityPlayerLocal).PlayerUI; playerUI.windowManager.Open("timer", true); var childByType = playerUI.xui.GetChildByType(); var timerEventData = new TimerEventData(); timerEventData.Data = new object[] { _cIdx, _blockValue, _blockPos, _player }; timerEventData.Event += EventData_Event; childByType.SetTimer(TakeDelay, timerEventData); #endregion } // Play the music when its activated. We stop the sound broadcasting, in case they want to restart it again; otherwise we can get two sounds playing. public bool OnBlockActivated(string _commandName, WorldBase _world, int _cIdx, Vector3i _blockPos, BlockValue _blockValue, EntityAlive _player) { #region OnBlockActivated // If there's no transform, no sense on keeping going for this class. var _ebcd = _world.GetChunkFromWorldPos(_blockPos).GetBlockEntity(_blockPos); if (_ebcd == null || _ebcd.transform == null) return false; var myMusicBoxScript = _ebcd.transform.GetComponent(); if (myMusicBoxScript == null) myMusicBoxScript = _ebcd.transform.gameObject.AddComponent(); var bRuntimeSwitch = myMusicBoxScript.enabled; // Turn off the music box before we do anything with it. myMusicBoxScript.enabled = false; switch (_commandName) { case "light": break; case "take": TakeItemWithTimer(_cIdx, _blockPos, _blockValue, _player); return true; case "search": base.OnBlockActivated(_world, _cIdx, _blockPos, _blockValue, _player as EntityPlayerLocal); return true; } bRuntimeSwitch = !bRuntimeSwitch; // Check if we have an animator and set it myMusicBoxScript.anim = _ebcd.transform.GetComponent(); // Check if we have a video player as well. myMusicBoxScript.videoPlayer = _ebcd.transform.GetComponent(); myMusicBoxScript.myBlockPos = _blockPos; // If the switch is on, then we want to look in the loot container to find a reference to any potential items, // which will over-ride the default audio clip / video clip. if (bRuntimeSwitch) { // We'll try to support getting sounds from multiple sound data nodes, based on all the items in the loot container. var mySounds = new List(); var myVideos = new List(); var tileLootContainer = (TileEntityLootContainer)_world.GetTileEntity(_cIdx, _blockPos); if (tileLootContainer.items != null) { var array = tileLootContainer.items; for (var i = 0; i < array.Length; i++) { if (array[i].IsEmpty()) continue; if (array[i].itemValue.ItemClass.Properties.Values.ContainsKey("OnPlayBuff")) { var Buff = array[i].itemValue.ItemClass.Properties.Values["OnPlayBuff"]; _player.Buffs.AddBuff(Buff); } if (array[i].itemValue.ItemClass.Properties.Values.ContainsKey("OnPlayQuest")) { var Quest = array[i].itemValue.ItemClass.Properties.Values["OnPlayQuest"]; if (_player is EntityPlayerLocal) { var myQuest = QuestClass.CreateQuest(Quest); if (myQuest != null) (_player as EntityPlayerLocal).QuestJournal.AddQuest(myQuest); } } // Check for a SoundDataNode for a potential sound clip. if (array[i].itemValue.ItemClass.Properties.Values.ContainsKey("SoundDataNode")) { var strSound = array[i].itemValue.ItemClass.Properties.Values["SoundDataNode"]; if (!mySounds.Contains(strSound)) mySounds.Add(strSound); } // Check for a video Source for a video clip. If we find it, load the asset and add it to the music box script. if (array[i].itemValue.ItemClass.Properties.Values.ContainsKey("VideoSource")) { // Check if the video source is an asset bundle, and if so, load it directly into the video clip on var strVideo = array[i].itemValue.ItemClass.Properties.Values["VideoSource"]; if (strVideo.IndexOf('#') == 0 && strVideo.IndexOf('?') > 0) if (!myVideos.Contains(strVideo)) myVideos.Add(strVideo); } } } // Initialize the data with our defaults. myMusicBoxScript.strAudioSource = strAudioSource; myMusicBoxScript.strSoundSource = strSoundSource; myMusicBoxScript.strVideoSource = strVideoSource; myMusicBoxScript.myEntity = _player; // List of Videos and Sound clips. myMusicBoxScript.VideoGroups = myVideos; myMusicBoxScript.SoundGroups = mySounds; myMusicBoxScript.myVideoClip = null; myMusicBoxScript.enabled = bRuntimeSwitch; } return false; #endregion } }