Иконка ресурса

FREE MarkerTeleport : 1.0.0 1.0.0

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using Oxide.Core;
using ProtoBuf;
using UnityEngine;

namespace Oxide.Plugins
{
  [Info("MarkerTeleport", "Choanie", "1.0.0")]
  [Description("Teleports players to their own map marker, with a teleport effect and auto-destruction of the marker used")]
  public class MarkerTeleport : RustPlugin
  {
    #region Fields

    private Configuration _config;
    private HashSet<ulong> _enabled;

    private const string DataFile = "MarkerTeleport_enabled";

    #endregion

    #region Config

    protected override void LoadDefaultConfig() => _config = Configuration.Default();

    protected override void LoadConfig()
    {
      base.LoadConfig();
      try
      {
        _config = Config.ReadObject<Configuration>();
        if (_config == null) throw new Exception();
      }
      catch
      {
        PrintWarning("Config file is corrupt or missing, creating a new one.");
        LoadDefaultConfig();
      }

      SaveConfig();
    }

    protected override void SaveConfig() => Config.WriteObject(_config);

    private class Configuration
    {
      public bool DestroyMarkerOnTeleport = true;
      public float DestroyMarkerDelaySeconds = 0.3f;

      public bool PlayVfx = true;
      public bool PlaySfx = true;
      public string TeleportDepartEffectPrefab = "assets/prefabs/missions/portal/proceduraldungeon/effects/disappear.prefab";
      public string TeleportArriveEffectPrefab = "assets/prefabs/missions/portal/proceduraldungeon/effects/appear.prefab";

      public float FlyhackPauseSeconds = 10f;

      public static Configuration Default() => new();
    }

    #endregion

    #region Data persistence

    private void LoadData()
    {
      try
      {
        _enabled = Interface.Oxide.DataFileSystem.ReadObject<HashSet<ulong>>(DataFile);
        if (_enabled == null) throw new Exception();
      }
      catch
      {
        _enabled = new();
      }
    }

    private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(DataFile, _enabled);

    #endregion

    #region Lifecycle

    private void Init()
    {
      LoadData();
    }

    private void OnServerInitialized()
    {
      foreach (var player in BasePlayer.activePlayerList)
        EnsureAdminDefault(player);
    }

    private void OnPlayerConnected(BasePlayer player) => EnsureAdminDefault(player);

    private void EnsureAdminDefault(BasePlayer player)
    {
      if (player == null || !player.IsAdmin) return;
      if (_enabled.Add(player.userID)) SaveData();
    }

    #endregion

    #region Commands

    [ChatCommand("tpm")]
    private void TpmCommand(BasePlayer player, string command, string[] args)
    {
      if (!player.IsAdmin)
      {
        player.ChatMessage("You don't have permission to use this command.");
        return;
      }

      if (_enabled.Add(player.userID))
      {
        SaveData();
        player.ChatMessage("MarkerTeleport enabled — placing a map marker will teleport you to it.");
        return;
      }

      _enabled.Remove(player.userID);
      SaveData();
      player.ChatMessage("MarkerTeleport disabled.");
    }

    #endregion

    #region Marker teleport

    private void OnMapMarkerAdded(BasePlayer player, MapNote note)
    {
      if (player == null || note == null) return;
      if (player.isMounted || !player.IsAlive()) return;
      if (!player.IsAdmin || !_enabled.Contains(player.userID)) return;

      TeleportToMarker(player, note);
    }

    private void TeleportToMarker(BasePlayer player, MapNote note)
    {
      var origin = player.transform.position;
      var destination = ResolveGroundPosition(note.worldPosition);

      player.PauseFlyHackDetection(_config.FlyhackPauseSeconds);
      player.Teleport(destination);
      player.UpdateNetworkGroup();
      player.SendCompleteSnapshot();

      if (_config.PlayVfx || _config.PlaySfx) PlayTeleportEffect(origin, destination);
      if (_config.DestroyMarkerOnTeleport)
        timer.Once(_config.DestroyMarkerDelaySeconds, () => DestroyMarker(player, note));
    }

    private static readonly int GroundLayerMask = LayerMask.GetMask("Terrain", "World", "Construction", "Deployed", "Debris");

    private static Vector3 ResolveGroundPosition(Vector3 target)
    {
      var castOrigin = target + Vector3.up * 200f;
      if (Physics.Raycast(castOrigin, Vector3.down, out var hit, 400f, GroundLayerMask, QueryTriggerInteraction.Ignore))
        return hit.point + Vector3.up * 0.5f;

      target.y = TerrainMeta.HeightMap.GetHeight(target);
      return target;
    }

    #endregion

    #region Effects

    private void PlayTeleportEffect(Vector3 origin, Vector3 destination)
    {
      if (!string.IsNullOrEmpty(_config.TeleportDepartEffectPrefab)) Effect.server.Run(_config.TeleportDepartEffectPrefab, origin);
      if (!string.IsNullOrEmpty(_config.TeleportArriveEffectPrefab)) Effect.server.Run(_config.TeleportArriveEffectPrefab, destination);
    }

    #endregion

    #region Marker destruction

    private void DestroyMarker(BasePlayer player, MapNote note)
    {
      try
      {
        if (player == null || !player.IsConnected) return;

        var notes = player.State?.pointsOfInterest;
        if (notes == null || !notes.Remove(note)) return;

        player.DirtyPlayerState();
        player.TeamUpdate();

        var mapNoteList = new MapNoteList { notes = new List<MapNote>() };
        if (player.ServerCurrentDeathNote != null) mapNoteList.notes.Add(player.ServerCurrentDeathNote);
        mapNoteList.notes.AddRange(notes);
        player.ClientRPC(RpcTarget.Player("Client_ReceiveMarkers", player), mapNoteList);
      }
      catch (Exception ex)
      {
        PrintWarning($"Failed to destroy marker after teleport: {ex}");
      }
    }

    #endregion
  }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху