Upload from upload_mods.ps1

This commit is contained in:
Nathaniel Cosford
2025-06-04 16:44:53 +09:30
commit f1fbbe67bb
1722 changed files with 165268 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
using Rebirth.RemoteCrafting;
namespace Features.RemoteCrafting
{
public class DropBoxToContainersPatches
{
[HarmonyPatch(typeof(XUiC_LootContainer))]
[HarmonyPatch("OnClose")]
public class XUiCLootContainerOnClose
{
public static bool Prefix(XUiC_LootContainer __instance, BlockValue ___blockValue, TileEntityLootContainer ___localTileEntity)
{
if (!___blockValue.Block.Properties.Values.ContainsKey("DropBox")) return true;
if (___localTileEntity == null) return true;
StringParsers.TryParseBool(___blockValue.Block.Properties.Values["DropBox"], out var isDropBox);
if (!isDropBox) return true;
var distance = 150f;
var primaryPlayer = __instance.xui.playerUI.entityPlayer;
var items = ___localTileEntity.GetItems();
for (var i = 0; i < items.Length; i++)
{
if (items[i].IsEmpty()) continue;
// If we successfully added, clear the stack.
if (RemoteCraftingUtils.AddToNearbyContainer(primaryPlayer, items[i], distance))
{
Debug.Log($"Removing {items[i].itemValue.ItemClass.GetItemName()}");
items[i] = ItemStack.Empty.Clone();
}
___localTileEntity.UpdateSlot(i, items[i]);
}
___localTileEntity.SetModified();
return true;
}
}
}
}

View File

