C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// Requires: ImageLibrary
using System;
using System.Text;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Plugins;
using UnityEngine;
using System.Linq;
using System.Globalization;
using System.IO;
using System.Drawing;
using Newtonsoft.Json;
namespace Oxide.Plugins {
[Info("Lusty Map", "k1lly0u", "2.1.42")]
[Description("In-game map and minimap GUI")]
class LustyMap : RustPlugin {
#region Fields
[PluginReference]
Plugin Clans, EventManager, Friends;
[PluginReference]
ImageLibrary ImageLibrary;
static MapSplitter mapSplitter;
static LustyMap instance;
static float mapSize;
static string mapSeed;
static string worldSize;
static string level;
private bool activated;
private bool isNewSave;
MarkerData storedMarkers;
private DynamicConfigFile markerData;
private Dictionary<string, MapUser> mapUsers;
private List<MapMarker> staticMarkers;
private Dictionary<string, MapMarker> customMarkers;
private Dictionary<string, MapMarker> temporaryMarkers;
private Dictionary<uint, ActiveEntity> entityMarkers;
private Dictionary<string, List<string>> clanData;
static string dataDirectory = $"file://{Interface.Oxide.DataDirectory}{Path.DirectorySeparatorChar}LustyMap{Path.DirectorySeparatorChar}";
#endregion
#region User Class
class MapUser : MonoBehaviour {
private Dictionary<string, List<string>> friends;
public HashSet<string> friendList;
public BasePlayer player;
public MapMode mode;
public MapMode lastMode;
private MapMarker marker;
private int mapX;
private int mapZ;
private int currentX;
private int currentZ;
private int mapZoom;
private bool mapOpen;
private bool inEvent;
private bool adminMode;
private int changeCount;
private double lastChange;
private bool isBlocked;
private ConfigData.SpamOptions spam;
private bool afkDisabled;
private int lastMoveTime;
private float lastX;
private float lastZ;
void Awake() {
player = GetComponent<BasePlayer>();
friends = new Dictionary<string, List<string>> {
{
"Clans", new List<string>()
}
, {
"Friends", new List<string>()
}
}
;
friendList = new HashSet<string>();
spam = instance.configData.Spam;
inEvent = false;
mapOpen = false;
afkDisabled = false;
enabled = false;
mode = MapMode.None;
lastMode = MapMode.None;
adminMode = false;
InvokeHandler.InvokeRepeating(this, UpdateMarker, 0.1f, 1f);
}
void OnDestroy() {
InvokeHandler.CancelInvoke(this, UpdateMarker);
InvokeHandler.CancelInvoke(this, UpdateMap);
DestroyUI();
}
public void InitializeComponent() {
if (MapSettings.friends) {
FillFriendList();
}
if (!instance.configData.Map.StartOpen) {
ToggleMapType(MapMode.None);
return;
}
if (MapSettings.complexmap) {
mapZoom = 1;
ToggleMapType(MapMode.Complex);
if (MapSettings.forcedzoom) mapZoom = MapSettings.zoomlevel;
}
else if (MapSettings.minimap) {
mode = MapMode.Minimap;
ToggleMapType(mode);
}
}
#region Friends
private void FillFriendList() {
if (instance.configData.Friends.UseClans) {
var clanTag = instance.GetClan(player.userID);
if (!string.IsNullOrEmpty(clanTag) && instance.clanData.ContainsKey(clanTag)) friends["Clans"] = instance.clanData[clanTag];
}
if (instance.configData.Friends.UseFriends) friends["Friends"] = instance.GetFriends(player.userID);
UpdateMembers();
}
private void UpdateMembers() {
friendList.Clear();
foreach (var list in friends) {
foreach (var member in list.Value) friendList.Add(member);
}
}
#endregion
#region Maps
public float Rotation() => GetDirection(player?.transform?.rotation.eulerAngles.y ?? 0);
public int Position(bool x) => x ? mapX : mapZ;
public void Position(bool x, int pos) {
if (x) mapX = pos;
else mapZ = pos;
}
public void ToggleMapType(MapMode mapMode) {
if (isBlocked || IsSpam()) return;
DestroyUI();
if (mapMode == MapMode.None) {
InvokeHandler.CancelInvoke(this, UpdateMap);
mode = MapMode.None;
mapOpen = false;
if (MapSettings.minimap) instance.CreateShrunkUI(player);
}
else {
mapOpen = true;
switch (mapMode) {
case MapMode.Main : mode = MapMode.Main;
instance.OpenMainMap(player);
break;
case MapMode.Complex : mode = MapMode.Complex;
instance.OpenComplexMap(player);
break;
case MapMode.Minimap : mode = MapMode.Minimap;
instance.OpenMiniMap(player);
break;
}
if (!IsInvoking("UpdateMap")) InvokeHandler.InvokeRepeating(this, UpdateMap, 0.1f, instance.configData.Map.UpdateSpeed);
}
}
public void UpdateMap() {
switch (mode) {
case MapMode.None : break;
case MapMode.Main : instance.UpdateOverlay(player, LustyUI.MainOverlay, LustyUI.MainMin, LustyUI.MainMax, 0.01f);
break;
case MapMode.Complex : CheckForChange();
instance.UpdateCompOverlay(player);
break;
case MapMode.Minimap : instance.UpdateOverlay(player, LustyUI.MiniOverlay, LustyUI.MiniMin, LustyUI.MiniMax, 0.03f);
break;
}
}
#endregion
#region Complex
public bool HasMapOpen() => (mapOpen && mode == MapMode.Main);
public int Zoom() => mapZoom;
public void Zoom(bool zoomIn) {
var zoom = mapZoom;
if (zoomIn) {
if (zoom < 3) zoom++;
else return;
}
else {
if (zoom > 0) zoom--;
else return;
}
InvokeHandler.CancelInvoke(this, UpdateMap);
SwitchZoom(zoom);
}
private void SwitchZoom(int zoom) {
if (zoom == 0 && MapSettings.minimap) {
mapZoom = zoom;
ToggleMapType(MapMode.Minimap);
}
else {
if (zoom == 0 && !MapSettings.minimap) zoom = 1;
mapZoom = zoom;
currentX = 0;
currentZ = 0;
ToggleMapType(MapMode.Complex);
}
}
public int Current(bool x) => x ? currentX : currentZ;
public void Current(bool x, int num) {
if (x) currentX = num;
else currentZ = num;
}
private void CheckForChange() {
var mapSlices = ZoomToCount(mapZoom);
float x = player.transform.position.x + mapSize / 2f;
float z = player.transform.position.z + mapSize / 2f;
var mapres = mapSize / mapSlices;
var newX = Convert.ToInt32(Math.Ceiling(x / mapres)) - 1;
var newZ = mapSlices - Convert.ToInt32(Math.Ceiling(z / mapres));
if (currentX != newX || currentZ != newZ) {
DestroyUI();
currentX = newX;
currentZ = newZ;
instance.OpenComplexMap(player);
}
}
#endregion
#region Spam Checking
private bool IsSpam() {
if (!spam.Enabled) return false;
changeCount++;
var current = GrabCurrentTime();
if (current - lastChange < spam.TimeBetweenAttempts) {
lastChange = current;
if (changeCount > spam.WarningAttempts && changeCount < spam.DisableAttempts) {
instance.SendReply(player, instance.msg("spamWarning", player.UserIDString));
return false;
}
if (changeCount >= spam.DisableAttempts) {
instance.SendReply(player, string.Format(instance.msg("spamDisable", player.UserIDString), spam.DisableSeconds));
Block();
Invoke("Unblock", spam.DisableSeconds);
return true;
}
}
else {
lastChange = current;
changeCount = 0;
}
return false;
}
private void Block() {
isBlocked = true;
OnDestroy();
}
private void Unblock() {
isBlocked = false;
ToggleMapType(lastMode);
instance.SendReply(player, instance.msg("spamEnable", player.UserIDString));
}
#endregion
#region Other
public bool InEvent() => inEvent;
public bool IsAdmin => adminMode;
public void ToggleEvent(bool isPlaying) => inEvent = isPlaying;
public void ToggleAdmin(bool enabled) => adminMode = enabled;
public void DestroyUI() => LustyUI.DestroyUI(player);
private void UpdateMarker() {
var currentX = (float)Math.Round(transform.position.x, 1);
var currentZ = (float)Math.Round(transform.position.z, 1);
marker = new MapMarker {
name = RemoveSpecialCharacters(player.displayName), r = GetDirection(player?.eyes?.rotation.eulerAngles.y ?? 0), x = GetPosition(transform.position.x), z = GetPosition(transform.position.z)
}
;
if (instance.configData.Map.EnableAFKTracking) {
if (lastX == currentX && lastZ == currentZ) ++lastMoveTime;
else {
lastX = currentX;
lastZ = currentZ;
lastMoveTime = 0;
if (afkDisabled) {
afkDisabled = false;
EnableUser();
}
}
if (lastMoveTime == 90) {
afkDisabled = true;
DisableUser();
}
}
}
public MapMarker GetMarker() => marker;
public void ToggleMain() {
if (HasMapOpen()) {
if (MapSettings.minimap) {
if (Zoom() > 0) ToggleMapType(MapMode.Complex);
else ToggleMapType(MapMode.Minimap);
}
else ToggleMapType(MapMode.None);
}
else {
lastMode = mode;
CuiHelper.DestroyUi(player, LustyUI.Buttons);
ToggleMapType(MapMode.Main);
}
}
public void DisableUser() {
if (!mapOpen) return;
InvokeHandler.CancelInvoke(this, UpdateMap);
CuiHelper.DestroyUi(player, LustyUI.Buttons);
if (mode != MapMode.None) LustyUI.DestroyUI(player);
mapOpen = false;
}
public void EnableUser() {
if (mapOpen) return;
ToggleMapType(mode);
}
public void EnterEvent() => inEvent = true;
public void ExitEvent() => inEvent = false;
#region Friends
public bool HasFriendList(string name) => friends.ContainsKey(name);
public void AddFriendList(string name, List<string> friendlist) {
friends.Add(name, friendlist);
UpdateMembers();
}
public void RemoveFriendList(string name) {
friends.Remove(name);
UpdateMembers();
}
public void UpdateFriendList(string name, List<string> friendlist) {
friends[name] = friendlist;
UpdateMembers();
}
public bool HasFriend(string name, string friendId) => friends[name].Contains(friendId);
public void AddFriend(string name, string friendId) {
friends[name].Add(friendId);
UpdateMembers();
}
public void RemoveFriend(string name, string friendId) {
friends[name].Remove(friendId);
UpdateMembers();
}
#endregion
#endregion
}
MapUser GetUser(BasePlayer player) => player.GetComponent<MapUser>() ?? null;
MapUser GetUserByID(string playerId) => mapUsers.ContainsKey(playerId) ? mapUsers[playerId] : null;
#endregion
#region Markers
class ActiveEntity : MonoBehaviour {
public BaseEntity entity;
private MapMarker marker;
public AEType type;
private string icon;
void Awake() {
entity = GetComponent<BaseEntity>();
marker = new MapMarker();
enabled = false;
}
void OnDestroy() {
InvokeHandler.CancelInvoke(this, UpdatePosition);
}
public void SetType(AEType type) {
this.type = type;
switch (type) {
case AEType.None : break;
case AEType.Plane : icon = "plane";
marker.name = instance.msg("Plane");
break;
case AEType.SupplyDrop : icon = "supply";
marker.name = instance.msg("Supply Drop");
break;
case AEType.Helicopter : icon = "heli";
marker.name = instance.msg("Helicopter");
break;
case AEType.Debris : icon = "debris";
marker.name = instance.msg("Debris");
break;
case AEType.Vending : icon = "vending";
marker.name = instance.msg("Vending");
break;
case AEType.Tank : icon = "tank";
marker.name = instance.msg("Tank");
break;
case AEType.Car : icon = "car";
marker.name = instance.msg("Car");
break;
}
InvokeHandler.InvokeRepeating(this, UpdatePosition, 0.1f, 1f);
}
public MapMarker GetMarker() => marker;
void UpdatePosition() {
if (type == AEType.Helicopter || type == AEType.Plane || type == AEType.Car || type == AEType.Tank) {
marker.r = GetDirection(entity?.transform?.rotation.eulerAngles.y ?? 0);
marker.icon = $"{icon}{marker.r}";
}
else marker.icon = $"{icon}";
marker.x = GetPosition(entity.transform.position.x);
marker.z = GetPosition(entity.transform.position.z);
if (type == AEType.Vending || type == AEType.SupplyDrop || type == AEType.Debris) InvokeHandler.CancelInvoke(this, UpdatePosition);
}
}
class MapMarker {
public string name {
get;
set;
}
public float x {
get;
set;
}
public float z {
get;
set;
}
public float r {
get;
set;
}
public string icon {
get;
set;
}
}
static class MapSettings {
static public bool minimap, complexmap, monuments, names, compass, caves, plane, heli, supply, debris, player, allplayers, friends, vending, forcedzoom, cars, tanks;
static public int zoomlevel;
}
public enum MapMode {
None, Main, Complex, Minimap
}
enum AEType {
None, Plane, SupplyDrop, Helicopter, Debris, Vending, Car, Tank
}
#endregion
#region UI
class LMUI {
static public CuiElementContainer CreateElementContainer(string panelName, string color, string aMin, string aMax, bool cursor = false, string parent = "Hud") {
var NewElement = new CuiElementContainer() {
{
new CuiPanel {
Image = {
Color = color
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
, CursorEnabled = cursor
}
, new CuiElement().Parent = parent, panelName
}
}
;
return NewElement;
}
static public void CreatePanel(ref CuiElementContainer container, string panel, string color, string aMin, string aMax, bool cursor = false) {
container.Add(new CuiPanel {
Image = {
Color = color
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
, CursorEnabled = cursor
}
, panel, CuiHelper.GetGuid());
}
static public void CreateLabel(ref CuiElementContainer container, string panel, string color, string text, int size, string aMin, string aMax, TextAnchor align = TextAnchor.MiddleCenter) {
container.Add(new CuiLabel {
Text = {
Color = color, FontSize = size, Align = align, FadeIn = 0, Text = text
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
}
, panel, CuiHelper.GetGuid());
}
static public void CreateButton(ref CuiElementContainer container, string panel, string color, string text, int size, string aMin, string aMax, string command, TextAnchor align = TextAnchor.MiddleCenter) {
container.Add(new CuiButton {
Button = {
Color = color, Command = command, FadeIn = 0
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
, Text = {
Text = text, FontSize = size, Align = align
}
}
, panel, CuiHelper.GetGuid());
}
static public void LoadImage(ref CuiElementContainer container, string panel, string png, string aMin, string aMax) {
container.Add(new CuiElement {
Name = CuiHelper.GetGuid(), Parent = panel, Components = {
new CuiRawImageComponent {
Png = png, Sprite = "assets/content/textures/generic/fulltransparent.tga"
}
, new CuiRectTransformComponent {
AnchorMin = aMin, AnchorMax = aMax
}
}
}
);
}
}
#endregion
#region Oxide Hooks
void OnNewSave(string filename) {
isNewSave = true;
}
void Loaded() {
markerData = Interface.Oxide.DataFileSystem.GetFile($"LustyMap{Path.DirectorySeparatorChar}CustomData");
mapUsers = new Dictionary<string, MapUser>();
staticMarkers = new List<MapMarker>();
customMarkers = new Dictionary<string, MapMarker>();
temporaryMarkers = new Dictionary<string, MapMarker>();
entityMarkers = new Dictionary<uint, ActiveEntity>();
clanData = new Dictionary<string, List<string>>();
permission.RegisterPermission("lustymap.admin", this);
}
void OnServerInitialized() {
instance = this;
worldSize = ConVar.Server.worldsize.ToString();
mapSeed = ConVar.Server.seed.ToString();
level = ConVar.Server.level;
mapSize = TerrainMeta.Size.x;
mapSplitter = new MapSplitter();
LoadVariables();
LoadData();
LoadSettings();
FindStaticMarkers();
FindVendingMachines();
FindVehicles();
ValidateImages();
GetClans();
}
void OnPlayerConnected(BasePlayer player) {
if (player == null) return;
if (player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot) || player.IsSleeping()) {
timer.In(2, () => OnPlayerConnected(player));
return;
}
if (activated) {
var user = GetUser(player);
if (user != null) {
UnityEngine.Object.DestroyImmediate(user);
if (mapUsers.ContainsKey(player.UserIDString)) mapUsers.Remove(player.UserIDString);
}
var mapUser = player.gameObject.AddComponent<MapUser>();
if (!mapUsers.ContainsKey(player.UserIDString)) mapUsers.Add(player.UserIDString, mapUser);
mapUser.InitializeComponent();
}
}
void OnPlayerDisconnected(BasePlayer player) {
if (player == null) return;
if (mapUsers.ContainsKey(player.UserIDString)) {
UnityEngine.Object.Destroy(mapUsers[player.UserIDString]);
mapUsers.Remove(player.UserIDString);
}
LustyUI.DestroyUI(player);
}
void OnEntitySpawned(BaseEntity entity) {
if (!activated) return;
if (entity == null) return;
if (entity is CargoPlane || entity is SupplyDrop || entity is BaseHelicopter || entity is HelicopterDebris || entity is VendingMachine || entity is BasicCar || entity is BradleyAPC) AddTemporaryEntityMarker(entity);
}
void OnEntityKill(BaseNetworkable entity) {
var activeEntity = entity?.GetComponent<ActiveEntity>();
if (activeEntity == null) return;
if (entity?.net?.ID == null) return;
if (entityMarkers.ContainsKey(entity.net.ID)) entityMarkers.Remove(entity.net.ID);
UnityEngine.Object.Destroy(activeEntity);
}
void Unload() {
foreach (var player in BasePlayer.activePlayerList) OnPlayerDisconnected(player);
var mapUsers = UnityEngine.Object.FindObjectsOfType<MapUser>();
if (mapUsers != null) foreach (var user in mapUsers) UnityEngine.Object.DestroyImmediate(user);
var tempMarkers = UnityEngine.Object.FindObjectsOfType<ActiveEntity>();
if (tempMarkers != null) foreach (var marker in tempMarkers) UnityEngine.Object.DestroyImmediate(marker);
}
#endregion
#region Static UI Generation
static class LustyUI {
public static string Main = "LMUI_MapMain";
public static string Mini = "LMUI_MapMini";
public static string Complex = "LMUI_Complex";
public static string MainOverlay = "LMUI_MainOverlay";
public static string MiniOverlay = "LMUI_MiniOverlay";
public static string ComplexOverlay = "LMUI_ComplexOverlay";
public static string Buttons = "LMUI_Buttons";
public static string MainMin;
public static string MainMax;
public static string MiniMin;
public static string MiniMax;
public static CuiElementContainer StaticMain;
public static CuiElementContainer StaticMini;
public static Dictionary<int, CuiElementContainer[, ]> StaticComplex = new Dictionary<int, CuiElementContainer[, ]>();
private static Dictionary<ulong, List<string>> OpenUI = new Dictionary<ulong, List<string>>();
public static void RenameComponents() {
if (StaticMain != null) {
foreach (var element in StaticMain) {
if (element.Name == "AddUI CreatedPanel") element.Name = CuiHelper.GetGuid();
}
}
if (StaticMini != null) {
foreach (var element in StaticMini) {
if (element.Name == "AddUI CreatedPanel") element.Name = CuiHelper.GetGuid();
}
}
if (StaticComplex != null) {
foreach (var size in StaticComplex) {
foreach (var piece in size.Value) {
foreach (var element in piece) {
if (element.Name == "AddUI CreatedPanel") element.Name = CuiHelper.GetGuid();
}
}
}
}
instance.activated = true;
if (instance.configData.Map.StartOpen) instance.ActivateMaps();
}
public static void AddBaseUI(BasePlayer player, MapMode type) {
try {
var user = instance.GetUser(player);
if (user == null) return;
DestroyUI(player);
CuiElementContainer element = null;
switch (type) {
case MapMode.None : return;
case MapMode.Main : element = StaticMain;
CuiHelper.AddUi(player, StaticMain);
AddElementIds(player, ref element);
return;
case MapMode.Complex : element = StaticComplex[(MapSettings.forcedzoom ? MapSettings.zoomlevel : user.Zoom())][user.Current(true), user.Current(false)];
instance.AddMapButtons(player);
CuiHelper.AddUi(player, element);
AddElementIds(player, ref element);
return;
case MapMode.Minimap : element = StaticMini;
instance.AddMapButtons(player);
CuiHelper.AddUi(player, element);
AddElementIds(player, ref element);
return;
}
}
catch {
}
}
private static void AddElementIds(BasePlayer player, ref CuiElementContainer container) {
if (!OpenUI.ContainsKey(player.userID)) OpenUI.Add(player.userID, new List<string>());
foreach (var piece in container) OpenUI[player.userID].Add(piece.Name);
}
public static void DestroyUI(BasePlayer player) {
CuiHelper.DestroyUi(player, Buttons);
CuiHelper.DestroyUi(player, Main);
CuiHelper.DestroyUi(player, MainOverlay);
CuiHelper.DestroyUi(player, Mini);
CuiHelper.DestroyUi(player, MiniOverlay);
CuiHelper.DestroyUi(player, Complex);
CuiHelper.DestroyUi(player, ComplexOverlay);
if (!OpenUI.ContainsKey(player.userID)) return;
foreach (var piece in OpenUI[player.userID]) CuiHelper.DestroyUi(player, piece);
}
public static string Color(string hexColor, float alpha) {
int red = int.Parse(hexColor.Substring(0, 2), NumberStyles.AllowHexSpecifier);
int green = int.Parse(hexColor.Substring(2, 2), NumberStyles.AllowHexSpecifier);
int blue = int.Parse(hexColor.Substring(4, 2), NumberStyles.AllowHexSpecifier);
return $"{(double)red / 255} {(double)green / 255} {(double)blue / 255} {alpha}";
}
}
void GenerateMaps(bool main, bool mini, bool complex) {
if (!ImageLibrary.IsReady()) {
timer.In(30, () => GenerateMaps(main, mini, complex));
Puts("[Warning] Waiting for Image Library to finish processing images");
return;
}
if (main) CreateStaticMain();
SetMinimapSize();
if (mini) CreateStaticMini();
if (complex) CreateStaticComplex();
}
void SetMinimapSize() {
float startx = 0f + configData.MiniMap.OffsetSide;
float endx = startx + (0.13f * configData.MiniMap.HorizontalScale);
float endy = 1f - configData.MiniMap.OffsetTop;
float starty = endy - (0.2301f * configData.MiniMap.VerticalScale);
if (!configData.MiniMap.OnLeftSide) {
endx = 1 - configData.MiniMap.OffsetSide;
startx = endx - (0.13f * configData.MiniMap.HorizontalScale);
}
LustyUI.MiniMin = $"{startx} {starty}";
LustyUI.MiniMax = $"{endx} {endy}";
}
void CreateStaticMain() {
Puts("[Warning] Generating the main map");
string mapimage = string.Empty;
if (ImageLibrary.HasImage("mapimage", 0)) mapimage = GetImage("mapimage");
else if (ImageLibrary.HasImage("mapimage_high", 0)) mapimage = GetImage("mapimage_high");
if (string.IsNullOrEmpty(mapimage)) {
Puts("[Error] Unable to load the map image from file storage.This may be caused by slow processing of the images being uploaded to your server.Wait for 5 minutes and reload the plugin.\nIf this problem persists after multiple attempts then unload the plugin and delete your ImageData.json data file or run the 'resetmap' command");
activated = false;
return;
}
float iconsize = 0.01f;
LustyUI.MainMin = "0.2271875 0.015";
LustyUI.MainMax = "0.7728125 0.985";
var mapContainer = LMUI.CreateElementContainer(LustyUI.Main, "0 0 0 1", LustyUI.MainMin, LustyUI.MainMax, true);
LMUI.LoadImage(ref mapContainer, LustyUI.Main, mapimage, "0 0", "1 1");
LMUI.CreatePanel(ref mapContainer, LustyUI.Main, LustyUI.Color("2b627a", 0.4f), "0 0.96", "1 1");
LMUI.CreateLabel(ref mapContainer, LustyUI.Main, "", $"{Title} v{Version}", 14, "0.01 0.96", "0.99 1");
foreach (var marker in staticMarkers) {
var image = GetImage(marker.icon);
if (string.IsNullOrEmpty(image)) continue;
LMUI.LoadImage(ref mapContainer, LustyUI.Main, image, $"{marker.x - iconsize} {marker.z - iconsize}", $"{marker.x + iconsize} {marker.z + iconsize}");
if (MapSettings.names) LMUI.CreateLabel(ref mapContainer, LustyUI.Main, "", marker.name, 10, $"{marker.x - 0.1} {marker.z - iconsize - 0.03}", $"{marker.x + 0.1} {marker.z - iconsize}");
}
LustyUI.StaticMain = mapContainer;
Puts("[Warning] Main map generated successfully!");
if (!MapSettings.minimap) LustyUI.RenameComponents();
}
void CreateStaticMini() {
Puts("[Warning] Generating the mini-map");
var mapimage = GetImage("mapimage");
if (string.IsNullOrEmpty(mapimage)) {
Puts("[Error] Unable to load the map image from file storage.This may be caused by slow processing of the images being uploaded to your server.Wait for 5 minutes and reload the plugin.\nIf this problem persists after multiple attempts then unload the plugin and delete your ImageData.json data file or run the 'resetmap' command");
activated = false;
return;
}
float iconsize = 0.03f;
var mapContainer = LMUI.CreateElementContainer(LustyUI.Mini, "0 0 0 1", LustyUI.MiniMin, LustyUI.MiniMax);
LMUI.LoadImage(ref mapContainer, LustyUI.Mini, mapimage, "0 0", "1 1");
foreach (var marker in staticMarkers) {
var image = GetImage(marker.icon);
if (string.IsNullOrEmpty(image)) continue;
LMUI.LoadImage(ref mapContainer, LustyUI.Mini, image, $"{marker.x - iconsize} {marker.z - iconsize}", $"{marker.x + iconsize} {marker.z + iconsize}");
}
LustyUI.StaticMini = mapContainer;
Puts("[Warning] Mini map generated successfully!");
if (!MapSettings.complexmap) LustyUI.RenameComponents();
}
void CreateStaticComplex() {
Puts("[Warning] Generating the complex map.This may take a few moments, please wait!");
foreach (var mapslices in new List<int> {
6, 12, 26
}
) //, 32 })
{
for (int number = 0; number < (mapslices * mapslices);
number++) {
int rowNum = 0;
int colNum = 0;
if (number > mapslices - 1) {
colNum = Convert.ToInt32(Math.Floor((float)number / (float)mapslices));
rowNum = number - (colNum * mapslices);
}
else rowNum = number;
var mapContainer = LMUI.CreateElementContainer(LustyUI.Complex, "0 0 0 1", LustyUI.MiniMin, LustyUI.MiniMax);
string imageId = GetImage($"map-{mapslices}-{rowNum}-{colNum}");
if (!string.IsNullOrEmpty(imageId)) LMUI.LoadImage(ref mapContainer, LustyUI.Complex, imageId, $"0 0", $"1 1");
else {
PrintError($"Missing map piece (Slices: {mapslices}, Column: {colNum}, Row: {rowNum}).When the plugin is splitting the map you must wait for it to finish otherwise the split will not complete and this error will occur");
PrintError($"Creating a new load order with ImageLibrary");
LoadImages();
LoadMapImage();
return;
}
double width = ((double)1 / (double)mapslices);
float iconsize = 0.03f;
var column = colNum;
var row = rowNum;
if (column < 1) column = 1;
if (column > mapslices - 2) column = mapslices - 2;
if (row < 1) row = 1;
if (row > mapslices - 2) row = mapslices - 2;
double colStart = (width * column) - width;
double colEnd = colStart + (width * 3);
double rowStart = 1 - ((width * row) - width);
double rowEnd = (rowStart - (width * 3));
foreach (var marker in staticMarkers) {
string markerId = GetImage(marker.icon);
if (string.IsNullOrEmpty(markerId)) continue;
float x = marker.x;
float z = marker.z;
if ((x > colStart && x < colEnd) && (z > rowEnd && z < rowStart)) {
var average = 1 / (colEnd - colStart);
double posX = (x - colStart) * average;
double posZ = (z - rowEnd) * average;
LMUI.LoadImage(ref mapContainer, LustyUI.Complex, markerId, $"{posX - iconsize} {posZ - iconsize}", $"{posX + iconsize} {posZ + iconsize}");
}
}
int zoom = CountToZoom(mapslices);
if (!LustyUI.StaticComplex.ContainsKey(zoom)) LustyUI.StaticComplex.Add(zoom, new CuiElementContainer[mapslices, mapslices]);
LustyUI.StaticComplex[zoom][colNum, rowNum] = mapContainer;
}
}
Puts("[Warning] Complex map generated successfully!");
LustyUI.RenameComponents();
}
static int ZoomToCount(int zoom) {
switch (zoom) {
case 1 : return 6;
case 2 : return 12;
case 3 : return 26;
case 4 : return 32;
default : return 0;
}
}
static int CountToZoom(int count) {
switch (count) {
case 6 : return 1;
case 12 : return 2;
case 26 : return 3;
case 32 : return 4;
default : return 0;
}
}
#endregion
#region Maps
void ActivateMaps() {
foreach (var player in BasePlayer.activePlayerList) OnPlayerConnected(player);
}
void AddMapCompass(BasePlayer player, ref CuiElementContainer mapContainer, string panel, int fontsize, string offsetMin, string offsetMax) {
string direction = null;
if (player?.eyes?.rotation == null) return;
float lookRotation = player?.eyes?.rotation.eulerAngles.y ?? 0;
int playerdirection = (Convert.ToInt16((lookRotation - 5) / 10 + 0.5) * 10);
if (lookRotation >= 355) playerdirection = 0;
if (lookRotation > 337.5 || lookRotation < 22.5) {
direction = msg("cpsN");
}
else if (lookRotation > 22.5 && lookRotation < 67.5) {
direction = msg("cpsNE");
}
else if (lookRotation > 67.5 && lookRotation < 112.5) {
direction = msg("cpsE");
}
else if (lookRotation > 112.5 && lookRotation < 157.5) {
direction = msg("cpsSE");
}
else if (lookRotation > 157.5 && lookRotation < 202.5) {
direction = msg("cpsS");
}
else if (lookRotation > 202.5 && lookRotation < 247.5) {
direction = msg("cpsSW");
}
else if (lookRotation > 247.5 && lookRotation < 292.5) {
direction = msg("cpsW");
}
else if (lookRotation > 292.5 && lookRotation < 337.5) {
direction = msg("cpsNW");
}
LMUI.CreateLabel(ref mapContainer, panel, "", $"<size={fontsize + 4}>{direction}</size> \n{player.transform.position}", fontsize, offsetMin, offsetMax, TextAnchor.UpperCenter);
}
void AddMapButtons(BasePlayer player) {
float startx = 0f + configData.MiniMap.OffsetSide;
float endx = startx + (0.13f * configData.MiniMap.HorizontalScale);
float endy = 1f - configData.MiniMap.OffsetTop;
float starty = endy - (0.2301f * configData.MiniMap.VerticalScale);
string b_text = "<<<";
var container = LMUI.CreateElementContainer(LustyUI.Buttons, "0 0 0 0", $"{endx + 0.001f} {starty}", $"{endx + 0.02f} {endy}");
if (!configData.MiniMap.OnLeftSide) {
endx = 1 - configData.MiniMap.OffsetSide;
startx = endx - (0.13f * configData.MiniMap.HorizontalScale);
b_text = ">>>";
container = LMUI.CreateElementContainer(LustyUI.Buttons, "0 0 0 0", $"{startx - 0.02f} {starty}", $"{startx - 0.001f} {endy}");
}
LMUI.CreateButton(ref container, LustyUI.Buttons, LustyUI.Color("696969", 0.6f), b_text, 12, $"0 0.9", $"1 1", "LMUI_Control shrink");
if (MapSettings.complexmap && !MapSettings.forcedzoom) {
LMUI.CreateButton(ref container, LustyUI.Buttons, LustyUI.Color("696969", 0.6f), "+", 14, $"0 0.79", $"1 0.89", "LMUI_Control zoomin");
LMUI.CreateButton(ref container, LustyUI.Buttons, LustyUI.Color("696969", 0.6f), "-", 14, $"0 0.68", $"1 0.78", "LMUI_Control zoomout");
}
CuiHelper.DestroyUi(player, LustyUI.Buttons);
CuiHelper.AddUi(player, container);
}
void CreateShrunkUI(BasePlayer player) {
var user = GetUser(player);
if (user == null) return;
float b_endy = 0.999f - configData.MiniMap.OffsetTop;
float b_startx = 0.001f + configData.MiniMap.OffsetSide;
float b_endx = b_startx + 0.02f;
string b_text = ">>>";
if (!configData.MiniMap.OnLeftSide) {
b_endx = 0.999f - configData.MiniMap.OffsetSide;
b_startx = b_endx - 0.02f;
b_text = "<<<";
}
var container = LMUI.CreateElementContainer(LustyUI.Buttons, "0 0 0 0", $"{b_startx} {b_endy - 0.025f}", $"{b_endx} {b_endy}");
LMUI.CreateButton(ref container, LustyUI.Buttons, LustyUI.Color("696969", 0.6f), b_text, 12, "0 0", "1 1", "LMUI_Control expand");
CuiHelper.DestroyUi(player, LustyUI.Buttons);
CuiHelper.AddUi(player, container);
}
#region Standard Maps
void OpenMainMap(BasePlayer player) => LustyUI.AddBaseUI(player, MapMode.Main);
void OpenMiniMap(BasePlayer player) => LustyUI.AddBaseUI(player, MapMode.Minimap);
void UpdateOverlay(BasePlayer player, string panel, string posMin, string posMax, float iconsize) {
var mapContainer = LMUI.CreateElementContainer(panel, "0 0 0 0", posMin, posMax);
var user = GetUser(player);
if (user == null) return;
foreach (var marker in customMarkers) {
var image = GetImage(marker.Key);
if (string.IsNullOrEmpty(image)) continue;
AddIconToMap(ref mapContainer, panel, image, marker.Value.name, iconsize * 1.25f, marker.Value.x, marker.Value.z);
}
foreach (var marker in temporaryMarkers) {
var image = GetImage(marker.Key);
if (string.IsNullOrEmpty(image)) continue;
AddIconToMap(ref mapContainer, panel, image, marker.Value.name, iconsize * 1.25f, marker.Value.x, marker.Value.z);
}
foreach (var entity in entityMarkers) {
if (entity.Value.type == AEType.Car && (entity.Value.entity as BasicCar).IsMounted()) continue;
var marker = entity.Value.GetMarker();
if (marker == null) continue;
var image = GetImage(marker.icon);
if (string.IsNullOrEmpty(image)) continue;
AddIconToMap(ref mapContainer, panel, image, "", entity.Value.type == AEType.Vending ? iconsize : iconsize * 1.4f, marker.x, marker.z);
}
if (user.IsAdmin || MapSettings.allplayers) {
foreach (var mapuser in mapUsers) {
if (mapuser.Key == player.UserIDString) continue;
var marker = mapuser.Value.GetMarker();
if (marker == null) continue;
var image = GetImage($"other{marker.r}");
if (string.IsNullOrEmpty(image)) continue;
AddIconToMap(ref mapContainer, panel, image, marker.name, iconsize * 1.25f, marker.x, marker.z);
}
}
else if (MapSettings.friends) {
foreach (var friendId in user.friendList) {
if (friendId == player.UserIDString) continue;
if (mapUsers.ContainsKey(friendId)) {
var friend = mapUsers[friendId];
if (friend.InEvent() && configData.Map.HideEventPlayers) continue;
var marker = friend.GetMarker();
if (marker == null) continue;
var image = GetImage($"friend{marker.r}");
if (string.IsNullOrEmpty(image)) continue;
AddIconToMap(ref mapContainer, panel, image, marker.name, iconsize * 1.25f, marker.x, marker.z);
}
}
}
if (MapSettings.player) {
var selfMarker = user.GetMarker();
if (selfMarker != null) {
var selfImage = GetImage($"self{selfMarker.r}");
AddIconToMap(ref mapContainer, panel, selfImage, "", iconsize * 1.25f, selfMarker.x, selfMarker.z);
}
}
if (panel == LustyUI.MainOverlay) {
LMUI.CreateButton(ref mapContainer, panel, LustyUI.Color("88a8b6", 1), "X", 14, "0.95 0.961", "0.999 0.999", "LMUI_Control map");
if (MapSettings.compass) AddMapCompass(player, ref mapContainer, panel, 14, "0.75 0.88", "1 0.95");
}
if (panel == LustyUI.MiniOverlay) {
if (MapSettings.compass) AddMapCompass(player, ref mapContainer, panel, 10, "0 -0.25", "1 -0.02");
}
CuiHelper.DestroyUi(player, panel);
CuiHelper.AddUi(player, mapContainer);
}
void AddIconToMap(ref CuiElementContainer mapContainer, string panel, string image, string name, float iconsize, float posX, float posZ) {
if (posX < iconsize || posX > 1 - iconsize || posZ < iconsize || posZ > 1 - iconsize) return;
LMUI.LoadImage(ref mapContainer, panel, image, $"{posX - iconsize} {posZ - iconsize}", $"{posX + iconsize} {posZ + iconsize}");
if (MapSettings.names) LMUI.CreateLabel(ref mapContainer, panel, "", name, 10, $"{posX - 0.1} {posZ - iconsize - 0.025}", $"{posX + 0.1} {p
// ... [Code preview truncated due to length. Full source in attached file] ...