From 9e77c2c9fcd08551de89eb75919fa705926c9758 Mon Sep 17 00:00:00 2001 From: jonathan-robertson Date: Mon, 30 Dec 2024 18:36:47 -0600 Subject: [PATCH 1/4] snap recovered entity to center of tile --- CHANGELOG.md | 4 ++++ ModInfo.xml | 2 +- src/Patches/Entity.cs | 8 ++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9433cd..8ebbb08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.4] - 2024-12-30 + +- snap recovered entity to center of tile + ## [0.1.3] - 2024-12-30 - further reduce and refine logging diff --git a/ModInfo.xml b/ModInfo.xml index 4542528..228f039 100644 --- a/ModInfo.xml +++ b/ModInfo.xml @@ -1,7 +1,7 @@ - + diff --git a/src/Patches/Entity.cs b/src/Patches/Entity.cs index 7eb6f73..61fb28e 100644 --- a/src/Patches/Entity.cs +++ b/src/Patches/Entity.cs @@ -44,12 +44,20 @@ public static bool Prefix(Entity __instance) if (!IsWithinWorldBoundsY(__instance.position)) { var newPos = __instance.position; + + // snap to x/z center of current block + newPos.x -= (newPos.x % 1.0f) + 0.5f; + newPos.z -= (newPos.z % 1.0f) + 0.5f; + + // find new y position based on height newPos.y = GameManager.Instance.World.GetHeightAt(__instance.position.x, __instance.position.z); if (!IsWithinWorldBoundsY(newPos)) { _log.Trace($"A valid position could not be determined to recover {__instance.entityId}; allowing entity unload."); return true; } + + // move entity _log.Info($"Detected {__instance.entityType} entity {__instance.entityId} ({__instance.GetType()} // {__instance.GetDebugName()}) fell out of bottom of world; repositioning from {__instance.position.ToCultureInvariantString()} to {newPos.ToCultureInvariantString()}"); __instance.SetPosition(newPos); ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage().Setup(__instance), false, -1, -1, -1, __instance.position, 192); From bb67d5ac3763c251d91c6aec7d9a00c125745c00 Mon Sep 17 00:00:00 2001 From: jonathan-robertson Date: Mon, 30 Dec 2024 20:58:31 -0600 Subject: [PATCH 2/4] pile entities if present at destination --- CHANGELOG.md | 1 + src/Patches/Entity.cs | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ebbb08..2e3a03f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.4] - 2024-12-30 +- pile entities if present at destination - snap recovered entity to center of tile ## [0.1.3] - 2024-12-30 diff --git a/src/Patches/Entity.cs b/src/Patches/Entity.cs index 61fb28e..80271d0 100644 --- a/src/Patches/Entity.cs +++ b/src/Patches/Entity.cs @@ -1,6 +1,8 @@ using HarmonyLib; using OffWorldFix.Utilities; using System; +using System.Collections.Generic; +using UnityEngine; namespace OffWorldFix.Patches { @@ -8,6 +10,7 @@ namespace OffWorldFix.Patches internal class Entity_MarkToUnload_Patches { private static readonly ModLog _log = new ModLog(); + private static readonly Vector3 BLOCK_CENTER = new Vector3(0.5f, 0, 0.5f); /// /// @@ -43,22 +46,29 @@ public static bool Prefix(Entity __instance) if (!IsWithinWorldBoundsY(__instance.position)) { - var newPos = __instance.position; - - // snap to x/z center of current block - newPos.x -= (newPos.x % 1.0f) + 0.5f; - newPos.z -= (newPos.z % 1.0f) + 0.5f; + var newPos = __instance.GetBlockPosition() + BLOCK_CENTER; + var entitySize = new Vector3(__instance.width, __instance.height, __instance.depth); // find new y position based on height - newPos.y = GameManager.Instance.World.GetHeightAt(__instance.position.x, __instance.position.z); + newPos.y = GameManager.Instance.World.GetHeightAt(__instance.position.x, __instance.position.z) + entitySize.y; if (!IsWithinWorldBoundsY(newPos)) { _log.Trace($"A valid position could not be determined to recover {__instance.entityId}; allowing entity unload."); return true; } + while (GetEntitiesAt(newPos, entitySize).Count > 0 && newPos.y < ModApi.MAP_MAX.y) + { + newPos.y += entitySize.y; + } + if (newPos.y >= ModApi.MAP_MAX.y) + { + _log.Trace($"A valid position was crawled but could not be determined to recover {__instance.entityId} due to too many entities at each possible vertical respawn destination; allowing entity unload."); + return true; // TODO: test! + } // move entity _log.Info($"Detected {__instance.entityType} entity {__instance.entityId} ({__instance.GetType()} // {__instance.GetDebugName()}) fell out of bottom of world; repositioning from {__instance.position.ToCultureInvariantString()} to {newPos.ToCultureInvariantString()}"); + __instance.SetVelocity(Vector3.zero); __instance.SetPosition(newPos); ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage().Setup(__instance), false, -1, -1, -1, __instance.position, 192); return false; @@ -71,7 +81,7 @@ public static bool Prefix(Entity __instance) return true; } - private static bool IsWithinWorldBoundsXAndZ(UnityEngine.Vector3 position) + private static bool IsWithinWorldBoundsXAndZ(Vector3 position) { return position.x > ModApi.MAP_MIN.x && position.z > ModApi.MAP_MIN.z @@ -79,10 +89,20 @@ private static bool IsWithinWorldBoundsXAndZ(UnityEngine.Vector3 position) && position.z <= ModApi.MAP_MAX.z; } - private static bool IsWithinWorldBoundsY(UnityEngine.Vector3 position) + private static bool IsWithinWorldBoundsY(Vector3 position) { return position.y > ModApi.MAP_MIN.y && position.y <= ModApi.MAP_MAX.y; } + + /// + /// Retrieve all entities currently within the given block position. + /// + /// Vector3i block position to check for entities within. + /// List of entities currently within the provided block position. + private static List GetEntitiesAt(Vector3 pos, Vector3 entitySize) + { + return GameManager.Instance.World.GetLivingEntitiesInBounds(null, new Bounds(pos, entitySize)); + } } } From 311b0c874ae471b0313f0047e61628b3b2c38d11 Mon Sep 17 00:00:00 2001 From: jonathan-robertson Date: Mon, 30 Dec 2024 22:55:17 -0600 Subject: [PATCH 3/4] skip falling blocks, trees, supply plane/crate --- CHANGELOG.md | 1 + src/Patches/Entity.cs | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e3a03f..d505d04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.4] - 2024-12-30 - pile entities if present at destination +- skip falling blocks, trees, supply plane/crate - snap recovered entity to center of tile ## [0.1.3] - 2024-12-30 diff --git a/src/Patches/Entity.cs b/src/Patches/Entity.cs index 80271d0..16197a8 100644 --- a/src/Patches/Entity.cs +++ b/src/Patches/Entity.cs @@ -33,16 +33,18 @@ public static bool Prefix(Entity __instance) return true; } - // TODO: check ownership... maybe teleport backpacks directly in front of player, for instance? - //switch (__instance.GetType()) - //{ - // // TODO: check more - // default: - // _log.Trace($"detected type: {__instance.GetType()}"); - // // TODO: do more - // break; - //} + switch (__instance) + { + // case EntityDrone _: // try to recover + // case EntityBackpack _: // try to recover + // TODO: check ownership... maybe teleport backpacks directly in front of player, for instance? + case EntityFallingBlock _: + case EntityFallingTree _: + case EntitySupplyCrate _: + case EntitySupplyPlane _: + return true; // immediately return for removal + } if (!IsWithinWorldBoundsY(__instance.position)) { From a72909f33c7244a3c1fca400efa63f5225b84d1b Mon Sep 17 00:00:00 2001 From: jonathan-robertson Date: Mon, 30 Dec 2024 21:01:20 -0600 Subject: [PATCH 4/4] update binary --- OffWorldFix.dll | Bin 13824 -> 14848 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/OffWorldFix.dll b/OffWorldFix.dll index 85ef2c210a09f3d0a54959f3fcbdcca4b4611a8f..69293d89494e1f8cd2a152f8a2a4a223efad30b6 100644 GIT binary patch delta 4998 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 Dw1s+N delta 4144 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