@@ -0,0 +1,243 @@
using Rebirth.RemoteCrafting;
using System.Collections.Generic;
namespace Features.RemoteCrafting
{
/// <summary>
/// Patches to support the Crafting From Remote Storage
/// </summary>
public class EnhancedRecipeLists
{
/// <summary>
/// Used to determine which recipes the player can craft based on the availability of ingredients in local containers.
/// </summary>
[HarmonyPatch(typeof(XUiC_RecipeList))]
[HarmonyPatch("BuildRecipeInfosList")]
public class BuildRecipeInfosList
{
public static bool Prefix(XUiC_RecipeList __instance, ref List<ItemStack> _items)
{
var player = __instance.xui.playerUI.entityPlayer;
_items.AddRange(RemoteCraftingUtils.SearchNearbyContainers(player));
return true;
}
}
/// <summary>
/// Extends what is considered to be in the player's backpack / tool belt to include local containers.
/// </summary>
[HarmonyPatch(typeof(XUiM_PlayerInventory))]
[HarmonyPatch("GetAllItemStacks")]
public class GetAllItemStacks
{
public static void Postfix(ref List<ItemStack> __result, EntityPlayerLocal ___localPlayer)
{
__result.AddRange(RemoteCraftingUtils.SearchNearbyContainers(___localPlayer));
}
}
/// <summary>
/// Hijacks the GetBindingValue so we can get an accurate count of all the items we have available, including from local storage.
/// </summary>
[HarmonyPatch(typeof(XUiC_IngredientEntry))]
[HarmonyPatch("GetBindingValue")]
public class GetBindingValue
{
public static bool Prefix(XUiC_IngredientEntry __instance, ref bool __result, ref string value,
string bindingName, CachedStringFormatter<int> ___needcountFormatter,
CachedStringFormatter<int> ___havecountFormatter, bool ___materialBased, ItemStack ___ingredient,
string ___material, XUiC_RecipeCraftCount ___craftCountControl,
CachedStringFormatterXuiRgbaColor ___itemicontintcolorFormatter)
{
var flag = ___ingredient != null;
switch (bindingName)
{
case "haveneedcount":
{
var text = (flag
? ___needcountFormatter.Format(___ingredient.count * ___craftCountControl.Count)
: "");
var value1 = 0;
var childByType = __instance.WindowGroup.Controller.GetChildByType<XUiC_WorkstationMaterialInputGrid>();
if (childByType != null)
{
if (___materialBased)
{
value = (flag
? (___havecountFormatter.Format(childByType.GetWeight(___material)) + "/" + text)
: "");
}
else
{
value = (flag
? (___havecountFormatter.Format(
__instance.xui.PlayerInventory.GetItemCount(___ingredient.itemValue)) + "/" +
text)
: "");
}
}
else
{
var childByType2 = __instance.WindowGroup.Controller
.GetChildByType<XUiC_WorkstationInputGrid>();
if (childByType2 != null)
{
value = (flag
? (___havecountFormatter.Format(
childByType2.GetItemCount(___ingredient.itemValue)) + "/" + text)
: "");
}
else
{
value = (flag
? (___havecountFormatter.Format(
__instance.xui.PlayerInventory.GetItemCount(___ingredient.itemValue)) + "/" +
text)
: "");
if (flag)
{
// add items from lootcontainers
value1 = __instance.xui.PlayerInventory.GetItemCount(___ingredient.itemValue);
var array = RemoteCraftingUtils.SearchNearbyContainers(__instance.xui.playerUI.entityPlayer,
___ingredient.itemValue).ToArray();
foreach (var t in array)
{
if (t != null && t.itemValue.type != 0 &&
___ingredient.itemValue.type == t.itemValue.type)
{
value1 += t.count;
}
}
value = ___havecountFormatter.Format(value1) + "/" + text;
}
}
}
__result = true;
return false;
}
default:
return true;
}
}
}
/// <summary>
/// Expands the HasItems search to include local containers.
/// </summary>
[HarmonyPatch(typeof(XUiM_PlayerInventory))]
[HarmonyPatch("HasItems")]
public class HasItems
{
public static bool Postfix(bool __result, IList<ItemStack> _itemStacks, EntityPlayerLocal ___localPlayer,
int _multiplier)
{
if (__result) return true;
// We need to make sure we satisfy all of the items.
var itemsWeHave = 0;
foreach (var itemStack in _itemStacks)
{
var totalCount = 0;
// This is how many we need.
var num = itemStack.count * _multiplier;
// check player inventory
var slots = ___localPlayer.bag.GetSlots();
foreach (var entry in slots)
{
if (entry.IsEmpty()) continue;
if (itemStack.itemValue.GetItemOrBlockId() != entry.itemValue.GetItemOrBlockId()) continue;
totalCount += entry.count;
// We have enough.
if (totalCount >= num)
{
break;
}
}
// We have enough.
if (totalCount >= num)
{
itemsWeHave++;
continue;
}
// Check the toolbelt now.
slots = ___localPlayer.inventory.GetSlots();
foreach (var entry in slots)
{
if (entry.IsEmpty()) continue;
if (itemStack.itemValue.GetItemOrBlockId() != entry.itemValue.GetItemOrBlockId()) continue;
totalCount += entry.count;
// We have enough.
if (totalCount >= num)
break;
}
// We have enough.
if (totalCount >= num)
{
itemsWeHave++;
continue;
}
// check container
var containers = RemoteCraftingUtils.SearchNearbyContainers(___localPlayer, itemStack.itemValue);
foreach (var stack in containers)
{
if (stack.IsEmpty()) continue;
if (itemStack.itemValue.GetItemOrBlockId() != stack.itemValue.GetItemOrBlockId()) continue;
totalCount += stack.count;
// We have enough.
if (totalCount >= num)
break;
}
// We don't have enough for this.
if (totalCount < num)
{
return false;
}
if (totalCount >= num)
{
itemsWeHave++;
}
}
return itemsWeHave >= _itemStacks.Count;
}
}
/// <summary>
/// Removes from local storage containers items which we've consumed.
/// </summary>
[HarmonyPatch(typeof(XUiM_PlayerInventory))]
[HarmonyPatch("RemoveItems")]
public class RemoveItems
{
public static bool Prefix(XUiM_PlayerInventory __instance, IList<ItemStack> _itemStacks, EntityPlayerLocal ___localPlayer, int _multiplier, IList<ItemStack> _removedItems
, Bag ___backpack, Inventory ___toolbelt)
{
RemoteCraftingUtils.ConsumeItem(_itemStacks, ___localPlayer, _multiplier, _removedItems, ___backpack, ___toolbelt);
return false;
}
}
// Code from OCB7D2D/OcbPinRecipes
// Patch world unload to cleanup and save on exit
[HarmonyPatch(typeof(World))]
[HarmonyPatch("UnloadWorld")]
public class WorldUnloadWorld
{
static void Postfix()
{
if (!Broadcastmanager.HasInstance) return;
Broadcastmanager.Cleanup();
}
}
}
}

View File

