generated from AriasCreations/vsmodtemplate
641 lines
28 KiB
C#
641 lines
28 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Vintagestory.API.Client;
|
|
using Vintagestory.API.Common;
|
|
using Vintagestory.API.Common.CommandAbbr;
|
|
using Vintagestory.API.Common.Entities;
|
|
using Vintagestory.API.Config;
|
|
using Vintagestory.API.Datastructures;
|
|
using Vintagestory.API.MathTools;
|
|
using Vintagestory.API.Server;
|
|
using Vintagestory.API.Util;
|
|
using Vintagestory.GameContent;
|
|
|
|
namespace AriasServerUtils
|
|
{
|
|
public class ServerUtilities : ModSystem
|
|
{
|
|
public static string MOD_ID = "ariasserverutils";
|
|
public static ASUModConfig config = new ASUModConfig();
|
|
internal static ICoreServerAPI API;
|
|
private static bool bDirty = false;
|
|
internal static Dictionary<string, PlayerInventory> backupInventory = new Dictionary<string, PlayerInventory>();
|
|
|
|
internal static Dictionary<string, PlayerStorage> mPlayerData = new Dictionary<string, PlayerStorage>();
|
|
|
|
internal static BackCaches backCaches = new BackCaches();
|
|
|
|
internal static Warps serverWarps = new Warps();
|
|
internal static Random rng = new Random((int)TimeUtil.GetUnixEpochTimestamp());
|
|
internal bool isFirstStart = true;
|
|
|
|
|
|
internal static string[] saveInvTypes = new string[] {
|
|
GlobalConstants.hotBarInvClassName,
|
|
GlobalConstants.backpackInvClassName,
|
|
GlobalConstants.craftingInvClassName,
|
|
GlobalConstants.mousecursorInvClassName,
|
|
GlobalConstants.characterInvClassName
|
|
};
|
|
|
|
List<EntityAgent> SleepingPlayers { get; set; } = new();
|
|
float OriginalSpeed { get; set; } = 0.0f;
|
|
public double Hours { get; private set; } = 0.0;
|
|
bool Sleeping { get; set; } = false;
|
|
public IServerNetworkChannel ServerNetworkChannel { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Method to register all mod blocks
|
|
/// </summary>
|
|
/// <param name="api"></param>
|
|
private void RegisterBlocks(ICoreAPI api)
|
|
{
|
|
api.Logger.Notification("Begin registering block classes for Aria's Server Utils...");
|
|
|
|
|
|
|
|
|
|
api.Logger.Notification("Block Classes have been registered for Aria's Server Utils!");
|
|
}
|
|
|
|
private void RegisterBlockEntities(ICoreAPI api)
|
|
{
|
|
}
|
|
|
|
|
|
public override bool ShouldLoad(EnumAppSide side)
|
|
{
|
|
return side == EnumAppSide.Server;
|
|
}
|
|
|
|
|
|
|
|
// Called on server and client
|
|
public override void Start(ICoreAPI api)
|
|
{
|
|
api.Logger.Notification(Lang.Get($"{MOD_ID}:start"));
|
|
|
|
RegisterBlocks(api);
|
|
RegisterBlockEntities(api);
|
|
|
|
|
|
}
|
|
|
|
public override void StartServerSide(ICoreServerAPI api)
|
|
{
|
|
API = api;
|
|
api.Logger.Notification(Lang.Get($"{MOD_ID}:start"));
|
|
|
|
api.Event.ServerRunPhase(EnumServerRunPhase.GameReady, OnGameReady);
|
|
api.Event.ServerRunPhase(EnumServerRunPhase.Shutdown, OnShutdown);
|
|
api.Event.PlayerDeath += OnPlayerDeath;
|
|
api.Event.PlayerJoin += OnPlayerJoin;
|
|
api.Event.PlayerDisconnect += OnPlayerDC;
|
|
api.Event.ChunkColumnLoaded += RTPFactory.ChunkLoaded;
|
|
api.Event.BreakBlock += Events.CheckBreakFarmland;
|
|
//api.Event.PlayerLeave += OnPlayerDC;
|
|
|
|
|
|
|
|
api.ChatCommands.Create("setspawn").RequiresPrivilege(Privilege.controlserver).HandleWith(Events.HandleSetSpawn);
|
|
api.ChatCommands.Create("spawn").RequiresPrivilege(Privilege.chat).HandleWith(Events.HandleSpawn);
|
|
api.ChatCommands.Create("delspawn").RequiresPrivilege(Privilege.controlserver).HandleWith(Events.HandleClearSpawn);
|
|
|
|
|
|
//api.ChatCommands.Create("test_death").RequiresPlayer().RequiresPrivilege(Privilege.controlserver).HandleWith(TestDeath);
|
|
var parsers = api.ChatCommands.Parsers;
|
|
api.ChatCommands.Create("restoreinv").RequiresPlayer().WithArgs(parsers.OnlinePlayer("player")).HandleWith(Events.HandleReturnItems).WithDescription("Returns items to a player in the event of a problem").RequiresPrivilege(Privilege.controlserver);
|
|
|
|
api.ChatCommands.Create("sethome").RequiresPlayer().WithArgs(parsers.OptionalWord("name")).WithDescription("Creates a home").RequiresPrivilege(Privilege.chat).HandleWith(Events.HandleSetHome);
|
|
api.ChatCommands.Create("home").RequiresPlayer().WithArgs(parsers.OptionalWord("name")).WithDescription("Teleports you to home").RequiresPrivilege(Privilege.chat).HandleWith(Events.HandleGoHome);
|
|
api.ChatCommands.Create("delhome").RequiresPlayer().WithArgs(parsers.OptionalWord("name")).WithDescription("Deletes a home entry").RequiresPrivilege(Privilege.chat).HandleWith(Events.HandleDelHome);
|
|
api.ChatCommands.Create("homes").RequiresPlayer().WithDescription("Lists your homes").RequiresPrivilege(Privilege.chat).HandleWith(Events.HandleListHomes);
|
|
|
|
api.ChatCommands.Create("asu")
|
|
.RequiresPrivilege(Privilege.chat)
|
|
.BeginSubCommand("update")
|
|
.BeginSubCommand("maxhomes")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Int("maxHomes")
|
|
)
|
|
.WithDescription("Updates the maximum number of homes")
|
|
.HandleWith(Events.HandleUpdateASUMaxHomes)
|
|
|
|
.EndSubCommand()
|
|
.BeginSubCommand("adminhomes")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Bool("adminsBypass")
|
|
)
|
|
.WithDescription("Updates the flag deciding whether admins can bypass max number of homes")
|
|
.HandleWith(Events.HandleUpdateASUBypass)
|
|
.EndSubCommand()
|
|
.WithDescription("Updates the ASU mod configuration")
|
|
.BeginSubCommand("onlyAdminManageWarps")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Bool("manageWarps")
|
|
)
|
|
.WithDescription("DANGER: This updates the flag allowing anybody to create warps, even non-admins. It is recommended to leave this alone. The default is true/on/yes")
|
|
.HandleWith(Events.HandleUpdateASUMgrWarps)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("adminBypassCooldown")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Bool("bypass")
|
|
)
|
|
.WithDescription("This flag controls whether admins can or can not bypass the cooldown system (Default: true)")
|
|
.HandleWith(Events.HandleUpdateASUBypassCD)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("adminsBypassRTPMaxDist")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Bool("bypass")
|
|
)
|
|
.WithDescription("This flag would allow admins to go further than the max server RTP distance when manually specifying a distance to RTP (Default: false)")
|
|
.HandleWith(Events.HandleUpdateASUBypassRTPMaxDist)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("maxback")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.OptionalInt("max")
|
|
)
|
|
.WithDescription("Max number of back positions cached for players")
|
|
.HandleWith(Events.HandleUpdateASUMaxBack)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("playerSleepingPercentage")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.OptionalIntRange("psp", 1, 100, 50)
|
|
)
|
|
.WithDescription("Percentage of players required to sleep before sleeping through the night")
|
|
.HandleWith(Events.HandleUpdateASUPSP)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("rtp")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Int("maxDistance")
|
|
)
|
|
.WithDescription("Update RTP Max block distance. Plus and/or minus this distance from player current position (Default is 50000)")
|
|
.HandleWith(Events.HandleUpdateASURTPMax)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("farmlandDowngrade")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(parsers.OptionalBool("downgrade"))
|
|
.WithDescription("Enables or disables farmland downgrade when breaking farmland")
|
|
.HandleWith(Events.HandleUpdateASUFarmlandDowngrade)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("farmlandDrop")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(parsers.OptionalBool("drop"))
|
|
.WithDescription("Enables or disables dropping soil when breaking farmland")
|
|
.HandleWith(Events.HandleUpdateASUFarmlandDrop)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("cooldowns")
|
|
.WithDescription("Commands related to all the various cooldowns")
|
|
.BeginSubCommand("back")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Word("cooldown")
|
|
)
|
|
.WithDescription("Updates the cooldown time on /back (Default is 5s)")
|
|
.HandleWith(Events.HandleUpdateASUCDBack)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("warp")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Word("cooldown")
|
|
)
|
|
.WithDescription("Updates the cooldown time on /warp (Default is 10s)")
|
|
.HandleWith(Events.HandleUpdateASUCDWarp)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("home")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Word("cooldown")
|
|
)
|
|
.WithDescription("Updates the cooldown time on /home (Default is 5s)")
|
|
.HandleWith(Events.HandleUpdateASUCDHome)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("spawn")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Word("cooldown")
|
|
)
|
|
.WithDescription("Updates the cooldown time on /spawn (Default is 5s)")
|
|
.HandleWith(Events.HandleUpdateASUCDSpawn)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("rtp")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithArgs(
|
|
parsers.Word("cooldown")
|
|
)
|
|
.WithDescription("Updates the cooldown time on /rtp (Default is 30s)")
|
|
.HandleWith(Events.HandleUpdateASUCDRTP)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("reset")
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.WithDescription("Resets all cooldowns to default values")
|
|
.HandleWith(Events.HandleUpdateASUCDReset)
|
|
.EndSubCommand()
|
|
.EndSubCommand()
|
|
.EndSubCommand()
|
|
.BeginSubCommand("help")
|
|
.RequiresPrivilege(Privilege.chat)
|
|
.HandleWith(Events.HandleASU)
|
|
.WithDescription("Lists all Aria's Server Utils commands")
|
|
.EndSubCommand()
|
|
.BeginSubCommand("test")
|
|
.RequiresPlayer()
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.BeginSubCommand("sleep")
|
|
.RequiresPlayer()
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.HandleWith(TestSleep)
|
|
.EndSubCommand()
|
|
.BeginSubCommand("sleepy")
|
|
.RequiresPlayer()
|
|
.RequiresPrivilege(Privilege.controlserver)
|
|
.HandleWith(Events.HandleSleepyDebug)
|
|
.EndSubCommand()
|
|
.EndSubCommand();
|
|
|
|
api.ChatCommands.Create("setwarp").RequiresPlayer().RequiresPrivilege(Privilege.chat).WithDescription("Creates a new server warp").WithArgs(parsers.OptionalWord("name")).HandleWith(Events.HandleWarpUpdate);
|
|
api.ChatCommands.Create("warp").RequiresPlayer().RequiresPrivilege(Privilege.chat).WithDescription("Warp to the specified server warp").WithArgs(parsers.OptionalWord("name")).HandleWith(Events.HandleWarp);
|
|
api.ChatCommands.Create("delwarp").RequiresPlayer().RequiresPrivilege(Privilege.chat).WithDescription("Deletes the specified warp").WithArgs(parsers.OptionalWord("name")).HandleWith(Events.HandleWarpDelete);
|
|
api.ChatCommands.Create("warps").RequiresPlayer().RequiresPrivilege(Privilege.chat).WithDescription("Lists all server warps").HandleWith(Events.HandleWarpList);
|
|
|
|
api.ChatCommands.Create("back").RequiresPlayer().RequiresPrivilege(Privilege.chat).WithDescription("Returns you to the last location you were at").HandleWith(Events.HandleBack);
|
|
|
|
api.ChatCommands.Create("rtp").RequiresPlayer().RequiresPrivilege(Privilege.chat).WithArgs(parsers.OptionalInt("maxDist", defaultValue: -1)).WithDescription("Seeks a position possibly thousands of blocks away to teleport to.").HandleWith(Events.HandleRTP);
|
|
|
|
api.ChatCommands.Create("listcooldowns").RequiresPrivilege(Privilege.chat).WithDescription("Lists the cooldown settings on the server, as well as your own active cooldowns if applicable.").HandleWith(Events.HandleListCooldowns);
|
|
}
|
|
|
|
private TextCommandResult TestSleep(TextCommandCallingArgs args)
|
|
{
|
|
// Initiate the sleep process
|
|
// Basically run all the same commands as we would on a player in bed
|
|
Events.HandleSleepyDebug(args);
|
|
|
|
OriginalSpeed = API.World.Calendar.CalendarSpeedMul;
|
|
if (args.Caller.Player is IServerPlayer isp)
|
|
{
|
|
Hours = API.World.Calendar.TotalHours;
|
|
SleepingPlayers.Add(isp.Entity);
|
|
API.Logger.Notification($"Game Hours: {API.World.Calendar.TotalHours}, Difference: {API.World.Calendar.TotalHours - Hours}");
|
|
EntityAgent Agent = isp.Entity;
|
|
|
|
EntityBehaviorTiredness ebt = Agent.GetBehavior<EntityBehaviorTiredness>();
|
|
|
|
ebt.IsSleeping = true;
|
|
ebt.Tiredness = 100;
|
|
Sleeping = true;
|
|
|
|
API.World.Calendar.SetTimeSpeedModifier("asu_psp", 1000);
|
|
}
|
|
|
|
return TextCommandResult.Success($"Test initiated, original calendar multiplier: '{OriginalSpeed}'");
|
|
}
|
|
|
|
private TextCommandResult TestCalendarSpeed(TextCommandCallingArgs args)
|
|
{
|
|
if (args.Caller.Player is IServerPlayer isp)
|
|
{
|
|
EntityAgent agent = isp.Entity;
|
|
EntityBehaviorTiredness ebt = agent.GetBehavior("tiredness") as EntityBehaviorTiredness;
|
|
|
|
SendMessageTo(isp, $"- Current calendar speed: {API.World.Calendar.CalendarSpeedMul}");
|
|
SendMessageTo(isp, $"- Total Hours: {API.World.Calendar.TotalHours}");
|
|
SendMessageTo(isp, $"- Tiredness: {ebt.Tiredness}");
|
|
if (OriginalSpeed == 0)
|
|
{
|
|
// Apply multiplier
|
|
OriginalSpeed = 0.5f;
|
|
ebt.IsSleeping = true;
|
|
|
|
API.World.Calendar.SetTimeSpeedModifier("asu_psp", 1000);
|
|
|
|
SendMessageTo(isp, "Applied calendar speed multiplier");
|
|
}
|
|
else
|
|
{
|
|
// Unapply multiplier
|
|
OriginalSpeed = 0;
|
|
ebt.IsSleeping = false;
|
|
|
|
API.World.Calendar.RemoveTimeSpeedModifier("asu_psp");
|
|
|
|
SendMessageTo(isp, "Restored default calendar speed");
|
|
}
|
|
}
|
|
|
|
return TextCommandResult.Success();
|
|
}
|
|
|
|
private void OnCheckSleepingPlayers()
|
|
{
|
|
if (API.Side == EnumAppSide.Client) return; // This must only ever be called on the server!
|
|
if (isFirstStart)
|
|
{
|
|
API.World.Calendar.RemoveTimeSpeedModifier("asu_psp");
|
|
isFirstStart = false;
|
|
}
|
|
|
|
if (Sleeping)
|
|
{
|
|
//API.Logger.Notification($"Game Hours: {API.World.Calendar.TotalHours}, Difference: {API.World.Calendar.TotalHours - Hours}");
|
|
if (API.World.Calendar.TotalHours - Hours >= 6)
|
|
{
|
|
Sleeping = false;
|
|
foreach (var player in SleepingPlayers)
|
|
{
|
|
EntityBehaviorTiredness ebt = player.GetBehavior<EntityBehaviorTiredness>();
|
|
ebt.IsSleeping = false;
|
|
ebt.Tiredness = 0;
|
|
}
|
|
|
|
SleepingPlayers.Clear();
|
|
|
|
API.World.Calendar.RemoveTimeSpeedModifier("asu_psp");
|
|
|
|
//API.Logger.Notification("Stopping PSP Time Acceleration");
|
|
}
|
|
return;
|
|
}
|
|
if (config.PlayerSleepingPercentage == 100) return; // Normal behavior
|
|
// Iterate over all players, get their entity, check if mounted on a bed.
|
|
// If mounted on a bed, check tiredness
|
|
int TotalOnline = API.World.AllOnlinePlayers.Length;
|
|
if (TotalOnline == 0) return; // No one on, just abort the checks.
|
|
int TotalInBed = 0;
|
|
|
|
List<BlockEntityBed> BEBs = new();
|
|
|
|
foreach (var player in API.World.AllOnlinePlayers)
|
|
{
|
|
EntityAgent ePlay = player.Entity;
|
|
if (ePlay.MountedOn is BlockEntityBed beb)
|
|
{
|
|
BEBs.Add(beb);
|
|
TotalInBed++;
|
|
//API.Logger.Notification($"Bed found for player {player.PlayerName}");
|
|
}
|
|
if (ePlay.MountedOn == null)
|
|
{
|
|
//API.Logger.Notification($"No bed found for player {player.PlayerName}");
|
|
|
|
if (SleepingPlayers.Contains(ePlay))
|
|
{
|
|
EntityBehaviorTiredness ebt = ePlay.GetBehavior<EntityBehaviorTiredness>();
|
|
if (ebt != null)
|
|
ebt.IsSleeping = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Sleeping) return; // Abort
|
|
|
|
SleepingPlayers.Clear();
|
|
|
|
int Percentage = TotalInBed * 100 / TotalOnline;
|
|
|
|
//API.Logger.Notification($"Percentage of players in bed: {Percentage}, Required percentage: {config.PlayerSleepingPercentage}");
|
|
|
|
if (Percentage >= config.PlayerSleepingPercentage)
|
|
{
|
|
|
|
API.World.Calendar.SetTimeSpeedModifier("asu_psp", 1000);
|
|
|
|
// Call the API to make sleep happen
|
|
foreach (var bed in BEBs)
|
|
{
|
|
if (bed.MountedBy != null) SleepingPlayers.Add(bed.MountedBy);
|
|
|
|
// Start sleep
|
|
EntityBehaviorTiredness EBT = bed.MountedBy.GetBehavior<EntityBehaviorTiredness>();
|
|
|
|
EBT.IsSleeping = true;
|
|
|
|
//API.Logger.Notification("Starting PSP Time Acceleration");
|
|
|
|
bed.MountedBy.TryUnmount(); // Stand up. We cant trigger the real sleep phase, but all code for starting time accel has been executed.
|
|
}
|
|
|
|
// Get current calendar speed
|
|
Hours = API.World.Calendar.TotalHours;
|
|
Sleeping = true;
|
|
}
|
|
}
|
|
|
|
private void OnCheckPlayerCooldowns()
|
|
{
|
|
foreach (var cdEntry in ServerUtilities.mPlayerData)
|
|
{
|
|
// Obtain the IServerPlayer instance for this player.
|
|
IServerPlayer player = API.Server.Players.First(x => x.PlayerName == cdEntry.Key);
|
|
if (player.HasPrivilege(Privilege.controlserver) && ServerUtilities.config.AdminsBypassCooldowns)
|
|
{
|
|
cdEntry.Value.ActiveCooldowns.Clear(); // Problem solved.
|
|
}
|
|
List<CooldownType> toRemove = new();
|
|
foreach (var cd in cdEntry.Value.ActiveCooldowns)
|
|
{
|
|
if (cd.Value < TimeUtil.GetUnixEpochTimestamp())
|
|
{
|
|
toRemove.Add(cd.Key);
|
|
}
|
|
}
|
|
|
|
foreach (var item in toRemove)
|
|
{
|
|
cdEntry.Value.ActiveCooldowns.Remove(item);
|
|
}
|
|
|
|
if (toRemove.Count > 0) MarkDirty();
|
|
}
|
|
}
|
|
|
|
public static void NewBackCacheForPlayer(IServerPlayer player)
|
|
{
|
|
backCaches.AddPosition(player.PlayerName, PlayerPosition.from(player.Entity));
|
|
}
|
|
|
|
private void OnPlayerDC(IServerPlayer byPlayer)
|
|
{
|
|
OnCheckModDirty();
|
|
|
|
mPlayerData.Remove(byPlayer.PlayerName);
|
|
}
|
|
|
|
private void OnPlayerJoin(IServerPlayer byPlayer)
|
|
{
|
|
API.Logger.Notification($"[ASU] {Lang.Get($"{MOD_ID}:playerjoin")}");
|
|
|
|
PlayerStorage data = API.LoadModConfig<PlayerStorage>(GetConfigurationFile(byPlayer.PlayerName, ModConfigType.World));
|
|
if (data == null) data = new PlayerStorage();
|
|
|
|
mPlayerData[byPlayer.PlayerName] = data;
|
|
}
|
|
|
|
public static PlayerStorage GetPlayerData(IServerPlayer player)
|
|
{
|
|
if (mPlayerData.ContainsKey(player.PlayerName))
|
|
{
|
|
return mPlayerData[player.PlayerName];
|
|
}
|
|
else
|
|
{
|
|
return new PlayerStorage();
|
|
}
|
|
}
|
|
|
|
private TextCommandResult TestDeath(TextCommandCallingArgs args)
|
|
{
|
|
if (args.Caller.Player is IServerPlayer isp) OnPlayerDeath(isp, null);
|
|
|
|
return TextCommandResult.Success();
|
|
}
|
|
|
|
private void OnPlayerDeath(IServerPlayer player, DamageSource damageSource)
|
|
{
|
|
PlayerInventory inv = new PlayerInventory();
|
|
var invMgr = player.InventoryManager;
|
|
|
|
NewBackCacheForPlayer(player);
|
|
|
|
|
|
var iBackpackSlotNum = 0;
|
|
foreach (var type in saveInvTypes)
|
|
{
|
|
foreach (var stack in invMgr.GetOwnInventory(type))
|
|
{
|
|
|
|
if (iBackpackSlotNum >= 4)
|
|
{
|
|
continue;
|
|
}
|
|
if (type == GlobalConstants.backpackInvClassName)
|
|
{
|
|
iBackpackSlotNum++;
|
|
}
|
|
if (stack.Empty) continue;
|
|
if (stack.Inventory.ClassName == GlobalConstants.characterInvClassName)
|
|
{
|
|
if (stack.Itemstack.ItemAttributes?["protectionModifiers"].Exists ?? false)
|
|
{
|
|
inv.Items.Add(stack.Itemstack.Clone());
|
|
}
|
|
}
|
|
else
|
|
inv.Items.Add(stack.Itemstack.Clone());
|
|
|
|
API.Logger.Notification($"SAVED STORAGE ITEM TYPE: {stack.Itemstack}");
|
|
|
|
}
|
|
}
|
|
|
|
backupInventory[player.PlayerName] = inv;
|
|
|
|
}
|
|
|
|
private void OnCheckModDirty()
|
|
{
|
|
if (bDirty)
|
|
{
|
|
//API.Logger.Notification(Lang.Get($"{MOD_ID}:timer"));
|
|
bDirty = false;
|
|
SaveGlobalConfig();
|
|
|
|
SavePlayerData();
|
|
}
|
|
}
|
|
|
|
private void SavePlayerData()
|
|
{
|
|
foreach (var data in mPlayerData)
|
|
{
|
|
API.StoreModConfig<PlayerStorage>(data.Value, GetConfigurationFile(data.Key, ModConfigType.World));
|
|
}
|
|
}
|
|
|
|
private void OnShutdown()
|
|
{
|
|
// Mod Shutdown //
|
|
// Handle any remaining tasks before shutdown
|
|
API.Logger.Notification(Lang.Get($"{MOD_ID}:halt"));
|
|
OnCheckModDirty();
|
|
}
|
|
|
|
public void SaveGlobalConfig()
|
|
{
|
|
API.StoreModConfig<ASUModConfig>(config, GetConfigurationFile("global", ModConfigType.Global));
|
|
|
|
API.StoreModConfig<Warps>(serverWarps, GetConfigurationFile("warps", ModConfigType.Global));
|
|
}
|
|
|
|
private void OnGameReady()
|
|
{
|
|
// Mod Setup Info //
|
|
// -> Step 1. Load Mod Global Config <-
|
|
|
|
config = API.LoadModConfig<ASUModConfig>(GetConfigurationFile("global", ModConfigType.Global));
|
|
if (config == null) config = new ASUModConfig();
|
|
|
|
// Step 2. Check if config needs Migrations
|
|
config.SanityCheck();
|
|
|
|
// -> Step 3. Load Mod Warps <-
|
|
serverWarps = API.LoadModConfig<Warps>(GetConfigurationFile("warps", ModConfigType.Global));
|
|
if (serverWarps == null) serverWarps = new Warps();
|
|
|
|
|
|
|
|
API.Event.Timer(OnCheckModDirty, 20);
|
|
API.Event.Timer(OnCheckPlayerCooldowns, 1);
|
|
API.Event.Timer(OnCheckSleepingPlayers, 5);
|
|
API.Event.Timer(RTPFactory.HandleRTPChecking, 1);
|
|
}
|
|
|
|
public string GetConfigurationFile(string sName, ModConfigType type)
|
|
{
|
|
if (type == ModConfigType.Global)
|
|
{
|
|
return $"ariaserverconfig/{sName}.json";
|
|
}
|
|
else if (type == ModConfigType.World)
|
|
{
|
|
return $"ariaserverconfig/{GetWorldName()}/{sName}.json";
|
|
}
|
|
else return $"ariaserverconfig/global.json";
|
|
}
|
|
|
|
/// <summary>
|
|
/// This function is used to mark the mod's global config, and all loaded player configs as dirty. They will be flushed to disk, then the dirty flag will be cleared.
|
|
/// </summary>
|
|
public static void MarkDirty()
|
|
{
|
|
bDirty = true;
|
|
}
|
|
|
|
public string GetWorldName()
|
|
{
|
|
string[] lName = API.WorldManager.CurrentWorldName.Split(Path.DirectorySeparatorChar);
|
|
string sName = lName[lName.Length - 1];
|
|
return sName.Substring(0, sName.Length - 6);
|
|
}
|
|
|
|
public override void StartClientSide(ICoreClientAPI api)
|
|
{
|
|
api.Logger.Notification(Lang.Get($"{MOD_ID}:start"));
|
|
}
|
|
|
|
public static void SendMessageTo(IServerPlayer player, string sMsg)
|
|
{
|
|
player.SendMessage(0, sMsg, EnumChatType.CommandSuccess);
|
|
}
|
|
}
|
|
}
|