Skip to content

Commit

Permalink
Convert SP placed Items to MP spawns on timers based on the m_index a…
Browse files Browse the repository at this point in the history
…nd m_respawns fields from OLE/Item class
  • Loading branch information
tobiasksu committed Jan 17, 2022
1 parent eab8588 commit 181a854
Showing 1 changed file with 182 additions and 11 deletions.
193 changes: 182 additions & 11 deletions GameMod/MPItemSpawns.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,205 @@
using HarmonyLib;
using Overload;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using UnityEngine;
using UnityEngine.Networking;

namespace GameMod
{

/// <summary>
/// Issue 200
/// In multiplayer, non-CM item spawns cause unexpected behavior due to being unsync'd (e.g. Ascent health orbs). Destroy these items and respawn as single-use sync'd spew.
/// </summary>
[HarmonyPatch(typeof(UpdateDynamicManager), "AddItem")]
public class UpdateDynamicManager_AddItem
public class MPFixedItemSpawn
{
static bool Prefix(Item item)
public ItemType type;
public bool respawns;
public float respawn_length;
public float respawn_timer;
public bool active;
public NetworkInstanceId netId;
public Vector3 position;
public bool super;

public void Update()
{
if (GameplayManager.IsMultiplayerActive)
respawn_timer += RUtility.FRAMETIME_GAME;

if (respawn_timer >= respawn_length && !active && netId == default)
{
GameObject gameObject = UnityEngine.Object.Instantiate<GameObject>(PrefabManager.item_prefabs[(int)MPFixedItemSpawns.GetPrefabFromType(type)], position, Quaternion.identity);
NetworkSpawnItem.Spawn(gameObject);
Item item = gameObject.GetComponent<Item>();
respawn_timer = 0f;
active = true;
super = item.m_super;
netId = item.netId;
}
}
}

public static class MPFixedItemSpawns
{
private static List<MPFixedItemSpawn> spawns = new List<MPFixedItemSpawn>();

public static void AddSpawn(MPFixedItemSpawn spawn)
{
spawns.Add(spawn);
}

public static List<MPFixedItemSpawn> GetSpawns()
{
return spawns;
}

public static MPFixedItemSpawn GetSpawn(NetworkInstanceId netId)
{
return spawns.FirstOrDefault(x => x.netId == netId);
}

public static void ClearSpawns()
{
spawns.Clear();
}

public static ItemPrefab GetPrefabFromType(ItemType itemType)
{
switch (itemType)
{
case ItemType.KEY_SECURITY:
return ItemPrefab.entity_item_security_key;
case ItemType.LOG_ENTRY:
return ItemPrefab.entity_item_log_entry;
case ItemType.POWERUP_SHIELD:
return ItemPrefab.entity_item_shields;
case ItemType.POWERUP_AMMO:
return ItemPrefab.entity_item_ammo;
case ItemType.POWERUP_ALIEN_ORB:
return ItemPrefab.entity_item_alien_orb;
case ItemType.TEMP_CLOAK:
return ItemPrefab.entity_item_cloak;
case ItemType.TEMP_RAPID:
return ItemPrefab.entity_item_rapid;
case ItemType.POWERUP_ENERGY:
return ItemPrefab.entity_item_energy;
case ItemType.WEAPON_DRILLER:
return ItemPrefab.entity_item_driller;
case ItemType.WEAPON_CYCLONE:
return ItemPrefab.entity_item_cyclone;
case ItemType.WEAPON_FLAK:
return ItemPrefab.entity_item_flak;
case ItemType.WEAPON_LANCER:
return ItemPrefab.entity_item_lancer;
case ItemType.WEAPON_REFLEX:
return ItemPrefab.entity_item_reflex;
case ItemType.WEAPON_SHOTGUN:
return ItemPrefab.entity_item_crusher;
case ItemType.WEAPON_IMPULSE:
return ItemPrefab.entity_item_impulse;
case ItemType.WEAPON_THUNDERBOLT:
return ItemPrefab.entity_item_thunderbolt;
case ItemType.MISSILE_CREEPER:
return ItemPrefab.entity_item_creeper;
case ItemType.MISSILE_DEVASTATOR:
return ItemPrefab.entity_item_devastator;
case ItemType.MISSILE_FALCON:
return ItemPrefab.entity_item_falcon4pack;
case ItemType.MISSILE_HUNTER:
return ItemPrefab.entity_item_hunter4pack;
case ItemType.MISSILE_POD:
return ItemPrefab.entity_item_missile_pod;
case ItemType.MISSILE_SMART:
return ItemPrefab.entity_item_nova;
case ItemType.MISSILE_TIMEBOMB:
return ItemPrefab.entity_item_timebomb;
case ItemType.MISSILE_VORTEX:
return ItemPrefab.entity_item_vortex;
default:
return ItemPrefab.entity_item_shields;
}
}
}

[HarmonyPatch(typeof(GameplayManager), "StartLevel")]
class MPItemSpawns_GameplayManager_StartLevel
{
static void Prefix()
{
MPFixedItemSpawns.ClearSpawns();

int count = 0;
foreach (var item in GameObject.FindObjectsOfType<Item>())
{
if (item.netId.Value <= 0)
{
UnityEngine.Object.Destroy(item.c_go);
if (GameplayManager.IsDedicatedServer())
{
Item.Spew(item.c_go, item.c_transform.position, default(Vector3), -1, item.m_super);
count++;
MPFixedItemSpawns.AddSpawn(new MPFixedItemSpawn
{
netId = default,
type = item.m_type,
respawns = item.m_respawning,
respawn_length = item.m_index,
respawn_timer = item.m_respawning ? 0f : item.m_index, // If not set to respawn after pickup, make immediately available
active = false,
position = item.gameObject.transform.position,
super = item.is_super
});
}
return false;
}
}

return true;
if (count > 0)
Debug.Log($"Server: converted {count} item spawns to fixed respawn points");
}
}

[HarmonyPatch(typeof(GameplayManager), "Update")]
class MPItemSpawns_GameplayManager_Update
{
static void Postfix()
{
if (!Overload.NetworkManager.IsServer())
return;

foreach (var spawn in MPFixedItemSpawns.GetSpawns())
{
spawn.Update();
}
}
}

[HarmonyPatch(typeof(Item), "OnTriggerEnter")]
class MPItemSpawns_Item_OnTriggerEnter
{
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> codes) {
foreach (var code in codes)
{
if (code.opcode == OpCodes.Call && code.operand == AccessTools.Method(typeof(RobotManager), "RemoveItemFromList"))
{
yield return code;
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(MPItemSpawns_Item_OnTriggerEnter), "UpdateFixedItemSpawn"));
continue;
}
yield return code;
}
}

static void UpdateFixedItemSpawn(Item item)
{
if (GameplayManager.IsMultiplayerActive && GameplayManager.IsDedicatedServer())
{
var fixedItemSpawn = MPFixedItemSpawns.GetSpawn(item.netId);
if (fixedItemSpawn != null)
{
fixedItemSpawn.netId = default;
fixedItemSpawn.respawn_timer = 0f;
fixedItemSpawn.active = false;
}

}
}
}
}

0 comments on commit 181a854

Please sign in to comment.