@@ -0,0 +1,322 @@
using HarmonyLib;
using Rebirth.RemoteCrafting;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
// todo - fix as methods have changed
namespace Features.RemoteCrafting
{
/// <summary>
/// Patches to support repairing from remote storage
/// </summary>
public class ItemActionRepairPatches
{
private struct UpgradeInfo
{
public string FromBlock;
public string ToBlock;
public string Item;
public int ItemCount;
public string Sound;
public int Hits;
}
[HarmonyPatch(typeof(ItemActionRepair))]
[HarmonyPatch("RemoveRequiredResource")]
public class RemoveRequiredResource
{
private static bool Prefix(ref bool __result, ItemActionRepair __instance, ItemInventoryData data, UpgradeInfo ___currentUpgradeInfo)
{
if (string.IsNullOrEmpty(___currentUpgradeInfo.Item))
{
__result = true;
return false;
}
var itemValue = ItemClass.GetItem(___currentUpgradeInfo.Item);
if (data.holdingEntity.inventory.DecItem(itemValue, ___currentUpgradeInfo.ItemCount) == ___currentUpgradeInfo.ItemCount)
{
var entityPlayerLocal = data.holdingEntity as EntityPlayerLocal;
if (entityPlayerLocal != null && ___currentUpgradeInfo.ItemCount != 0)
{
entityPlayerLocal.AddUIHarvestingItem(new ItemStack(itemValue, -___currentUpgradeInfo.ItemCount));
}
__result = true;
return false;
}
if (data.holdingEntity.bag.DecItem(itemValue, ___currentUpgradeInfo.ItemCount) == ___currentUpgradeInfo.ItemCount)
{
var entityPlayerLocal2 = data.holdingEntity as EntityPlayerLocal;
if (entityPlayerLocal2 != null)
{
entityPlayerLocal2.AddUIHarvestingItem(new ItemStack(itemValue, -___currentUpgradeInfo.ItemCount));
}
__result = true;
return false;
}
var primaryPlayer = GameManager.Instance.World.GetPrimaryPlayer();
var distance = 150f;
var tileEntities = RemoteCraftingUtils.GetTileEntities(primaryPlayer, distance);
// counter quantity needed from item
var q = ___currentUpgradeInfo.ItemCount;
var itemStack = new ItemStack(ItemClass.GetItem(___currentUpgradeInfo.Item, false), ___currentUpgradeInfo.ItemCount);
//check player inventory for materials and reduce counter
var slots = primaryPlayer.bag.GetSlots();
q = q - slots
.Where(x => x.itemValue.ItemClass == itemStack.itemValue.ItemClass)
.Sum(y => y.count);
// check storage boxes
foreach (var tileEntity in tileEntities)
{
if (q <= 0) break;
if (tileEntity is not TileEntityLootContainer lootTileEntity) continue;
// If there's no items in this container, skip.
if (!lootTileEntity.HasItem(itemStack.itemValue)) continue;
for (var y = 0; y < lootTileEntity.items.Length; y++)
{
var item = lootTileEntity.items[y];
if (item.IsEmpty()) continue;
if (item.itemValue.ItemClass != itemStack.itemValue.ItemClass) continue;
// If we can completely satisfy the result, let's do that.
if (item.count >= q)
{
item.count -= q;
q = 0;
}
else
{
// Otherwise, let's just count down until we meet the requirement.
while (q >= 0)
{
item.count--;
q--;
if (item.count <= 0)
break;
}
}
//Update the slot on the container, and do the Setmodified(), so that the dedis can get updated.
if (item.count < 1)
lootTileEntity.UpdateSlot(y, ItemStack.Empty.Clone());
else
lootTileEntity.UpdateSlot(y, item);
lootTileEntity.SetModified();
}
}
primaryPlayer.AddUIHarvestingItem(new ItemStack(itemValue, -___currentUpgradeInfo.ItemCount), false);
__result = true;
return false;
}
}
[HarmonyPatch(typeof(ItemActionRepair))]
[HarmonyPatch("CanRemoveRequiredResource")]
public class CanRemoveRequiredResource
{
private static bool Prefix(ref bool __result, ItemActionRepair __instance, ItemInventoryData data, BlockValue blockValue, ref UpgradeInfo ___currentUpgradeInfo, string ___allowedUpgradeItems, string ___restrictedUpgradeItems, string ___upgradeActionSound, float ___hitCountOffset)
{
var block = blockValue.Block;
var flag = block.Properties.Values.ContainsKey("UpgradeBlock.Item");
var upgradeInfo = default(UpgradeInfo);
upgradeInfo.FromBlock = block.GetBlockName();
upgradeInfo.ToBlock = block.Properties.Values[Block.PropUpgradeBlockClassToBlock];
upgradeInfo.Sound = "";
if (flag)
{
upgradeInfo.Item = block.Properties.Values["UpgradeBlock.Item"];
if (___allowedUpgradeItems.Length > 0 && !___allowedUpgradeItems.ContainsCaseInsensitive(upgradeInfo.Item))
{
__result = false;
return false;
}
if (___restrictedUpgradeItems.Length > 0 && ___restrictedUpgradeItems.ContainsCaseInsensitive(upgradeInfo.Item))
{
__result = false;
return false;
}
}
if (___upgradeActionSound.Length > 0)
{
upgradeInfo.Sound = ___upgradeActionSound;
}
else if (flag)
{
var item = ItemClass.GetItem(upgradeInfo.Item);
if (item != null)
{
var itemClass = ItemClass.GetForId(item.type);
if (itemClass != null)
{
upgradeInfo.Sound =
$"ImpactSurface/{data.holdingEntity.inventory.holdingItem.MadeOfMaterial.SurfaceCategory}hit{itemClass.MadeOfMaterial.SurfaceCategory}";
}
}
}
if (!int.TryParse(block.Properties.Values["UpgradeBlock.UpgradeHitCount"], out var num))
{
__result = false;
return false;
}
upgradeInfo.Hits = (int)(num + ___hitCountOffset < 1f ? 1f : num + ___hitCountOffset);
if (!int.TryParse(block.Properties.Values[Block.PropUpgradeBlockClassItemCount], out upgradeInfo.ItemCount) && flag)
{
__result = false;
return false;
}
___currentUpgradeInfo = upgradeInfo;
if (___currentUpgradeInfo.FromBlock != null && flag)
{
var item = ItemClass.GetItem(___currentUpgradeInfo.Item, false);
if (data.holdingEntity.inventory.GetItemCount(item) >= ___currentUpgradeInfo.ItemCount)
{
__result = true;
return false;
}
if (data.holdingEntity.bag.GetItemCount(item) >= ___currentUpgradeInfo.ItemCount)
{
__result = true;
return false;
}
}
else if (!flag)
{
__result = true;
return false;
}
var primaryPlayer = GameManager.Instance.World.GetPrimaryPlayer();
var itemStack = new ItemStack(ItemClass.GetItem(___currentUpgradeInfo.Item), ___currentUpgradeInfo.ItemCount);
var distance = 150f;
var totalCount = RemoteCraftingUtils.SearchNearbyContainers(primaryPlayer, itemStack.itemValue, distance).Sum(y => y.count);
if (totalCount >= ___currentUpgradeInfo.ItemCount)
{
__result = true;
return false;
}
__result = false;
return false;
}
}
[HarmonyPatch(typeof(ItemActionRepair))]
[HarmonyPatch("removeRequiredItem")]
public class RemoveRequiredItem
{
private static bool Prefix(ref bool __result, ItemActionRepair __instance, ItemInventoryData _data, ItemStack _itemStack)
{
__result = false;
__result = _data.holdingEntity.inventory.DecItem(_itemStack.itemValue, _itemStack.count) == _itemStack.count || _data.holdingEntity.bag.DecItem(_itemStack.itemValue, _itemStack.count, false) == _itemStack.count;
if (__result)
{
return false;
}
var primaryPlayer = GameManager.Instance.World.GetPrimaryPlayer();
var distance = 150f;
var tileEntities = RemoteCraftingUtils.GetTileEntities(primaryPlayer, distance);
// counter quantity needed from item
var q = _itemStack.count;
//check player inventory for materials and reduce counter
var slots = primaryPlayer.bag.GetSlots();
q -= slots
.Where(x => x.itemValue.ItemClass == _itemStack.itemValue.ItemClass)
.Sum(y => y.count);
// check storage boxes
foreach (var tileEntity in tileEntities)
{
if (q <= 0) break;
if (tileEntity is not TileEntityLootContainer lootTileEntity) continue;
// If there's no items in this container, skip.
if (!lootTileEntity.HasItem(_itemStack.itemValue)) continue;
for (var y = 0; y < lootTileEntity.items.Length; y++)
{
var item = lootTileEntity.items[y];
if (item.IsEmpty()) continue;
if (item.itemValue.ItemClass != _itemStack.itemValue.ItemClass) continue;
// If we can completely satisfy the result, let's do that.
if (item.count >= q)
{
item.count -= q;
q = 0;
}
else
{
// Otherwise, let's just count down until we meet the requirement.
while (q >= 0)
{
item.count--;
q--;
if (item.count <= 0)
break;
}
}
//Update the slot on the container, and do the Setmodified(), so that the dedis can get updated.
if (item.count < 1)
lootTileEntity.UpdateSlot(y, ItemStack.Empty.Clone());
else
lootTileEntity.UpdateSlot(y, item);
lootTileEntity.SetModified();
}
}
return false;
}
}
[HarmonyPatch(typeof(ItemActionRepair))]
[HarmonyPatch("canRemoveRequiredItem")]
public class CanRemoveRequiredItem
{
private static bool Prefix(ref bool __result, ItemActionRepair __instance, ItemInventoryData _data, ItemStack _itemStack)
{
__result = false;
if (_data.holdingEntity.inventory.GetItemCount(_itemStack.itemValue) >= _itemStack.count || _data.holdingEntity.bag.GetItemCount(_itemStack.itemValue) >= _itemStack.count)
{
__result = true;
return false;
}
var primaryPlayer = GameManager.Instance.World.GetPrimaryPlayer();
var distance = 150f;
var totalCount = RemoteCraftingUtils.SearchNearbyContainers(primaryPlayer, _itemStack.itemValue, distance).Sum(y => y.count);
if (totalCount <= 0) return false;
__result = true;
return false;
}
}
}
}

