C#:
using Rust;
using System;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Plugins.ShipwreckExtensionMethods;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using CompanionServer.Handlers;
using UnityEngine;
using Time = UnityEngine.Time;
namespace Oxide.Plugins {
[Info("Shipwreck", "Adem", "1.4.3")]
class Shipwreck : RustPlugin {
#region API
private bool IsShipwreckCrate(StorageContainer crate) {
if (eventController == null || crate == null || crate.net == null) return false;
return LootManager.GetContainerDataByNetId(crate.net.ID.Value) != null;
}
#endregion API
#region Variables
const bool en = false;
static Shipwreck ins;
[PluginReference]
Plugin NpcSpawn, Notify, GUIAnnouncements, DiscordMessages, PveMode, Economics, ServerRewards, IQEconomic, DynamicPVP;
HashSet<string> subscribeMetods = new HashSet<string> {
"OnEntitySpawned", "OnCorpsePopulate", "OnEntityTakeDamage", "CanMountEntity", "OnEntityMounted", "CanExplosiveStick", "CanBuild", "CanAffordUpgrade", "OnStructureRotate", "OnDoorOpened", "OnCardSwipe", "OnEntityDeath", "CanHackCrate", "OnPlayerSleep", "OnDispenserGather", "OnDispenserBonus", "CanEntityTakeDamage", "CanEntityTakeDamage", "OnRestoreUponDeath", "OnPlayerSleep"
}
;
EventController eventController;
#endregion Variables
#region Hooks
void Init() {
Unsubscribes();
}
void OnServerInitialized() {
ins = this;
if (!NpcSpawnManager.IsNpcSpawnReady()) return;
UpdateConfig();
PostLoadCheck();
LoadDefaultMessages();
GuiManager.LoadImages();
LootManager.InitialLootManagerUpdate();
EventLauncher.AutoStartEvent();
}
void Unload() {
EventLauncher.StopEvent(true);
ins = null;
}
void OnEntitySpawned(SimpleShark simpleShark) {
if (!simpleShark.IsExists()) return;
if (ZoneController.IsEventPosition(simpleShark.transform.position)) simpleShark.Kill();
}
void OnEntitySpawned(DiveSite diveSite) {
if (!diveSite.IsExists()) return;
if (ZoneController.IsEventPosition(diveSite.transform.position)) diveSite.Kill();
}
void OnEntitySpawned(PlayerCorpse playerCorpse) {
if (ins._config.mainConfig.disableFloatingCorpse && playerCorpse.IsExists()) DisableCorpseFloating(playerCorpse);
}
void OnEntitySpawned(DroppedItemContainer droppedItemContainer) {
if (ins._config.mainConfig.disableFloatingCorpse && droppedItemContainer.IsExists()) DisableCorpseFloating(droppedItemContainer);
}
void OnCorpsePopulate(ScientistNPC scientistNPC, NPCPlayerCorpse corpse) {
if (scientistNPC == null || scientistNPC.net == null || corpse == null) return;
if (NpcSpawnManager.GetScientistByNetId(scientistNPC.net.ID.Value) == null) return;
NpcConfig npcConfig = NpcSpawnManager.GetNpcConfigByDisplayName(scientistNPC.displayName);
if (npcConfig != null) {
ins.NextTick(() => {
if (corpse == null) return;
LootManager.UpdateItemContainer(corpse.containers[0], npcConfig.lootTableConfig, npcConfig.lootTableConfig.clearDefaultItemList);
if (npcConfig.deleteCorpse && !corpse.IsDestroyed) corpse.Kill();
}
);
}
}
object OnEntityTakeDamage(BaseSubmarine baseSubmarine, HitInfo info) {
if (!baseSubmarine.IsExists() || baseSubmarine.net == null || info == null) return null;
PatrolSubmarine patrolSubmarine = PatrolSubmarine.GetPatrolSubmarineByNetID(baseSubmarine.net.ID.Value);
if (patrolSubmarine != null) {
if (info.InitiatorPlayer.IsRealPlayer()) patrolSubmarine.OnAttackedByPlayer(info.InitiatorPlayer);
else if (info.Initiator == null) return true;
}
if (info.Initiator == null && info.WeaponPrefab != null && info.WeaponPrefab.name == "TorpedoStraight") info.damageTypes.ScaleAll(_config.mainConfig.submarineDamageScale);
return null;
}
object OnEntityTakeDamage(PatrolShark patrolShark, HitInfo info) {
if (!patrolShark.IsExists() || patrolShark.net == null || info == null) return null;
if (info.Initiator == null) return true;
return null;
}
object OnEntityTakeDamage(ScientistNPC scientistNPC, HitInfo info) {
if (!scientistNPC.IsExists() || scientistNPC.net == null || info == null) return null;
if (NpcSpawnManager.GetScientistByNetId(scientistNPC.net.ID.Value) != null) {
if (info.Initiator == null) return true;
}
return null;
}
void OnEntityTakeDamage(BasePlayer player, HitInfo info) {
if (player == null || info == null) return;
ScientistNPC scientistNPC = player as ScientistNPC;
if (scientistNPC != null) {
if (info.Initiator == null && scientistNPC.net != null && NpcSpawnManager.GetScientistByNetId(scientistNPC.net.ID.Value) != null) return;
return;
}
if (info.Initiator == null && info.WeaponPrefab != null && info.WeaponPrefab.name == "TorpedoStraight") {
info.damageTypes.ScaleAll(_config.mainConfig.submarineDamageScale);
return;
}
PatrolShark patrolShark = info.Initiator as PatrolShark;
if (patrolShark != null) {
info.damageTypes.ScaleAll(patrolShark.sharkConfig.damageScale);
return;
}
}
object CanMountEntity(BasePlayer player, BaseMountable seat) {
if (!player.IsRealPlayer() || seat == null) return null;
BaseVehicle vehicle = seat.VehicleParent();
if (vehicle == null || vehicle.net == null) return null;
PatrolSubmarine patrolSubmarine = PatrolSubmarine.GetPatrolSubmarineByNetID(vehicle.net.ID.Value);
if (patrolSubmarine != null) return true;
return null;
}
void OnEntityMounted(BaseMountable entity, BasePlayer player) {
if (entity == null || player == null) return;
BaseSubmarine baseSubmarine = entity.VehicleParent() as BaseSubmarine;
if (baseSubmarine != null && baseSubmarine.buoyancy.rigidBody == null) baseSubmarine.buoyancy.rigidBody = baseSubmarine.rigidBody;
}
void OnLootEntity(BasePlayer player, StorageContainer storageContainer) {
if (player == null || storageContainer == null || storageContainer.net == null) return;
StorageContainerData storageContainerData = LootManager.GetContainerDataByNetId(storageContainer.net.ID.Value);
if (storageContainerData == null) return;
LootManager.OnEventCrateLooted(storageContainer, player.userID);
}
object CanExplosiveStick(TimedExplosive timedExplosive, BaseSubmarine baseSubmarine) {
if (!_config.mainConfig.allowStickC4 || baseSubmarine == null || baseSubmarine.net == null) return null;
PatrolSubmarine patrolSubmarine = PatrolSubmarine.GetPatrolSubmarineByNetID(baseSubmarine.net.ID.Value);
if (patrolSubmarine != null) return true;
return null;
}
object CanBuild(Planner planner, Construction prefab, Construction.Target target) {
BasePlayer player = planner.GetOwnerPlayer();
if (player.IsRealPlayer() && ZoneController.IsPlayerInZone(player.userID)) return false;
return null;
}
object CanAffordUpgrade(BasePlayer player, BuildingBlock block, BuildingGrade.Enum grade) {
if (player == null) return null;
if (player.IsRealPlayer() && ZoneController.IsPlayerInZone(player.userID)) return false;
return null;
}
object OnStructureRotate(BuildingBlock block, BasePlayer player) {
if (player == null) return null;
if (player.IsRealPlayer() && ZoneController.IsPlayerInZone(player.userID)) return false;
return null;
}
void OnDoorOpened(Door door, BasePlayer player) {
if (door == null || player == null || door.OwnerID == 0) return;
ShipContainer shipContainer = ShipContainer.GetShipContainerByDoor(door);
if (shipContainer != null) shipContainer.OnPlayerOpenContainerDoor(player, door);
}
object OnCardSwipe(CardReader cardReader, Keycard card, BasePlayer player) {
if (cardReader == null || cardReader.net == null || card == null || player == null) return null;
CardDoor cardDoor = CardDoor.GetCardDoorByCardReaderNetId(cardReader.net.ID.Value);
if (cardDoor != null) {
cardDoor.OnCardSwipe(card, player, cardReader);
return true;
}
return null;
}
void CanHackCrate(BasePlayer player, HackableLockedCrate crate) {
if (player == null || crate == null || crate.net == null) return;
StorageContainerData storageContainerData = LootManager.GetContainerDataByNetId(crate.net.ID.Value);
if (storageContainerData == null) return;
CrateConfig crateConfig = LootManager.GetCrateConfigByPrefabName(storageContainerData.storageContainer.PrefabName);
crate.Invoke(() => LootManager.UpdateCrateHackTime(crate, crateConfig.hackTime), 1.1f);
if (!PveModeManager.IsPveModeBlockAction(player)) EconomyManager.AddBalance(player.userID, ins._config.supportedPluginsConfig.economicsConfig.lockedCratePoint);
}
void OnEntityDeath(ScientistNPC scientistNPC, HitInfo info) {
if (scientistNPC == null || info == null || !info.InitiatorPlayer.IsRealPlayer()) return;
if (info.InitiatorPlayer.IsRealPlayer() && NpcSpawnManager.IsEventNpc(scientistNPC)) EconomyManager.AddBalance(info.InitiatorPlayer.userID, ins._config.supportedPluginsConfig.economicsConfig.npcPoint);
}
void OnEntityDeath(PatrolShark patrolShark, HitInfo info) {
if (patrolShark == null || info == null || !info.InitiatorPlayer.IsRealPlayer()) return;
EconomyManager.AddBalance(info.InitiatorPlayer.userID, ins._config.supportedPluginsConfig.economicsConfig.sharkPoint);
}
void OnEntityDeath(BaseSubmarine baseSubmarine, HitInfo info) {
if (baseSubmarine == null || baseSubmarine.net == null || info == null || !info.InitiatorPlayer.IsRealPlayer()) return;
PatrolSubmarine patrolSubmarine = PatrolSubmarine.GetPatrolSubmarineByNetID(baseSubmarine.net.ID.Value);
if (patrolSubmarine != null) EconomyManager.AddBalance(info.InitiatorPlayer.userID, ins._config.supportedPluginsConfig.economicsConfig.submarinePoint);
}
void OnEntityDeath(Door door, HitInfo info) {
if (door == null || door.net == null || info == null || !info.InitiatorPlayer.IsRealPlayer()) return;
CardDoor cardDoor = CardDoor.GetCardDoorByDoorNetId(door.net.ID.Value);
if (cardDoor != null) EconomyManager.AddBalance(info.InitiatorPlayer.userID, ins._config.supportedPluginsConfig.economicsConfig.doorPoint);
}
void OnEntityDeath(LootContainer lootContainer, HitInfo info) {
if (lootContainer == null || lootContainer.net == null || info == null || !info.InitiatorPlayer.IsRealPlayer()) return;
StorageContainerData storageContainerData = LootManager.GetContainerDataByNetId(lootContainer.net.ID.Value);
if (storageContainerData == null) return;
LootManager.OnEventCrateLooted(lootContainer, info.InitiatorPlayer.userID);
}
void OnPlayerDeath(BasePlayer player) {
if (player == null) return;
ZoneController.OnPlayerLeaveZone(player);
}
void OnPlayerSleep(BasePlayer player) {
if (player == null) return;
ZoneController.OnPlayerLeaveZone(player);
}
void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item) {
if (item == null || entity == null) return;
if (ZoneController.IsEventPosition(entity.transform.position)) item.amount = (int)(item.amount * _config.mainConfig.resourseScale);
}
void OnDispenserBonus(ResourceDispenser dispenser, BaseEntity entity, Item item) {
if (item == null || entity == null) return;
if (ZoneController.IsEventPosition(entity.transform.position)) item.amount = (int)(item.amount * _config.mainConfig.resourseScale);
}
#region SupportedPLugins
object CanEntityTakeDamage(BasePlayer victim, HitInfo info) {
if (eventController == null) return null;
if (info == null || !victim.IsRealPlayer()) return null;
if (info.InitiatorPlayer.IsRealPlayer()) {
if (_config.zoneConfig.isPVPZone && ZoneController.IsPlayerInZone(victim.net.ID.Value) && ZoneController.IsPlayerInZone(info.InitiatorPlayer.net.ID.Value)) return true;
}
return null;
}
object CanEntityTakeDamage(BaseSubmarine baseSubmarine, HitInfo info) {
if (eventController == null) return null;
if (!baseSubmarine.IsExists() || info == null) return null;
PatrolSubmarine patrolSubmarine = PatrolSubmarine.GetPatrolSubmarineByNetID(baseSubmarine.net.ID.Value);
if (patrolSubmarine != null) {
if (info.InitiatorPlayer.IsRealPlayer()) {
patrolSubmarine.OnAttackedByPlayer(info.InitiatorPlayer);
return true;
}
else if (info.Initiator == null) return false;
}
else if (info.Initiator == null && ZoneController.IsEventPosition(baseSubmarine.transform.position)) return true;
return null;
}
object CanEntityTakeDamage(SimpleShark shark, HitInfo info) {
if (!shark.IsExists() || info == null || shark.net == null) return null;
PatrolShark patrolShark = PatrolShark.GetPatrolSharkByNetId(shark.net.ID.Value);
if (patrolShark != null) {
if (info.Initiator == null) return false;
else if (info.InitiatorPlayer.IsRealPlayer()) return true;
}
return null;
}
object OnRestoreUponDeath(BasePlayer player) {
if (player == null) return null;
if (_config.zoneConfig.blockRestoreUponDeath && ZoneController.IsPlayerInZone(player.userID)) return false;
return null;
}
void SetOwnerPveMode(string eventName, BasePlayer player) {
if (eventController == null || string.IsNullOrEmpty(eventName) || eventName != Name || !player.IsRealPlayer()) return;
if (eventName == Name) PveModeManager.OnNewOwnerSet(player);
}
void ClearOwnerPveMode(string shortname) {
if (eventController == null || string.IsNullOrEmpty(shortname)) return;
if (shortname == Name) PveModeManager.OnOwnerDeleted();
}
#endregion SupportedPLugins
#endregion Hooks
#region Commands
[ChatCommand("shipwreckstart")]
void ChatStartCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
if (arg == null || arg.Length == 0) EventLauncher.DelayStartEvent(false, player);
else {
string eventPresetName = arg[0];
EventLauncher.DelayStartEvent(false, player, eventPresetName);
}
}
[ChatCommand("shipwreckstop")]
void ChatStopCommand(BasePlayer player, string command, string[] arg) {
if (player.IsAdmin) EventLauncher.StopEvent();
}
[ConsoleCommand("shipwreckstart")]
void ConsoleStartCommand(ConsoleSystem.Arg arg) {
if (arg.Player() != null) return;
if (arg == null || arg.Args == null || arg.Args.Length == 0) EventLauncher.DelayStartEvent();
else {
string eventPresetName = arg.Args[0].ToString();
EventLauncher.DelayStartEvent(presetName : eventPresetName);
}
}
[ConsoleCommand("shipwreckstop")]
void ConsoleStopCommand(ConsoleSystem.Arg arg) {
if (arg.Player() == null) EventLauncher.StopEvent();
}
[ChatCommand("screatepath")]
void ChatCreatePathCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
float step = 5;
if (arg.Length > 0) {
step = Convert.ToInt32(arg[0]);
if (step <= 0) step = 5;
}
if (eventController == null) {
NotifyManager.PrintError(player, "EventNoActive_Exeption", _config.prefix);
return;
}
PathRecorder.CreatePathRecorder(player, step);
NotifyManager.SendMessageToPlayer(player, "PathRecordStart", _config.prefix);
}
[ChatCommand("ssavepath")]
void ChatSavePathCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
if (eventController == null) {
NotifyManager.PrintError(player, "EventNoActive_Exeption", _config.prefix);
return;
}
PathRecorder pathRecorder = PathRecorder.GetPathRecorderByPlayerUID(player.userID);
if (pathRecorder == null) {
NotifyManager.PrintError(player, "PathSaveFailed", _config.prefix);
return;
}
pathRecorder.SaveRout(arg[0]);
NotifyManager.SendMessageToPlayer(player, "PathSaved", _config.prefix);
}
[ChatCommand("scancelpath")]
void ChatCancelPathCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
if (eventController == null) {
NotifyManager.PrintError(player, "EventNoActive_Exeption", _config.prefix);
return;
}
PathRecorder pathRecorder = PathRecorder.GetPathRecorderByPlayerUID(player.userID);
if (pathRecorder == null) return;
GameObject.Destroy(pathRecorder.gameObject);
NotifyManager.SendMessageToPlayer(player, "PathCancelled", _config.prefix);
}
[ChatCommand("swsavemap")]
void ChatSaveMapCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
MapSaver.SaveNewDataFile(arg[0]);
}
[ChatCommand("swdeletecrate")]
void ChatDeleteCrateCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
if (eventController == null) return;
BaseEntity target = PositionDefiner.RaycastAll<BaseEntity>(player.eyes.HeadRay());
if (target == null) return;
Vector3 localPosition = PositionDefiner.GetLocalPosition(eventController.transform, target.transform.position);
EntityConfig entityConfig = eventController.eventConfig.crates.FirstOrDefault(x => x.prefab == target.PrefabName);
if (entityConfig == null) return;
LocationConfig targetLocationConfig = null;
foreach (LocationConfig locationConfig in entityConfig.locations) {
Vector3 crateLocalPosition = locationConfig.position.ToVector3();
if (Vector3.Distance(crateLocalPosition, localPosition) < 0.1f) {
targetLocationConfig = locationConfig;
break;
}
}
if (targetLocationConfig != null) {
target.Kill();
Debug(entityConfig.prefab);
Debug(targetLocationConfig.position);
Debug(targetLocationConfig.rotation);
//entityConfig.locations.Remove(targetLocationConfig);
//SaveConfig();
}
}
#endregion Commands
#region Methods
void UpdateConfig() {
if (_config.version == null || _config.version == new VersionNumber(0, 0, 0)) {
PrintError("The configuration file is corrupted!");
return;
}
if (_config.version != Version) {
PluginConfig defaultConfig = PluginConfig.DefaultConfig();
PrefabLootTableConfigs prefabConfigs = new PrefabLootTableConfigs {
isEnable = false, prefabs = new List<PrefabConfig> {
new PrefabConfig {
minLootScale = 1, maxLootScale = 1, prefabName = "assets/bundled/prefabs/radtown/underwater_labs/crate_food_1.prefab"
}
}
}
;
LootTableConfig defaultLootTable = new LootTableConfig {
clearDefaultItemList = false, isAlphaLoot = false, isCustomLoot = false, prefabConfigs = prefabConfigs, isRandomItemsEnable = false, maxItemsAmount = 1, minItemsAmount = 2, items = new List<LootItemConfig> {
new LootItemConfig {
shortname = "scrap", minAmount = 100, maxAmount = 200, chance = 100f, isBluePrint = false, skin = 0, name = "", genomes = new List<string>()
}
}
}
;
if (_config.version.Minor == 0) {
if (_config.version.Patch <= 3) {
_config.animationConfig = new AnimationConfig {
timeBeforeF15TakeOff = 60, enableExplosionsEffects = true
}
;
_config.supportedPluginsConfig.pveMode.showEventOwnerNameOnMap = true;
_config.supportedPluginsConfig.pveMode.damage = 25;
}
if (_config.version.Patch <= 5) {
_config.animationConfig.decorEntities = new HashSet<SkinnedEntityConfig> {
new SkinnedEntityConfig {
prefab = "assets/prefabs/building/wall.frame.garagedoor/wall.frame.garagedoor.prefab", skin = 1788350229, locations = new HashSet<LocationConfig> {
new LocationConfig {
position = "(-7.512, 6.5, 57.093)", rotation = "(0, 90, 0)"
}
, new LocationConfig {
position = "(7.550, 6.5, 57.093)", rotation = "(0, 90, 0)"
}
, new LocationConfig {
position = "(7.488, 6.430, -33.062)", rotation = "(0, 270, 0)"
}
, new LocationConfig {
position = "(-7.488, 6.430, -33.062)", rotation = "(0, 270, 0)"
}
}
}
}
;
}
if (_config.version.Patch <= 9) {
_config.supportedPluginsConfig.superCardConfig = new SuperCardConfig {
enable = false, skin = 1988408422
}
;
}
_config.version = new VersionNumber(1, 1, 0);
}
if (_config.version.Minor == 1) {
if (_config.version.Patch <= 3) {
_config.supportedPluginsConfig.pveMode.scaleDamage = new Dictionary<string, float> {
["Npc"]
= 1f,
}
;
}
if (_config.version.Patch <= 5) {
foreach (CrateConfig crateConfig in _config.crateConfigs) {
if (crateConfig.lootTableConfig == null) crateConfig.lootTableConfig = defaultLootTable;
crateConfig.lootTableConfig.prefabConfigs = prefabConfigs;
if (crateConfig.prefab.Contains("crate_elite") || crateConfig.prefab.Contains("codelockedhackablecrate")) crateConfig.screenMarkerPreset = "Crate_Marker";
else crateConfig.screenMarkerPreset = "";
foreach (LootItemConfig lootItemConfig in crateConfig.lootTableConfig.items) lootItemConfig.genomes = new List<string>();
}
foreach (NpcConfig npcConfig in _config.npcConfigs) {
if (npcConfig.lootTableConfig == null) {
npcConfig.lootTableConfig = new LootTableConfig {
clearDefaultItemList = false, isAlphaLoot = false, isCustomLoot = false, prefabConfigs = new PrefabLootTableConfigs {
isEnable = false, prefabs = new List<PrefabConfig> {
new PrefabConfig {
minLootScale = 1, maxLootScale = 1, prefabName = "assets/bundled/prefabs/radtown/underwater_labs/crate_food_1.prefab"
}
}
}
, isRandomItemsEnable = false, minItemsAmount = 1, maxItemsAmount = 1, items = new List<LootItemConfig> {
new LootItemConfig {
shortname = "scrap", minAmount = 100, maxAmount = 200, chance = 100f, isBluePrint = false, skin = 0, name = "", genomes = new List<string>()
}
}
}
;
}
else {
npcConfig.lootTableConfig.prefabConfigs = prefabConfigs;
foreach (LootItemConfig lootItemConfig in npcConfig.lootTableConfig.items) lootItemConfig.genomes = new List<string>();
}
}
_config.notifyConfig.guiConfig.offsetMinY = defaultConfig.notifyConfig.guiConfig.offsetMinY;
_config.notifyConfig.gameTipConfig = defaultConfig.notifyConfig.gameTipConfig;
_config.notifyConfig.timeNotifications = defaultConfig.notifyConfig.timeNotifications;
_config.screenMarkersConfig = defaultConfig.screenMarkersConfig;
_config.oxygenRefillerConfig = defaultConfig.oxygenRefillerConfig;
_config.zoneConfig.isColoredBorder = defaultConfig.zoneConfig.isColoredBorder;
_config.zoneConfig.brightness = defaultConfig.zoneConfig.brightness;
_config.zoneConfig.borderColor = defaultConfig.zoneConfig.borderColor;
_config.mainConfig.resourseScale = defaultConfig.mainConfig.resourseScale;
_config.mainConfig.endAfterLootTime = defaultConfig.mainConfig.endAfterLootTime;
foreach (EventConfig eventConfig in _config.eventConfigs) {
eventConfig.minTimeAfterWipe = 0;
eventConfig.maxTimeAfterWipe = -1;
EventConfig sameEventConfig = defaultConfig.eventConfigs.FirstOrDefault(x => x.dataFileName == eventConfig.dataFileName);
if (sameEventConfig != null) eventConfig.oxygenRefillerLocations = sameEventConfig.oxygenRefillerLocations;
else eventConfig.oxygenRefillerLocations = new HashSet<LocationConfig>();
}
}
if (_config.version.Patch <= 6) {
_config.screenMarkersConfig.oreMarkerName = "";
}
if (_config.version.Patch <= 7) {
OreProbabilityConfig defaultOreProbability = new OreProbabilityConfig {
stoneProbability = 30, metalProbability = 30, sulfurProbability = 40,
}
;
foreach (CrateConfig crateConfig in _config.crateConfigs) if (crateConfig.lootTableConfig == null) crateConfig.lootTableConfig = defaultLootTable;
foreach (EventConfig eventConfig in _config.eventConfigs) {
EventConfig oldMonumentConfig = LoadDataFile<EventConfig>($"Configs/{eventConfig.dataFileName}");
if (oldMonumentConfig == null) {
NotifyManager.PrintError(null, "FileNotFound_Exeption", eventConfig.dataFileName, "data/Shipwreck/Configs");
PrintError("The configuration file is corrupted!");
return;
}
EventConfig sameDefaultConfig = defaultConfig.eventConfigs.FirstOrDefault(x => x.presetName == eventConfig.presetName);
eventConfig.minRockAmount = sameDefaultConfig != null ? sameDefaultConfig.minRockAmount : 0;
eventConfig.maxRockAmount = sameDefaultConfig != null ? sameDefaultConfig.maxRockAmount : 0;
eventConfig.shipContainerConfigs = oldMonumentConfig.shipContainerConfigs;
eventConfig.cardReaderConfigs = oldMonumentConfig.cardReaderConfigs;
eventConfig.crates = oldMonumentConfig.crates;
eventConfig.oreProbabilityConfig = defaultOreProbability;
}
PrintWarning("The data files have been successfully added to the config. You can delete data/Shipwreck/Configs and data/Shipwreck/Images folders!");
}
_config.version = new VersionNumber(1, 2, 0);
}
if (_config.version.Minor == 2) {
if (_config.version.Patch <= 3) {
EventConfig farmConfig = _config.eventConfigs.FirstOrDefault(x => x.dataFileName == "farm");
if (farmConfig != null) {
PatrolCustomConfig patrolCustomConfig = farmConfig.customPatrolRoutes.FirstOrDefault(x => x.patrolPathList[0] == "(7.7, 8.7, 26.4)");
if (patrolCustomConfig != null) {
farmConfig.customPatrolRoutes.Remove(patrolCustomConfig);
}
}
EventConfig bargeConfig = _config.eventConfigs.FirstOrDefault(x => x.dataFileName == "barge");
if (bargeConfig != null) {
PatrolCustomConfig patrolCustomConfig = bargeConfig.customPatrolRoutes.FirstOrDefault(x => x.patrolPathList[0] == "(-18.4, 1.6, -13.3)");
if (patrolCustomConfig != null) {
bargeConfig.customPatrolRoutes.Remove(patrolCustomConfig);
}
}
}
if (_config.version.Patch <= 4) {
EventConfig cargoConfig = _config.eventConfigs.FirstOrDefault(x => x.dataFileName == "cargo");
if (cargoConfig != null) {
EntityConfig entityConfig = cargoConfig.crates.FirstOrDefault(x => x.prefab == "assets/bundled/prefabs/radtown/crate_underwater_basic.prefab");
if (entityConfig != null) {
LocationConfig locationConfig1 = entityConfig.locations.FirstOrDefault(x => x.position == "(-52.40511, 3.953003, 6.321566)");
if (locationConfig1 != null) {
locationConfig1.position = "(-52.40511, 4.453003, 6.321566)";
}
LocationConfig locationConfig2 = entityConfig.locations.FirstOrDefault(x => x.position == "(-46.00111, 3.723999, 8.936565)");
if (locationConfig2 != null) {
locationConfig2.position = "(-46.00111, 4.723999, 8.936565)";
}
}
}
}
if (_config.version.Patch <= 7) {
if (_config.supportedPluginsConfig.discordMessagesConfig.keys.Remove("PreStartEvent")) _config.supportedPluginsConfig.discordMessagesConfig.keys.Add("PreStart");
if (_config.supportedPluginsConfig.discordMessagesConfig.keys.Remove("StartEvent")) _config.supportedPluginsConfig.discordMessagesConfig.keys.Add("EventStart");
if (_config.supportedPluginsConfig.discordMessagesConfig.keys.Remove("Crash")) _config.supportedPluginsConfig.discordMessagesConfig.keys.Add("Animation_Stage_2");
}
}
_config.version = Version;
SaveConfig();
}
}
void Unsubscribes() {
foreach (string hook in subscribeMetods) Unsubscribe(hook);
}
void Subscribes() {
foreach (string hook in subscribeMetods) Subscribe(hook);
}
void PostLoadCheck() {
foreach (EventConfig eventConfig in _config.eventConfigs) {
HashSet<DataFileEntity> dataFile = LoadDataFile<HashSet<DataFileEntity>>($"Prefabs/{eventConfig.dataFileName}");
if (dataFile == null || dataFile.Count == 0) {
ins.NextTick(() => Interface.Oxide.UnloadPlugin(ins.Name));
return;
}
}
}
void DisableCorpseFloating(BaseEntity entity) {
if (ZoneController.IsEventPosition(entity.transform.position)) {
Rigidbody rigidbody = entity.GetComponent<Rigidbody>();
if (rigidbody != null) rigidbody.mass = 100;
}
}
Vector3 GetPatrolInitiatePosition(PatrolCustomConfig patrolCustomConfig) {
Vector3 patrolInitiatePosition = Vector3.zero;
if (patrolCustomConfig != null) patrolInitiatePosition = PositionDefiner.GetGlobalPosition(ins.eventController.transform, patrolCustomConfig.patrolPathList[0].ToVector3());
return patrolInitiatePosition;
}
static void Debug(params object[] arg) {
string result = "";
foreach (object obj in arg) if (obj != null) result += obj.ToString() + " ";
ins.Puts(result);
}
#endregion Methods
#region Classes
static class EventLauncher {
static Coroutine autoEventCoroutine;
static Coroutine delayedEventStartCorountine;
internal static bool IsEventActive() {
return ins != null && ins.eventController != null;
}
internal static void AutoStartEvent() {
if (!ins._config.mainConfig.isAutoEvent) return;
if (autoEventCoroutine != null) ServerMgr.Instance.StopCoroutine(autoEventCoroutine);
autoEventCoroutine = ServerMgr.Instance.StartCoroutine(AutoEventCorountine());
}
internal static void DelayStartEvent(bool isAutoActivated = false, BasePlayer activator = null, string presetName = "") {
if (IsEventActive() || delayedEventStartCorountine != null) {
NotifyManager.PrintError(activator, "EventActive_Exeption");
return;
}
if (autoEventCoroutine != null) ServerMgr.Instance.StopCoroutine(autoEventCoroutine);
EventConfig eventConfig = DefineEventConfig(presetName);
if (eventConfig == null) {
NotifyManager.PrintError(activator, "ConfigurationNotFound_Exeption");
StopEvent();
return;
}
delayedEventStartCorountine = ServerMgr.Instance.StartCoroutine(DelayedStartEventCorountine(eventConfig));
if (!isAutoActivated) NotifyManager.PrintInfoMessage(activator, "SuccessfullyLaunched");
}
static IEnumerator AutoEventCorountine() {
yield return CoroutineEx.waitForSeconds(UnityEngine.Random.Range(ins._config.mainConfig.minTimeBetweenEvents, ins._config.mainConfig.maxTimeBetweenEvents));
yield return CoroutineEx.waitForSeconds(5f);
DelayStartEvent(true);
}
static IEnumerator DelayedStartEventCorountine(EventConfig eventConfig) {
if (ins._config.mainConfig.preStartTime > 0) NotifyManager.SendMessageToAll("PreStart", ins._config.prefix, ins._config.mainConfig.preStartTime);
yield return CoroutineEx.waitForSeconds(ins._config.mainConfig.preStartTime);
StartEvent(eventConfig);
}
static void StartEvent(EventConfig eventConfig) {
GameObject gameObject = new GameObject();
ins.eventController = gameObject.AddComponent<EventController>();
ins.eventController.Init(eventConfig);
if (ins._config.mainConfig.enableStartStopLogs) NotifyManager.PrintLogMessage("EventStart_Log", eventConfig.presetName);
Interface.CallHook("OnShipwreckStart");
}
internal static void StopEvent(bool isPluginUnloadingOrFailed = false) {
if (IsEventActive()) {
ins.Unsubscribes();
ins.eventController.DeleteController();
ZoneController.TryDeleteZone();
PveModeManager.OnEventEnd();
EventMapMarker.DeleteMapMarker();
NpcSpawnManager.ClearData();
LootManager.ClearLootData(true);
GuiManager.DestroyAllGui();
EconomyManager.OnEventEnd();
DdrawMarkerController.ClearData();
NotifyManager.SendMessageToAll("Finish", ins._config.prefix);
Interface.CallHook("OnShipwreckStop");
if (ins._config.mainConfig.enableStartStopLogs) NotifyManager.PrintLogMessage("EventStop_Log");
if (!isPluginUnloadingOrFailed) AutoStartEvent();
}
if (delayedEventStartCorountine != null) {
ServerMgr.Instance.StopCoroutine(delayedEventStartCorountine);
delayedEventStartCorountine = null;
}
}
static EventConfig DefineEventConfig(string eventPresetName) {
if (eventPresetName != "") return ins._config.eventConfigs.FirstOrDefault(x => x.presetName == eventPresetName);
HashSet<EventConfig> suitableEventConfigs = ins._config.eventConfigs.Where(x => x.chance > 0 && x.isAutoStart && IsEventConfigSuitableByTime(x));
if (suitableEventConfigs == null || suitableEventConfigs.Count == 0) return null;
float sumChance = 0;
foreach (EventConfig eventConfig in suitableEventConfigs) sumChance += eventConfig.chance;
float random = UnityEngine.Random.Range(0, sumChance);
foreach (EventConfig eventConfig in suitableEventConfigs) {
random -= eventConfig.chance;
if (random <= 0) return eventConfig;
}
return null;
}
static bool IsEventConfigSuitableByTime(EventConfig eventConfig) {
if (eventConfig.minTimeAfterWipe <= 0 && eventConfig.maxTimeAfterWipe <= 0) return true;
int timeScienceWipe = GetTimeScienceLastWipe();
if (timeScienceWipe < eventConfig.minTimeAfterWipe) return false;
if (eventConfig.maxTimeAfterWipe > 0 && timeScienceWipe > eventConfig.maxTimeAfterWipe) return false;
return true;
}
static int GetTimeScienceLastWipe() {
DateTime startTime = new DateTime(2019, 1, 1, 0, 0, 0);
double realTime = DateTime.UtcNow.Subtract(startTime).TotalSeconds;
double wipeTime = SaveRestore.SaveCreatedTime.Subtract(startTime).TotalSeconds;
return Convert.ToInt32(realTime - wipeTime);
}
}
sealed class EventController : FacepunchBehaviour {
internal EventConfig eventConfig;
Coroutine spawnCoroutine;
Coroutine eventCoroutine;
CargoSinkEffect cargoSinkEffect;
HashSet<BaseEntity> decorEntities = new HashSet<BaseEntity>();
HashSet<BaseEntity> oreEntities = new HashSet<BaseEntity>();
int eventTime;
bool isEventLooted;
internal int GetEventTime() {
return eventTime;
}
internal Vector3 GetEventPosition() {
return gameObject.transform.position;
}
internal void Init(EventConfig eventConfig) {
this.eventConfig = eventConfig;
eventTime = eventConfig.eventTime;
Vector3 eventPosition = Vector3.zero;
eventPosition = PositionDefiner.DefineEventPosition();
if (eventPosition == Vector3.zero) {
NotifyManager.PrintError(null, "LocationNotFound_Exeption");
EventLauncher.StopEvent();
return;
}
transform.position = eventPosition;
DeleteEntitiesInEventArea();
spawnCoroutine = ServerMgr.Instance.StartCoroutine(SpawnCorountine());
}
void DeleteEntitiesInEventArea() {
foreach (Collider collider in UnityEngine.Physics.OverlapSphere(gameObject.transform.position, eventConfig.zoneRadius)) {
BaseEntity entity = collider.ToBaseEntity();
if (entity.IsExists() && (entity is SimpleShark || entity is DiveSite || entity is FreeableLootContainer || entity is SimpleShark)) entity.Kill();
}
}
IEnumerator SpawnCorountine() {
EventMapMarker.CreateMarker();
if (eventConfig.enableCargoSinkEffect) {
if (ins._config.animationConfig.timeBeforeF15TakeOff > 0) NotifyManager.SendMessageToAll("Animation_Stage_1", ins._config.prefix, ins._config.animationConfig.timeBeforeF15TakeOff);
Vector3 cargoPosition = new Vector3(transform.position.x, 0, transform.position.z);
cargoSinkEffect = CargoSinkEffect.CreateCargoSinkControoler(cargoPosition, transform.rotation);
yield return CoroutineEx.waitForSeconds(ins._config.animationConfig.timeBeforeF15TakeOff);
cargoSinkEffect.StartAnimation();
NotifyManager.SendMessageToAll("Animation_Stage_2", ins._config.prefix);
while (cargoSinkEffect != null) yield return CoroutineEx.waitForSeconds(1f);
}
DeleteEntitiesInEventArea();
HashSet<DataFileEntity> entitiesDataFile = ins.LoadDataFile<HashSet<DataFileEntity>>($"Prefabs/{eventConfig.dataFileName}");
foreach (DataFileEntity dataFileEntity in entitiesDataFile) {
SpawnDecorEnity(dataFileEntity);
yield return null;
}
foreach (LocationConfig locationConfig in eventConfig.shipContainerConfigs.locations) {
SpawnShipContainer(eventConfig.shipContainerConfigs, locationConfig);
yield return null;
}
foreach (CardDoorConfig dataCardDoorConfig in eventConfig.cardReaderConfigs) {
CardDoor cardDoor = new CardDoor(dataCardDoorConfig, eventConfig.doorType);
yield return null;
}
foreach (LocationConfig locationConfig in eventConfig.oxygenRefillerLocations) {
SpawnOxygenRefiller(locationConfig);
yield return null;
}
foreach (PatrolCustomConfig patrolConfig in eventConfig.customPatrolRoutes) {
SpawnPatrolEntity(patrolConfig);
yield return null;
}
foreach (EntityConfig dataEntityConfig in eventConfig.crates) {
foreach (LocationConfig locationConfig in dataEntityConfig.locations) {
Vector3 globalPosition = PositionDefiner.GetGlobalPosition(transform, locationConfig.position.ToVector3());
Quaternion globalRotation = PositionDefiner.GetGlobalRotation(transform, locationConfig.rotation.ToVector3());
SpawnEventCrate(dataEntityConfig.prefab, globalPosition, globalRotation);
yield return null;
}
}
OnEventSpawned();
// Only spawn ores if this is the main event area, not for decor or cargo presets
if (eventConfig.oreProbabilityConfig.sulfurProbability > 1 || eventConfig.oreProbabilityConfig.stoneProbability > 1 || eventConfig.oreProbabilityConfig.metalProbability > 1) {
int randomOreCount = UnityEngine.Random.Range(eventConfig.minRockAmount, eventConfig.maxRockAmount + 1);
int attempts = 0;
int maxAttempts = randomOreCount * 5;
// Prevent infinite loop
while (oreEntities.Count < randomOreCount && attempts < maxAttempts) {
Vector3 orePosition;
Quaternion oreRotation;
OreSpawner.GetRandomLocationForOre(this.transform.position, eventConfig.zoneRadius, out orePosition, out oreRotation);
// Prevent spawning on/near cargo or decor entities
bool nearDecor = false;
foreach (var decor in decorEntities) {
if (Vector3.Distance(decor.transform.position, orePosition)
// ... [Code preview truncated due to length. Full source in attached file] ...