C#:
using System;
using System.Collections.Generic;
using Network;
using Oxide.Core;
using UnityEngine;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using Newtonsoft.Json;
using Time = UnityEngine.Time;
namespace Oxide.Plugins
{
[Info("WelcomePlayerSound", "DezLife", "1.0.0")]
public class WelcomePlayerSound : RustPlugin
{
private const string perm = "WelcomePlayerSound.use";
#region hook
private void OnPlayerConnected(BasePlayer player)
{
if (player.IsReceivingSnapshot || player.IsSleeping())
{
NextTick(() => OnPlayerConnected(player));
return;
}
NextTick(() => { API__PlaySoundOnPlayer(player); });
}
private void Unload()
{
SaveData();
SpeakerEntityMgr.Shutdown();
}
void Init()
{
Unsubscribe(nameof(OnPlayerConnected));
LoadData();
permission.RegisterPermission(perm, this);
}
#endregion
#region Data
private void LoadDataSound()
{
if (_Data?.AudioClips.Name == null)
{
PrintWarning("Загрузка звука");
webrequest.Enqueue($"http://utilite.skyplugins.ru/schizophrenia/WelcomePlayer.json", null, (i, s) => {
if (i == 200)
WriteToData(s);
else
{
PrintError("Ошибка при загрузке звуков!\nОбратитесь к разработчику");
}
}, this, RequestMethod.GET);
;
}
_Data = _DataFile.ReadObject<BotSpeakerData>();
Subscribe(nameof(OnPlayerConnected));
}
void WriteToData(string calback)
{
_Data = JsonConvert.DeserializeObject<BotSpeakerData>(calback);
_DataFile.WriteObject(_Data);
}
public class AudioData
{
public String Name;
public Single Length = 0;
public List<VoicePacket> VoicePacketList = new List<VoicePacket>();
private Single TimeStart = -1f;
public void Append(Byte[] data)
{
if (TimeStart < 0)
{
TimeStart = Time.time;
}
VoicePacketList.Add(new VoicePacket()
{
Stream = data,
TimeOffset = Time.time - TimeStart
});
}
public class VoicePacket
{
public Single TimeOffset;
public Byte[] Stream;
}
}
public class BotSpeakerData
{
public AudioData AudioClips = new AudioData();
}
private BotSpeakerData _Data;
private DynamicConfigFile _DataFile = Interface.Oxide.DataFileSystem.GetFile("WelcomePlayer");
private void LoadData()
{
_Data = _DataFile.ReadObject<BotSpeakerData>();
LoadDataSound();
}
private void SaveData() => _DataFile.WriteObject(_Data);
#endregion
#region Metods
void API__PlaySoundOnPlayer(BasePlayer player)
{
AudioData audio = _Data.AudioClips;
if (audio == null)
return;
var clip = _Data.AudioClips;
var speaker = SpeakerEntityMgr.Create(player);
speaker.SendEntitities();
speaker.PlayAudioStream(clip, timer);
timer.Once(clip.Length, () => {speaker?.Kill();});
}
public class SpeakerEntity
{
private UInt32 UID_SPEAKER = Net.sv.TakeUID();
private UInt32 UID_CHAIR = Net.sv.TakeUID();
/// <summary>
/// Слушатели звукового потока
/// </summary>
public BasePlayer Listeners
{
get; private set;
}
public void SetListeners(BasePlayer listeners)
{
Listeners = listeners;
}
public void SendEntitities()
{
SendEntity(GetEntityChair);
SendEntity(GetEntitySpeaker);
}
private ProtoBuf.Entity GetEntitySpeaker(BasePlayer player) =>
new ProtoBuf.Entity()
{
baseNetworkable = new ProtoBuf.BaseNetworkable()
{
prefabID = player.prefabID,
@group = BaseNetworkable.GlobalNetworkGroup.ID,
uid = UID_SPEAKER,
},
baseEntity = new ProtoBuf.BaseEntity()
{
flags = 0,
pos = new Vector3(0, 0, 0),
rot = new Vector3(0, 0, 0),
skinid = 0,
time = Time.time,
},
baseCombat = new ProtoBuf.BaseCombat()
{
health = 10000,
state = (Int32)BaseCombatEntity.LifeState.Alive
},
basePlayer = new ProtoBuf.BasePlayer()
{
health = 10000,
modelState = new ModelState()
{
mounted = true,
onground = true,
ducked = true,
prone = true
},
userid = UID_SPEAKER,
name = "DezLife",
playerFlags = (Int32)0,
mounted = UID_CHAIR
},
parent = new ProtoBuf.ParentInfo()
{
uid = UID_CHAIR,
bone = 0
}
};
private ProtoBuf.Entity GetEntityChair(BasePlayer player) =>
new ProtoBuf.Entity()
{
baseNetworkable = new ProtoBuf.BaseNetworkable()
{
prefabID = 624857933, // static chair
@group = BaseNetworkable.GlobalNetworkGroup.ID,
uid = UID_CHAIR,
},
baseEntity = new ProtoBuf.BaseEntity()
{
flags = 0,
pos = new Vector3(0, 0.5f, -2.3f),
rot = new Vector3(90, 180, 180),
skinid = 0,
time = Time.time,
},
parent = new ProtoBuf.ParentInfo()
{
uid = player.net.ID,
bone = 2822582055 // head
}
};
public void PlayAudioStream(AudioData audio, PluginTimers timer)
{
audio.VoicePacketList.ForEach(packet =>
{
timer.Once(packet.TimeOffset, () =>
{
if (Net.sv.write.Start())
{
Net.sv.write.PacketID(Message.Type.VoiceData);
Net.sv.write.UInt32(UID_SPEAKER);
Net.sv.write.BytesWithSize(packet.Stream);
Net.sv.write.Send(new SendInfo(Listeners.Connection) { priority = Priority.Immediate });
}
});
});
}
public void Kill()
{
DestroyEntity(UID_SPEAKER);
DestroyEntity(UID_CHAIR);
SpeakerEntityMgr.Kill(this);
}
private void SendEntity(Func<BasePlayer, ProtoBuf.Entity> entityGetter)
{
if (Net.sv.write.Start())
{
Net.sv.write.PacketID(Message.Type.Entities);
Net.sv.write.UInt32(++Listeners.net.connection.validate.entityUpdates);
entityGetter(Listeners)?.WriteToStream(Net.sv.write);
Net.sv.write.Send(new SendInfo(Listeners.net.connection));
}
}
private void DestroyEntity(UInt32 uid)
{
if (Net.sv.write.Start())
{
Net.sv.write.PacketID(Message.Type.EntityDestroy);
Net.sv.write.UInt32(uid);
Network.Net.sv.write.Send(new SendInfo(Listeners.Connection) { priority = Priority.Immediate });
}
}
}
public class SpeakerEntityMgr
{
private static List<SpeakerEntity> _Entities = new List<SpeakerEntity>();
/// <summary>
/// Spawn speaker
/// </summary>
/// <returns>Speaker Instance</returns>
public static SpeakerEntity Create(BasePlayer listeners)
{
var speaker = new SpeakerEntity();
speaker.SetListeners(listeners);
_Entities.Add(speaker);
return speaker;
}
/// <summary>
/// Called when plugin unloaded
/// </summary>
public static void Shutdown()
{
_Entities.ForEach(entity => entity?.Kill());
}
/// <summary>
/// Kill entity
/// </summary>
/// <param name="entity">Speaker</param>
public static void Kill(SpeakerEntity entity)
{
_Entities.Remove(entity);
}
}
#endregion
#region Commands
[ChatCommand("wps.test")]
void SchizophreniaTest(BasePlayer player)
{
if (!permission.UserHasPermission(player.UserIDString, perm))
{
SendReply(player, "Недостаточно прав");
return;
}
OnPlayerConnected(player);
}
#endregion
}
}