View File

@@ -0,0 +1,204 @@
using System.Collections.Concurrent;
// Stripped down Firemanager
public class Broadcastmanager
{
private static Broadcastmanager instance = null;
private static ConcurrentDictionary<Vector3i, BlockValue> Broadcastmap = new ConcurrentDictionary<Vector3i, BlockValue>();
private const string saveFile = "Broadcastmanager.dat";
private ThreadManager.ThreadInfo dataSaveThreadInfo;
public static bool HasInstance => instance != null;
//public bool Enabled { private set; get; }
public static Broadcastmanager Instance
{
get
{
return instance;
}
}
public static void Init()
{
Broadcastmanager.instance = new Broadcastmanager();
Log.Out("Starting Broadcast Manager");
// Read the Broadcastmanager
Broadcastmanager.Instance.Load();
}
// Save the lootcontainer location.
public void Write(BinaryWriter _bw)
{
_bw.Write("V1");
foreach (var temp in Broadcastmap)
_bw.Write(temp.Key.ToString());
}
// Read lootcontainer location.
public void Read(BinaryReader _br)
{
var version = _br.ReadString();
if (version == "V1")
{
while (_br.BaseStream.Position != _br.BaseStream.Length)
{
string container = _br.ReadString();
add(StringParsers.ParseVector3i(container));
}
}
else
{
foreach (var position in version.Split(';'))
while (_br.BaseStream.Position != _br.BaseStream.Length)
{
if (string.IsNullOrEmpty(position)) continue;
var vector = StringParsers.ParseVector3i(position);
add(vector);
add(StringParsers.ParseVector3i(_br.ReadString()));
}
}
}
// check if lootcontainer exists in dictionary
public bool Check(Vector3i _blockPos)
{
return Broadcastmap.TryGetValue(_blockPos, out _);
}
public void Add(Vector3i _blockPos, int entityID = -1)
{
if (!GameManager.IsDedicatedServer)
add(_blockPos);
if (!SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer)
{
SingletonMonoBehaviour<ConnectionManager>.Instance.SendToServer(NetPackageManager.GetPackage<NetPackageAddBroadcastPosition>().Setup(_blockPos, entityID), false);
return;
}
SingletonMonoBehaviour<ConnectionManager>.Instance.SendPackage(NetPackageManager.GetPackage<NetPackageAddBroadcastPosition>().Setup(_blockPos, entityID), false, -1, -1, -1, null, 192);
}
public void Remove(Vector3i _blockPos, int entityID = -1)
{
if (!GameManager.IsDedicatedServer)
remove(_blockPos);
if (!SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer)
{
SingletonMonoBehaviour<ConnectionManager>.Instance.SendToServer(NetPackageManager.GetPackage<NetPackageRemoveBroadcastPosition>().Setup(_blockPos, entityID), false);
return;
}
SingletonMonoBehaviour<ConnectionManager>.Instance.SendPackage(NetPackageManager.GetPackage<NetPackageRemoveBroadcastPosition>().Setup(_blockPos, entityID), false, -1, -1, -1, null, 192);
}
// Remove lootcontainer from dictionary
public void remove(Vector3i _blockPos)
{
if (!Broadcastmap.ContainsKey(_blockPos)) return;
Broadcastmap.TryRemove(_blockPos, out var block);
}
// Add lootcontainer to dictionary
public void add(Vector3i _blockPos)
{
var block = GameManager.Instance.World.GetBlock(_blockPos);
Broadcastmap.TryAdd(_blockPos, block);
}
private int saveDataThreaded(ThreadManager.ThreadInfo _threadInfo)
{
PooledExpandableMemoryStream pooledExpandableMemoryStream = (PooledExpandableMemoryStream)_threadInfo.parameter;
string text = string.Format("{0}/{1}", GameIO.GetSaveGameDir(), saveFile);
if (!Directory.Exists(GameIO.GetSaveGameDir()))
{
Directory.CreateDirectory(GameIO.GetSaveGameDir());
}
if (File.Exists(text))
{
File.Copy(text, string.Format("{0}/{1}", GameIO.GetSaveGameDir(), $"{saveFile}.bak"), true);
}
pooledExpandableMemoryStream.Position = 0L;
StreamUtils.WriteStreamToFile(pooledExpandableMemoryStream, text);
MemoryPools.poolMemoryStream.FreeSync(pooledExpandableMemoryStream);
Log.Out($"Broadcast Manager {text} Saving: {Broadcastmap.Count}");
return -1;
}
public void Save()
{
if (this.dataSaveThreadInfo == null || !ThreadManager.ActiveThreads.ContainsKey("silent_BroadcastDataSave"))
{
PooledExpandableMemoryStream pooledExpandableMemoryStream = MemoryPools.poolMemoryStream.AllocSync(true);
using (PooledBinaryWriter pooledBinaryWriter = MemoryPools.poolBinaryWriter.AllocSync(false))
{
pooledBinaryWriter.SetBaseStream(pooledExpandableMemoryStream);
this.Write(pooledBinaryWriter);
}
this.dataSaveThreadInfo = ThreadManager.StartThread("silent_BroadcastDataSave", null, new ThreadManager.ThreadFunctionLoopDelegate(this.saveDataThreaded), null, System.Threading.ThreadPriority.Normal, pooledExpandableMemoryStream, null, false);
}
}
public void Load()
{
string path = string.Format("{0}/{1}", GameIO.GetSaveGameDir(), saveFile);
if (Directory.Exists(GameIO.GetSaveGameDir()) && File.Exists(path))
{
try
{
using (FileStream fileStream = File.OpenRead(path))
{
using (PooledBinaryReader pooledBinaryReader = MemoryPools.poolBinaryReader.AllocSync(false))
{
pooledBinaryReader.SetBaseStream(fileStream);
this.Read(pooledBinaryReader);
}
}
}
catch (Exception)
{
path = string.Format("{0}/{1}", GameIO.GetSaveGameDir(), $"{saveFile}.bak");
if (File.Exists(path))
{
using (FileStream fileStream2 = File.OpenRead(path))
{
using (PooledBinaryReader pooledBinaryReader2 = MemoryPools.poolBinaryReader.AllocSync(false))
{
pooledBinaryReader2.SetBaseStream(fileStream2);
this.Read(pooledBinaryReader2);
}
}
}
}
Log.Out($"Broadcast Manager {path} Loaded: {Broadcastmap.Count}");
}
}
private void WaitOnSave()
{
if (this.dataSaveThreadInfo != null)
{
this.dataSaveThreadInfo.WaitForEnd();
this.dataSaveThreadInfo = null;
}
}
public static void Cleanup()
{
if (instance != null)
{
instance.SaveAndClear();
}
}
private void SaveAndClear()
{
WaitOnSave();
Save();
WaitOnSave();
Broadcastmap.Clear();
instance = null;
Log.Out("Broadcastmanager stopped");
}
}

