C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Network;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
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.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using WebSocketSharp;
using static BuildingManager;
namespace Oxide.Plugins {
[Info("PocketDimensions", "Nikedemos", "1.0.8")]
[Description("It's bigger on the inside")]
public class PocketDimensions : RustPlugin {
private const string VERSION = "1.0.8";
[PluginReference]
private Plugin CopyPaste, NoEscape, ServerRewards, Economics;
public static PocketDimensions Instance;
#region CONST/STATIC
public const string PREFAB_FOUNDATION_SQUARE = "assets/prefabs/building core/foundation/foundation.prefab";
public const string PREFAB_FOUNDATION_TRIANGLE = "assets/prefabs/building core/foundation.triangle/foundation.triangle.prefab";
public const string PREFAB_FLOOR_SQUARE = "assets/prefabs/building core/floor/floor.prefab";
public const string PREFAB_FLOOR_FRAME = "assets/prefabs/building core/floor.frame/floor.frame.prefab";
public const string PREFAB_WALL = "assets/prefabs/building core/wall/wall.prefab";
public const string PREFAB_WALL_WINDOW = "assets/prefabs/building core/wall.window/wall.window.prefab";
public const string PREFAB_WALL_FRAME = "assets/prefabs/building core/wall.frame/wall.frame.prefab";
public const string PREFAB_WALL_DOORWAY = "assets/prefabs/building core/wall.doorway/wall.doorway.prefab";
public const string PREFAB_DOOR_METAL = "assets/prefabs/building/door.hinged/door.hinged.metal.prefab";
public const string PREFAB_TC = "assets/prefabs/deployable/tool cupboard/cupboard.tool.deployed.prefab";
public const string PREFAB_WOOD_STORAGE_BOX = "assets/prefabs/deployable/woodenbox/woodbox_deployed.prefab";
public const string PREFAB_BUNKER_PORTAL = "assets/prefabs/missions/portal/bunker_door_portal.prefab";
public const string PREFAB_MAPMARKER_GENERIC = "assets/prefabs/tools/map/genericradiusmarker.prefab";
public const string PREFAB_BUILD_EFFECT = "assets/bundled/prefabs/fx/build/frame_place.prefab";
//specific to doorway
public const string SOCKET_NAME_WALL_DOORWAY_DOORWAY_FEMALE_1 = "wall.doorway/sockets/doorway-female/1";
public const string SOCKET_NAME_WALL_DOORWAY_DOORWAY_FEMALE_2 = "wall.doorway/sockets/doorway-female/2";
//specific to wall frame
public const string SOCKET_NAME_WALL_FRAME_FRAME_FEMALE_1 = "wall.frame/sockets/frame-female/1";
public const string SOCKET_NAME_WALL_FRAME_FRAME_FEMALE_2 = "wall.frame/sockets/frame-female/2";
//specific to window frame
public const string SOCKET_NAME_WALL_WINDOW_WINDOW_FEMALE_1 = "wall.window/sockets/window-female/1";
public const string SOCKET_NAME_WALL_WINDOW_WINDOW_FEMALE_2 = "wall.window/sockets/window-female/2";
public const string SOCKET_NAME_WALL_WINDOW_SHUTTERS_FEMALE_1 = "wall.window/sockets/shutters-female/1";
public const string SOCKET_NAME_WALL_WINDOW_SHUTTERS_FEMALE_2 = "wall.window/sockets/shutters-female/2";
public const string SOCKET_NAME_WALL_WINDOW_DRESSING_FEMALE_1 = "wall.window/sockets/dressing-female/1";
public const string SOCKET_NAME_WALL_WINDOW_DRESSING_FEMALE_2 = "wall.window/sockets/dressing-female/2";
//specific to floor frame
public const string SOCKET_NAME_FLOOR_FRAME_FRAME_FEMALE_1 = "floor.frame/sockets/frame-female/1";
public const string SOCKET_NAME_FLOOR_FRAME_FRAME_FEMALE_2 = "floor.frame/sockets/frame-female/2";
public const string SOCKET_NAME_FLOOR_FRAME_FRAME_FEMALE_3 = "floor.frame/sockets/frame-female/3";
public const string SOCKET_NAME_FLOOR_FRAME_FRAME_FEMALE_4 = "floor.frame/sockets/frame-female/4";
public const string FX_CODELOCK = "assets/prefabs/locks/keypad/effects/lock.code.shock.prefab";
public const string FX_TELEPORT_APPEAR = "assets/prefabs/missions/portal/proceduraldungeon/effects/appear.prefab";
public const string FX_TELEPORT_DISAPPEAR = "assets/prefabs/missions/portal/proceduraldungeon/effects/disappear.prefab";
public const string ITEM_SHORTNAME_WOOD_STORAGE_BOX = "box.wooden";
public static ItemDefinition ItemDefinitionWoodStorageBox;
public static readonly BaseEntity.Flags FLAG_INTERNAL = BaseEntity.Flags.Reserved7;
public static readonly BaseEntity.Flags FLAG_INDESTRUCTIBLE = BaseEntity.Flags.Reserved9;
public static readonly BaseEntity.Flags FLAG_SPECIFIC = BaseEntity.Flags.OnFire;
//used to mark middle foundations and external doorway
public static readonly BasePlayer.PlayerFlags FLAG_IMMUNE_AFTER_TELEPORT = BasePlayer.PlayerFlags.Unused1;
public static readonly BasePlayer.PlayerFlags FLAG_TOAST_TIMEOUT = BasePlayer.PlayerFlags.Unused2;
public const string PREFIX_SHORT = "pd.";
public const string PREFIX_LONG = "pocketdimensions.";
public const string CMD_CHECK = PREFIX_SHORT + "check";
public const string CMD_CONVERT = PREFIX_SHORT + "convert";
public const string CMD_GIVE_BOX = PREFIX_SHORT + "givebox";
public const string CMD_LOST_FOUND = PREFIX_SHORT + "lostnfound";
public const string CMD_LIST = PREFIX_SHORT + "list";
public const string CMD_LIST_ARG_RECLAIM_ITEM = "reclaim_item";
public const string CMD_LIST_ARG_TP_TO_PORTAL = "tp_to_portal";
public const string CMD_LIST_ARG_TP_TO_BOX = "tp_to_box";
public const string CMD_LIST_ARG_KILL_DIMENSION = "kill_dimension";
public const string CMD_LIST_ARG_PLAYER_INFO = "player_info";
public const string CMD_LIST_USAGE_PART_1 = "Please provide a valid dimension number followed by one of these options: ";
public const string CMD_LIST_USAGE_PART_2 = CMD_LIST_ARG_PLAYER_INFO + ", " + CMD_LIST_ARG_TP_TO_BOX + ", " + CMD_LIST_ARG_TP_TO_PORTAL + ", " + CMD_LIST_ARG_RECLAIM_ITEM + ", " + CMD_LIST_ARG_KILL_DIMENSION;
public const string CMD_LIST_USAGE_FULL = CMD_LIST_USAGE_PART_1 + CMD_LIST_USAGE_PART_2;
public const string CMD_LIST_REQUIRES_PLAYER = "This option requires executing of the `" + CMD_LIST + "` command as a player in-game, from chat or F1 console, it cannot be invoked from RCON.";
public const string CMD_EMERGENCY_CLEANUP = PREFIX_SHORT + "emergencycleanup";
public const string CMD_REPLACE = PREFIX_SHORT + "replace";
public const string PERM_ADMIN = PREFIX_LONG + "admin";
public const string PERM_REPLACE = PREFIX_LONG + "replace";
public const string PERM_ALL = PREFIX_LONG + "player.all";
public const string PERM_DEPLOY_PICKUP = PREFIX_LONG + "deploy.pickup";
public const string PERM_ENTER_EXIT = PREFIX_LONG + "player.enter.exit";
public const string PERM_CONVERT_TC = PREFIX_LONG + "player.convert";
public const string PERM_RESPAWN_IN_POCKET = PREFIX_LONG + "player.respawn";
public const ulong SKIN_WATERBASE_TC = 1337424002;
public static bool Unloading = false;
public const int BREAK_TOASTS_EVERY_N_CHARACTERS = 80;
public static Dictionary<string, string> ToastsCached;
public static readonly Vector3 OFFSET_TC_POS_SIZE_1 = new Vector3(0F, 0.08F, -1F);
public static readonly Vector3 OFFSET_PORTAL_POS_SIZE_1 = new Vector3(0F, 1F, 1.5F);
public static readonly Vector3 OFFSET_PORTAL_ROT_SIZE_1 = new Vector3(270F, 0F, 0F);
public const byte LAYER_VEHICLE_WORLD = 15;
public const byte LAYER_DEFAULT = 0;
public const byte LAYER_PLAYER = 17;
public const byte LAYER_DEBRIS = 26;
public const byte LAYER_DEPLOYED = 8;
public const byte LAYER_RAGDOLL = 9;
public const byte LAYER_AI = 11;
public const byte LAYER_CONSTRUCTION = 21;
public const byte LAYER_CONSTRUCTION_SOCKET = 22;
public const byte LAYER_CLUTTER = 25;
public const byte LAYER_WORLD = 16;
public const byte LAYER_PREVENT_BUILDING = 29;
public const int LAYERMASK_INTERESTING_ENTITIES = (1 << LAYER_VEHICLE_WORLD) | (1 << LAYER_DEFAULT) | (1 << LAYER_PLAYER) | (1 << LAYER_DEBRIS) | (1 << LAYER_DEPLOYED) | (1 << LAYER_RAGDOLL) | (1 << LAYER_AI) | (1 << LAYER_CONSTRUCTION) | (1 << LAYER_CONSTRUCTION_SOCKET) | (1 << LAYER_CLUTTER) | (1 << LAYER_WORLD) | (1 << LAYER_PREVENT_BUILDING);
public const uint PREFAB_ID_SMALL_WOODEN_BOX = 1560881570;
public const string KILL_PORTAL_REASON_BOX_KILLED = "BOX_KILLED";
public const string KILL_PORTAL_REASON_SHELLBLOCK_KILLED = "SHELL_KILLED";
public const string KILL_PORTAL_REASON_AWAKE_BUILDING_NOT_FOUND = "BUILDING_NULL";
public const string KILL_PORTAL_REASON_AWAKE_SHELLBLOCK_MISCOUNT = "SHELL_MICOUNT";
public const string KILL_PORTAL_REASON_AWAKE_MIDDLE_FOUNDATION_NULL = "MID_FLOOR_NULL";
public const string KILL_PORTAL_REASON_AWAKE_EXIT_DOORWAY_NULL = "EXIT_DOOR_NULL";
public const string KILL_PORTAL_REASON_PARENT_DIMENSION_KILLED = "PARENT_DIM_KILLED";
public const string KILL_PORTAL_REASON_MANUAL_ADMIN_CMD = "MANUAL_ADM_CMD";
public const string LOGFILE_PORTAL_KILLS_PREVENTED = "portal_kills_prevented";
public const string LOGFILE_PORTAL_KILLS_EXPECTED = "portal_kills_expected";
#endregion
#region HOOK SUBSCRIPTIONS
void OnServerInitialized() {
Instance = this;
KillPortalReasonLast = string.Empty;
lang.RegisterMessages(LangMessages, this);
permission.RegisterPermission(PERM_ADMIN, this);
permission.RegisterPermission(PERM_REPLACE, this);
permission.RegisterPermission(PERM_ALL, this);
permission.RegisterPermission(PERM_DEPLOY_PICKUP, this);
permission.RegisterPermission(PERM_ENTER_EXIT, this);
permission.RegisterPermission(PERM_CONVERT_TC, this);
permission.RegisterPermission(PERM_RESPAWN_IN_POCKET, this);
LoadConfigData();
ProcessConfigData();
AddCovalenceCommand(CMD_EMERGENCY_CLEANUP, nameof(CommandEmergencyCleanup), PERM_ADMIN);
AddCovalenceCommand(CMD_CONVERT, nameof(CommandConvert), PERM_ADMIN);
AddCovalenceCommand(CMD_CHECK, nameof(CommandViabilityCheck), PERM_ADMIN);
AddCovalenceCommand(CMD_GIVE_BOX, nameof(CommandGiveBox), PERM_ADMIN);
AddCovalenceCommand(CMD_LOST_FOUND, nameof(CommandLostFound), PERM_ADMIN);
AddCovalenceCommand(CMD_LIST, nameof(CommandList), PERM_ADMIN);
AddCovalenceCommand(CMD_REPLACE, nameof(CommandReplace));
//no perm here.checked inside.ItemDefinitionWoodStorageBox = ItemManager.FindItemDefinition(ITEM_SHORTNAME_WOOD_STORAGE_BOX);
SpawnedPasteRequest.RequestByPosition = new Dictionary<Vector3, SpawnedPasteRequest>();
ReusableCardinalDirectionPositions = new Vector3[4];
ReusableNeighbourPosTable = new Vector3[4][] {
new Vector3[8], new Vector3[8], new Vector3[8], new Vector3[8],
}
;
ReusableFloorList = new List<BuildingBlock>();
ReusableFoundationList = new List<BuildingBlock>();
ReusableCombinedWallAndDoorwayList = new List<BuildingBlock>();
ReusableShellElementList = new List<BuildingBlock>();
ReusableExtraBaseCombatEntities = new List<BaseCombatEntity>();
ReusableVisibilityList = new ListHashSet<BaseEntity>();
ReusableColBuffer = new Collider[2048];
ReusableCopypasteArgs = new string[] {
"autoheight", "false"
}
;
ReusableMatchFoundationToCeiling = new Dictionary<BuildingBlock, BuildingBlock>(9);
ReusableGatherItemAmountArray = new GatherItemAmount[512];
DimensionalBox.ServerCacheBox = new Dictionary<ulong, DimensionalBox>();
DimensionalPocket.ServerCachePortal = new Dictionary<ulong, DimensionalPocket>();
DimensionalPocket.ServerCacheShellBlockToPocket = new Dictionary<ulong, DimensionalPocket>();
DimensionalPocket.ServerCacheBuildingIDToPocket = new Dictionary<uint, DimensionalPocket>();
ToastsCached = new Dictionary<string, string>();
ExternalShellBlockReplacementsShortnameToFull = new Dictionary<string, string> {
[Path.GetFileNameWithoutExtension(PREFAB_WALL)]
= PREFAB_WALL, [Path.GetFileNameWithoutExtension(PREFAB_WALL_FRAME)] = PREFAB_WALL_FRAME, [Path.GetFileNameWithoutExtension(PREFAB_WALL_WINDOW)] = PREFAB_WALL_WINDOW, [Path.GetFileNameWithoutExtension(PREFAB_FLOOR_SQUARE)] = PREFAB_FLOOR_SQUARE, [Path.GetFileNameWithoutExtension(PREFAB_FLOOR_FRAME)] = PREFAB_FLOOR_FRAME,
}
;
//populate families...ExternalShellBlockReplacementFamilies = new ListHashSet<string>[]
{
//sides
new ListHashSet<string> {
PREFAB_WALL, PREFAB_WALL_FRAME, PREFAB_WALL_WINDOW
}
, //tops
new ListHashSet<string> {
PREFAB_FLOOR_SQUARE, PREFAB_FLOOR_FRAME
}
,
}
;
//and now from families to final replacements
ExternalShellBlockReplacements = new Dictionary<string, ListHashSet<string>>();
//for every family...for (var f = 0; f < ExternalShellBlockReplacementFamilies.Length; f++)
{
var family = ExternalShellBlockReplacementFamilies[f];
//and for every member of that family
for (var m = 0; m < family.Count; m++) {
var memberName = family[m];
var membersOtherMembers = new ListHashSet<string>();
//and for every member's other members
for (var o = 0; o < family.Count; o++) {
if (m == o) {
//not you.continue;
}
var otherMemberName = family[o];
membersOtherMembers.Add(otherMemberName);
}
ExternalShellBlockReplacements.Add(memberName, membersOtherMembers);
}
}
//and sockets to check
ExternalShellBlockReplacementsSocketsToCheck = new Dictionary<string, ListHashSet<string>>() {
[PREFAB_FLOOR_SQUARE]
= new ListHashSet<string>(), //empty, no sockets there to check
[PREFAB_WALL]
= new ListHashSet<string>(), //empty, no sockets to check there
[PREFAB_WALL_FRAME]
= new ListHashSet<string>() {
SOCKET_NAME_WALL_FRAME_FRAME_FEMALE_1, SOCKET_NAME_WALL_FRAME_FRAME_FEMALE_2
}
, [PREFAB_WALL_WINDOW] = new ListHashSet<string> {
SOCKET_NAME_WALL_WINDOW_DRESSING_FEMALE_1, SOCKET_NAME_WALL_WINDOW_SHUTTERS_FEMALE_1, SOCKET_NAME_WALL_WINDOW_WINDOW_FEMALE_1, SOCKET_NAME_WALL_WINDOW_DRESSING_FEMALE_2, SOCKET_NAME_WALL_WINDOW_SHUTTERS_FEMALE_2, SOCKET_NAME_WALL_WINDOW_WINDOW_FEMALE_2
}
, [PREFAB_FLOOR_FRAME] = new ListHashSet<string> {
SOCKET_NAME_FLOOR_FRAME_FRAME_FEMALE_1, SOCKET_NAME_FLOOR_FRAME_FRAME_FEMALE_2, SOCKET_NAME_FLOOR_FRAME_FRAME_FEMALE_3, SOCKET_NAME_FLOOR_FRAME_FRAME_FEMALE_4
}
,
}
;
Unloading = false;
DimensionalPlayer.PrepareStatic();
var findAllPortals = BaseNetworkable.serverEntities.OfType<BasePortal>().ToArray();
BasePortal candidatePortal;
for (var e = 0; e < findAllPortals.Length; e++) {
candidatePortal = findAllPortals[e];
if (!BaseNetworkableEx.IsValid(candidatePortal)) {
continue;
}
if (!IsEntityMarkedInternal(candidatePortal)) {
continue;
}
candidatePortal.gameObject.AddComponent<DimensionalPocket>();
}
var findAllStorageContainers = BaseNetworkable.serverEntities.OfType<StorageContainer>().ToArray();
StorageContainer candidateContainer;
for (var e = 0; e < findAllStorageContainers.Length; e++) {
candidateContainer = findAllStorageContainers[e];
if (!BaseNetworkableEx.IsValid(candidateContainer)) {
continue;
}
if (!IsEntityMarkedInternal(candidateContainer)) {
continue;
}
candidateContainer.gameObject.AddComponent<DimensionalBox>();
}
CheckAllLocks();
CheckAllVendingMachines();
ConversionGuiManager.Initialize();
PositionCheckResult.Reset();
foreach (var player in BasePlayer.activePlayerList) {
OnPlayerConnected(player);
}
}
public void CheckAllVendingMachines() {
if (Configuration.DimensionaPocketsAllowVendingMachineBroadcast) {
return;
}
var findAllVendingMachines = BaseNetworkable.serverEntities.OfType<VendingMachine>().ToArray();
VendingMachine candidateMachine;
for (var e = 0; e < findAllVendingMachines.Length; e++) {
candidateMachine = findAllVendingMachines[e];
OnEntitySpawned(candidateMachine);
}
}
public void CheckAllLocks() {
if (Configuration.DimensionalBoxesAllowLockingWithLocks) {
return;
}
var findAllLocks = BaseNetworkable.serverEntities.OfType<BaseLock>().ToArray();
BaseLock candidateLock;
for (var e = 0; e < findAllLocks.Length; e++) {
candidateLock = findAllLocks[e];
OnEntitySpawned(candidateLock);
}
}
void Unload() {
Unloading = true;
foreach (var player in BasePlayer.activePlayerList) {
ConversionGuiManager.PlayerHideAllUI(player);
}
ConversionGuiManager.Cleanup();
InternalBehaviour.DetachEverythingInternal();
DimensionalBox.ServerCacheBox = null;
DimensionalPocket.ServerCachePortal = null;
DimensionalPocket.ServerCacheShellBlockToPocket = null;
DimensionalPocket.ServerCacheBuildingIDToPocket = null;
ToastsCached = null;
ReusableNeighbourPosTable = null;
ReusableCardinalDirectionPositions = null;
ReusableFloorList = null;
ReusableFoundationList = null;
ReusableCombinedWallAndDoorwayList = null;
ReusableVisibilityList = null;
ReusableColBuffer = null;
ReusableCopypasteArgs = null;
ReusableMatchFoundationToCeiling = null;
ReusableGatherItemAmountArray = null;
ReusableShellElementList = null;
ReusableExtraBaseCombatEntities = null;
ItemDefinitionWoodStorageBox = null;
SpawnedPasteRequest.RequestByPosition = null;
DimensionalPlayer.UnloadStatic();
PositionCheckResult.Reset();
ExternalShellBlockReplacementsShortnameToFull = null;
ExternalShellBlockReplacementFamilies = null;
ExternalShellBlockReplacements = null;
ExternalShellBlockReplacementsSocketsToCheck = null;
Instance = null;
Unloading = false;
}
object OnPlayerCommand(BasePlayer player, string command, string[] args) {
if (Instance == null) {
return null;
}
if (!PositionWithinDimensionLayer(player.transform.position)) {
return null;
}
if (!Configuration.ForbiddenCommandsCheckingEnabled) {
return null;
}
if (Configuration.ForbiddenCommandsInsideDimensions.IsNullOrEmpty()) {
return null;
}
if (!Configuration.ForbiddenCommandsInsideDimensions.Contains(command)) {
return null;
}
if (HasAdminPermission(player)) {
return null;
}
ToastPlayer(player, MSG(MSG_COMMAND_FORBIDDEN_INSIDE, player.UserIDString, command));
return true;
}
//RemoverTool fix
object canRemove(BasePlayer player, StorageContainer container) {
if (container == null) {
return null;
}
if (container.PrefabName != PREFAB_WOOD_STORAGE_BOX) {
return null;
}
if (!IsEntityMarkedInternal(container)) {
return null;
}
return true;
//return non null
}
//TruePVE fix
object CanEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo) {
if (!BaseNetworkableEx.IsValid(entity)) {
return null;
}
if (hitInfo == null) {
return null;
}
if (!hitInfo.damageTypes.Has(Rust.DamageType.Generic)) {
return null;
}
if (Mathf.Abs(hitInfo.damageTypes.Get(Rust.DamageType.Generic) - SPECIAL_DAMAGE_AMOUNT) > 0.001F) {
return null;
}
return true;
}
void OnEntitySpawned(VendingMachine machine) {
if (Instance == null) {
return;
}
if (Instance.Configuration.DimensionaPocketsAllowVendingMachineBroadcast) {
//nothing to see here
return;
}
machine.Invoke(() => {
if (Instance == null) {
return;
}
if (machine == null) {
return;
}
if (!machine.IsBroadcasting()) {
return;
}
var buildingID = machine.buildingID;
if (buildingID == 0) {
return;
}
if (!DimensionalPocket.ServerCacheBuildingIDToPocket.ContainsKey(buildingID)) {
return;
}
machine.SetFlag(BaseEntity.Flags.Reserved4, false);
machine.UpdateMapMarker();
}
, 0.02F);
}
void OnToggleVendingBroadcast(VendingMachine machine, BasePlayer player) {
OnEntitySpawned(machine);
if (Instance == null) {
return;
}
if (Instance.Configuration.DimensionaPocketsAllowVendingMachineBroadcast) {
//nothing to see here
return;
}
if (!machine.IsBroadcasting()) {
return;
}
var buildingID = machine.buildingID;
if (buildingID == 0) {
return;
}
if (!DimensionalPocket.ServerCacheBuildingIDToPocket.ContainsKey(buildingID)) {
return;
}
ToastPlayer(player, MSG(MSG_NO_VENDING_MACHINE_BROADCASTING_IN_POCKETS, player.UserIDString));
}
object OnSleepingBagValidCheck(SleepingBag sleepingBag, ulong playerID, bool ignoreTimers) {
if (Instance == null) {
return null;
}
if (sleepingBag == null) {
return null;
}
var player = BasePlayer.FindByID(playerID);
if (player == null) {
return null;
}
var buildingID = sleepingBag.buildingID;
if (buildingID == 0) {
return null;
}
if (!DimensionalPocket.ServerCacheBuildingIDToPocket.ContainsKey(buildingID)) {
return null;
}
bool hasRespawnInPocketPermission = HasRespawnInPocketPermission(player);
//if both the permission is present, AND you CAN respawn inside without the box being deployed, no need to go further
if (hasRespawnInPocketPermission && !Configuration.DimensionalPocketsRespawningInsideRequiresDeployment) {
return null;
}
//check if the player had just respawned in a non-deployed pocket Dimension
object returnObject = null;
if (!hasRespawnInPocketPermission) {
returnObject = false;
}
else {
//check if the pocket is deployed
CheckPositionResultDeep(sleepingBag.transform.position);
if (PositionCheckResult.BottomPocketFound != null && !PositionCheckResult.PocketIsDeployed) {
returnObject = false;
ToastPlayer(player, MSG(MSG_CANT_RESPAWN_INSIDE_NON_DEPLOYED, player.UserIDString));
}
}
return returnObject;
}
void OnEntitySpawned(BaseLock baseLock) {
if (Instance == null) {
return;
}
if (Configuration.DimensionalBoxesAllowLockingWithLocks) {
return;
}
if (baseLock == null) {
return;
}
var lockOwnerThing = baseLock.parentEntity.Get(true) as StorageContainer;
if (lockOwnerThing == null) {
return;
}
if (lockOwnerThing.PrefabName != PREFAB_WOOD_STORAGE_BOX) {
return;
}
if (!IsEntityMarkedInternal(lockOwnerThing)) {
return;
}
DimensionalBox box;
if (!DimensionalBox.ServerCacheBox.TryGetValue(lockOwnerThing.net.ID.Value, out box)) {
return;
}
//drop the lock as an item
baseLock.Invoke(() => {
if (box == null) {
baseLock.Kill();
return;
}
if (box.ThisStorageContainer == null) {
baseLock.Kill();
return;
}
var item = ItemManager.Create(baseLock.itemType, 1, baseLock.skinID);
if (item != null) {
item.Drop(baseLock.transform.position, Vector3.zero, baseLock.transform.rotation);
}
if (baseLock.PrefabName.Contains("code")) {
Effect.server.Run(FX_CODELOCK, baseLock.transform.position, baseLock.transform.up);
}
baseLock.Kill();
}
, 0.01F);
}
public static string KillPortalReasonLast = string.Empty;
object OnEntityKill(BasePortal portal) {
//ignore non-internal portals from consideration, just let them through
if (!IsEntityMarkedInternal(portal)) {
return null;
}
//non-specific means "do not kill"
//specific means "yes kill, we're expecting it, there's also a reason for it"
if (!IsEntityMarkedSpecific(portal)) {
//thwart the attempt and log to file
LogToFile(LOGFILE_PORTAL_KILLS_PREVENTED, $"[{DateTime.Now}] Net.ID:{portal.net.ID}", this, false);
return true;
}
//log the killing
LogToFile(LOGFILE_PORTAL_KILLS_EXPECTED, $"[{DateTime.Now}] Net.ID:{portal.net.ID}; {KillPortalReasonLast} ", this, false);
return null;
}
object OnEntityKill(BuildingBlock buildingBlock) {
if (Instance == null) {
return null;
}
if (buildingBlock == null) {
return null;
}
if (!IsEntityMarkedInternal(buildingBlock)) {
return null;
}
DimensionalPocket pocket;
if (!DimensionalPocket.ServerCacheShellBlockToPocket.TryGetValue(buildingBlock.net.ID.Value, out pocket)) {
return null;
}
return pocket.OnShellBlockKilled(buildingBlock);
}
object CanBeTargeted(BasePlayer player, DecayEntity entity) {
if (Instance == null) {
return null;
}
if (player.HasPlayerFlag(FLAG_IMMUNE_AFTER_TELEPORT)) {
return false;
}
return null;
}
object OnItemPickup(Item item, BasePlayer player) {
if (Instance == null) {
return null;
}
if (!Instance.Configuration.DimensionalBoxesItemCheckTCAuthInsideWhenHandlingItem) {
return null;
}
if (item == null) {
return null;
}
if (player == null) {
return null;
}
if (!IsDimensionalBoxItem(item)) {
return null;
}
var pocket = TryGetDimensionalPocketFromNonNullItem(item);
if (pocket == null) {
return null;
}
if (pocket.IsPlayerBuildingBlockedOnFirstTcInsideIfThereIsAnyButOnlyIfAtLeast1Auth(player)) {
ToastPlayer(player, MSG(MSG_CANT_HANDLE_WITHOUT_TC_AUTH2, player.UserIDString));
return true;
}
return null;
}
private void OnPlayerDeath(BasePlayer player, HitInfo info) => OnPlayerMissingCommon(player);
private void OnPlayerDisconnected(BasePlayer player, string reason) => OnPlayerMissingCommon(player);
//not actually a hook
private void OnPlayerMissingCommon(BasePlayer player) {
if (Instance == null) {
return;
}
if (IsPlayerNPC(player)) {
return;
}
DimensionalPlayer dimensionalPlayer;
if (!DimensionalPlayer.ServerCachePlayer.TryGetValue(player.userID, out dimensionalPlayer)) {
return;
}
UnityEngine.Object.DestroyImmediate(dimensionalPlayer);
}
void OnPlayerSleepEnded(BasePlayer player) => OnPlayerConnected(player);
void OnPlayerConnected(BasePlayer player) {
if (Instance == null) {
return;
}
if (!Configuration.DimensionalPocketsTeleportingInsideRequiresDeployment) {
return;
}
if (IsPlayerNPC(player)) {
return;
}
DimensionalPlayer compo;
if (DimensionalPlayer.ServerCachePlayer.ContainsKey(player.userID)) {
compo = DimensionalPlayer.ServerCachePlayer[player.userID];
}
else {
compo = player.gameObject.AddComponent<DimensionalPlayer>();
}
compo.OnPlayerMajorUpdate(player);
}
object CanMoveItem(Item item, PlayerInventory playerLoot, ItemContainerId targetContainer, int targetSlot, int amount) {
//TODO: Test this
//ALso: don't allow the player to drop this if not authed.if (Instance == null)
{
return null;
}
if (!Instance.Configuration.DimensionalBoxesItemCheckTCAuthInsideWhenHandlingItem) {
return null;
}
if (item == null) {
return null;
}
if (!IsDimensionalBoxItem(item)) {
return null;
}
if (playerLoot == null) {
return null;
}
var player = playerLoot.GetComponent<BasePlayer>();
if (player == null) {
return null;
}
var pocket = TryGetDimensionalPocketFromNonNullItem(item);
if (pocket == null) {
return null;
}
if (pocket.IsPlayerBuildingBlockedOnFirstTcInsideIfThereIsAnyButOnlyIfAtLeast1Auth(player)) {
ToastPlayer(player, MSG(MSG_CANT_HANDLE_WITHOUT_TC_AUTH2, player.UserIDString));
return true;
}
return null;
}
object CanCombineDroppedItem(DroppedItem droppedItem, DroppedItem droppedTargetItem) {
if (Instance == null) {
return null;
}
if (droppedItem == null) {
return null;
}
if (droppedTargetItem == null) {
return null;
}
if (droppedItem.item == null) {
return null;
}
if (droppedTargetItem.item == null) {
return null;
}
if (!(IsDimensionalBoxItem(droppedItem.item) || IsDimensionalBoxItem(droppedItem.item))) {
return null;
}
return false;
}
/*
void OnItemRemove(Item item)
{
if (Instance == null)
{
return;
}
if (item == null)
{
return;
}
if (!IsDimensionalBoxItem(item))
{
return;
}
if (item.instanceData == null)
{
return;
}
var pocket = TryGetDimensionalPocketFromNonNullItem(item);
if (pocket == null)
{
return;
}
//MarkEntityAsSpecific(pocket.ThisPortal);
}*/
object OnPortalUse(BasePlayer player, BasePortal portal) {
if (Instance == null) {
return null;
}
if (player == null) {
return null;
}
if (!IsEntityMarkedInternal(portal)) {
return null;
}
DimensionalPocket pocket;
if (!DimensionalPocket.ServerCachePortal.TryGetValue(portal.net.ID.Value, out pocket)) {
return null;
}
if (!HasEnterExitPermission(player)) {
ToastPlayer(player, MSG(MSG_NO_PERMISSION_ENTER_EXIT, player.UserIDString));
return true;
}
if (Instance.Configuration.CheckEscapeBlockWhenExitingDimensions) {
if (IsEscapeBlocked(player)) {
ToastPlayer(player, MSG(MSG_ESCAPE_BLOCKED_CANT_EXIT, player.UserIDString));
return true;
}
}
pocket.PlayerUsePortal(player);
//return non null
return true;
}
object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
if (Instance == null) {
return null;
}
if (info == null) {
return null;
}
if (!IsEntityMarkedInternal(entity)) {
return null;
}
//always let decay damage through
if (info.damageTypes.GetMajorityDamageType() == Rust.DamageType.Decay) {
return null;
}
if (!Configuration.DimensionalPocketsExteriorBlocksAllowNonDecayDamage) {
if (DimensionalPocket.ServerCacheShellBlockToPocket.ContainsKey(entity.net.ID.Value)) {
return true;
}
}
if (!IsEntityMarkedIndestructible(entity)) {
return null;
}
//is this a box?...if (DimensionalBox.ServerCacheBox.ContainsKey(entity.net.ID.Value))
{
if (!Configuration.DimensionalBoxesAllowDamage) {
return true;
}
else {
//adjust the damage
info.damageTypes.ScaleAll(1F / Mathf.Max(0.001F, Configuration.DimensionaBoxesDamageResistanceDivisor));
return null;
}
}
return null;
}
void OnLootEntity(BasePlayer player, BuildingPrivlidge tc) {
if (Instance == null) {
return;
}
if (player == null) {
return;
}
if (!HasConvertTCPermission(player)) {
return;
}
if (tc.buildingID == 0) {
return;
}
if (IsTCWaterBaseTC(tc)) {
return;
}
//is it already converted?
if (DimensionalPocket.ServerCacheBuildingIDToPocket.ContainsKey(tc.buildingID)) {
return;
}
ConversionGuiManager.PlayerOpenTC(player, tc);
}
void OnLootEntityEnd(BasePlayer player, BuildingPrivlidge tc) {
if (Instance == null) {
return;
}
if (player == null) {
return;
}
if (IsTCWaterBaseTC(tc)) {
return;
}
ConversionGuiManager.PlayerHideAllUI(player);
}
object CanLootEntity(BasePlayer player, StorageContainer container) {
if (Instance == null) {
return null;
}
if (player == null) {
return null;
}
if (container == null) {
return null;
}
if (container.PrefabName != PREFAB_WOOD_STORAGE_BOX) {
return null;
}
if (!IsEntityMarkedInternal(container)) {
return null;
}
DimensionalBox box;
if (!DimensionalBox.ServerCacheBox.TryGetValue(container.net.ID.Value, out box)) {
return null;
}
if (!HasEnterExitPermission(player)) {
ToastPlayer(player, MSG(MSG_NO_PERMISSION_ENTER_EXIT, player.UserIDString));
return true;
}
if (Instance.Configuration.CheckEscapeBlockWhenEnteringDimensions) {
if (IsEscapeBlocked(player)) {
ToastPlayer(player, MSG(MSG_CANT_ENTER_ESCAPE_BLOCKED, player.UserIDString));
return true;
}
}
if (Instance.Configuration.DimensionalBoxesCheckBuildingBlockOutsideWhenEnteringDimension) {
if (player.IsBuildingBlocked()) {
ToastPlayer(player, MSG(MSG_CANT_ENTER_BUILDING_BLOCKED, player.UserIDString));
return true;
}
}
if (Instance.Configuration.DimensionalBoxesCheckTCAuthInsideWhenEnteringDimension) {
if (box.PairedPocket.IsPlayerBuildingBlockedOnFirstTcInsideIfThereIsAnyButOnlyIfAtLeast1Auth(player)) {
ToastPlayer(player, MSG(MSG_CANT_ENTER_WITHOUT_TC_AUTH2, player.UserIDString));
return true;
}
}
if (container.IsLocked()) {
player.ShowToast(GameTip.Styles.Red_Normal, StorageContainer.LockedMessage);
return true;
}
;
if (!container.CanOpenLootPanel(player, container.panelName)) {
return true;
}
;
box.PlayerOpenedBox(player);
//return non null
return true;
}
object CanBuild(Planner planner, Construction prefab, Construction.Target target) {
if (Instance == null) {
return null;
}
if (prefab.prefabID != PREFAB_ID_SMALL_WOODEN_BOX) {
return null;
}
var player = planner.GetOwnerPlayer();
if (player == null) {
return null;
}
//ok, it's a small box.have you verified the item or what...?
var item = planner.GetItem();
//looking for existing and fresh
bool isExisting = IsDimensionalBoxItem(item);
bool isFresh = IsDimensionalBoxItem(item, true);
if (!(isExisting || isFresh)) {
return null;
}
//now player!
if (!HasDeployPickupPermission(player)) {
ToastPlayer(player, MSG(MSG_NO_PERM_DEPLOY_PICKUP, player.UserIDString));
return true;
}
if (Instance.Configuration.CheckEscapeBlockWhenDeployingDimensions) {
if (IsEscapeBlocked(player)) {
ToastPlayer(player, MSG(MSG_ESCAPE_BLOCKED_CANT_DEPLOY, player.UserIDString));
return true;
}
}
var targetPosition = target.entity && target.entity.transform && target.socket ? target.GetWorldPosition() : target.position;
DimensionalPocket itemDimension = null;
bool itemDimensionNotNull = false;
if (isExisting) {
var pocket = TryGetDimensionalPocketFromNonNullItem(item);
if (pocket != null) {
itemDimension = pocket;
itemDimensionNotNull = true;
}
}
CheckPositionResultDeep(targetPosition, itemDimension);
//now check for any problems.//first, cannot deploy in itself.if (PositionCheckResult.BottomPocketFound != null)
{
if (Instance.Configuration.DimensionalPocketsMaxInceptionDepth == 0) {
ToastPlayer(player, MSG(MSG_CANT_DEPLOY_DIMENSIONS_INSIDE_DIMENSIONS, player.UserIDString));
return true;
}
//ok, we're trying to deploy a dimension inside a dimension.if (itemDimensionNotNull)
{
//are you trying to deploy in yourself?!
//check if you short circuited
if (PositionCheckResult.ShortCircuitDetected) {
ToastPlayer(player, MSG(MSG_CANT_DEPLOY_SHORT_CIRCUIT, player.UserIDString));
return true;
}
if (itemDimension == PositionCheckResult.BottomPocketFound) {
ToastPlayer(player, MSG(MSG_CANT_DEPLOY_IN_ITSELF, player.UserIDString));
return true;
//return non null
}
//what about deploying in undeployed dimensions?!
//should that be a config value?
}
//for depth, new dimensions should be checked too!
if (PositionCheckResult.NoMoreDepthAllowed) {
ToastPlayer(player, MSG(MSG_CANT_DEPLOY_TOO_DEEP, player.UserIDString, Instance.Configuration.DimensionalPocketsMaxInceptionDepth));
return true;
}
}
return null;
}
void OnEntityBuilt(Planner planner, GameObject gameObject) {
if (Instance == null) {
return;
}
var maybeDimensionalBoxItem = planner.GetItem();
if (maybeDimensionalBoxItem == null) {
return;
}
var maybeStorage = gameObject.GetComponent<StorageContainer>();
if (maybeStorage == null) {
return;
}
//here, only non-fresh matter
if (!IsDimensionalBoxItem(maybeDimensionalBoxItem)) {
return;
}
MarkEntityAsIndestructible(maybeStorage);
MarkEntityAsInternal(maybeStorage);
var newDimensionalBox = maybeStorage.gameObject.AddComponent<DimensionalBox>();
if (!newDimensionalBox.TryBuildFromItem(maybeDimensionalBoxItem)) {
var player = planner.GetOwnerPlayer();
if (player == null) {
return;
}
ToastPlayer(player, MSG(MSG_DIMENSION_DOESNT_EXIST, player.UserIDString));
maybeStorage.Invoke(() => maybeStorage.Kill(BaseNetworkable.DestroyMode.Gib), 0.01F);
}
}
object CanPickupEntity(BasePlayer player, StorageContainer entity) {
if (Instance == null) {
return null;
}
if (player == null) {
return null;
}
if (!IsEntityMarkedInternal(entity)) {
return null;
}
DimensionalBox box;
if (!DimensionalBox.ServerCacheBox.TryGetValue(entity.net.ID.Value, out box)) {
return null;
}
if (!HasDeployPickupPermission(player)) {
ToastPlayer(player, MSG(MSG_NO_PERM_DEPLOY_PICKUP, player.UserIDString));
return false;
}
if (Instance.Configuration.CheckEscapeBlockWhenPickingUpDimensions) {
if (IsEscapeBlocked(player)) {
ToastPlayer(player, MSG(MSG_ESCAPE_BLOCKED_CANT_PICKUP, player.UserIDString));
return false;
}
}
var res = box.CanPickupBox(player);
return res;
}
void OnEntityPickedUp(StorageContainer container, Item createdItem, BasePlayer player) {
if (Instance == null) {
return;
}
if (container.PrefabName != PREFAB_WOOD_STORAGE_BOX) {
return;
}
if (!IsEntityMarkedInternal(container)) {
return;
}
DimensionalBox box;
if (!DimensionalBox.ServerCacheBox.TryGetValue(container.net.ID.Value, out box)) {
return;
}
box.OnPickedUp(createdItem, player);
}
#endregion
#region DIMENSIONAL PLAYER
public class DimensionalPlayer : InternalBehaviour {
public static Hash<ulong, DimensionalPlayer> ServerCachePlayer;
public BasePlayer Player;
public ulong SteamID;
public Vector3 LastCheckedPosition;
public bool WasFlyingLastTimeChecked;
public static void PrepareStatic() {
ServerCachePlayer = new Hash<ulong, DimensionalPlayer>();
}
public static void UnloadStatic() {
ServerCachePlayer = null;
}
public void OnPlayerMajorUpdate(BasePlayer player) {
Player = player;
SteamID = Player.use
// ... [Code preview truncated due to length. Full source in attached file] ...