Remvoed Hotbar and GameClient since their functions are also implemented in OOP classes Added static methods to add/remove persistent debug info Made some patches and other things internal Added support for FlyCams in SetLocationtags/v2.0.0
@@ -396,19 +396,20 @@ namespace TechbloxModdingAPI.App | |||
/// <summary> | |||
/// Add information to the in-game debug display. | |||
/// When this object is garbage collected, this debug info is automatically removed. | |||
/// When this object is garbage collected, this debug info is automatically removed. | |||
/// The provided getter function is called each frame so make sure it returns quickly. | |||
/// </summary> | |||
/// <param name="id">Debug info identifier.</param> | |||
/// <param name="contentGetter">Content getter.</param> | |||
public void AddDebugInfo(string id, Func<string> contentGetter) | |||
/// <param name="contentGetter">A function that returns the current information.</param> | |||
public void AddDebugInfo(string id, Func<string> contentGetter) | |||
{ | |||
if (!VerifyMode()) return; | |||
if (menuMode) | |||
{ | |||
throw new GameNotFoundException("Game object references a menu item but AddDebugInfo only works on the currently-loaded game"); | |||
} | |||
debugOverlayEngine.SetInfo(id, contentGetter); | |||
debugIds.Add(id); | |||
if (!VerifyMode()) return; | |||
if (menuMode) | |||
{ | |||
throw new GameNotFoundException("Game object references a menu item but AddDebugInfo only works on the currently-loaded game"); | |||
} | |||
debugOverlayEngine.SetInfo("game_" + id, contentGetter); | |||
debugIds.Add(id); | |||
} | |||
/// <summary> | |||
@@ -418,14 +419,36 @@ namespace TechbloxModdingAPI.App | |||
/// <param name="id">Debug info identifier.</param> | |||
public bool RemoveDebugInfo(string id) | |||
{ | |||
if (!VerifyMode()) return false; | |||
if (menuMode) | |||
{ | |||
throw new GameNotFoundException("Game object references a menu item but RemoveDebugInfo only works on the currently-loaded game"); | |||
} | |||
if (!debugIds.Contains(id)) return false; | |||
debugOverlayEngine.RemoveInfo(id); | |||
return debugIds.Remove(id); | |||
if (!VerifyMode()) return false; | |||
if (menuMode) | |||
{ | |||
throw new GameNotFoundException("Game object references a menu item but RemoveDebugInfo only works on the currently-loaded game"); | |||
} | |||
if (!debugIds.Contains(id)) return false; | |||
debugOverlayEngine.RemoveInfo("game_" + id); | |||
return debugIds.Remove(id); | |||
} | |||
/// <summary> | |||
/// Add information to the in-game debug display. | |||
/// This debug info will be present for all games until it is manually removed. | |||
/// The provided getter function is called each frame so make sure it returns quickly. | |||
/// </summary> | |||
/// <param name="id">Debug info identifier.</param> | |||
/// <param name="contentGetter">A function that returns the current information.</param> | |||
public static void AddPersistentDebugInfo(string id, Func<string> contentGetter) | |||
{ | |||
debugOverlayEngine.SetInfo("persistent_" + id, contentGetter); | |||
} | |||
/// <summary> | |||
/// Remove persistent information from the in-game debug display. | |||
/// </summary> | |||
/// <returns><c>true</c>, if debug info was removed, <c>false</c> otherwise.</returns> | |||
/// <param name="id">Debug info identifier.</param> | |||
public static bool RemovePersistentDebugInfo(string id) | |||
{ | |||
return debugOverlayEngine.RemoveInfo("persistent_" + id); | |||
} | |||
/// <summary> | |||
@@ -113,7 +113,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
public bool isRemovable => false; | |||
[HarmonyPatch] | |||
public class FactoryObtainerPatch | |||
class FactoryObtainerPatch | |||
{ | |||
static void Postfix(BlockEntityFactory blockEntityFactory, IEntityFactory entityFactory) | |||
{ | |||
@@ -44,7 +44,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
public bool isRemovable => false; | |||
[HarmonyPatch] | |||
public class FactoryObtainerPatch | |||
class FactoryObtainerPatch | |||
{ | |||
static void Postfix(IEntityFunctions entityFunctions, | |||
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory) | |||
@@ -41,7 +41,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
} | |||
[HarmonyPatch] | |||
public class PhysicsEnginePatch | |||
class PhysicsEnginePatch | |||
{ | |||
static void Postfix(IReactOnAddAndRemove<UECSPhysicsEntityCreationStruct> __instance) | |||
{ | |||
@@ -1,46 +0,0 @@ | |||
using System; | |||
using RobocraftX.Common.Input; | |||
using RobocraftX.Multiplayer.Input; | |||
using HarmonyLib; | |||
using TechbloxModdingAPI.Blocks; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.Inventory | |||
{ | |||
public static class Hotbar | |||
{ | |||
private static readonly HotbarEngine hotbarEngine = new HotbarEngine(); | |||
/// <summary> | |||
/// Switch the block in the player's hand | |||
/// </summary> | |||
/// <param name="block">The block to switch to.</param> | |||
/// <param name="playerID">The player. Omit this to use the local player.</param> | |||
public static void EquipBlock(BlockIDs block, uint playerID = uint.MaxValue) | |||
{ | |||
if (playerID == uint.MaxValue) | |||
{ | |||
playerID = hotbarEngine.GetLocalPlayerID(); | |||
} | |||
hotbarEngine.SelectBlock((int) block, playerID); | |||
// cubeSelectedByPick = true will crash the game | |||
// (this would be equivalent to mouse middle click pick block action) | |||
// reason: the game expects a Dictionary entry for the tweaked stats | |||
} | |||
/// <summary> | |||
/// Gets the block in the player's hand | |||
/// </summary> | |||
/// <returns>The equipped block.</returns> | |||
public static BlockIDs GetEquippedBlock() | |||
{ | |||
return HotbarSlotSelectionHandlerEnginePatch.EquippedPartID; | |||
} | |||
public static void Init() | |||
{ | |||
GameEngineManager.AddGameEngine(hotbarEngine); | |||
} | |||
} | |||
} |
@@ -1,55 +0,0 @@ | |||
using System; | |||
using RobocraftX.Character; | |||
using RobocraftX.GUI.Hotbar; | |||
using RobocraftX.Players; | |||
using RobocraftX.Common; | |||
using RobocraftX.Common.Input; | |||
using RobocraftX.Common.Players; | |||
using Svelto.ECS; | |||
using TechbloxModdingAPI.Blocks; | |||
using TechbloxModdingAPI.Utility; | |||
using RobocraftX.Blocks; | |||
using Techblox.FlyCam; | |||
using TechbloxModdingAPI.Engines; | |||
namespace TechbloxModdingAPI.Inventory | |||
{ | |||
public class HotbarEngine : IApiEngine | |||
{ | |||
public string Name { get; } = "TechbloxModdingAPIHotbarGameEngine"; | |||
public EntitiesDB entitiesDB { set; private get; } | |||
public bool isRemovable => false; | |||
public bool IsInGame = false; | |||
public void Dispose() | |||
{ | |||
IsInGame = false; | |||
} | |||
public void Ready() | |||
{ | |||
IsInGame = true; | |||
} | |||
public bool SelectBlock(int block, uint playerID, bool cubeSelectedByPick = false) | |||
{ | |||
if (!entitiesDB.TryQueryEntitiesAndIndex<EquippedPartStruct>(playerID, Techblox.FlyCam.FlyCam.Group, | |||
out var index, out var inputs)) | |||
return false; | |||
inputs[index].CubeSelectedByPick = cubeSelectedByPick; | |||
inputs[index].SelectedDBPartID = block; | |||
// TODO: expose the rest of the input functionality | |||
return true; | |||
} | |||
public uint GetLocalPlayerID() | |||
{ | |||
return LocalPlayerIDUtility.GetLocalPlayerID(entitiesDB); | |||
} | |||
} | |||
} |
@@ -9,7 +9,7 @@ using TechbloxModdingAPI.Blocks; | |||
namespace TechbloxModdingAPI.Inventory | |||
{ | |||
[HarmonyPatch] | |||
public class HotbarSlotSelectionHandlerEnginePatch | |||
class HotbarSlotSelectionHandlerEnginePatch | |||
{ | |||
private static int selectedBlockInt = 0; | |||
@@ -65,8 +65,6 @@ namespace TechbloxModdingAPI | |||
Utility.GameState.Init(); | |||
// init block implementors | |||
Logging.MetaDebugLog($"Initializing Blocks"); | |||
// init inventory | |||
Inventory.Hotbar.Init(); | |||
// init input | |||
Input.FakeInput.Init(); | |||
// init object-oriented classes | |||
@@ -75,7 +73,6 @@ namespace TechbloxModdingAPI | |||
BlockGroup.Init(); | |||
Wire.Init(); | |||
Logging.MetaDebugLog($"Initializing Client"); | |||
GameClient.Init(); | |||
Client.Init(); | |||
Game.Init(); | |||
// init UI | |||
@@ -58,7 +58,7 @@ namespace TechbloxModdingAPI.Persistence | |||
return _serializers.Count; | |||
} | |||
public static void RegisterSerializers(EnginesRoot enginesRoot) | |||
internal static void RegisterSerializers(EnginesRoot enginesRoot) | |||
{ | |||
_lastEnginesRoot = enginesRoot; | |||
IEntitySerialization ies = enginesRoot.GenerateEntitySerializer(); | |||
@@ -102,23 +102,17 @@ namespace TechbloxModdingAPI.Players | |||
public bool SetLocation(uint playerId, float3 location, bool exitSeat = true) | |||
{ | |||
if (entitiesDB == null) return false; | |||
var characterGroups = CharacterExclusiveGroups.AllCharacters; | |||
for (int i = 0; i < characterGroups.count; i++) | |||
{ | |||
EGID egid = new EGID(playerId, characterGroups[i]); | |||
if (entitiesDB.Exists<RigidBodyEntityStruct>(egid)) | |||
{ | |||
ref RigidBodyEntityStruct rbes = ref entitiesDB.QueryEntity<RigidBodyEntityStruct>(egid); | |||
if (characterGroups[i] == CharacterExclusiveGroups.InPilotSeatGroup && exitSeat) | |||
{ | |||
entitiesDB.QueryEntity<CharacterPilotSeatEntityStruct>(egid).instantExit = true; | |||
entitiesDB.PublishEntityChange<CharacterPilotSeatEntityStruct>(egid); | |||
} | |||
rbes.position = location; | |||
return true; | |||
} | |||
} | |||
return false; | |||
var rbesOpt = GetCharacterStruct<RigidBodyEntityStruct>(playerId, out var group); | |||
if (!rbesOpt) | |||
return false; | |||
if (group == CharacterExclusiveGroups.InPilotSeatGroup && exitSeat) | |||
{ | |||
EGID egid = new EGID(playerId, group); | |||
entitiesDB.QueryEntity<CharacterPilotSeatEntityStruct>(egid).instantExit = true; | |||
entitiesDB.PublishEntityChange<CharacterPilotSeatEntityStruct>(egid); | |||
} | |||
rbesOpt.Get().position = location; | |||
return true; | |||
} | |||
public bool GetGameOverScreen(uint playerId) | |||
@@ -137,9 +131,14 @@ namespace TechbloxModdingAPI.Players | |||
// reusable methods | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public OptionalRef<T> GetCharacterStruct<T>(uint playerId) where T : unmanaged, IEntityComponent | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public OptionalRef<T> GetCharacterStruct<T>(uint playerId) where T : unmanaged, IEntityComponent => | |||
GetCharacterStruct<T>(playerId, out _); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public OptionalRef<T> GetCharacterStruct<T>(uint playerId, out ExclusiveGroupStruct group) where T : unmanaged, IEntityComponent | |||
{ | |||
group = default; | |||
if (GameState.IsBuildMode()) | |||
return entitiesDB.QueryEntityOptional<T>(new EGID(playerId, Techblox.FlyCam.FlyCam.Group)); | |||
@@ -149,7 +148,10 @@ namespace TechbloxModdingAPI.Players | |||
EGID egid = new EGID(playerId, characterGroups[i]); | |||
var opt = entitiesDB.QueryEntityOptional<T>(egid); | |||
if (opt.Exists) | |||
{ | |||
group = characterGroups[i]; | |||
return opt; | |||
} | |||
} | |||
return new OptionalRef<T>(); | |||
@@ -25,7 +25,7 @@ namespace TechbloxModdingAPI.Tests | |||
/// Modding API implemented as a standalone IPA Plugin. | |||
/// Ideally, TechbloxModdingAPI should be loaded by another mod; not itself | |||
/// </summary> | |||
public class TechbloxModdingAPIPluginTest : IllusionPlugin.IEnhancedPlugin | |||
class TechbloxModdingAPIPluginTest : IllusionPlugin.IEnhancedPlugin | |||
{ | |||
private static Harmony harmony { get; set; } | |||
@@ -194,7 +194,7 @@ namespace TechbloxModdingAPI.Tests | |||
Game.CurrentGame().ToggleTimeMode(); | |||
}).Build(); | |||
GameClient.SetDebugInfo("InstalledMods", InstalledMods); | |||
Game.AddPersistentDebugInfo("InstalledMods", InstalledMods); | |||
Block.Placed += (sender, args) => | |||
Logging.MetaDebugLog("Placed block " + args.Block); | |||
Block.Removed += (sender, args) => | |||
@@ -1,30 +0,0 @@ | |||
using System; | |||
using TechbloxModdingAPI.Blocks; | |||
namespace TechbloxModdingAPI.Utility | |||
{ | |||
public static class GameClient | |||
{ | |||
private static DebugInterfaceEngine _engine = new DebugInterfaceEngine(); | |||
/// <summary> | |||
/// Saves the extra information to be displayed on the debug view. | |||
/// The provided getter function is called each time the view updates so make sure it returns quickly. | |||
/// </summary> | |||
/// <param name="id">A global ID for the custom information</param> | |||
/// <param name="contentGetter">A function that returns the current information</param> | |||
public static void SetDebugInfo(string id, Func<string> contentGetter) => _engine.SetInfo(id, contentGetter); | |||
/// <summary> | |||
/// Removes an information provided by a plugin. | |||
/// </summary> | |||
/// <param name="id">The ID of the custom information</param> | |||
/// <returns></returns> | |||
public static bool RemoveDebugInfo(string id) => _engine.RemoveInfo(id); | |||
public static void Init() | |||
{ | |||
GameEngineManager.AddGameEngine(_engine); | |||
} | |||
} | |||
} |