View File

@@ -0,0 +1,54 @@
using Rebirth.RemoteCrafting;
public class BlockDropBoxContainer : BlockSecureLootSigned
{
private float _distance;
private float _updateTime;
public override void Init()
{
base.Init();
_distance = RebirthVariables.broadcastDistance;
Properties.ParseFloat("Distance", ref _distance);
_updateTime = 100UL;
Properties.ParseFloat("UpdateTick", ref _updateTime);
}
public override ulong GetTickRate()
{
return (ulong)_updateTime;
}
public override void OnBlockAdded(WorldBase world, Chunk _chunk, Vector3i _blockPos, BlockValue _blockValue)
{
base.OnBlockAdded(world, _chunk, _blockPos, _blockValue);
if (!world.IsRemote())
{
world.GetWBT().AddScheduledBlockUpdate(0, _blockPos, this.blockID, GetTickRate());
}
}
public override bool UpdateTick(WorldBase world, int _clrIdx, Vector3i _blockPos, BlockValue _blockValue,
bool _bRandomTick, ulong _ticksIfLoaded, GameRandom _rnd)
{
var tileLootContainer = (TileEntityLootContainer)world.GetTileEntity(_clrIdx, _blockPos);
if (tileLootContainer == null) return false;
if (!tileLootContainer.IsUserAccessing())
{
var primaryPlayer = GameManager.Instance.World.GetPrimaryPlayer();
foreach (var itemStack in tileLootContainer.GetItems())
{
if (itemStack.IsEmpty()) continue;
// If we successfully added, clear the stack.
if (RemoteCraftingUtils.AddToNearbyContainer(primaryPlayer, itemStack, _distance))
itemStack.Clear();
}
tileLootContainer.bTouched = true;
tileLootContainer.SetModified();
}
world.GetWBT().AddScheduledBlockUpdate(0, _blockPos, this.blockID, GetTickRate());
return true;
}
}

