C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
//Requires: ZoneManager
#region Using Statements
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using UnityEngine;
#endregion
namespace Oxide.Plugins {
[Info("Hotel", "Shady14u", "2.0.26")]
[Description("Complete Hotel System for Rust.")]
public class Hotel : RustPlugin {
#region PluginReferences
[PluginReference]
Plugin ZoneManager, Economics, ServerRewards, Backpacks;
#endregion
#region Fields
private Timer hotelGuiTimer;
private Timer hotelRoomCheckoutTimer;
private readonly Hash<BasePlayer, Timer> playerGuiTimers = new Hash<BasePlayer, Timer>();
private readonly Hash<BasePlayer, Timer> playerBlackListGuiTimers = new Hash<BasePlayer, Timer>();
private readonly Hash<ulong, HotelData> hotelGuests = new Hash<ulong, HotelData>();
private StoredData storedData;
static readonly int ConstructionColl = LayerMask.GetMask("Construction", "Construction Trigger");
static readonly int DeployableColl = LayerMask.GetMask("Deployed");
static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0);
public static Quaternion DefaultQuaternion = new Quaternion(0f, 0f, 0f, 0f);
private static Dictionary<string, HotelData> EditHotel = new Dictionary<string, HotelData>();
private static Dictionary<string, HotelMarker> HotelMarkers = new Dictionary<string, HotelMarker>();
private static readonly Vector3 Vector3Up = new Vector3(0f, 0.1f, 0f);
private static readonly Vector3 Vector3Up2 = new Vector3(0f, 1.5f, 0f);
#endregion
void Init() {
AddCovalenceCommand("hotelextend", "HotelExtend");
}
#region Config
private Configuration config;
public class Configuration {
[JsonProperty(PropertyName = "adminGuiJson")]
public string AdminGuiJson;
[JsonProperty(PropertyName = "authLevel")]
public int AuthLevel;
[JsonProperty(PropertyName = "enterZoneShowPlayerGUI")]
public bool EnterZoneShowPlayerGui;
[JsonProperty(PropertyName = "enterZoneShowRoom")]
public bool EnterZoneShowRoom;
[JsonProperty(PropertyName = "KickHobos")]
public bool KickHobos;
[JsonProperty(PropertyName = "mapMarker")]
public string MapMarker;
[JsonProperty(PropertyName = "mapMarkerColor")]
public string MapMarkerColor;
[JsonProperty(PropertyName = "mapMarkerColorBorder")]
public string MapMarkerColorBorder;
[JsonProperty(PropertyName = "mapMarkerRadius")]
public float MapMarkerRadius;
[JsonProperty(PropertyName = "openDoorPlayerGUI")]
public bool OpenDoorPlayerGui;
[JsonProperty(PropertyName = "openDoorShowRoom")]
public bool OpenDoorShowRoom;
[JsonProperty(PropertyName = "panelTimeOut")]
public int PanelTimeOut;
[JsonProperty(PropertyName = "panelXMax")]
public string PanelXMax;
[JsonProperty(PropertyName = "panelXMin")]
public string PanelXMin;
[JsonProperty(PropertyName = "panelYMax")]
public string PanelYMax;
[JsonProperty(PropertyName = "panelYMin")]
public string PanelYMin;
[JsonProperty(PropertyName = "playerGuiJson")]
public string PlayerGuiJson;
[JsonProperty(PropertyName = "useNPCShowPlayerGUI")]
public bool UseNpcShowPlayerGui;
[JsonProperty(PropertyName = "useNPCShowRoom")]
public bool UseNpcShowRoom;
[JsonProperty(PropertyName = "xMax")]
public string XMax;
[JsonProperty(PropertyName = "xMin")]
public string XMin;
[JsonProperty(PropertyName = "yMax")]
public string YMax;
[JsonProperty(PropertyName = "yMin")]
public string YMin;
[JsonProperty(PropertyName = "blackListGuiJson")]
public string BlackListGuiJson;
[JsonProperty(PropertyName = "blackList")]
public string[] BlackList;
[JsonProperty(PropertyName = "defaultZoneFlags")]
public string[] DefaultZoneFlags;
[JsonProperty(PropertyName = "showRoomCounterUi")]
public bool ShowRoomCounterUi {
get;
set;
}
= false;
[JsonProperty(PropertyName = "counterUiAnchorMin")]
public string CounterUiAnchorMin {
get;
set;
}
= "0.11 0.9";
[JsonProperty(PropertyName = "counterUiAnchorMax")]
public string CounterUiAnchorMax {
get;
set;
}
= "0.28 0.98";
[JsonProperty(PropertyName = "counterUiTextColor")]
public string CounterUiTextColor {
get;
set;
}
= "0 1 0 1";
[JsonProperty(PropertyName = "counterUiTextSize")]
public int CounterUiTextSize {
get;
set;
}
= 12;
[JsonProperty(PropertyName = "hideUiForNonRenters")]
public bool HideUiForNonRenters {
get;
set;
}
= true;
#region Methods (Public)
public static Configuration DefaultConfig() {
return new Configuration {
OpenDoorPlayerGui = true, OpenDoorShowRoom = false, UseNpcShowPlayerGui = true, UseNpcShowRoom = true, EnterZoneShowPlayerGui = false, EnterZoneShowRoom = true, KickHobos = true, ShowRoomCounterUi = true, XMin = "0.65", XMax = "1.0", YMin = "0.6", YMax = "0.9", PanelXMin = "0.3", PanelXMax = "0.6", PanelYMin = "0.6", PanelYMax = "0.95", PanelTimeOut = 10, AuthLevel = 2, AdminGuiJson = @"[{""name"": ""HotelAdmin"",""parent"": ""Overlay"",""components"":[{""type"":""UnityEngine.UI.Image"",""color"":""0.1 0.1 0.1 0.7"",},
{""type"":""RectTransform"",""anchormin"": ""{xmin} {ymin}"", ""anchormax"": ""{xmax} {ymax}""}]},{""parent"": ""HotelAdmin"",""components"":
[{""type"":""UnityEngine.UI.Text"", ""text"":""{msg}"",""fontSize"":15, ""align"": ""MiddleLeft""},{""type"":""RectTransform"",
""anchormin"": ""0.1 0.1"",""anchormax"": ""1 1"" }]}]", PlayerGuiJson = @"[{""name"": ""HotelPlayer"",""parent"": ""Overlay"",""components"":[{""type"":""UnityEngine.UI.Image"",""color"":""0.1 0.1 0.1 0.7"",},
{""type"":""RectTransform"",""anchormin"": ""{pxmin} {pymin}"",""anchormax"": ""{pxmax} {pymax}""}]},{""parent"": ""HotelPlayer"",""components"":
[{""type"":""UnityEngine.UI.Text"",""text"":""{msg}"",""fontSize"":15,""align"": ""MiddleLeft"",},{""type"":""RectTransform"",
""anchormin"": ""0.1 0.1"",""anchormax"": ""1 0.8""}]}]", BlackListGuiJson = @"[{""name"": ""HotelBlackList"",""parent"": ""Overlay"",""components"":[{""type"":""UnityEngine.UI.Image"",""color"":""0.1 0.1 0.1 0.7"",},
{""type"":""RectTransform"",""anchormin"": ""{pxmin} {pymin}"",""anchormax"": ""{pxmax} {pymax}""}]},{""parent"": ""HotelBlackList"",""components"":
[{""type"":""UnityEngine.UI.Text"",""text"":""{msg}"",""fontSize"":15,""align"": ""MiddleLeft"",},{""type"":""RectTransform"",
""anchormin"": ""0.1 0.1"",""anchormax"": ""1 1""}]}]", MapMarker = "\t\t\t{name} Hotel\r\n{fnum} of {rnum} Rooms Available\r\n{rp} {rc} per {durHours} hours", MapMarkerColor = "#710AC1", MapMarkerColorBorder = "#5FCEA8", MapMarkerRadius = 0.25f, BlackList = new[] {
"explosive.timed"
}
, DefaultZoneFlags = new[] {
"lootself", "nobuild", "nocup", "nodecay", "noentitypickup", "noplayerloot", "nostash", "notrade", "pvpgod", "sleepgod", "undestr"
}
}
;
}
#endregion
}
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
SaveConfig();
}
catch (Exception) {
PrintWarning("Creating new config file.");
LoadDefaultConfig();
}
if (config != null) {
config.AdminGuiJson = config.AdminGuiJson.Replace("{xmin}", config.XMin).Replace("{xmax}", config.XMax).Replace("{ymin}", config.YMin).Replace("{ymax}", config.YMax);
config.PlayerGuiJson = config.PlayerGuiJson.Replace("{pxmin}", config.PanelXMin).Replace("{pxmax}", config.PanelXMax).Replace("{pymin}", config.PanelYMin).Replace("{pymax}", config.PanelYMax);
config.BlackListGuiJson = config.BlackListGuiJson.Replace("{pxmin}", config.PanelXMin).Replace("{pxmax}", config.PanelXMax).Replace("{pymin}", config.PanelYMin).Replace("{pymax}", config.PanelYMax);
var blackListTemp = new List<string>();
if (config.BlackList == null) {
config.BlackList = blackListTemp.ToArray();
}
foreach (var item in config.BlackList) {
if (item.Contains("_")) {
blackListTemp.Add(item);
continue;
}
int itemId;
var itemDefinition = int.TryParse(item, out itemId) ? ItemManager.FindItemDefinition(itemId) : ItemManager.FindItemDefinition(item);
if (itemDefinition == null) continue;
blackListTemp.Add($"{itemDefinition.itemid}_{itemDefinition.displayName.translated}");
}
config.BlackList = blackListTemp.ToArray();
}
LoadData();
LoadPermissions();
}
protected override void LoadDefaultConfig() => config = Configuration.DefaultConfig();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Localization
private static class PluginMessages {
public const string MessageHotelDisableHelp = "MessageHotelDisableHelp";
public const string MessagePlayerIsRenter = "MessagePlayerIsRenter";
public const string MessagePlayerNotRenter = "MessagePlayerNotRenter";
public const string MessageHotelEnableHelp = "MessageHotelEnableHelp";
public const string MessageErrorPlayerNotFound = "MessageErrorPlayerNotFound";
public const string MessageAlreadyEditing = "MessageAlreadyEditing";
public const string MessageNoHotelHelp = "MessageNoHotelHelp";
public const string MessageHotelNewHelp = "MessageHotelNewHelp";
public const string MessageHotelEditHelp = "MessageHotelEditHelp";
public const string MessageHotelEditEditing = "MessageHotelEditEditing";
public const string MessageErrorAlreadyExist = "MessageErrorAlreadyExist";
public const string MessageErrorNotAllowed = "MessageErrorNotAllowed";
public const string MessageErrorEditDoesNotExist = "MessageErrorEditDoesNotExist";
public const string MessageMaintenance = "MessageMaintenance";
public const string MessageErrorUnavailableRoom = "MessageErrorUnavailableRoom";
public const string MessageHotelNewCreated = "MessageHotelNewCreated";
public const string MessageErrorNotAllowedToEnter = "MessageErrorNotAllowedToEnter";
public const string MessageHotelExtendHelp = "MessageHotelExtendHelp";
public const string MessageErrorAlreadyGotRoom = "MessageErrorAlreadyGotRoom";
public const string MessageErrorPermissionsNeeded = "MessageErrorPermissionsNeeded";
public const string MessageCouldNotFindToExtend = "MessageCouldNotFindToExtend";
public const string MessageRentUnlimited = "MessageRentUnlimited";
public const string MessageRentTimeLeft = "MessageRentTimeLeft";
public const string MessagePayedRent = "MessagePayedRent";
public const string MessageErrorNotEnoughCoins = "MessageErrorNotEnoughCoins";
public const string MessageErrorNotEnoughRp = "MessageErrorNotEnoughRP";
public const string MessageErrorNotEnoughItems = "MessageErrorNotEnoughItems";
public const string GuiBoardAdmin = "GUIBoardAdmin";
public const string GuiBoardBlackList = "GuiBoardBlackList";
public const string GuiBoardPlayer = "GUIBoardPlayer";
public const string GuiBoardPlayerRoom = "GUIBoardPlayerRoom";
public const string GuiBoardPlayerMaintenance = "GUIBoardPlayerMaintenance";
public const string MessageMustLookAtDoor = "MessageMustLookAtDoor";
public const string Menu1 = "Menu1";
public const string Menu2 = "Menu2";
public const string Menu3 = "Menu3";
public const string Menu4 = "Menu4";
public const string Menu5 = "Menu5";
public const string Menu6 = "Menu6";
public const string Menu7 = "Menu7";
public const string Menu8 = "Menu8";
public const string Menu9 = "Menu9";
public const string Menu10 = "Menu10";
public const string Menu11 = "Menu11";
public const string Menu12 = "Menu12";
public const string Menu13 = "Menu13";
public const string ExtendButtonText = "ExtendButtonText";
}
private string GetMsg(string key, object userId = null) {
return lang.GetMessage(key, this, userId?.ToString());
}
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
[PluginMessages.MessageHotelDisableHelp]
= "You must enter the name/id of the person you want to disable renting hotels: <color=green>/hotel_disable \"Player Name/Id\"</color>", [PluginMessages.MessagePlayerNotRenter] = "Player <color=green>{playerName}</color> revoked from the <color=green>hotel.renter</color> permission.", [PluginMessages.MessagePlayerIsRenter] = "Player <color=green>{playerName}</color> granted the <color=green>hotel.renter</color> permission.", [PluginMessages.MessageHotelEnableHelp] = "You must enter the name/id of the person you want to enable renting hotels: <color=green>/hotel_enable \"Player Name/Id\"</color>", [PluginMessages.MessageErrorPlayerNotFound] = "Player was not found.", [PluginMessages.MessageAlreadyEditing] = "You are already editing a hotel.You must close or save it first.", [PluginMessages.MessageNoHotelHelp] = "You are not editing a hotel.Create a new one with <color=green>/hotel_new</color>, or edit an existing one with <color=green>/hotel_edit</color>", [PluginMessages.MessageHotelNewHelp] = "You must select a name for the new hotel: <color=green>/hotel_new \"Hotel Name\"</color>", [PluginMessages.MessageHotelEditHelp] = "You must select the name of the hotel you want to edit: <color=green>/hotel_edit \"Hotel Name\"</color>", [PluginMessages.MessageHotelEditEditing] = "You are editing the hotel named: <color=purple>{0}</color>.Now say <color=green>/hotel</color> to continue configuring your hotel.Note that no one can register/leave the hotel while you are editing it.", [PluginMessages.MessageErrorAlreadyExist] = "{0} is already the name of a hotel", [PluginMessages.MessageErrorNotAllowed] = "You are not allowed to use this command", [PluginMessages.MessageErrorEditDoesNotExist] = "The hotel \"<color=purple>{0}</color>\" doesn't exist", [PluginMessages.MessageMaintenance] = "This Hotel is under maintenance by the admin, you may not open this door at the moment", [PluginMessages.MessageErrorUnavailableRoom] = "This room is unavailable, seems like it wasn't set correctly", [PluginMessages.MessageHotelNewCreated] = "You've created a new Hotel named: <color=purple>{0}</color>.Now say <color=green>/hotel</color> to continue configuring your hotel.", [PluginMessages.MessageErrorNotAllowedToEnter] = "You are not allowed to enter this room, it's already being used my someone else", [PluginMessages.MessageCouldNotFindToExtend] = "Could not find your room to extend, in the {0} hotel", [PluginMessages.MessageHotelExtendHelp] = "You must enter the name of the hotel you want to extend your stay at: <color=green>/hotel_extend \"Hotel Name\"</color>", [PluginMessages.MessageErrorAlreadyGotRoom] = "You already have a room in this hotel!", [PluginMessages.MessageErrorPermissionsNeeded] = "You must have the <color=purple>{0}</color> permission to rent a room here", [PluginMessages.MessageRentUnlimited] = "You now have access to this room for an unlimited time", [PluginMessages.MessageRentTimeLeft] = "You now have access to this room.You are allowed to keep this room for <color=purple>{0}</color>", [PluginMessages.MessagePayedRent] = "You payed for this room <color=purple>{0}</color> coins", [PluginMessages.MessageErrorNotEnoughCoins] = "This room costs <color=purple>{0}</color> coins.You only have <color=purple>{1}</color> coins", [PluginMessages.MessageErrorNotEnoughRp] = "This room costs <color=purple>{0}</color> RP.You only have<color=purple>{1}</color> Reward Points", [PluginMessages.MessageErrorNotEnoughItems] = "Not enough <color=purple>{0}</color>(s) for this room, you need <color=purple>{1}</color> more.", [PluginMessages.MessageMustLookAtDoor] = "You must look at the door of the room or put the roomId", [PluginMessages.GuiBoardAdmin] = "\t\t\t\t\t<color=green>HOTEL MANAGER</color>\n\n<color=cyan>Hotel Name:\t\t{name}</color>\n<color=grey>Hotel Location:</color>\t{loc}\n<color=orange>Hotel Radius:\t\t{hrad}</color>\t<color=yellow>Rooms Radius:\t{rrad}</color>\n<color=blue>Rooms:\t{rnum}</color>\t\t<color=red>Occupied:\t{onum}</color>\t\t<color=green>Vacant:\t{fnum}</color>\n<color=cyan>Rent Price:\t{rp}\t</color><color=purple>{rc}</color>\n<color=grey>Duration:\t{rd} Seconds</color>\n<color=orange>Kick Hobos:\t{kh}</color>\t\t<color=yellow>NPC Id:\t{npcId}</color>\n<color=blue>Show Marker:\t{sm}</color>\n<color=red>Permission:\t{p}</color>", [PluginMessages.GuiBoardBlackList] = "<color=blue>You cannot enter {name} Hotel with any of the following items:</color>\r\n<size=10>{blacklist}</size>", [PluginMessages.GuiBoardPlayer] = "\t\t\t\t\t\t\t\t\t\t<color=yellow><size=16>{name}</size></color>\n\t\t\t\t\t<color=yellow><size=12>Location: ({loc})</size></color>\n\t\t<color=blue>Rooms:\t\t{rnum}</color>\t\t<color=green>Price:\t{price} {currency} per {durHours} hours </color>\n\t\t<color=red>Occupied:\t{onum}</color>\n\t\t<color=green>Vacant:\t\t{fnum}</color>", [PluginMessages.GuiBoardPlayerRoom] = "\n\t\t\t\t\t\t\t\t<color=yellow><size=14>Your Room</size></color>\n\t\t\t\t\t<color=blue><size=12>Id:\t\t\t\t{rid}</size></color>\n\t\t\t\t\t<color=orange><size=12>Joined:\t\t\t{jdate}</size></color>\n\t\t\t\t\t<color=cyan><size=12>Time Left:\t\t{timeleft}</size></color>", [PluginMessages.GuiBoardPlayerMaintenance] = "\t\t\t\t\t\t\t\t\t\t<color=green>{name}</color>\n\nHotel is under maintenance.Please wait couple seconds/minutes until the admin is finished.", [PluginMessages.Menu1] = "<color=purple>==== Available options ====</color>", [PluginMessages.Menu2] = "<color=green>/hotel location</color> => sets the center hotel location where you stand", [PluginMessages.Menu3] = "<color=green>/hotel npc NpcId </color> => sets the NPC that is hooked to this hotel (for UseNPC items)", [PluginMessages.Menu4] = "<color=green>/hotel permission \"Permission Name\"</color> => sets the oxide permissions that the player needs to rent a room here", [PluginMessages.Menu5] = "<color=green>/hotel radius XX</color> => sets the radius of the hotel (the entire structure of the hotel needs to be covered by the zone)", [PluginMessages.Menu6] = "<color=green>/hotel rentduration XX</color> => Sets the duration of a default rent in this hotel.0 is infinite.", [PluginMessages.Menu7] = "<color=green>/hotel rentcurrency XX</color> => (<color=orange>0</color> - Economics, <color=orange>1</color> - Server Rewards, \"<color=orange>short name</color>\" of item ie.scrap).", [PluginMessages.Menu8] = "<color=green>/hotel rentprice XX</color> => Sets the rental price of a room.", [PluginMessages.Menu9] = "<color=green>/hotel kickhobos [true/false]</color> => Toggles kicking sleepers without rooms.", [PluginMessages.Menu10] = "<color=green>/hotel showmarker [true/false]</color> => Toggles showing of map marker.", [PluginMessages.Menu11] = "<color=green>/hotel reset</color> => resets the hotel data (all players and rooms, but keeps the hotel)", [PluginMessages.Menu12] = "<color=green>/hotel roomradius XX</color> => sets the radius of the rooms", [PluginMessages.Menu13] = "<color=green>/hotel rooms</color> => refreshes the rooms (detects new rooms, deletes rooms if they don't exist anymore, if rooms are in use they won't get taken in count)", [PluginMessages.ExtendButtonText] = "Extend Your Stay"
}
, this);
}
#endregion
#region OxideHooks
object CanPickupLock(BasePlayer player, BaseLock baseLock) {
var codeLock = baseLock as CodeLock;
var parentEntity = codeLock?.GetParentEntity();
if (parentEntity == null || !parentEntity.name.Contains("door")) return null;
if (hotelGuests.Any(x => x.Key == player.userID)) {
return false;
}
return null;
}
object CanUseLockedEntity(BasePlayer player, BaseLock baseLock) {
var codeLock = baseLock as CodeLock;
var parentEntity = codeLock?.GetParentEntity();
if (parentEntity == null || !parentEntity.name.Contains("door")) return null;
var playersZones = ZoneManager.Call<string[]>("GetPlayerZoneIDs", player);
if (!storedData.Hotels.Any(hotel => playersZones.Contains(hotel.hotelName))) {
return null;
}
var targetHotel = storedData.Hotels.FirstOrDefault(hotel => playersZones.Contains(hotel.hotelName));
if (targetHotel == null) return null;
if (config.OpenDoorPlayerGui) RefreshPlayerHotelGui(player, targetHotel);
if (config.OpenDoorShowRoom) ShowPlayerRoom(player, targetHotel);
if (!targetHotel.enabled) {
SendReply(player, GetMsg(PluginMessages.MessageMaintenance, player.userID));
return false;
}
var room = FindRoomByDoorAndHotel(targetHotel, parentEntity);
if (room == null) {
SendReply(player, GetMsg(PluginMessages.MessageErrorUnavailableRoom, player.userID));
return false;
}
if (room.renter == null) {
if (!CanRentRoom(player, targetHotel)) return false;
NewRoomOwner(codeLock, player, targetHotel, room);
if (targetHotel.currency == "0" && Economics) {
EconomicsWithdraw(player, targetHotel.Price());
}
if (targetHotel.currency == "1" && ServerRewards) {
ServerRewardsWithdraw(player, targetHotel.Price());
}
if (targetHotel.currency != "0" && targetHotel.currency != "1") {
var collect = Pool.GetList<Item>();
var itemDefinition = ItemManager.FindItemDefinition(targetHotel.currency);
if (itemDefinition != null) {
player.inventory.Take(collect, itemDefinition.itemid, int.Parse(targetHotel.e));
player.Command("note.inv", itemDefinition.itemid, -1 * int.Parse(targetHotel.e));
}
}
CreateMapMarker(targetHotel);
}
LockLock(codeLock);
if (room.renter != player.UserIDString) {
SendReply(player, GetMsg(PluginMessages.MessageErrorNotAllowedToEnter, player.userID));
return false;
}
SaveData();
return true;
}
private void LoadData() {
try {
storedData = Interface.GetMod().DataFileSystem.ReadObject<StoredData>("Hotel");
}
catch (Exception e) {
Puts(e.Message);
Puts(e.StackTrace);
storedData = new StoredData();
}
}
void OnServerSave() {
SaveData();
}
void OnEnterZone(string zoneId, BasePlayer player) {
foreach (var hotel in storedData.Hotels.Where(hotel => hotel.hotelName != null).Where(hotel => hotel.hotelName == zoneId)) {
//Log in our guest
hotelGuests.Add(player.userID, hotel);
//TODO: Let each Hotel blacklist items?
//var blackList = hotel.BlackList;
if (HasBlackListedItems(player, config.BlackList.ToList())) {
var zone = ZoneManager.Call<ZoneManager.Zone>("GetZoneByID", hotel.hotelName);
ZoneManager.Call("EjectPlayer", player, zone);
RefreshBlackListGui(player, hotel, config.BlackList.ToList());
return;
}
if (config.EnterZoneShowPlayerGui) RefreshPlayerHotelGui(player, hotel);
if (config.EnterZoneShowRoom) ShowPlayerRoom(player, hotel);
}
}
void OnExitZone(string ZoneID, BasePlayer player) // Called when a player leaves a zone
{
hotelGuests.Remove(player.userID);
}
object OnItemPickup(Item item, BasePlayer player) {
HotelData hotel;
if (!hotelGuests.TryGetValue(player.userID, out hotel)) return null;
if (config.BlackList.Any(x => x.Split('_')[0] == item.info.itemid.ToString() || x.Split('_')[1] == item.info.displayName.translated) || HasBlackListedItems(player, config.BlackList.ToList())) {
var zone = ZoneManager.Call<ZoneManager.Zone>("GetZoneByID", hotel.hotelName);
ZoneManager.Call("EjectPlayer", player, zone);
RefreshBlackListGui(player, hotel, config.BlackList.ToList());
}
return null;
}
void OnPlayerLootEnd(PlayerLoot inventory) {
HotelData hotel;
if (!hotelGuests.TryGetValue(inventory.baseEntity.userID, out hotel)) return;
if (HasBlackListedItems(inventory.baseEntity, config.BlackList.ToList())) {
var zone = ZoneManager.Call<ZoneManager.Zone>("GetZoneByID", hotel.hotelName);
ZoneManager.Call("EjectPlayer", inventory.baseEntity, zone);
RefreshBlackListGui(inventory.baseEntity, hotel, config.BlackList.ToList());
}
}
void OnPlayerDisconnected(BasePlayer player) {
if (player == null) return;
foreach (var hotel in from hotel in storedData.Hotels where hotel.kickHobos let isInZone = ZoneManager.Call<bool>("IsPlayerInZone", hotel.hotelName, player) where isInZone select hotel) {
if (hotel.rooms.Any(hotelRoom => hotelRoom.Value.renter == player.userID.ToString())) {
return;
}
//Player is in a hotel and they don't have a room..Kick them.var zone = ZoneManager.Call<ZoneManager.Zone>("GetZoneByID", hotel.hotelName);
ZoneManager.Call("EjectPlayer", player, zone);
return;
}
}
void OnServerInitialized(bool initial) {
CheckTimeOutRooms();
if (config.ShowRoomCounterUi) {
hotelGuiTimer = timer.Repeat(5f, 0, UpdateHotelCounter);
}
hotelRoomCheckoutTimer = timer.Repeat(60f, 0, CheckTimeOutRooms);
}
void OnUseNPC(BasePlayer npc, BasePlayer player) {
var npcId = npc.UserIDString;
foreach (var hotel in storedData.Hotels.Where(hotel => hotel.npc != null && hotel.npc == npcId)) {
if (config.UseNpcShowPlayerGui) RefreshPlayerHotelGui(player, hotel);
if (config.UseNpcShowRoom) ShowPlayerRoom(player, hotel);
}
}
#endregion
#region Helper Methods
private bool CanRentRoom(BasePlayer player, HotelData hotel, bool isExtending = false) {
var playerHasRoom = false;
if (hotel.rooms.Values.Any(room => room.renter == player.UserIDString)) {
if (!isExtending) {
SendReply(player, GetMsg(PluginMessages.MessageErrorAlreadyGotRoom, player.UserIDString));
return false;
}
playerHasRoom = true;
}
if (isExtending && !playerHasRoom) {
SendReply(player, PluginMessages.MessageCouldNotFindToExtend.Replace("{0}", hotel.hotelName));
return false;
}
if (hotel.p != null) {
if (!permission.UserHasPermission(player.UserIDString, $"hotel.{hotel.p.ToLower()}")) {
SendReply(player, GetMsg(PluginMessages.MessageErrorPermissionsNeeded, player.UserIDString).Replace("{0}", hotel.p));
return false;
}
}
if (hotel.currency == "0" && Economics == null) return false;
if (hotel.currency == "0") {
var money = Convert.ToInt32((double)Economics.Call("Balance", player.UserIDString));
if (money >= hotel.Price()) return true;
SendReply(player, GetMsg(PluginMessages.MessageErrorNotEnoughCoins, player.UserIDString).Replace("{0}", hotel.e).Replace("{1}", money.ToString()));
return false;
}
if (hotel.currency == "1" && ServerRewards == null) return false;
if (hotel.currency == "1") {
var money = Convert.ToInt32(ServerRewards?.Call("CheckPoints", player.UserIDString));
if (money >= hotel.Price()) return true;
SendReply(player, GetMsg(PluginMessages.MessageErrorNotEnoughRp, player.UserIDString).Replace("{0}", hotel.e).Replace("{1}", money.ToString()));
return false;
}
var missingAmount = 0;
var itemName = hotel.currency;
var itemDefinition = ItemManager.FindItemDefinition(hotel.currency);
if (itemDefinition != null) {
missingAmount = int.Parse(hotel.e) - player.inventory.GetAmount(itemDefinition.itemid);
itemName = itemDefinition.displayName.translated;
}
if (missingAmount <= 0) return true;
SendReply(player, GetMsg(PluginMessages.MessageErrorNotEnoughItems, player.UserIDString).Replace("{0}", itemName).Replace("{1}", missingAmount.ToString()));
return false;
}
void CheckTimeOutRooms() {
var currentTime = LogTime();
foreach (var hotel in storedData.Hotels.Where(hotel => hotel.enabled)) {
foreach (var room in hotel.rooms.Values.Where(x => (x.CheckOutTime() != 0.0 && x.CheckOutTime() < currentTime))) {
ResetRoom(room);
}
foreach (var room in hotel.rooms.Values.Where(x => string.IsNullOrEmpty(x.renter))) {
var codeLock = FindCodeLockByPos(room.Pos());
if (codeLock != null) {
UnlockLock(codeLock);
}
}
CreateMapMarker(hotel);
}
}
private void CleanUpMarkers() {
foreach (var hotelMarker in HotelMarkers) {
hotelMarker.Value.VendingMachineMapMarker?.Kill();
hotelMarker.Value.GenericMapMarker?.Kill();
}
}
private static void CloseDoor(Door door) {
door.SetFlag(BaseEntity.Flags.Open, false);
door.SendNetworkUpdateImmediate(true);
}
private void EconomicsWithdraw(BasePlayer player, int amount) {
Economics?.Call("Withdraw", player.UserIDString, (double)amount);
SendReply(player, $"You payed for this room {amount} coins");
}
private static void EmptyDeployablesRoom(BaseEntity door, float radius) {
var foundItems = new List<BaseEntity>();
var doorPos = door.transform.position;
foreach (var col in Physics.OverlapSphere(doorPos, radius, DeployableColl)) {
var deploy = col.GetComponentInParent<BaseEntity>();
if (deploy == null) continue;
if (foundItems.Contains(deploy)) continue;
var canReach = Physics.RaycastAll(deploy.transform.position + Vector3Up, (doorPos + Vector3Up - deploy.transform.position).normalized, Vector3.Distance(deploy.transform.position, doorPos) - 0.2f, ConstructionColl).All(rayHit => rayHit.collider.GetComponentInParent<Door>() != null && rayHit.collider.GetComponentInParent<Door>() == door);
if (!canReach) continue;
foreach (var col2 in Physics.OverlapSphere(doorPos, radius, ConstructionColl)) {
BaseEntity door2 = col2.GetComponentInParent<Door>();
if (door2 == null) continue;
if (door2.transform.position == doorPos) continue;
var canReach2 = !Physics.RaycastAll(deploy.transform.position + Vector3Up, (door2.transform.position + Vector3Up - deploy.transform.position).normalized, Vector3.Distance(deploy.transform.position, door2.transform.position) - 0.2f, ConstructionColl).Any();
if (!canReach2) continue;
canReach = false;
break;
}
if (!canReach) continue;
foundItems.Add(deploy);
}
foreach (var deploy in foundItems.Where(deploy => deploy != null && !deploy.IsDestroyed)) {
deploy.KillMessage();
}
}
private static Dictionary<string, Room> FindAllRooms(Vector3 position, float radius, float roomradius) {
var listLocks = FindDoorsFromPosition(position, radius);
var deployables = new Hash<BaseEntity, string>();
var tempRooms = new Dictionary<string, Room>();
foreach (var door in listLocks) {
var pos = door.transform.position;
var newRoom = new Room(pos) {
defaultDeployables = new List<DeployableItem>()
}
;
var foundItems = new List<BaseEntity>();
foreach (var col in Physics.OverlapSphere(pos, roomradius, DeployableColl)) {
var deploy = col.GetComponentInParent<BaseEntity>();
if (deploy == null) continue;
if (foundItems.Contains(deploy)) continue;
foundItems.Add(deploy);
var canReach = Physics.RaycastAll(deploy.transform.position + Vector3Up, (pos + Vector3Up - deploy.transform.position).normalized, Vector3.Distance(deploy.transform.position, pos) - 0.2f, ConstructionColl).All(rayHit => rayHit.collider.GetComponentInParent<Door>() != null && rayHit.collider.GetComponentInParent<Door>() == door);
if (!canReach) continue;
if (deployables[deploy] != null) deployables[deploy] = "0";
else deployables[deploy] = newRoom.roomId;
}
tempRooms.Add(newRoom.roomId, newRoom);
}
foreach (var pair in deployables) {
if (pair.Value == "0") continue;
var newDeployItem = new DeployableItem(pair.Key);
tempRooms[pair.Value].defaultDeployables.Add(newDeployItem);
}
return tempRooms;
}
private static BuildingBlock FindBlockFromRay(Vector3 pos, Vector3 aim) {
var hits = Physics.RaycastAll(pos, aim);
var distance = 100000f;
BuildingBlock target = null;
foreach (var hit in hits) {
if (hit.collider.GetComponentInParent<BuildingBlock>() == null || !(hit.distance < distance)) continue;
distance = hit.distance;
target = hit.collider.GetComponentInParent<BuildingBlock>();
}
return target;
}
private static CodeLock FindCodeLockByPos(Vector3 pos) {
CodeLock findCode = null;
foreach (var col in Physics.OverlapSphere(pos, 2f, ConstructionColl)) {
if (col.GetComponentInParent<Door>() == null) continue;
if (!col.GetComponentInParent<Door>().HasSlot(BaseEntity.Slot.Lock)) continue;
var slotEntity = col.GetComponentInParent<Door>().GetSlot(BaseEntity.Slot.Lock);
if (slotEntity == null) continue;
if (slotEntity.GetComponent<CodeLock>() == null) continue;
if (findCode != null) if (Vector3.Distance(pos, findCode.GetParentEntity().transform.position) < Vector3.Distance(pos, col.transform.position)) continue;
findCode = slotEntity.GetComponent<CodeLock>();
}
return findCode;
}
private static CodeLock FindCodeLockByRoomId(string roomId) {
var roomPos = roomId.Split(':');
return roomPos.Length != 3 ? null : FindCodeLockByPos(new Vector3(Convert.ToSingle(roomPos[0]), Convert.ToSingle(roomPos[1]), Convert.ToSingle(roomPos[2])));
}
private static List<Door> FindDoorsFromPosition(Vector3 position, float radius) {
var listLocks = new List<Door>();
foreach (var col in Physics.OverlapSphere(position, radius, ConstructionColl)) {
var door = col.GetComponentInParent<Door>();
if (door == null) continue;
if (!door.HasSlot(BaseEntity.Slot.Lock)) continue;
if (door.GetSlot(BaseEntity.Slot.Lock) == null) continue;
if (!(door.GetSlot(BaseEntity.Slot.Lock) is CodeLock)) continue;
if (listLocks.Contains(door)) continue;
CloseDoor(door);
listLocks.Add(door);
}
return listLocks;
}
private bool FindHotelAndRoomByPos(Vector3 position, out HotelData hotelData, out Room roomData) {
hotelData = null;
roomData = null;
position.x = Mathf.Ceil(position.x);
position.y = Mathf.Ceil(position.y);
position.z = Mathf.Ceil(position.z);
foreach (var hotel in storedData.Hotels) {
foreach (var room in hotel.rooms.Values.Where(room => room.Pos() == position)) {
hotelData = hotel;
roomData = room;
return true;
}
}
return false;
}
private IPlayer FindPlayer(string nameOrIdOrIp) {
foreach (var activePlayer in covalence.Players.All) {
if (activePlayer.Id == nameOrIdOrIp) return activePlayer;
if (activePlayer.Name.Contains(nameOrIdOrIp)) return activePlayer;
if (activePlayer.Name.ToLower().Contains(nameOrIdOrIp.ToLower())) return activePlayer;
if (activePlayer.Address == nameOrIdOrIp) return activePlayer;
}
return null;
}
private bool FindRoomById(string roomId, out HotelData targetHotel, out Room targetRoom) {
targetHotel = null;
targetRoom = null;
foreach (var hotel in storedData.Hotels.Where(hotel => hotel.rooms.ContainsKey(roomId))) {
targetHotel = hotel;
targetRoom = (hotel.rooms)[roomId];
return true;
}
return false;
}
private static Room FindRoomByDoorAndHotel(HotelData hotel, BaseEntity door) {
var roomId = $"{Math.Ceiling(door.transform.position.x)}:{Math.Ceiling(door.transform.position.y)}:{Math.Ceiling(door.transform.position.z)}";
return !hotel.rooms.ContainsKey(roomId) ? null : hotel.rooms[roomId];
}
private RoomTimeMessage GetRoomTimeLeft(HotelData hotel, string userIdString) {
var roomTimeMessage = new RoomTimeMessage {
TimeMessage = "No Room Rented.", TimeRemaining = double.MaxValue
}
;
foreach (var secondsLeft in from room in hotel.rooms.Values where room.renter == userIdString select room.CheckOutTime() - LogTime()) {
roomTimeMessage.TimeRemaining = secondsLeft;
if (secondsLeft > 0) {
roomTimeMessage.TimeMessage = ConvertSecondsToBetter(secondsLeft) + " (" + hotel.hotelName + " Expires)";
}
else {
roomTimeMessage.TimeMessage = "Your " + hotel.hotelName + " room expired";
}
}
return roomTimeMessage;
}
private bool HasBlackListedItems(BasePlayer player, List<string> blackList) {
ItemContainer backpack = null;
if (Backpacks && Backpacks.IsLoaded) {
backpack = Backpacks.Call<ItemContainer>("API_GetBackpackContainer", player.userID);
}
foreach (var item in blackList) {
if (player.inventory.GetAmount(int.Parse(item.Split('_')[0])) > 0) {
return true;
}
;
if (backpack != null && backpack.GetAmount(int.Parse(item.Split('_')[0]), false) > 0) {
return true;
}
}
return false;
}
private bool HasAccess(BasePlayer player, string accessRole = "admin") {
if (player == null) return false;
return player.net.connection.authLevel >= config.AuthLevel || permission.UserHasPermission(player.UserIDString, $"hotel.{accessRole}");
}
private void LoadPermissions() {
permission.RegisterPermission("hotel.admin", this);
permission.RegisterPermission("hotel.extend", this);
permission.RegisterPermission("hotel.renter", this);
foreach (var hotel in storedData.Hotels.Where(hotel => hotel.p != null && hotel.p.ToLower() != "renter")) {
permission.RegisterPermission("hotel." + hotel.p, this);
}
}
private static void LockLock(CodeLock codeLock) {
codeLock.SetFlag(BaseEntity.Flags.Locked, true);
codeLock.SendNetworkUpdate();
}
static double LogTime() {
return DateTime.UtcNow.Subtract(Epoch).TotalSeconds;
}
private void NewRoomOwner(CodeLock codeLock, BasePlayer player, HotelData hotel, Room room) {
var door = codeLock.GetParentEntity();
//Reset only if new renter
if (string.IsNullOrEmpty(room.lastRenter) || room.lastRenter != player.UserIDString) {
EmptyDeployablesRoom(door, Convert.ToSingle(hotel.rr));
foreach (var deploy in room.defaultDeployables) {
SpawnDeployable(deploy.prefabName, deploy.Pos(), deploy.Rot(), player, deploy.skinId);
}
if (!string.IsNullOrEmpty(room.lastRenter)) {
var oldTenant = BasePlayer.FindByID(ulong.Parse(room.lastRenter));
if (oldTenant != null) {
//Kick the old tenant out?
var isInZone = ZoneManager.Call<bool>("IsPlayerInZone", hotel.hotelName, oldTenant);
if (isInZone) {
//Player is in a hotel and they don't have a room..Kick them.var zone = ZoneManager.Call<ZoneManager.Zone>("GetZoneByID", hotel.hotelName);
ZoneManager.Call("EjectPlayer", oldTenant, zone);
}
}
}
}
var whitelist = new List<ulong> {
player.userID
}
;
codeLock.whitelistPlayers = whitelist;
room.renter = player.UserIDString;
room.lastRenter = player.UserIDString;
room.checkingTime = LogTime().ToString(CultureInfo.InvariantCulture);
room.checkoutTime = hotel.rd == "0" ? "0" : (LogTime() + double.Parse(hotel.rd)).ToString(CultureInfo.InvariantCulture);
room.Reset();
LockLock(codeLock);
OpenDoor(door as Door);
var message = hotel.rd == "0" ? GetMsg(PluginMessages.MessageRentUnlimited, player.userID) : GetMsg(PluginMessages.MessageRentTimeLeft, player.userID).Replace("{0}", ConvertSecondsToBetter(hotel.rd));
SendReply(player, message);
}
private static void OpenDoor(Door door) {
door.SetFlag(BaseEntity.Flags.Open, true);
door.SendNetworkUpdateImmediate(true);
}
static object RaycastAll<T>(Ray ray) where T : BaseEntity {
var hits = Physics.RaycastAll(ray);
GamePhysics.Sort(hits);
var distance = 100f;
object target = null;
foreach (var hit in hits) {
var ent = hit.GetEntity();
if (!(ent is T) || !(hit.distance < distance)) continue;
target = ent;
break;
}
return target;
}
private Vector3 RayForDoor(BasePlayer player) {
var target = RaycastAll<BaseEntity>(player.eyes.HeadRay());
if (target == null) return default(Vector3);
return ((BaseEntity)target).transform.position;
}
private void ResetRoom(Room room) {
var codeLock = FindCodeLockByPos(room.Pos());
if (codeLock == null) return;
ResetRoom(codeLock, room);
}
private static void ResetRoom(CodeLock codeLock, Room room) {
var door = codeLock.GetParentEntity();
codeLock.whitelistPlayers = new List<ulong>();
UnlockLock(codeLock);
CloseDoor(door as Door);
room.lastRenter = room.renter;
room.renter = null;
room.checkingTime = null;
room.checkoutTime = null;
room.Reset();
}
private void SaveData() {
Interface.GetMod().DataFileSystem.WriteObject("Hotel", storedData);
}
private void ServerRewardsWithdra
// ... [Code preview truncated due to length. Full source in attached file] ...