diff --git a/Libraries/0Harmony.dll b/Libraries/0Harmony.dll new file mode 100644 index 0000000..a95b6df Binary files /dev/null and b/Libraries/0Harmony.dll differ diff --git a/Libraries/Assembly-CSharp-firstpass.dll b/Libraries/Assembly-CSharp-firstpass.dll new file mode 100644 index 0000000..3924583 Binary files /dev/null and b/Libraries/Assembly-CSharp-firstpass.dll differ diff --git a/Libraries/Assembly-CSharp.dll b/Libraries/Assembly-CSharp.dll new file mode 100644 index 0000000..3cd65c6 Binary files /dev/null and b/Libraries/Assembly-CSharp.dll differ diff --git a/Libraries/Rocket.API.dll b/Libraries/Rocket.API.dll new file mode 100644 index 0000000..e273f32 Binary files /dev/null and b/Libraries/Rocket.API.dll differ diff --git a/Libraries/Rocket.Core.dll b/Libraries/Rocket.Core.dll new file mode 100644 index 0000000..c008dc6 Binary files /dev/null and b/Libraries/Rocket.Core.dll differ diff --git a/Libraries/Rocket.Unturned.dll b/Libraries/Rocket.Unturned.dll new file mode 100644 index 0000000..9c74167 Binary files /dev/null and b/Libraries/Rocket.Unturned.dll differ diff --git a/Libraries/Uconomy.dll b/Libraries/Uconomy.dll new file mode 100644 index 0000000..fc9ba5a Binary files /dev/null and b/Libraries/Uconomy.dll differ diff --git a/Libraries/UnityEngine.dll b/Libraries/UnityEngine.dll new file mode 100644 index 0000000..d062eaf Binary files /dev/null and b/Libraries/UnityEngine.dll differ diff --git a/RealEstate.sln b/RealEstate.sln new file mode 100644 index 0000000..dfd03dc --- /dev/null +++ b/RealEstate.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RealEstate", "RealEstate\RealEstate.csproj", "{EF549899-855F-4A80-86AB-4E5E3BD0933E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EF549899-855F-4A80-86AB-4E5E3BD0933E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF549899-855F-4A80-86AB-4E5E3BD0933E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF549899-855F-4A80-86AB-4E5E3BD0933E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF549899-855F-4A80-86AB-4E5E3BD0933E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F840385C-38B7-47B1-9E75-1391D9532A5E} + EndGlobalSection +EndGlobal diff --git a/RealEstate/Commands/CommandAbandonHouse.cs b/RealEstate/Commands/CommandAbandonHouse.cs new file mode 100644 index 0000000..6ad0a73 --- /dev/null +++ b/RealEstate/Commands/CommandAbandonHouse.cs @@ -0,0 +1,53 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate.Commands +{ + public class CommandAbandonHouse : IRocketCommand + { + #region Properties + + public AllowedCaller AllowedCaller => AllowedCaller.Player; + + public string Name => "abandonhouse"; + + public string Help => "Lets the player give up ownership of their house."; + + public string Syntax => "/abandonhouse"; + + public List Aliases => new List(); + + public List Permissions => new List { "realestate.abandonhouse" }; + + #endregion + + public void Execute(IRocketPlayer caller, string[] args) + { + UnturnedPlayer player = (UnturnedPlayer)caller; + + House h = RealEstate.manager.HouseFromPosition(player.Position); + + if (h == null) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("registered_house_not_found"), Color.red); + return; + } + + if (h.OwnerId != player.CSteamID.m_SteamID) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("cannot_abandon"), Color.red); + return; + } + + RealEstate.manager.SetHouseOwner(h.Id, null); + UnturnedChat.Say(caller, RealEstate.instance.Translate("abandoned")); + } + } +} \ No newline at end of file diff --git a/RealEstate/Commands/CommandAddHouse.cs b/RealEstate/Commands/CommandAddHouse.cs new file mode 100644 index 0000000..1a48686 --- /dev/null +++ b/RealEstate/Commands/CommandAddHouse.cs @@ -0,0 +1,68 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate.Commands +{ + public class CommandAddHouse : IRocketCommand + { + #region Properties + + public AllowedCaller AllowedCaller => AllowedCaller.Player; + + public string Name => "addhouse"; + + public string Help => "Allows the house that the caller is standing in to be sold at the defined price."; + + public string Syntax => "/addhouse "; + + public List Aliases => new List(); + + public List Permissions => new List { "realestate.addhouse" }; + + #endregion + + public void Execute(IRocketPlayer caller, string[] args) + { + if (args.Length < 1) + { + UnturnedChat.Say(caller, Syntax, Color.red); + return; + } + + if (!Decimal.TryParse(args[0], out decimal price)) + { + UnturnedChat.Say(caller, Syntax, Color.red); + return; + } + + UnturnedPlayer player = (UnturnedPlayer)caller; + + LevelObject h = RealEstate.manager.LevelObjectFromPosition(player.Position); + + if (h == null) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("house_not_found"), Color.red); + return; + } + + if (RealEstate.manager.Homes.Any(x => x.Id == h.asset.id)) + { + RealEstate.manager.SetHousePrice(h.id, price); + UnturnedChat.Say(caller, RealEstate.instance.Translate("house_updated", RealEstate.instance.Configuration.Instance.currencySymbol, price)); + } + else + { + RealEstate.manager.AddHouse(new House(h.asset.id, price)); + UnturnedChat.Say(caller, RealEstate.instance.Translate("house_added", RealEstate.instance.Configuration.Instance.currencySymbol, price)); + } + } + } +} \ No newline at end of file diff --git a/RealEstate/Commands/CommandBuyHouse.cs b/RealEstate/Commands/CommandBuyHouse.cs new file mode 100644 index 0000000..2f78420 --- /dev/null +++ b/RealEstate/Commands/CommandBuyHouse.cs @@ -0,0 +1,68 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using fr34kyn01535.Uconomy; +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate.Commands +{ + public class CommandBuyHouse : IRocketCommand + { + #region Properties + + public AllowedCaller AllowedCaller => AllowedCaller.Player; + + public string Name => "buyhouse"; + + public string Help => "Buys the house that the caller is standing in."; + + public string Syntax => "/buyhouse"; + + public List Aliases => new List(); + + public List Permissions => new List { "realestate.buyhouse" }; + + #endregion + + public void Execute(IRocketPlayer caller, string[] args) + { + UnturnedPlayer player = (UnturnedPlayer)caller; + + House h = RealEstate.manager.HouseFromPosition(player.Position); + + if (h == null) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("registered_house_not_found"), Color.red); + return; + } + + int max = RealEstate.manager.GetPlayerMax(player); + + if (RealEstate.manager.CountPlayerHouses(player.CSteamID.m_SteamID) >= max) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("max_reached", max), Color.red); + return; + } + + if (h.OwnerId != null) + UnturnedChat.Say(caller, RealEstate.instance.Translate("owner_exists")); + else + { + if (Uconomy.Instance.Database.GetBalance(player.CSteamID.ToString()) < h.Price) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("cannot_afford", RealEstate.instance.Configuration.Instance.currencySymbol, h.Price), Color.red); + return; + } + + Uconomy.Instance.Database.IncreaseBalance(player.CSteamID.ToString(), -h.Price); + UnturnedChat.Say(caller, RealEstate.instance.Translate("house_purchased", RealEstate.instance.Configuration.Instance.currencySymbol, h.Price)); + RealEstate.manager.SetHouseOwner(h.Id, player.CSteamID.m_SteamID); + } + } + } +} \ No newline at end of file diff --git a/RealEstate/Commands/CommandCheckHouse.cs b/RealEstate/Commands/CommandCheckHouse.cs new file mode 100644 index 0000000..22f497f --- /dev/null +++ b/RealEstate/Commands/CommandCheckHouse.cs @@ -0,0 +1,50 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate.Commands +{ + public class CommandCheckHouse : IRocketCommand + { + #region Properties + + public AllowedCaller AllowedCaller => AllowedCaller.Player; + + public string Name => "checkhouse"; + + public string Help => "Tells the caller the price and owner of the house that they are standing in."; + + public string Syntax => "/checkhouse"; + + public List Aliases => new List(); + + public List Permissions => new List { "realestate.checkhouse" }; + + #endregion + + public void Execute(IRocketPlayer caller, string[] args) + { + UnturnedPlayer player = (UnturnedPlayer)caller; + + House h = RealEstate.manager.HouseFromPosition(player.Position); + + if (h == null) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("registered_house_not_found"), Color.red); + return; + } + + if (h.OwnerId != null) + UnturnedChat.Say(caller, RealEstate.instance.Translate("check_house_owned", RealEstate.manager.GetName(h.OwnerId.Value), RealEstate.instance.Configuration.Instance.currencySymbol, h.Price)); + else + UnturnedChat.Say(caller, RealEstate.instance.Translate("check_house_unowned", RealEstate.instance.Configuration.Instance.currencySymbol, h.Price)); + } + } +} \ No newline at end of file diff --git a/RealEstate/Commands/CommandEvictHouse.cs b/RealEstate/Commands/CommandEvictHouse.cs new file mode 100644 index 0000000..fd86fd6 --- /dev/null +++ b/RealEstate/Commands/CommandEvictHouse.cs @@ -0,0 +1,47 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate.Commands +{ + public class CommandEvictHouse : IRocketCommand + { + #region Properties + + public AllowedCaller AllowedCaller => AllowedCaller.Player; + + public string Name => "evicthouse"; + + public string Help => "Allows a player to reset the owner of the home that they are standing in."; + + public string Syntax => "/evicthouse"; + + public List Aliases => new List(); + + public List Permissions => new List { "realestate.evicthouse" }; + + #endregion + + public void Execute(IRocketPlayer caller, string[] args) + { + UnturnedPlayer player = (UnturnedPlayer)caller; + + House h = RealEstate.manager.HouseFromPosition(player.Position); + + if (h == null) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("registered_house_not_found"), Color.red); + return; + } + + RealEstate.manager.SetHouseOwner(h.Id, null); + UnturnedChat.Say(caller, RealEstate.instance.Translate("eviction")); + } + } +} \ No newline at end of file diff --git a/RealEstate/Commands/CommandRemoveHouse.cs b/RealEstate/Commands/CommandRemoveHouse.cs new file mode 100644 index 0000000..af622ce --- /dev/null +++ b/RealEstate/Commands/CommandRemoveHouse.cs @@ -0,0 +1,48 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate.Commands +{ + public class CommandRemoveHouse : IRocketCommand + { + #region Properties + + public AllowedCaller AllowedCaller => AllowedCaller.Player; + + public string Name => "removehouse"; + + public string Help => "Removes a house from the catalog."; + + public string Syntax => "/removehouse"; + + public List Aliases => new List(); + + public List Permissions => new List { "realestate.removehouse" }; + + #endregion + + public void Execute(IRocketPlayer caller, string[] args) + { + UnturnedPlayer player = (UnturnedPlayer)caller; + + House h = RealEstate.manager.HouseFromPosition(player.Position); + + if (h == null) + { + UnturnedChat.Say(caller, RealEstate.instance.Translate("registered_house_not_found"), Color.red); + return; + } + + RealEstate.manager.RemoveHouse(h); + UnturnedChat.Say(caller, RealEstate.instance.Translate("removed")); + } + } +} \ No newline at end of file diff --git a/RealEstate/Entities/DisplayName.cs b/RealEstate/Entities/DisplayName.cs new file mode 100644 index 0000000..5b94e47 --- /dev/null +++ b/RealEstate/Entities/DisplayName.cs @@ -0,0 +1,17 @@ +namespace ExtraConcentratedJuice.RealEstate.Entities +{ + public class DisplayName + { + // Can't serialize a dictionary to XML for some reason, better go with this I guess. + public ulong Id { get; set; } + public string Name { get; set; } + + public DisplayName(ulong id, string name) + { + Id = id; + Name = name; + } + + public DisplayName() { } + } +} diff --git a/RealEstate/Entities/House.cs b/RealEstate/Entities/House.cs new file mode 100644 index 0000000..b02bd93 --- /dev/null +++ b/RealEstate/Entities/House.cs @@ -0,0 +1,21 @@ +using System; + +namespace ExtraConcentratedJuice.RealEstate.Entities +{ + public class House + { + public ushort Id { get; set; } + public decimal Price { get; set; } + + public ulong? OwnerId { get; set; } + public DateTime? LastPaid { get; set; } + + public House(ushort id, decimal price) + { + Id = id; + Price = price; + } + + public House() { } + } +} diff --git a/RealEstate/HouseManager.cs b/RealEstate/HouseManager.cs new file mode 100644 index 0000000..d5fc583 --- /dev/null +++ b/RealEstate/HouseManager.cs @@ -0,0 +1,146 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Harmony; +using Rocket.API; +using Rocket.API.Serialisation; +using Rocket.Unturned.Player; +using SDG.Unturned; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate +{ + public class HouseManager + { + private RealEstate plugin; + + public List Homes { get => plugin.Configuration.Instance.homes; } + public List Names { get => plugin.Configuration.Instance.displayNames; } + + public HouseManager(RealEstate plugin) + { + this.plugin = plugin; + } + + public string GetName(ulong id) => Names.Any(x => x.Id == id) ? Names.First(x => x.Id == id).Name : "???"; + + public void AddHouse(House house) + { + Homes.Add(house); + plugin.Configuration.Save(); + } + + public void RemoveHouse(House house) + { + Homes.Remove(house); + plugin.Configuration.Save(); + } + + public int CountPlayerHouses(ulong id) => Homes.Count(x => x.OwnerId == id); + + public int GetPlayerMax(UnturnedPlayer p) + { + Permission per = p.GetPermissions().FirstOrDefault(x => x.Name.StartsWith("realestate.maxhouses.")); + + if (per != null) + if (int.TryParse(per.Name.Split('.').Last(), out int max)) + return max; + + return plugin.Configuration.Instance.defaultMaxHomes; + } + + public void SetHousePrice(ushort id, decimal price) + { + House home = Homes.FirstOrDefault(x => x.Id == id); + + if (home != null) + { + home.Price = price; + plugin.Configuration.Save(); + } + } + + public void SetHouseOwner(ushort id, ulong? ownerId) + { + House home = Homes.FirstOrDefault(x => x.Id == id); + + if (home != null) + { + home.OwnerId = ownerId; + + if (ownerId == null && plugin.Configuration.Instance.destroyStructuresOnEviction) + { + foreach (BarricadeRegion r in BarricadeManager.regions) + for (int i = r.drops.Count - 1; i >= 0; i--) + { + if (HouseFromPosition(r.drops.ElementAt(i).model.position) != home) + continue; + + if (!BarricadeManager.tryGetInfo(r.drops.ElementAt(i).model, out byte x, out byte y, out ushort plant, out ushort index, out BarricadeRegion region)) + continue; + + BarricadeManager.instance.channel.send("tellTakeBarricade", ESteamCall.ALL, ESteamPacket.UPDATE_RELIABLE_BUFFER, new object[] + { + x, + y, + plant, + index + }); + } + + foreach (StructureRegion r in StructureManager.regions) + for (int i = r.drops.Count - 1; i >= 0; i--) + { + if (HouseFromPosition(r.drops.ElementAt(i).model.position) != home) + continue; + + if (!StructureManager.tryGetInfo(r.drops.ElementAt(i).model, out byte x, out byte y, out ushort plant, out StructureRegion region, out StructureDrop index)) + continue; + + StructureManager.instance.channel.send("tellTakeStructure", ESteamCall.ALL, ESteamPacket.UPDATE_RELIABLE_BUFFER, new object[] + { + x, + y, + plant, + index + }); + } + } + + home.LastPaid = DateTime.Now; + plugin.Configuration.Save(); + } + } + + public LevelObject LevelObjectFromPosition(Vector3 pos) + { + foreach (List o in LevelObjects.objects) + { + LevelObject obj = o.Where(x => NullCheck(x)).FirstOrDefault(x => x.transform.GetComponent().bounds.Contains(pos)); + + if (obj != null) + return obj; + } + + return null; + } + + public House HouseFromPosition(Vector3 pos) + { + foreach (List o in LevelObjects.objects) + { + LevelObject obj = o.Where(x => NullCheck(x)).FirstOrDefault(x => x.transform.GetComponent().bounds.Contains(pos)); + + if (obj != null) + return Homes.FirstOrDefault(x => x.Id == obj.asset.id); + } + + return null; + } + + private bool NullCheck(LevelObject o) => o.transform != null && o.transform.GetComponent() != null; + } +} diff --git a/RealEstate/Overrides/SimulateBarricadeOverride.cs b/RealEstate/Overrides/SimulateBarricadeOverride.cs new file mode 100644 index 0000000..ad2da7c --- /dev/null +++ b/RealEstate/Overrides/SimulateBarricadeOverride.cs @@ -0,0 +1,44 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; +using Steamworks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate.Overrides +{ + internal class SimulateBarricadeOverride + { + internal static bool Prefix(UseableBarricade __instance, uint simulation, bool inputSteady) + { + UnturnedPlayer player = UnturnedPlayer.FromPlayer(__instance.player); + + if (player.HasPermission("realestate.bypass")) + return true; + + if (GetValue(__instance, "isUsing", BindingFlags.NonPublic | BindingFlags.Instance)) + { + House house = RealEstate.manager.HouseFromPosition(GetValue(__instance, "point", BindingFlags.NonPublic | BindingFlags.Instance)); + + if (house != null && (house.OwnerId == null || house.OwnerId != null && house.OwnerId.Value != player.CSteamID.m_SteamID)) + { + __instance.player.equipment.dequip(); + UnturnedChat.Say(player, "You cannot place barricades in a house that does not belong to you.", Color.red); + return false; + } + } + + return true; + } + + internal static void PostFix() { /* lol */ } + + private static T GetValue(UseableBarricade instance, string name, BindingFlags flags) + => (T)typeof(UseableBarricade).GetField(name, flags).GetValue(instance); + } +} diff --git a/RealEstate/Overrides/SimulateStructureOverride.cs b/RealEstate/Overrides/SimulateStructureOverride.cs new file mode 100644 index 0000000..7a17af0 --- /dev/null +++ b/RealEstate/Overrides/SimulateStructureOverride.cs @@ -0,0 +1,43 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; +using System.Reflection; +using UnityEngine; + +namespace ExtraConcentratedJuice.RealEstate.Overrides +{ + internal class SimulateStructureOverride + { + internal static bool Prefix(UseableStructure __instance, uint simulation, bool inputSteady) + { + UnturnedPlayer player = UnturnedPlayer.FromPlayer(__instance.player); + + if (player.HasPermission("realestate.bypass")) + return true; + + if (GetValue(__instance, "isUsing", BindingFlags.NonPublic | BindingFlags.Instance)) + { + House house = RealEstate.manager.HouseFromPosition(GetValue(__instance, "point", BindingFlags.NonPublic | BindingFlags.Instance)); + + if (house != null && (house.OwnerId == null || house.OwnerId != null && house.OwnerId.Value != player.CSteamID.m_SteamID)) + { + __instance.player.equipment.dequip(); + UnturnedChat.Say(player, "You cannot place structures in a house that does not belong to you.", Color.red); + return false; + } + } + + return true; + } + + internal static void PostFix() + { + // lol + } + + private static T GetValue(UseableStructure instance, string name, BindingFlags flags) + => (T)typeof(UseableStructure).GetField(name, flags).GetValue(instance); + } +} diff --git a/RealEstate/Properties/AssemblyInfo.cs b/RealEstate/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..dcdbcdd --- /dev/null +++ b/RealEstate/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RealEstate")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("RealEstate")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ef549899-855f-4a80-86ab-4e5e3bd0933e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/RealEstate/RealEstate.cs b/RealEstate/RealEstate.cs new file mode 100644 index 0000000..301b299 --- /dev/null +++ b/RealEstate/RealEstate.cs @@ -0,0 +1,139 @@ +using fr34kyn01535.Uconomy; +using Harmony; +using Rocket.Core.Plugins; +using Rocket.Unturned; +using Rocket.Unturned.Player; +using SDG.Unturned; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Timers; +using Rocket.API.Collections; +using Rocket.Unturned.Chat; +using UnityEngine; +using ExtraConcentratedJuice.RealEstate.Overrides; +using ExtraConcentratedJuice.RealEstate.Entities; + +namespace ExtraConcentratedJuice.RealEstate +{ + public class RealEstate : RocketPlugin + { + public static RealEstate instance; + public static HouseManager manager; + private Timer timer; + + protected override void Load() + { + instance = this; + + if (Configuration.Instance.feePaymentTimeInMinutes > 0) + { + timer = new Timer(1000 * Configuration.Instance.paymentCheckIntervalInSeconds); + timer.Elapsed += OnTimerElapsed; + timer.Start(); + } + + U.Events.OnPlayerConnected += OnConnected; + + manager = new HouseManager(this); + + HarmonyInstance harmony = HarmonyInstance.Create("pw.cirno.extraconcentratedjuice"); + + var orig = typeof(UseableStructure).GetMethod("simulate", BindingFlags.Instance | BindingFlags.Public); + var pre = typeof(SimulateStructureOverride).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic); + var post = typeof(SimulateStructureOverride).GetMethod("Postfix", BindingFlags.Static | BindingFlags.NonPublic); + + harmony.Patch(orig, new HarmonyMethod(pre), new HarmonyMethod(post)); + + var orig2 = typeof(UseableBarricade).GetMethod("simulate", BindingFlags.Instance | BindingFlags.Public); + var pre2 = typeof(SimulateBarricadeOverride).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic); + var post2 = typeof(SimulateBarricadeOverride).GetMethod("Postfix", BindingFlags.Static | BindingFlags.NonPublic); + + harmony.Patch(orig2, new HarmonyMethod(pre2), new HarmonyMethod(post2)); + } + + protected override void Unload() + { + if (timer != null) + { + timer.Elapsed -= OnTimerElapsed; + timer.Stop(); + } + + U.Events.OnPlayerConnected -= OnConnected; + } + + private void OnTimerElapsed(object s, ElapsedEventArgs t) + { + foreach (House x in Configuration.Instance.homes) + { + if (x.LastPaid == null || x.OwnerId == null) + continue; + + UnturnedPlayer player = PlayerTool.getPlayer(new Steamworks.CSteamID(x.OwnerId.Value)) == null ? null : + UnturnedPlayer.FromCSteamID(new Steamworks.CSteamID(x.OwnerId.Value)); + + if ((DateTime.Now - x.LastPaid.Value).TotalMinutes > Configuration.Instance.feePaymentTimeInMinutes) + { + if (Uconomy.Instance.Database.GetBalance(x.OwnerId.ToString()) < x.Price) + { + if (player != null) + UnturnedChat.Say(player, Translate("eviction_notice"), Color.red); + + manager.SetHouseOwner(x.Id, null); + continue; + } + + if (player != null) + UnturnedChat.Say(player, Translate("upkeep_payment", Configuration.Instance.currencySymbol, x.Price)); + + Uconomy.Instance.Database.IncreaseBalance(x.OwnerId.ToString(), -x.Price); + x.LastPaid = DateTime.Now; + Configuration.Save(); + } + } + } + + private void OnConnected(UnturnedPlayer p) + { + DisplayName n = Configuration.Instance.displayNames.FirstOrDefault(x => x.Id == p.CSteamID.m_SteamID); + + if (n != null) + { + if (p.DisplayName != n.Name) + { + n.Name = p.DisplayName; + Configuration.Save(); + } + } + else + { + Configuration.Instance.displayNames.Add(new DisplayName(p.CSteamID.m_SteamID, p.DisplayName)); + Configuration.Save(); + } + } + + public override TranslationList DefaultTranslations => + new TranslationList + { + { "house_not_found", "You aren't within the bounds of a house." }, + { "registered_house_not_found", "You aren't within the bounds of a registered home." }, + { "eviction", "The owner of this house has been evicted." }, + { "removed", "This house has been removed from the catalog." }, + { "check_house_owned", "This house belongs to {0} and is valued at {1}{2}."}, + { "check_house_unowned", "This house currently does not belong to anybody and is valued at {0}{1}." }, + { "owner_exists", "This house already has an owner." }, + { "cannot_afford", "You cannot afford this house ({0}{1})." }, + { "house_purchased", "You've purchased this house for {0}{1}." }, + { "house_added", "You've added this house to the catalog for {0}{1}." }, + { "house_updated", "You've updated the price of this house to {0}{1}." }, + { "eviction_notice", "You have failed to pay one of your house's upkeeps and have been evicted." }, + { "upkeep_payment", "You've paid {0}{1} for the upkeep of one of your homes." }, + { "max_reached", "You have reached the maximum number of homes allocated to you. ({0})" }, + { "abandoned", "You have abandoned this house." }, + { "cannot_abandon", "This house doesn't even belong to you!" } + }; + } +} diff --git a/RealEstate/RealEstate.csproj b/RealEstate/RealEstate.csproj new file mode 100644 index 0000000..2ccd454 --- /dev/null +++ b/RealEstate/RealEstate.csproj @@ -0,0 +1,82 @@ + + + + + Debug + AnyCPU + {EF549899-855F-4A80-86AB-4E5E3BD0933E} + Library + Properties + ExtraConcentratedJuice.RealEstate + RealEstate + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\Libraries\0Harmony.dll + + + ..\Libraries\Assembly-CSharp.dll + + + ..\Libraries\Assembly-CSharp-firstpass.dll + + + ..\Libraries\Rocket.API.dll + + + ..\Libraries\Rocket.Core.dll + + + ..\Libraries\Rocket.Unturned.dll + + + + + + + + + ..\Libraries\Uconomy.dll + + + ..\Libraries\UnityEngine.dll + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RealEstate/RealEstateConfiguration.cs b/RealEstate/RealEstateConfiguration.cs new file mode 100644 index 0000000..67912e5 --- /dev/null +++ b/RealEstate/RealEstateConfiguration.cs @@ -0,0 +1,32 @@ +using ExtraConcentratedJuice.RealEstate.Entities; +using Rocket.API; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ExtraConcentratedJuice.RealEstate +{ + public class RealEstateConfiguration : IRocketPluginConfiguration + { + public string currencySymbol; + public int defaultMaxHomes; + public int paymentCheckIntervalInSeconds; + public int feePaymentTimeInMinutes; + public bool destroyStructuresOnEviction; + public List homes; + public List displayNames; + + public void LoadDefaults() + { + currencySymbol = "$"; + defaultMaxHomes = 1; + paymentCheckIntervalInSeconds = 10; + feePaymentTimeInMinutes = 1440; + destroyStructuresOnEviction = false; + + homes = new List(); + displayNames = new List(); + } + } +}