View File

@@ -0,0 +1,49 @@
//copy of NetPackageAddFirePosition
public class NetPackageAddBroadcastPosition : NetPackage
{
private Vector3i position;
private int entityThatCausedIt;
public NetPackageAddBroadcastPosition Setup(Vector3i _position, int _entityThatCausedIt)
{
this.position = _position;
this.entityThatCausedIt = _entityThatCausedIt;
return this;
}
public override void read(PooledBinaryReader _br)
{
this.position = new Vector3i((float)_br.ReadInt32(), (float)_br.ReadInt32(), (float)_br.ReadInt32());
this.entityThatCausedIt = _br.ReadInt32();
}
public override void write(PooledBinaryWriter _bw)
{
base.write(_bw);
_bw.Write((int)this.position.x);
_bw.Write((int)this.position.y);
_bw.Write((int)this.position.z);
_bw.Write(this.entityThatCausedIt);
}
public override int GetLength()
{
return 20;
}
public override void ProcessPackage(World _world, GameManager _callbacks)
{
if (_world == null)
{
return;
}
if (!_world.IsRemote())
{
return;
}
Broadcastmanager.Instance.add(position);
}
}

View File

@@ -0,0 +1,49 @@
//copy of NetPackageRemoveFirePosition
public class NetPackageRemoveBroadcastPosition : NetPackage
{
private Vector3i position;
private int entityThatCausedIt;
public NetPackageRemoveBroadcastPosition Setup(Vector3i _position, int _entityThatCausedIt)
{
this.position = _position;
this.entityThatCausedIt = _entityThatCausedIt;
return this;
}
public override void read(PooledBinaryReader _br)
{
this.position = new Vector3i((float)_br.ReadInt32(), (float)_br.ReadInt32(), (float)_br.ReadInt32());
this.entityThatCausedIt = _br.ReadInt32();
}
public override void write(PooledBinaryWriter _bw)
{
base.write(_bw);
_bw.Write((int)this.position.x);
_bw.Write((int)this.position.y);
_bw.Write((int)this.position.z);
_bw.Write(this.entityThatCausedIt);
}
public override int GetLength()
{
return 20;
}
public override void ProcessPackage(World _world, GameManager _callbacks)
{
if (_world == null)
{
return;
}
if (!_world.IsRemote())
{
return;
}
Broadcastmanager.Instance.remove(position);
}
}

View File

