Skip to content

Commit

Permalink
Merge pull request #1 from jonathan-robertson/dev
Browse files Browse the repository at this point in the history
Initial Pre-Release
  • Loading branch information
jonathan-robertson authored Apr 14, 2023
2 parents ebff660 + 27ec97c commit 0c664f7
Show file tree
Hide file tree
Showing 13 changed files with 366 additions and 4 deletions.
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [TODO]

- update trader restock to days remaining
- update vend expiration to days remaining
- update trader restock on day change
- update trader restock on login
- update trader restock ui to days remaining

## [UNRELEASED]
## [0.1.0] - 2023-04-14

- add vend expiration buff
- update vend expiration on day change
- update vend expiration on login
- update vend expiration on rent
- update vend expiration ui to days remaining
5 changes: 5 additions & 0 deletions Config/Localization.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Key,File,Type,UsedInMainMenu,NoTranslate,english,Context / Alternate Text,german,latam,french,italian,japanese,koreana,polish,brazilian,russian,turkish,schinese,tchinese,spanish
buffDaysRemainingVendingExpirationFormat,UI,XUI,,?,{0:0} Days,,{0:0} Tage,{0:0} Días,{0:0} Jours,{0:0} Giorni,{0:0} 日,{0:0} 일,{0:0} Dni,{0:0} Dias,{0:0} Дней,{0:0} Gün,{0:0} 天数,{0:0} 天,{0:0} Días
buffDaysRemainingVendingExpirationName,buffs,Buff,,x,Vending Machine,,Automat,Máquina expendedora,Distributeur automatique,Distributore automatico,自動販売機,자판기,Automat sprzedający,Máquina de Vendas,Торговый автомат,Otomat,自动贩卖机,自動販賣機,Máquina expendedora
buffDaysRemainingVendingExpirationDesc,buffs,Buff,,x,Your vending machine rental will expire in [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] days.,,Ihre Automatenmiete läuft in [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] Tagen ab.,El alquiler de su máquina expendedora caducará en [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] días.,Votre location de distributeur expirera dans [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] jours.,Il noleggio del tuo distributore automatico scadrà tra [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] giorni.,自動販売機のレンタルは [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] 日後に期限切れになります.,자판기 대여가 [007fff]{cvar(daysRemainingVendingExpiration:0)}일 후에 만료됩니다.,Wypożyczenie automatu wygaśnie za [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] dni.,O aluguel da máquina de venda automática expira em [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] dias.,Срок аренды вашего торгового автомата истекает через [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] дней.,Otomat kiralama süreniz [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] gün içinde sona erecek.,您的自动售货机租赁将在 [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] 天后到期.,您的自動售貨機租賃將在 [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] 天后到期.,El alquiler de su máquina expendedora caducará en [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] días.
buffDaysRemainingVendingExpirationTooltip,buffs,Buff,,x,Your vending machine rental will expire in [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] days.,,Ihre Automatenmiete läuft in [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] Tagen ab.,El alquiler de su máquina expendedora caducará en [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] días.,Votre location de distributeur expirera dans [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] jours.,Il noleggio del tuo distributore automatico scadrà tra [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] giorni.,自動販売機のレンタルは [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] 日後に期限切れになります.,자판기 대여가 [007fff]{cvar(daysRemainingVendingExpiration:0)}일 후에 만료됩니다.,Wypożyczenie automatu wygaśnie za [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] dni.,O aluguel da máquina de venda automática expira em [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] dias.,Срок аренды вашего торгового автомата истекает через [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] дней.,Otomat kiralama süreniz [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] gün içinde sona erecek.,您的自动售货机租赁将在 [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] 天后到期.,您的自動售貨機租賃將在 [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] 天后到期.,El alquiler de su máquina expendedora caducará en [007fff]{cvar(daysRemainingVendingExpiration:0)}[-] días.
3 changes: 3 additions & 0 deletions Config/XUi/windows.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<config>
<set xpath="/windows/window[@name='windowTrader']/panel[@name='content']/rect[@name='searchControls']/label[@text='{renttimeleft}']/@text">{# localization('xuiExpires')}: {cvar(daysRemainingVendingExpiration:0)} {# localization('xuiBuffStatDays')}</set>
</config>
10 changes: 10 additions & 0 deletions Config/buffs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<config>
<append xpath="/buffs">
<buff name="buffDaysRemainingVendingExpiration" name_key="buffDaysRemainingVendingExpirationName" description_key="buffDaysRemainingVendingExpirationDesc" tooltip_key="buffDaysRemainingVendingExpirationTooltip" icon="ui_game_symbol_vending" icon_color="0,127,255">
<duration value="30" />
<stack_type value="duration" />
<display_value_key value="buffDaysRemainingVendingExpirationFormat" />
<display_value value="daysRemainingVendingExpiration" />
</buff>
</append>
</config>
Binary file added DaysRemaining.dll
Binary file not shown.
9 changes: 9 additions & 0 deletions ModInfo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<xml>
<ModInfo>
<Name value="Days Remaining" />
<Description value="Update trader restock date and vending expiration date to show days until vs date of." />
<Author value="Jonathan Robertson (Kanaverum)" />
<Version value="0.1.0" />
<Website value="https://github.com/jonathan-robertson/days-remaining" />
</ModInfo>
</xml>
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Days Remaining

[![🧪 Tested On](https://img.shields.io/badge/🧪%20Tested%20On-A20.6%20b9-blue.svg)](https://7daystodie.com/) [![📦 Automated Release](https://github.com/jonathan-robertson/days-remaining/actions/workflows/release.yml/badge.svg)](https://github.com/jonathan-robertson/days-remaining/actions/workflows/release.yml)

- [Days Remaining](#days-remaining)
- [Summary](#summary)
- [Sister Project](#sister-project)
- [Compatibility](#compatibility)

## Summary

7 Days to Die mod: update trader restock date and vending expiration date to show days until vs date of.

This mod does not alter the actual days within a server (many components in the game rely on server/world time increasing); it simply updates how the days are reported for Trader Restock and the Rentable Vending Machine Expiration Date.

## Sister Project

This mod is designed to be used with another to complete your experience:

- [Days of the Week](https://github.com/jonathan-robertson/days-of-the-week)
- Replace days count in UI with a day of the week
- *be sure to use the `windows-days-remaining.xml` option in this mod to get the best experience*

## Compatibility

Environment | Compatible | Does EAC Need to be Disabled? | Who needs to install?
--- | --- | --- | ---
Dedicated Server | Yes | no | only server
Peer-to-Peer Hosting | Yes | only on the host | only the host
Single Player Game | Yes | Yes | self (of course)
91 changes: 91 additions & 0 deletions src/Helpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;

namespace DaysRemaining
{
internal class Helpers
{
private static readonly ModLog<Helpers> _log = new ModLog<Helpers>();
private static readonly string CVAR_VENDING_EXPIRATION = "daysRemainingVendingExpiration";
private static readonly string BUFF_VENDING_EXPIRATION = "buffDaysRemainingVendingExpiration";

public static bool TryGetTileEntityVendingMachine(Vector3i blockPos, out TileEntityVendingMachine tileEntityVendingMachine)
{
var world = GameManager.Instance.World;
var tileEntity = world.GetTileEntity(world.ChunkCache.ClusterIdx, blockPos);
if (tileEntity == null || !(tileEntity is TileEntityVendingMachine te))
{
tileEntityVendingMachine = null;
return false;
}
tileEntityVendingMachine = te;
return true;
}

public static bool TryGetTileEntityVendingMachine(TileEntity tileEntity, out TileEntityVendingMachine tileEntityVendingMachine)
{
if (tileEntity is TileEntityVendingMachine te)
{
tileEntityVendingMachine = te;
return true;
}
tileEntityVendingMachine = null;
return false;
}

public static bool TryGetOwner(ILockable lockable, out PlatformUserIdentifierAbs owner)
{
owner = lockable.GetOwner();
return owner != null;
}

public static bool TryGetClientInfo(PlatformUserIdentifierAbs id, out ClientInfo clientInfo)
{
clientInfo = ConnectionManager.Instance.Clients.ForUserId(id);
return clientInfo != null;
}

public static bool TryGetClientInfo(int entityId, out ClientInfo clientInfo)
{
clientInfo = ConnectionManager.Instance.Clients.ForEntityId(entityId);
return clientInfo != null;
}

public static bool TryGetVendingMachineRentalData(Vector3i blockPos, out PlatformUserIdentifierAbs owner, out int rentalEndDay)
{
if (!TryGetTileEntityVendingMachine(blockPos, out var tileEntityVendingMachine))
{
_log.Warn($"could not find vending machine tile entity at {blockPos}");
owner = null;
rentalEndDay = 0;
return false;
}
owner = tileEntityVendingMachine.GetOwner();
rentalEndDay = tileEntityVendingMachine.RentalEndDay;
return true;
}

/// <summary>
/// Call this to update the player's client-side data related to vending expiration date.
/// </summary>
/// <param name="clientInfo">ClientInfo containing the current rental information.</param>
/// <param name="player">EntityPlayer to update.</param>
public static void SetExpirationDaysRemaining(ClientInfo clientInfo, EntityPlayer player)
{
if (clientInfo == null || player == null)
{
_log.Warn($"ClientInfo and EntityPlayer params must not be null; ClientInfo {(clientInfo != null ? "exists" : "does not exist")}, EntityPlayer {(player != null ? "exists" : "does not exist")}.");
return;
}
if (clientInfo.latestPlayerData.rentalEndDay == 0)
{
return;
}
var daysRemaining = Math.Max(clientInfo.latestPlayerData.rentalEndDay - GameUtils.WorldTimeToDays(GameManager.Instance.World.worldTime), 0);
if (daysRemaining != player.GetCVar(CVAR_VENDING_EXPIRATION))
{
player.SetCVar(CVAR_VENDING_EXPIRATION, daysRemaining);
_ = player.Buffs.AddBuff(BUFF_VENDING_EXPIRATION);
}
}
}
}
50 changes: 50 additions & 0 deletions src/ModApi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using HarmonyLib;
using System;
using System.Reflection;

namespace DaysRemaining
{
internal class ModApi : IModApi
{
private static readonly ModLog<ModApi> _log = new ModLog<ModApi>();

public static bool DebugMode { get; set; } = true; // TODO: disable before release

public void InitMod(Mod _modInstance)
{
var harmony = new Harmony(GetType().ToString());
harmony.PatchAll(Assembly.GetExecutingAssembly());

// TODO: confirm if rental state only updates when vend is closed
// TODO: on rental agreement changed, calculate and send cvar

ModEvents.PlayerSpawnedInWorld.RegisterHandler(OnPlayerSpawnedInWorld);
}

private void OnPlayerSpawnedInWorld(ClientInfo _cInfo, RespawnType _respawnReason, Vector3i _pos)
{
try
{
if (_cInfo == null) // is client local?
{
// TODO: var ppId = ((_cInfo != null) ? _cInfo.InternalId : null) ?? PlatformManager.InternalLocalUserIdentifier;
return;
}

switch (_respawnReason)
{
case RespawnType.JoinMultiplayer:
if (GameManager.Instance.World.Players.dict.TryGetValue(_cInfo.entityId, out var player))
{
Helpers.SetExpirationDaysRemaining(_cInfo, player);
}
return;
}
}
catch (Exception e)
{
_log.Error("OnPlayerSpawnedInWorld", e);
}
}
}
}
58 changes: 58 additions & 0 deletions src/ModLog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;

namespace DaysRemaining
{
internal class ModLog<T>
{
private readonly string _className;

public ModLog()
{
_className = typeof(T).FullName;
}

public void Trace(string message)
{
if (ModApi.DebugMode)
{
Log.Out($"[{_className}] TRACE: {message}");
}
}

public void Debug(string message)
{
if (ModApi.DebugMode)
{
Log.Out($"[{_className}] DEBUG: {message}");
}
}

public void Info(string message)
{
Log.Out($"[{_className}] {message}");
}

public void Warn(string message, Exception e = null)
{
Log.Warning($"[{_className}] {message}");
if (e != null)
{
Log.Warning($"[{_className}] {message}\n{e.Message}\n{e.StackTrace}");
Log.Exception(e);
}
}

public void Error(string message, Exception e = null)
{
if (e == null)
{
Log.Error($"[{_className}] {message}");
}
else
{
Log.Error($"[{_className}] {message}\n{e.Message}\n{e.StackTrace}");
Log.Exception(e);
}
}
}
}
96 changes: 96 additions & 0 deletions src/Patches.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using HarmonyLib;
using System;

namespace DaysRemaining
{
[HarmonyPatch(typeof(NetPackageTileEntity), "Setup", typeof(TileEntity), typeof(TileEntity.StreamModeWrite), typeof(byte))]
internal class NetPackageTileEntity_Setup_Patches
{
private static readonly ModLog<NetPackageTileEntity_Setup_Patches> _log = new ModLog<NetPackageTileEntity_Setup_Patches>();

/// <summary>
/// Called from server-side NetPackageTileEntity.ProcessPackage after ingesting data from client.
/// Also called from client to update server.
/// </summary>
/// <param name="_te">TileEntity to be inspected if also a TileEntityVendingMachine.</param>
/// <param name="___teWorldPos">Vector3i calculated world position of this tile.</param>
public static void Postfix(TileEntity _te, Vector3i ___teWorldPos)
{
try
{
if (Helpers.TryGetTileEntityVendingMachine(_te, out var tileEntityVendingMachine))
{
if (Helpers.TryGetOwner(tileEntityVendingMachine, out var owner))
{
if (Helpers.TryGetClientInfo(owner, out var clientInfo))
{
if (GameManager.Instance.World.Players.dict.TryGetValue(clientInfo.entityId, out var player))
{
// update this data on server's end now since we know it'll be on the way next time a player save packet is sent from client.
clientInfo.latestPlayerData.rentedVMPosition = ___teWorldPos;
clientInfo.latestPlayerData.rentalEndDay = tileEntityVendingMachine.RentalEndDay;
// close the open trader (vending machine) window because the cvar cannot auto-refresh its ui value on its own
clientInfo.SendPackage(NetPackageManager.GetPackage<NetPackageConsoleCmdClient>().Setup("xui close trader", true));
Helpers.SetExpirationDaysRemaining(clientInfo, player);
}
}
}
}
}
catch (Exception e)
{
_log.Error("Postfix", e);
}
}
}

[HarmonyPatch(typeof(GameManager), "SetWorldTime")]
internal class GameManager_SetWorldTime_Patches
{
private static readonly ModLog<GameManager_SetWorldTime_Patches> _log = new ModLog<GameManager_SetWorldTime_Patches>();

public static void Postfix()
{
try
{
var players = GameManager.Instance.World.Players.list;
for (var i = 0; i < players.Count; i++)
{
if (Helpers.TryGetClientInfo(players[i].entityId, out var clientInfo))
{
Helpers.SetExpirationDaysRemaining(clientInfo, players[i]);
}
}
}
catch (Exception e)
{
_log.Error("Postfix", e);
}
}
}

[HarmonyPatch(typeof(GameManager), "updateTimeOfDay")]
internal class GameManager_updateTimeOfDay_Patches
{
private static readonly ModLog<GameManager_updateTimeOfDay_Patches> _log = new ModLog<GameManager_updateTimeOfDay_Patches>();

public static void Postfix()
{
try
{
var players = GameManager.Instance.World.Players.list;
for (var i = 0; i < players.Count; i++)
{
if (Helpers.TryGetClientInfo(players[i].entityId, out var clientInfo))
{
Helpers.SetExpirationDaysRemaining(clientInfo, players[i]);
}
}
}
catch (Exception e)
{
_log.Error("Postfix", e);
}
}
}
}
1 change: 0 additions & 1 deletion src/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
Expand Down
4 changes: 4 additions & 0 deletions src/src.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Helpers.cs" />
<Compile Include="ModLog.cs" />
<Compile Include="Patches.cs" />
<Compile Include="ModApi.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Expand Down

0 comments on commit 0c664f7

Please sign in to comment.