C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
//#define DEBUG
using Oxide.Core;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Rust;
using System.Linq;
using Oxide.Core.Libraries.Covalence;
using System;
using System.Globalization;
using Oxide.Core.Plugins;
namespace Oxide.Plugins
{
[Info("Flying Carpet", "RFC1920", "1.1.7")]
[Description("Fly a custom object consisting of carpet, chair, lantern, lock, and small sign")]
// Thanks to Colon Blow for his fine work on GyroCopter, upon which this was originally based.class FlyingCarpet : RustPlugin
{
#region Load
static LayerMask layerMask;
BaseEntity newCarpet;
static Dictionary<ulong, PlayerCarpetData> loadplayer = new Dictionary<ulong, PlayerCarpetData>();
static List<ulong> pilotslist = new List<ulong>();
// SignArtist plugin
[PluginReference]
Plugin SignArtist;
public class PlayerCarpetData
{
public BasePlayer player;
public int carpetcount;
}
void Init()
{
LoadVariables();
layerMask = (1 << 29);
layerMask |= (1 << 18);
layerMask = ~layerMask;
AddCovalenceCommand("fc", "cmdCarpetBuild");
AddCovalenceCommand("fcc", "cmdCarpetCount");
AddCovalenceCommand("fcd", "cmdCarpetDestroy");
AddCovalenceCommand("fcg", "cmdCarpetGiveChat");
AddCovalenceCommand("fchelp", "cmdCarpetHelp");
permission.RegisterPermission("flyingcarpet.use", this);
permission.RegisterPermission("flyingcarpet.vip", this);
permission.RegisterPermission("flyingcarpet.admin", this);
permission.RegisterPermission("flyingcarpet.unlimited", this);
lang.RegisterMessages(new Dictionary<string, string>
{
["helptext1"] = "Flying Carpet instructions:",
["helptext2"] = " type /fc to spawn a Flying Carpet",
["helptext3"] = " type /fcd to destroy your flyingcarpet.",
["helptext4"] = " type /fcc to show a count of your carpets",
["notauthorized"] = "You don't have permission to do that !!",
["notfound"] = "Could not locate a carpet.You must be within {0} meters for this!!",
["notflyingcarpet"] = "You are not piloting a flying carpet !!",
["maxcarpets"] = "You have reached the maximum allowed carpets",
["landingcarpet"] = "Carpet landing sequence started !!",
["risingcarpet"] = "Carpet takeoff sequence started !!",
["carpetlocked"] = "You must unlock the Carpet first !!",
["carpetspawned"] = "Flying Carpet spawned! Don't forget to lock it !!",
["carpetdestroyed"] = "Flying Carpet destroyed !!",
["carpetfuel"] = "You will need fuel to fly.Do not start without fuel !!",
["carpetnofuel"] = "You have been granted unlimited fly time, no fuel required !!",
["nofuel"] = "You're out of fuel !!",
["noplayer"] = "Unable to find player {0}!",
["gaveplayer"] = "Gave carpet to player {0}!",
["lowfuel"] = "You're low on fuel !!",
["nocarpets"] = "You have no Carpets",
["currcarpets"] = "Current Carpets : {0}",
["giveusage"] = "You need to supply a valid SteamId."
}, this);
}
bool isAllowed(BasePlayer player, string perm) => permission.UserHasPermission(player.UserIDString, perm);
private bool HasPermission(ConsoleSystem.Arg arg, string permname) => (arg.Connection.player as BasePlayer) == null ? true : permission.UserHasPermission((arg.Connection.player as BasePlayer).UserIDString, permname);
private static HashSet<BasePlayer> FindPlayers(string nameOrIdOrIp)
{
var players = new HashSet<BasePlayer>();
if (string.IsNullOrEmpty(nameOrIdOrIp)) return players;
foreach (var activePlayer in BasePlayer.activePlayerList)
{
if (activePlayer.UserIDString.Equals(nameOrIdOrIp))
players.Add(activePlayer);
else if (!string.IsNullOrEmpty(activePlayer.displayName) && activePlayer.displayName.Contains(nameOrIdOrIp, CompareOptions.IgnoreCase))
players.Add(activePlayer);
else if (activePlayer.net?.connection != null && activePlayer.net.connection.ipaddress.Equals(nameOrIdOrIp))
players.Add(activePlayer);
}
foreach (var sleepingPlayer in BasePlayer.sleepingPlayerList)
{
if (sleepingPlayer.UserIDString.Equals(nameOrIdOrIp))
players.Add(sleepingPlayer);
else if (!string.IsNullOrEmpty(sleepingPlayer.displayName) && sleepingPlayer.displayName.Contains(nameOrIdOrIp, CompareOptions.IgnoreCase))
players.Add(sleepingPlayer);
}
return players;
}
#endregion
#region Configuration
bool UseMaxCarpetChecks = true;
bool playemptysound = true;
public int maxcarpets = 1;
public int vipmaxcarpets = 2;
static float MinAltitude = 5f;
static float MinDistance = 10f;
static ulong rugSkinID = 871503616;
static ulong chairSkinID = 943293895;
static float NormalSpeed = 12f;
static float SprintSpeed = 25f;
static bool requirefuel = true;
static bool doublefuel = false;
static bool nameOnSign = true;
//bool Changed = false;
protected override void LoadDefaultConfig()
{
#if DEBUG
Puts("Creating a new config file...");
#endif
Config.Clear();
LoadVariables();
}
private void LoadConfigVariables()
{
CheckCfgFloat("Minimum Flight Altitude : ", ref MinAltitude);
CheckCfgFloat("Minimum Distance for FCD: ", ref MinDistance);
CheckCfgFloat("Speed - Normal Flight Speed is : ", ref NormalSpeed);
CheckCfgFloat("Speed - Sprint Flight Speed is : ", ref SprintSpeed);
CheckCfg("Deploy - Enable limited FlyingCarpets per person : ", ref UseMaxCarpetChecks);
CheckCfg("Deploy - Limit of Carpets players can build : ", ref maxcarpets);
CheckCfg("Deploy - Limit of Carpets VIP players can build : ", ref vipmaxcarpets);
CheckCfg("Require Fuel to Operate : ", ref requirefuel);
CheckCfg("Play low fuel sound : ", ref playemptysound);
CheckCfg("Double Fuel Consumption: ", ref doublefuel);
CheckCfg("RugSkinID : ", ref rugSkinID);
CheckCfg("ChairSkinID : ", ref chairSkinID);
CheckCfg("Owner Name on Sign: ", ref nameOnSign);
}
private void LoadVariables()
{
LoadConfigVariables();
SaveConfig();
}
private void CheckCfg<T>(string Key, ref T var)
{
if(Config[Key] is T)
{
var = (T)Config[Key];
}
else
{
Config[Key] = var;
}
}
private void CheckCfgFloat(string Key, ref float var)
{
if(Config[Key] != null)
{
var = Convert.ToSingle(Config[Key]);
}
else
{
Config[Key] = var;
}
}
object GetConfig(string menu, string datavalue, object defaultValue)
{
var data = Config[menu] as Dictionary<string, object>;
if(data == null)
{
data = new Dictionary<string, object>();
Config[menu] = data;
//Changed = true;
}
object value;
if(!data.TryGetValue(datavalue, out value))
{
value = defaultValue;
data[datavalue] = value;
//Changed = true;
}
return value;
}
#endregion
#region Message
private string _(string msgId, BasePlayer player, params object[] args)
{
var msg = lang.GetMessage(msgId, this, player?.UserIDString);
return args.Length > 0 ? string.Format(msg, args) : msg;
}
private void PrintMsgL(BasePlayer player, string msgId, params object[] args)
{
if(player == null) return;
PrintMsg(player, _(msgId, player, args));
}
private void PrintMsg(BasePlayer player, string msg)
{
if(player == null) return;
SendReply(player, $"{msg}");
}
#endregion
#region Chat Commands
[Command("fc"), Permission("flyingcarpet.use")]
void cmdCarpetBuild(IPlayer iplayer, string command, string[] args)
{
bool vip = false;
var player = iplayer.Object as BasePlayer;
if(!iplayer.HasPermission("flyingcarpet.use")) { PrintMsgL(player, "notauthorized"); return; }
if(iplayer.HasPermission("flyingcarpet.vip"))
{
vip = true;
}
if(CarpetLimitReached(player, vip)) { PrintMsgL(player, "maxcarpets"); return; }
AddCarpet(player, player.transform.position);
}
[Command("fcg"), Permission("flyingcarpet.admin")]
void cmdCarpetGiveChat(IPlayer iplayer, string command, string[] args)
{
var player = iplayer.Object as BasePlayer;
if(args.Length == 0)
{
PrintMsgL(player, "giveusage");
return;
}
bool vip = false;
string pname = args[0] == null ? null : args[0];
if(!iplayer.HasPermission("flyingcarpet.admin")) { PrintMsgL(player, "notauthorized"); return; }
if(pname == null) { PrintMsgL(player, "noplayer", "NAME_OR_ID"); return; }
BasePlayer Bplayer = BasePlayer.Find(pname);
if(Bplayer == null)
{
PrintMsgL(player, "noplayer", pname);
return;
}
var Iplayer = Bplayer.IPlayer;
if(Iplayer.HasPermission("flyingcarpet.vip"))
{
vip = true;
}
if(CarpetLimitReached(Bplayer, vip)) { PrintMsgL(player, "maxcarpets"); return; }
AddCarpet(Bplayer, Bplayer.transform.position);
PrintMsgL(player, "gaveplayer", pname);
}
[ConsoleCommand("fcgive")]
void cmdCarpetGive(ConsoleSystem.Arg arg)
{
if(arg.IsRcon)
{
if(arg.Args == null)
{
Puts("You need to supply a valid SteamId.");
return;
}
}
else if(!HasPermission(arg, "flyingcarpet.admin"))
{
SendReply(arg, _("notauthorized", arg.Connection.player as BasePlayer));
return;
}
else if(arg.Args == null)
{
SendReply(arg, _("giveusage", arg.Connection.player as BasePlayer));
return;
}
bool vip = false;
string pname = arg.GetString(0);
if(pname.Length < 1) { Puts("Player name or id cannot be null"); return; }
BasePlayer Bplayer = BasePlayer.Find(pname);
if(Bplayer == null) { Puts($"Unable to find player '{pname}'"); return; }
var Iplayer = Bplayer.IPlayer;
if(Iplayer.HasPermission("flyingcarpet.vip")) { vip = true; }
if(CarpetLimitReached(Bplayer, vip))
{
Puts($"Player '{pname}' has reached maxcarpets"); return;
}
AddCarpet(Bplayer, Bplayer.transform.position);
Puts($"Gave carpet to '{Bplayer.displayName}'");
}
[Command("fcc"), Permission("flyingcarpet.use")]
void cmdCarpetCount(IPlayer iplayer, string command, string[] args)
{
var player = iplayer.Object as BasePlayer;
if(!iplayer.HasPermission("flyingcarpet.use")) { PrintMsgL(player, "notauthorized"); return; }
if(!loadplayer.ContainsKey(player.userID))
{
PrintMsgL(player, "nocarpets");
return;
}
string ccount = loadplayer[player.userID].carpetcount.ToString();
#if DEBUG
Puts("CarpetCount: " + ccount);
#endif
PrintMsgL(player, "currcarpets", ccount);
}
[Command("fcd"), Permission("flyingcarpet.use")]
void cmdCarpetDestroy(IPlayer iplayer, string command, string[] args)
{
var player = iplayer.Object as BasePlayer;
if(!iplayer.HasPermission("flyingcarpet.use")) { PrintMsgL(player, "notauthorized"); return; }
string target = null;
if(args.Length > 0)
{
target = args[0];
}
if(iplayer.HasPermission("flyingcarpet.admin") && target != null)
{
if(target == "all")
{
DestroyAllCarpets(player);
return;
}
var players = FindPlayers(target);
if (players.Count <= 0)
{
PrintMsgL(player, "PlayerNotFound", target);
return;
}
if (players.Count > 1)
{
PrintMsgL(player, "MultiplePlayers", target, string.Join(", ", players.Select(p => p.displayName).ToArray()));
return;
}
var targetPlayer = players.First();
RemoveCarpet(targetPlayer);
DestroyRemoteCarpet(targetPlayer);
}
else
{
RemoveCarpet(player);
DestroyLocalCarpet(player);
}
}
[Command("fchelp"), Permission("flyingcarpet.use")]
void cmdCarpetHelp(IPlayer iplayer, string command, string[] args)
{
var player = iplayer.Object as BasePlayer;
if(!iplayer.HasPermission("flyingcarpet.use")) { PrintMsgL(player, "notauthorized"); return; }
PrintMsgL(player, "helptext1");
PrintMsgL(player, "helptext2");
PrintMsgL(player, "helptext3");
PrintMsgL(player, "helptext4");
}
#endregion
#region Hooks
// This is how we take off or land the carpet!
object OnOvenToggle(BaseOven oven, BasePlayer player)
{
bool rtrn = false; // Must match other plugins with this call to avoid conflicts.QuickSmelt uses false
CarpetEntity activecarpet;
try
{
activecarpet = player.GetMounted().GetComponentInParent<CarpetEntity>() ?? null;
if(activecarpet == null)
{
oven.StopCooking();
return rtrn;
}
}
catch
{
return null;
}
if(activecarpet.carpetlock != null && activecarpet.carpetlock.IsLocked()) { PrintMsgL(player, "carpetlocked"); return rtrn; }
if(!player.isMounted) return rtrn; // player offline, does not mean ismounted on carpet
if(player.GetMounted() != activecarpet.entity) return rtrn; // online player not in seat on carpet
#if DEBUG
Puts("OnOvenToggle: Player cycled lantern!");
#endif
if(oven.IsOn())
{
oven.StopCooking();
}
else
{
oven.StartCooking();
}
if(!activecarpet.FuelCheck())
{
if(activecarpet.needfuel)
{
PrintMsgL(player, "nofuel");
PrintMsgL(player, "landingcarpet");
activecarpet.engineon = false;
}
}
var ison = activecarpet.engineon;
if(ison) { activecarpet.islanding = true; PrintMsgL(player, "landingcarpet"); return null; }
if(!ison) { AddPlayerToPilotsList(player); activecarpet.engineon = true; return null; }
return rtrn;
}
// Check for carpet lantern fuel
void OnFuelConsume(BaseOven oven, Item fuel, ItemModBurnable burnable)
{
// Only work on lanterns
if(oven.ShortPrefabName != "lantern.deployed") return;
int dbl = doublefuel ? 4 : 2;
BaseEntity lantern = oven as BaseEntity;
// Only work on lanterns attached to a Carpet
var activecarpet = lantern.GetComponentInParent<CarpetEntity>() ?? null;
if(activecarpet == null) return;
#if DEBUG
Puts("OnConsumeFuel: found a carpet lantern!");
#endif
if(activecarpet.needfuel)
{
#if DEBUG
Puts("OnConsumeFuel: carpet requires fuel!");
#endif
}
else
{
#if DEBUG
Puts("OnConsumeFuel: carpet does not require fuel!");
#endif
fuel.amount++; // Required to keep it from decrementing
return;
}
BasePlayer player = activecarpet.GetComponent<BaseMountable>().GetMounted() as BasePlayer;
if(!player) return;
#if DEBUG
Puts("OnConsumeFuel: checking fuel level...");
#endif
// Before it drops to 1 (3 for doublefuel) AFTER this hook call is complete, warn them that the fuel is low (1) - ikr
if(fuel.amount == dbl)
{
#if DEBUG
Puts("OnConsumeFuel: sending low fuel warning...");
#endif
if(playemptysound)
{
Effect.server.Run("assets/bundled/prefabs/fx/well/pump_down.prefab", player.transform.position);
}
PrintMsgL(player, "lowfuel");
}
if(doublefuel)
{
fuel.amount--;
}
if(fuel.amount == 0)
{
#if DEBUG
Puts("OnConsumeFuel: out of fuel.");
#endif
PrintMsgL(player, "lowfuel");
var ison = activecarpet.engineon;
if(ison)
{
activecarpet.islanding = true;
activecarpet.engineon = false;
PrintMsgL(player, "landingcarpet");
OnOvenToggle(oven, player);
return;
}
}
}
// To skip cycling our lantern (thanks, k11l0u)
private object OnNightLanternToggle(BaseEntity entity, bool status)
{
// Only work on lanterns
if(entity.ShortPrefabName != "lantern.deployed") return null;
#if DEBUG
Puts("OnNightLanternToggle: Called on a lantern.Checking for carpet...");
#endif
// Only work on lanterns attached to a Carpet
var activecarpet = entity.GetComponentInParent<CarpetEntity>() ?? null;
if(activecarpet != null)
{
#if DEBUG
Puts("OnNightLanternToggle: Do not cycle this lantern!");
#endif
return true;
}
#if DEBUG
Puts("OnNightLanternToggle: Not a carpet lantern.");
#endif
return null;
}
#endregion
#region Primary
private void AddCarpet(BasePlayer player, Vector3 location)
{
if(player == null && location == null) return;
if(location == null && player != null) location = player.transform.position;
Vector3 spawnpos = new Vector3();
// Set initial default for fuel requirement based on config
bool needfuel = requirefuel;
if(isAllowed(player, "flyingcarpet.unlimited"))
{
// User granted unlimited fly time without fuel
needfuel = false;
#if DEBUG
Puts("AddCarpet: Unlimited fuel granted!");
#endif
}
if(needfuel)
{
// Don't put them on the carpet since they need to fuel up first
spawnpos = player.transform.position + -player.transform.forward * 2f + new Vector3(0, 1f, 0);
}
else
{
// Spawn at point of player
spawnpos = new Vector3(location.x, location.y + 0.5f, location.z);
}
string staticprefab = "assets/bundled/prefabs/static/chair.invisible.static.prefab";
newCarpet = GameManager.server.CreateEntity(staticprefab, spawnpos, new Quaternion(), true);
newCarpet.name = "FlyingCarpet";
var chairmount = newCarpet.GetComponent<BaseMountable>();
chairmount.isMobile = true;
newCarpet.enableSaving = false;
newCarpet.OwnerID = player.userID;
newCarpet.skinID = chairSkinID;
newCarpet.Spawn();
var carpet = newCarpet.gameObject.AddComponent<CarpetEntity>();
carpet.needfuel = needfuel;
// Unlock the tank if they need fuel.carpet.lantern1.SetFlag(BaseEntity.Flags.Locked, !needfuel);
if(needfuel)
{
#if DEBUG
// We have to set this after the spawn.Puts("AddCarpet: Emptying the tank!");
#endif
carpet.SetFuel(0);
}
// paint sign with username
if(SignArtist && nameOnSign)
{
// This only works with version 1.1.7 on
if(SignArtist.Version >= new VersionNumber(1, 1, 7))
{
string message = player.displayName;
int fontsize = Convert.ToInt32(Math.Floor(150f / message.Length));
SignArtist.Call("signText", player, carpet.sign, message, fontsize, "00FF00", "000000");
}
}
carpet.sign.SetFlag(BaseEntity.Flags.Locked, true);
AddPlayerID(player.userID);
if(chairmount != null && player != null)
{
PrintMsgL(player, "carpetspawned");
if(carpet.needfuel)
{
PrintMsgL(player, "carpetfuel");
}
else
{
// Put them in the chair.They will still need to unlock it.PrintMsgL(player, "carpetnofuel");
chairmount.MountPlayer(player);
}
return;
}
}
public bool PilotListContainsPlayer(BasePlayer player)
{
if(pilotslist.Contains(player.userID)) return true;
return false;
}
void AddPlayerToPilotsList(BasePlayer player)
{
if(PilotListContainsPlayer(player)) return;
pilotslist.Add(player.userID);
}
public void RemovePlayerFromPilotsList(BasePlayer player)
{
if(PilotListContainsPlayer(player))
{
pilotslist.Remove(player.userID);
return;
}
}
void DestroyLocalCarpet(BasePlayer player)
{
if(player == null) return;
List<BaseEntity> carpetlist = new List<BaseEntity>();
Vis.Entities<BaseEntity>(player.transform.position, MinDistance, carpetlist);
bool foundcarpet = false;
foreach(BaseEntity p in carpetlist)
{
var foundent = p.GetComponentInParent<CarpetEntity>() ?? null;
if(foundent != null)
{
foundcarpet = true;
if(foundent.ownerid != player.userID) return;
foundent.entity.Kill(BaseNetworkable.DestroyMode.Gib);
PrintMsgL(player, "carpetdestroyed");
}
}
if(!foundcarpet)
{
PrintMsgL(player, "notfound", MinDistance.ToString());
}
}
void DestroyAllCarpets(BasePlayer player)
{
List<BaseEntity> carpetlist = new List<BaseEntity>();
Vis.Entities<BaseEntity>(new Vector3(0,0,0), 3500f, carpetlist);
bool foundcarpet = false;
foreach(BaseEntity p in carpetlist)
{
var foundent = p.GetComponentInParent<CarpetEntity>() ?? null;
if(foundent != null)
{
foundcarpet = true;
foundent.entity.Kill(BaseNetworkable.DestroyMode.Gib);
PrintMsgL(player, "carpetdestroyed");
}
}
if(!foundcarpet)
{
PrintMsgL(player, "notfound", MinDistance.ToString());
}
}
void DestroyRemoteCarpet(BasePlayer player)
{
if(player == null) return;
List<BaseEntity> carpetlist = new List<BaseEntity>();
Vis.Entities<BaseEntity>(new Vector3(0,0,0), 3500f, carpetlist);
bool foundcarpet = false;
foreach(BaseEntity p in carpetlist)
{
var foundent = p.GetComponentInParent<CarpetEntity>() ?? null;
if(foundent != null)
{
foundcarpet = true;
if(foundent.ownerid != player.userID) return;
foundent.entity.Kill(BaseNetworkable.DestroyMode.Gib);
PrintMsgL(player, "carpetdestroyed");
}
}
if(!foundcarpet)
{
PrintMsgL(player, "notfound", MinDistance.ToString());
}
}
void OnPlayerInput(BasePlayer player, InputState input)
{
if(player == null || input == null) return;
if(!player.isMounted) return;
var activecarpet = player.GetMounted().GetComponentInParent<CarpetEntity>() ?? null;
if(activecarpet == null) return;
if(player.GetMounted() != activecarpet.entity) return;
if(input != null)
{
activecarpet.CarpetInput(input, player);
}
return;
}
void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo)
{
if(entity == null || hitInfo == null) return;
var iscarpet = entity.GetComponentInParent<CarpetEntity>() ?? null;
if(iscarpet != null) hitInfo.damageTypes.ScaleAll(0);
return;
}
object OnEntityGroundMissing(BaseEntity entity)
{
var iscarpet = entity.GetComponentInParent<CarpetEntity>() ?? null;
if(iscarpet != null) return false;
return null;
}
bool CarpetLimitReached(BasePlayer player, bool vip=false)
{
if(UseMaxCarpetChecks)
{
if(loadplayer.ContainsKey(player.userID))
{
var currentcount = loadplayer[player.userID].carpetcount;
int maxallowed = maxcarpets;
if(vip)
{
maxallowed = vipmaxcarpets;
}
if(currentcount >= maxallowed) return true;
}
}
return false;
}
object CanDismountEntity(BasePlayer player, BaseMountable entity)
{
if(player == null) return null;
if(PilotListContainsPlayer(player)) return false;
return null;
}
void OnEntityMounted(BaseMountable mountable, BasePlayer player)
{
var activecarpet = mountable.GetComponentInParent<CarpetEntity>() ?? null;
if(activecarpet != null)
{
#if DEBUG
Puts("OnEntityMounted: player mounted copter!");
#endif
if(mountable.GetComponent<BaseEntity>() != activecarpet.entity) return;
activecarpet.lantern1.SetFlag(BaseEntity.Flags.On, false);
}
}
void OnEntityDismounted(BaseMountable mountable, BasePlayer player)
{
var activecarpet = mountable.GetComponentInParent<CarpetEntity>() ?? null;
if(activecarpet != null)
{
#if DEBUG
Puts("OnEntityMounted: player dismounted copter!");
#endif
if(mountable.GetComponent<BaseEntity>() != activecarpet.entity) return;
}
}
private object CanLootEntity(BasePlayer player, StorageContainer container)
{
if(container == null || player == null) return null;
var iscarpet = container.GetComponentInParent<CarpetEntity>() ?? null;
if(iscarpet != null)
{
if(iscarpet.carpetlock != null && iscarpet.carpetlock.IsLocked()) return false;
}
return null;
}
private object CanPickupEntity(BasePlayer player, BaseCombatEntity entity)
{
if(entity == null || player == null) return null;
BaseEntity myent = entity as BaseEntity;
string myparent = null;
try
{
myparent = myent.GetParentEntity().name;
}
catch {}
if(myparent == "FlyingCarpet" || myent.name == "FlyingCarpet")
{
#if DEBUG
if(myent.name == "FlyingCarpet")
{
Puts("CanPickupEntity: player trying to pickup the carpet!");
}
else if(myparent == "FlyingCarpet")
{
string entity_name = myent.LookupPrefab().name;
Puts($"CanPickupEntity: player trying to remove {entity_name} from a carpet!");
}
#endif
PrintMsgL(player, "notauthorized");
return false;
}
return null;
}
private object CanPickupLock(BasePlayer player, BaseLock baseLock)
{
if(baseLock == null || player == null) return null;
BaseEntity myent = baseLock as BaseEntity;
string myparent = null;
try
{
myparent = myent.GetParentEntity().name;
}
catch {}
if(myparent == "FlyingCarpet")
{
#if DEBUG
Puts("CanPickupLock: player trying to remove lock from a carpet!");
#endif
PrintMsgL(player, "notauthorized");
return false;
}
return null;
}
void AddPlayerID(ulong ownerid)
{
if(!loadplayer.ContainsKey(ownerid))
{
loadplayer.Add(ownerid, new PlayerCarpetData
{
carpetcount = 1,
});
return;
}
loadplayer[ownerid].carpetcount = loadplayer[ownerid].carpetcount + 1;
}
void RemovePlayerID(ulong ownerid)
{
if(loadplayer.ContainsKey(ownerid)) loadplayer[ownerid].carpetcount = loadplayer[ownerid].carpetcount - 1;
return;
}
object OnPlayerDeath(BasePlayer player, HitInfo info)
{
RemovePlayerFromPilotsList(player);
return null;
}
void RemoveCarpet(BasePlayer player)
{
RemovePlayerFromPilotsList(player);
return;
}
void OnPlayerDisconnected(BasePlayer player, string reason)
{
RemoveCarpet(player);
}
void OnPlayerRespawned(BasePlayer player)
{
RemoveCarpet(player);
}
void DestroyAll<T>()
{
var objects = GameObject.FindObjectsOfType(typeof(T));
if(objects != null)
{
foreach(var gameObj in objects)
{
GameObject.Destroy(gameObj);
}
}
}
void Unload()
{
DestroyAll<CarpetEntity>();
}
#endregion
#region Carpet Antihack check
static List<BasePlayer> carpetantihack = new List<BasePlayer>();
object OnPlayerViolation(BasePlayer player, AntiHackType type, float amount)
{
if(player == null) return null;
if(carpetantihack.Contains(player)) return false;
return null;
}
#endregion
#region Carpet Entity
class CarpetEntity : BaseEntity
{
public BaseEntity entity;
public BasePlayer player;
public BaseEntity sitbox;
public BaseEntity carpet1;
public BaseEntity lantern1;
public BaseEntity carpetlock;
public BaseEntity lights1;
public BaseEntity lights2;
public BaseEntity sign;
public string entname = "FlyingCarpet";
Quaternion entityrot;
Vector3 entitypos;
public bool moveforward;
public bool movebackward;
public bool moveup;
public bool movedown;
public bool rotright;
public bool rotleft;
public bool sprinting;
public bool islanding;
public bool mounted;
public bool engineon;
public bool hasFuel;
public bool needfuel;
public ulong skinid = 1;
public ulong ownerid;
//int count;
float minaltitude;
FlyingCarpet instance;
public bool throttleup;
float sprintspeed;
float normalspeed;
//bool isenabled = true;
SphereCollider sphereCollider;
string prefabbox = "assets/prefabs/deployable/signs/sign.small.wood.prefab";
string prefabcarpet = "assets/prefabs/deployable/rug/rug.deployed.prefab";
string prefablamp = "assets/prefabs/deployable/lantern/lantern.deployed.prefab";
string prefablights = "assets/prefabs/misc/xmas/christmas_lights/xmas.lightstring.deployed.prefab";
string prefablock = "assets/prefabs/locks/keypad/lock.code.prefab";
string prefabsign = "assets/prefabs/deployable/signs/sign.small.wood.prefab";
void Awake()
{
entity = GetComponentInParent<BaseEntity>();
entityrot = Quaternion.identity;
entitypos = entity.transform.position;
minaltitude = MinAltitude;
instance = new FlyingCarpet();
ownerid = entity.OwnerID;
gameObject.name = "FlyingCarpet";
engineon = false;
hasFuel = false;
//needfuel = requirefuel;
if(!needfuel)
{
hasFuel = true;
}
moveforward = false;
movebackward = false;
moveup = false;
movedown = false;
rotright = false;
rotleft = false;
sprinting = false;
islanding = false;
mounted = false;
throttleup = false;
sprintspeed = SprintSpeed;
normalspeed = NormalSpeed;
//isenabled = false;
skinid = rugSkinID;
SpawnCarpet();
lantern1.OwnerID = entity.OwnerID;
sign.OwnerID = entity.OwnerID;
sphereCollider = entity.gameObject.AddComponent<SphereCollider>();
sphereCollider.gameObject.layer = (int)Layer.Reserved1;
sphereCollider.isTrigger = true;
sphereCollider.radius = 6f;
}
BaseEntity SpawnPart(string prefab, BaseEntity entitypart, bool setactive, int eulangx, int eulangy, int eulangz, float locposx, float locposy, float locposz, BaseEntity parent, ulong skinid)
{
entitypart = new BaseEntity();
entitypart = GameManager.server.CreateEntity(prefab, entitypos, entityrot, setactive);
entitypart.transform.localEulerAngles = new Vector3(eulangx, eulangy, eulangz);
entitypart.transform.localPosition = new Vector3(locposx, locposy, locposz);
entitypart.SetParent(parent, 0);
entitypart.skinID = skinid;
entitypart?.Spawn();
SpawnRefresh(entitypart);
return entitypart;
}
void SpawnRefresh(BaseEntity entity)
{
var hasstab = entity.GetComponent<StabilityEntity>() ?? null;
if(hasstab != null)
{
hasstab.grounded = true;
}
var hasmount = entity.GetComponent<BaseMountable>() ?? null;
if(hasmount != null)
{
hasmount.isMobile = true;
}
}
public void SetFuel(int amount = 0)
{
BaseOven lanternCont = lantern1 as BaseOven;
ItemContainer container1 = lanternCont.inventory;
if(amount == 0)
{
while(container1.itemList.Count > 0)
{
var item = container1.itemList[0];
item.RemoveFromContainer();
item.Remove(0f);
}
}
else
{
Item addfuel = ItemManager.CreateByItemID(-946369541, amount);
container1.itemList.Add(addfuel);
addfuel.parent = container1;
addfuel.MarkDirty();
}
}
public void SpawnCarpet()
{
sitbox = SpawnPart(prefabbox, sitbox, false, 90, 0, 0, -0.01f, 0.5f, -0.1f, entity, skinid);
sitbox.SetFlag(BaseEntity.Flags.Locked, true);
carpet1 = SpawnPart(prefabcarpet, carpet1, false, 0, 0, 0, 0f, 0.3f, 0f, entity, skinid);
carpet1.SetFlag(BaseEntity.Flags.Busy, true, true);
carpet1.SetFlag(BaseEntity.Flags.Locked, true);
lantern1 = SpawnPart(prefablamp, lantern1, true, 0, 0, 0, 0f, 0.3f, 1f, entity, 1);
lantern1.SetFlag(BaseEntity.Flags.On, false);
carpetlock = SpawnPart(prefablock, carpetlock, true, 0, 90, 90, 0.5f, 0.3f, 0.7f, entity, 1);
sign = SpawnPart(prefabsign, sign, true, -45, 0, 0, 0, 0.25f, 1.75f, entity, 1);
if(needfuel)
{
// Empty tank
SetFuel(0);
}
else
{
// Cannot be looted
lantern1.SetFlag(BaseEntity.Flags.Locked, true);
// Add some fuel (1 lgf) so it lights up anyway.It should always stay at 1.SetFuel(1);
}
lights1 = SpawnPart(prefablights, lights1, true, 0, 90, 0, 0.8f, 0.31f, 0.1f, entity, 1);
lights1.SetFlag(BaseEntity.Flags.Busy, true);
lights2 = SpawnPart(prefablights, lights2, true, 0, 90, 0, -0.9f, 0.31f, 0.1f, entity, 1);
lights2.SetFlag(BaseEntity.Flags.Busy, true);
sitbox.SetFlag(BaseEntity.Flags.Busy, true);
}
private void OnTriggerEnter(Collider col)
{
var target = col.GetComponentInParent<BasePlayer>();
if(target != null)
{
carpetantihack.Add(target);
}
}
private void OnTriggerExit(Collider col)
{
var target = col.GetComponentInParent<BasePlayer>();
if(target != null)
{
carpetantihack.Remove(target);
}
}
BasePlayer GetPilot()
{
player = entity.GetComponent<BaseMountable>().GetMounted() as BasePlayer;
return player;
}
public void CarpetInput(InputState input, BasePlayer player)
{
if(input == null || player == null) return;
if(input.WasJustPressed(BUTTON.FORWARD)) moveforward = true;
if(input.WasJustReleased(BUTTON.FORWARD)) moveforward = false;
if(input.WasJustPressed(BUTTON.BACKWARD)) movebackward = true;
if(input.WasJustReleased(BUTTON.BACKWARD)) movebackward = false;
if(input.WasJustPressed(BUTTON.RIGHT)) rotright = true;
if(input.WasJustReleased(BUTTON.RIGHT)) rotright = false;
if(input.WasJustPressed(BUTTON.LEFT)) rotleft = true;
if(input.WasJustReleased(BUTTON.LEFT)) rotleft = false;
if(input.IsDown(BUTTON.SPRINT)) throttleup = true;
if(input.WasJustReleased(BUTTON.SPRINT)) throttleup = false;
if(input.WasJustPressed(BUTTON.JUMP)) moveup = true;
if(input.WasJustReleased(BUTTON.JUMP)) moveup = false;
if(input.WasJustPressed(BUTTON.DUCK)) movedown = true;
if(input.WasJustReleased(BUTTON.DUCK)) movedown = false;
}
public bool FuelCheck()
{
if(!needfuel)
{
return true;
}
BaseOven lantern = lantern1 as BaseOven;
Item slot = lantern.inventory.GetSlot(0);
if(slot == null)
{
islanding = true;
hasFuel = false;
return false;
}
else
{
hasFuel = true;
return true;
}
}
void FixedUpdate()
{
if(engineon)
{
if(!GetPilot()) islanding = true;
var currentspeed = normalspeed;
if(throttleup) { currentspeed = sprintspeed; }
// This is a little weird.Fortunately, some of the hooks determine fuel status...if(!hasFuel)
{
if(needfuel)
{
islanding = false;
engineon = false;
return;
}
}
if(islanding)
{
entity.transform.localPosition += (transform.up * -5f) * Time.deltaTime;
RaycastHit hit;
if(Physics.Raycast(new Ray(entity.transform.position, Vector3.down), out hit, 1f, layerMask))
{
islanding = false;
engineon = false;
if(pilotslist.Contains(player.userID))
{
pilotslist.Remove(player.userID);
}
}
ResetMovement();
ServerMgr.Instance.StartCoroutine(RefreshTrain());
return;
}
if(Physics.Raycast(new Ray(entity.transform.position, Vector3.down), minaltitude, layerMask))
{
entity.transform.localPosition += transform.up * minaltitude * Time.deltaTime;
ServerMgr.Instance.StartCoroutine(RefreshTrain());
return;
}
if(rotright) entity.transform.eulerAngles += new Vector3(0, 2, 0);
else if(rotleft) entity.transform.eulerAngles += new Vector3(0, -2, 0);
if(moveforward) entity.transform.localPosition += ((transform.forward * currentspeed) * Time.deltaTime);
else if(movebackward) entity.transform.localPosition = entity.transform.localPosition - ((transform.forward * currentspeed) * Time.deltaTime);
if(moveup) entity.transform.localPosition += ((transform.up * currentspeed) * Time.deltaTime);
else if(movedown) entity.transform.localPosition += ((transform.up * -currentspeed) * Time.deltaTime);
ServerMgr.Instance.StartCoroutine(RefreshTrain());
}
}
private IEnumerator RefreshTrain()
{
entity.transform.hasChanged = true;
for(int i = 0; i < entity.children.Count; i++)
{
entity.children[i].transform.hasChanged = true;
entity.children[i].SendNetworkUpdateImmediate();
entity.children[i].UpdateNetworkGroup();
}
entity.SendNetworkUpdateImmediate();
entity.UpdateNetworkGroup();
yield return new WaitForEndOfFrame();
}
void ResetMovement()
{
moveforward = false;
movebackward = false;
moveup = false;
movedown = false;
rotright = false;
rotleft = false;
throttleup = false;
}
public void OnDestroy()
{
if(loadplayer.ContainsKey(ownerid)) loadplayer[ownerid].carpetcount = loadplayer[ownerid].carpetcount - 1;
if(entity != null) { entity.Invoke("KillMessage", 0.1f); }
}
}
#endregion
}
}