@@ -0,0 +1,281 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using System.Linq;
namespace Rebirth.RemoteCrafting
{
[UsedImplicitly]
public class RemoteCraftingUtils
{
public static List<TileEntity> GetTileEntities(EntityAlive player)
{
var distance = 150f;
var tileEntities = RebirthUtilities.GetTileEntities(player, distance);
return tileEntities;
}
public static bool DisableSender(IEnumerable<string> value, TileEntity tileEntity)
{
if (tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage))
{
if (value.All(x => x.Trim() != storage.lootListName))
{
return true;
}
}
else
{
return false;
}
return false;
}
private static bool BindToWorkstation(string value, EntityAlive player, TileEntity tileEntity)
{
var result = false;
if (player is not EntityPlayerLocal playerLocal) return false;
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) return false;
// TODO: we want to refactor this to remove the complex LinQ.
// what could be easier than linq?
// bind storage to workstation
if (value.Split(';').Where(x =>
x.Split(':')[0].Split(',').Any(ws => ws.Trim() == playerLocal.PlayerUI.xui.currentWorkstation))
.Any(x => x.Split(':')[1].Split(',').Any(y => y == storage.lootListName))) result = true;
// bind storage to other workstations if allowed
if (value.Split(';').Any(x =>
x.Split(':')[0].Split(',').Any(ws => ws.Trim() == playerLocal.PlayerUI.xui.currentWorkstation)))
return result;
{
if (value.Split(';').Any(x => x.Split(':')[1].Split(',').Any(y => y == storage.lootListName)))
{
result = false;
}
else
{
result = true;
}
}
return result;
}
private static bool NotToWorkstation(string value, EntityAlive player, TileEntity tileEntity)
{
var result = false;
if (player is not EntityPlayerLocal playerLocal) return false;
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) return false;
foreach (var bind in value.Split(';'))
{
var workstation = bind.Split(':')[0].Split(',');
var disablebinding = bind.Split(':')[1].Split(',');
if ((workstation.Any(ws => ws.Trim() == playerLocal.PlayerUI.xui.currentWorkstation)) &&
(disablebinding.Any(x => x.Trim() == storage.lootListName))) result = true;
}
return result;
}
public static List<ItemStack> SearchNearbyContainers(EntityAlive player)
{
var items = new List<ItemStack>();
var tileEntities = GetTileEntities(player);
foreach (var tileEntity in tileEntities)
{
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) continue;
if (storage.IsUserAccessing()) continue;
items.AddRange(storage.items);
}
return items;
}
public static List<ItemStack> SearchNearbyContainers(EntityAlive player, ItemValue itemValue)
{
var item = new List<ItemStack>();
var items = new List<ItemStack>();
var tileEntities = GetTileEntities(player);
foreach (var tileEntity in tileEntities)
{
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) continue;
// If the container is open, don't use it.
if (storage.IsUserAccessing()) continue;
item.AddRange(storage.items);
}
foreach (var t in item)
{
if ((!t.itemValue.HasModSlots || !t.itemValue.HasMods()) &&
t.itemValue.type == itemValue.type)
{
items.Add(t);
}
}
return items;
}
public static List<ItemStack> SearchNearbyContainers(EntityAlive player, ItemValue itemValue, float distance)
{
var item = new List<ItemStack>();
var items = new List<ItemStack>();
var tileEntities = RebirthUtilities.GetTileEntities(player, distance);
foreach (var tileEntity in tileEntities)
{
if (tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage))
{
if (storage.IsUserAccessing()) continue;
item.AddRange(storage.items);
}
}
foreach (var t in item)
{
if ((!t.itemValue.HasModSlots || !t.itemValue.HasMods()) &&
t.itemValue.type == itemValue.type)
{
items.Add(t);
}
}
return items;
}
public static bool AddToNearbyContainer(EntityAlive player, ItemStack itemStack, float distance)
{
var tileEntities = RebirthUtilities.GetTileEntities(player, distance);
foreach (var tileEntity in tileEntities)
{
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) continue;
// If the container is open, don't include it.
if (storage.IsUserAccessing()) continue;
// Don't try to add to a drop box.
if (storage.blockValue.Block.Properties.Values.ContainsKey("DropBox")) continue;
// Can we quickly find a incomplete stack?
//if (lootTileEntity.TryStackItem(0, itemStack)) return true;
var result = storage.TryStackItem(0, itemStack);
if (result.allMoved) return true;
var matchingItem = false;
// Loop through the items and see if we have any matching items.
foreach (var item in storage.items)
{
// We match with something.
if (item.itemValue.type != itemStack.itemValue.type) continue;
matchingItem = true;
break;
}
// If we don't match, don't try to add.
if (!matchingItem) continue;
// We added a full stack! No need to keep processing.
if (storage.AddItem(itemStack)) return true;
}
return false;
}
public static void ConsumeItem(IEnumerable<ItemStack> itemStacks, EntityPlayerLocal localPlayer, int multiplier, IList<ItemStack> _removedItems, Bag bag, Inventory toolbelt)
{
var tileEntities = GetTileEntities(localPlayer);
var enumerable = itemStacks as ItemStack[] ?? itemStacks.ToArray();
for (var i = 0; i < enumerable.Count(); i++)
{
// Grab from the backpack first.
var num = enumerable[i].count * multiplier;
if (bag != null)
{
num -= bag.DecItem(enumerable[i].itemValue, num, true, _removedItems);
if (num > 0)
{
// Check tool belt
if (toolbelt != null)
{
num -= toolbelt.DecItem(enumerable[i].itemValue, num, true, _removedItems);
}
}
}
// We've met our goals for this.
if (num <= 0) continue;
// check storage boxes
foreach (var tileEntity in tileEntities)
{
if (num <= 0) break;
if (!tileEntity.TryGetSelfOrFeature(out ITileEntityLootable storage)) continue;
// If someone is using the tool account, skip it.
if (storage.IsUserAccessing()) continue;
// If there's no items in this container, skip.
if (!storage.HasItem(enumerable[i].itemValue)) continue;
for (var y = 0; y < storage.items.Length; y++)
{
var item = storage.items[y];
if (item.IsEmpty()) continue;
if (item.itemValue.ItemClass != enumerable[i].itemValue.ItemClass) continue;
// If we can completely satisfy the result, let's do that.
if (item.count >= num)
{
item.count -= num;
// Add the item to the removed items list so we can return it.
_removedItems.Add(new ItemStack(item.itemValue.Clone(), num));
num = 0;
}
else
{
// Otherwise, let's just count down until we meet the requirement.
while (num >= 0)
{
item.count--;
num--;
if (item.count <= 0)
{
_removedItems.Add(new ItemStack(item.itemValue.Clone(), num));
break;
}
}
}
//Update the slot on the container, and do the Setmodified(), so that the dedis can get updated.
if (item.count < 1)
{
// Add it to the removed list.
_removedItems.Add(item.Clone());
storage.UpdateSlot(y, ItemStack.Empty.Clone());
}
else
{
storage.UpdateSlot(y, item);
}
}
storage.SetModified();
}
}
}
}
}

View File

@@ -0,0 +1,89 @@
// Code from Laydor slightly modified
public class XUiC_BroadcastButton : XUiController
{
private XUiV_Button _button;
public override void Init()
{
base.Init();
_button = viewComponent as XUiV_Button;
OnPress += Grab_OnPress;
}
public override void Update(float dt)
{
base.Update(dt);
if (!IsDirty) return;
IsDirty = false;
SetupButton();
}
public override void OnOpen()
{
base.OnOpen();
IsDirty = true;
}
private void Grab_OnPress(XUiController sender, int mouseButton)
{
//Check if Broadcastmanager is running
if (!Broadcastmanager.HasInstance) return;
if (Broadcastmanager.Instance.Check(xui.lootContainer.ToWorldPos()))
{
//Unselect button
_button.Selected = true;
// Remove from Broadcastmanager dictionary
Broadcastmanager.Instance.remove(xui.lootContainer.ToWorldPos());
}
else
{
//Select button
_button.Selected = false;
// Add to Broadcastmanager dictionary
Broadcastmanager.Instance.add(xui.lootContainer.ToWorldPos());
}
}
private void SetupButton()
{
//Log.Out("XUiC_BroadcastButton-SetupButton START");
//Unselect button and disable it
_button.Enabled = false;
_button.Selected = false;
_button.IsVisible = false;
if (xui.lootContainer != null)
{
Entity entity = GameManager.Instance.World.GetEntity(xui.lootContainer.EntityId) as Entity;
//Log.Out("XUiC_BroadcastButton-SetupButton entity: " + entity.EntityClass.entityClassName);
//Log.Out("XUiC_BroadcastButton-SetupButton entity is EntityAliveV2: " + (entity is EntityAliveV2));
if (entity is EntityAliveV2)
{
return;
}
}
if (xui.lootContainer == null || !Broadcastmanager.HasInstance ||
xui.vehicle != null ||
(xui.lootContainer != null && GameManager.Instance.World.GetEntity(xui.lootContainer.EntityId) is EntityDrone))
{
//Log.Out("XUiC_BroadcastButton-SetupButton xui.lootContainer == null: " + (xui.lootContainer == null));
//Log.Out("XUiC_BroadcastButton-SetupButton !Broadcastmanager.HasInstance: " + (!Broadcastmanager.HasInstance));
//Log.Out("XUiC_BroadcastButton-SetupButton xui.vehicle != null: " + (xui.vehicle != null));
//Log.Out("XUiC_BroadcastButton-SetupButton EntityNPCRebirth: " + ((xui.lootContainer != null && GameManager.Instance.World.GetEntity(xui.lootContainer.entityId)) is EntityNPCRebirth));
//Log.Out("XUiC_BroadcastButton-SetupButton EntityDrone: " + ((xui.lootContainer != null && GameManager.Instance.World.GetEntity(xui.lootContainer.entityId) is EntityDrone)));
return;
}
//Enable button and set if button is selected
_button.IsVisible = true;
_button.Enabled = true;
_button.Selected = !Broadcastmanager.Instance.Check(xui.lootContainer.ToWorldPos());
//Log.Out("XUiC_BroadcastButton-SetupButton END");
}
}