# Conflicts: # Automation/gen_csproj.py # TechbloxModdingAPI/TechbloxModdingAPI.csprojtags/v2.2.0
@@ -0,0 +1,56 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using HarmonyLib; | |||
using Svelto.Tasks; | |||
namespace TechbloxModdingAPI.App | |||
{ | |||
public static class AntiAntiCheatPatch | |||
{ | |||
private delegate bool AntiAnticheatDelegate(ref object __result); | |||
private delegate bool AntiAnticheatDelegateBool(ref bool __result); | |||
private delegate bool AntiAnticheatDelegateTask(ref IEnumerator<TaskContract> __result); | |||
public static void Init(Harmony harmony) | |||
{ | |||
var type = AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.AnticheatClientService"); | |||
harmony.Patch(type.GetConstructors()[0], new HarmonyMethod(((Func<bool>) AntiAntiCheat).Method)); | |||
harmony.Patch(AccessTools.Method(type, "Shutdown"), new HarmonyMethod(((Func<bool>) AntiAntiCheat).Method)); | |||
harmony.Patch(AccessTools.Method(type, "StartProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegate) AntiAntiCheat).Method)); | |||
harmony.Patch(AccessTools.Method(type, "StopProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegateBool) AntiAntiCheat).Method)); | |||
harmony.Patch(AccessTools.Method("Techblox.Services.Eos.Anticheat.Client.EosGetPendingMessagesToSendServiceRequest:Execute"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method)); | |||
harmony.Patch(AccessTools.Method("Techblox.Anticheat.Client.Engines.ShowFeedbackDialogEngine:PollAnticheatStatus"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method)); | |||
} | |||
private static bool AntiAntiCheat() => false; | |||
private static bool AntiAntiCheat(ref object __result) | |||
{ | |||
var targetType = | |||
AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.StartProtectedSessionResult"); | |||
var target = Activator.CreateInstance(targetType); | |||
targetType.GetField("Success").SetValue(target, true); | |||
__result = target; | |||
return false; | |||
} | |||
private static bool AntiAntiCheat(ref bool __result) | |||
{ | |||
__result = true; | |||
return false; | |||
} | |||
private static bool AntiAntiCheatTask(ref IEnumerator<TaskContract> __result) | |||
{ | |||
IEnumerator<TaskContract> Func() | |||
{ | |||
yield return Yield.It; | |||
} | |||
__result = Func(); | |||
return false; | |||
} | |||
} | |||
} |
@@ -1,44 +0,0 @@ | |||
using System; | |||
using RobocraftX.GUI.MyGamesScreen; | |||
using Svelto.ECS; | |||
using TechbloxModdingAPI.Engines; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.App | |||
{ | |||
public class AppEngine : IFactoryEngine | |||
{ | |||
public WrappedHandler<MenuEventArgs> EnterMenu; | |||
public WrappedHandler<MenuEventArgs> ExitMenu; | |||
public IEntityFactory Factory { set; private get; } | |||
public string Name => "TechbloxModdingAPIAppEngine"; | |||
public bool isRemovable => false; | |||
public EntitiesDB entitiesDB { set; private get; } | |||
public void Dispose() | |||
{ | |||
IsInMenu = false; | |||
ExitMenu.Invoke(this, new MenuEventArgs { }); | |||
} | |||
public void Ready() | |||
{ | |||
IsInMenu = true; | |||
EnterMenu.Invoke(this, new MenuEventArgs { }); | |||
} | |||
// app functionality | |||
public bool IsInMenu | |||
{ | |||
get; | |||
private set; | |||
} = false; | |||
} | |||
} |
@@ -14,12 +14,12 @@ namespace TechbloxModdingAPI.App | |||
/// </summary> | |||
public class Client | |||
{ | |||
public static Client Instance { get; } = new Client(); | |||
protected static Func<object> ErrorHandlerInstanceGetter; | |||
protected static Action<object, Error> EnqueueError; | |||
protected static Action<object> HandleErrorClosed; | |||
/// <summary> | |||
/// An event that fires whenever the main menu is loaded. | |||
/// </summary> | |||
@@ -93,14 +93,31 @@ namespace TechbloxModdingAPI.App | |||
EnqueueError(errorHandlerInstance, popup); | |||
} | |||
// TODO | |||
/*public void CloseCurrentPrompt() | |||
public void CloseCurrentPrompt() | |||
{ | |||
object errorHandlerInstance = ErrorHandlerInstanceGetter(); | |||
var popup = GetPopupCloseMethods(errorHandlerInstance); | |||
popup.Close(); | |||
} | |||
public void SelectFirstPromptButton() | |||
{ | |||
object errorHandlerInstance = ErrorHandlerInstanceGetter(); | |||
var popup = GetPopupCloseMethods(errorHandlerInstance); | |||
popup.FirstButton(); | |||
} | |||
public void SelectSecondPromptButton() | |||
{ | |||
// RobocraftX.Services.ErrorHandler.Instance.HandlePopupClosed(); | |||
// FIXME: this is a call that is also called when closing, not the actual closing action itself (so it doesn't work) | |||
object errorHandlerInstance = ErrorHandlerInstanceGetter(); | |||
HandleErrorClosed(errorHandlerInstance); | |||
}*/ | |||
var popup = GetPopupCloseMethods(errorHandlerInstance); | |||
popup.SecondButton(); | |||
} | |||
internal void CloseBetaPopup() | |||
{ | |||
Game.menuEngine.CloseBetaPopup(); | |||
} | |||
internal static void Init() | |||
{ | |||
@@ -113,9 +130,6 @@ namespace TechbloxModdingAPI.App | |||
EnqueueError = (Action<object, Error>) AccessTools.Method("TechbloxModdingAPI.App.Client:GenEnqueueError") | |||
.MakeGenericMethod(errorHandler, errorHandle) | |||
.Invoke(null, new object[0]); | |||
/*HandleErrorClosed = (Action<object>) AccessTools.Method("TechbloxModdingAPI.App.Client:GenHandlePopupClosed") | |||
.MakeGenericMethod(errorHandler) | |||
.Invoke(null, new object[0]);*/ | |||
} | |||
// Creating delegates once is faster than reflection every time | |||
@@ -140,14 +154,23 @@ namespace TechbloxModdingAPI.App | |||
return enqueueCasted; | |||
} | |||
private static Action<object> GenHandlePopupClosed<T>() | |||
private static (Action Close, Action FirstButton, Action SecondButton) _errorPopup; | |||
private static (Action Close, Action FirstButton, Action SecondButton) GetPopupCloseMethods(object handler) | |||
{ | |||
Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); | |||
MethodInfo handlePopupClosed = AccessTools.Method(errorHandler, "HandlePopupClosed"); | |||
Action<T> handleSimple = | |||
(Action<T>) Delegate.CreateDelegate(typeof(Action<T>), handlePopupClosed); | |||
Action<object> handleCasted = (object instance) => handleSimple((T) instance); | |||
return handleCasted; | |||
if (_errorPopup.Close != null) | |||
return _errorPopup; | |||
Type errorHandler = handler.GetType(); | |||
FieldInfo field = AccessTools.Field(errorHandler, "errorPopup"); | |||
var errorPopup = (ErrorPopup)field.GetValue(handler); | |||
MethodInfo info = AccessTools.Method(errorPopup.GetType(), "ClosePopup"); | |||
var close = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info); | |||
info = AccessTools.Method(errorPopup.GetType(), "HandleFirstOption"); | |||
var first = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info); | |||
info = AccessTools.Method(errorPopup.GetType(), "HandleSecondOption"); | |||
var second = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info); | |||
_errorPopup = (close, first, second); | |||
return _errorPopup; | |||
} | |||
} | |||
} |
@@ -42,17 +42,25 @@ namespace TechbloxModdingAPI.App | |||
[APITestCase(TestType.Menu)] | |||
public static void TestPopUp2() | |||
{ | |||
Client c = new Client(); | |||
c.PromptUser(popup2); | |||
//c.CloseCurrentPrompt(); | |||
Client.Instance.PromptUser(popup2); | |||
} | |||
[APITestCase(TestType.Menu)] | |||
public static void TestPopUp1() | |||
{ | |||
Client c = new Client(); | |||
c.PromptUser(popup1); | |||
//c.CloseCurrentPrompt(); | |||
Client.Instance.PromptUser(popup1); | |||
} | |||
[APITestCase(TestType.Menu)] | |||
public static void TestPopUpClose1() | |||
{ | |||
Client.Instance.CloseCurrentPrompt(); | |||
} | |||
[APITestCase(TestType.Menu)] | |||
public static void TestPopUpClose2() | |||
{ | |||
Client.Instance.CloseCurrentPrompt(); | |||
} | |||
} | |||
#endif |
@@ -1,23 +1,27 @@ | |||
namespace TechbloxModdingAPI.App | |||
using System; | |||
namespace TechbloxModdingAPI.App | |||
{ | |||
public enum CurrentGameMode | |||
{ | |||
None, | |||
/// <summary> | |||
/// Building a game | |||
/// Building a world | |||
/// </summary> | |||
Build, | |||
/// <summary> | |||
/// Playing a game | |||
/// Playing on a map | |||
/// </summary> | |||
Play, | |||
/// <summary> | |||
/// Viewing a prefab | |||
/// Viewing a prefab (doesn't exist anymore) | |||
/// </summary> | |||
[Obsolete] | |||
View, | |||
/// <summary> | |||
/// Viewing a tutorial | |||
/// Viewing a tutorial (doesn't exist anymore) | |||
/// </summary> | |||
[Obsolete] | |||
Tutorial | |||
} | |||
} |
@@ -2,12 +2,10 @@ | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using RobocraftX.Common; | |||
using RobocraftX.GUI.MyGamesScreen; | |||
using RobocraftX.StateSync; | |||
using Svelto.ECS; | |||
using Techblox.GameSelection; | |||
using TechbloxModdingAPI; | |||
using TechbloxModdingAPI.Blocks; | |||
using TechbloxModdingAPI.Tasks; | |||
using TechbloxModdingAPI.Utility; | |||
@@ -318,7 +316,7 @@ namespace TechbloxModdingAPI.App | |||
get | |||
{ | |||
if (menuMode || !VerifyMode()) return CurrentGameMode.None; | |||
return (CurrentGameMode) GameMode.CurrentMode; | |||
return gameEngine.GetGameData().gameMode == GameMode.CreateWorld ? CurrentGameMode.Build : CurrentGameMode.Play; | |||
} | |||
} | |||
@@ -27,12 +27,14 @@ namespace TechbloxModdingAPI.App | |||
public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps) | |||
{ | |||
Console.WriteLine("Init time running mode"); | |||
SimulationMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" }); // TODO | |||
return inputDeps; | |||
} | |||
public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps) | |||
{ | |||
Console.WriteLine("Init time stopped mode"); | |||
BuildMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" }); | |||
return inputDeps; | |||
} | |||
@@ -1,5 +1,7 @@ | |||
using System.Collections.Generic; | |||
using HarmonyLib; | |||
using RobocraftX; | |||
using RobocraftX.Common; | |||
using RobocraftX.Schedulers; | |||
using RobocraftX.SimulationModeState; | |||
@@ -8,11 +10,15 @@ using Svelto.Tasks; | |||
using Svelto.Tasks.Lean; | |||
using RobocraftX.Blocks; | |||
using RobocraftX.Common.Loading; | |||
using RobocraftX.Multiplayer; | |||
using RobocraftX.ScreenshotTaker; | |||
using Techblox.Environment.Transition; | |||
using Techblox.GameSelection; | |||
using TechbloxModdingAPI.Blocks; | |||
using TechbloxModdingAPI.Engines; | |||
using TechbloxModdingAPI.Input; | |||
using TechbloxModdingAPI.Players; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.App | |||
@@ -30,16 +36,34 @@ namespace TechbloxModdingAPI.App | |||
public EntitiesDB entitiesDB { set; private get; } | |||
private bool enteredGame; | |||
private bool loadingFinished; | |||
private bool playerJoined; | |||
public void Dispose() | |||
{ | |||
if (GameReloadedPatch.IsReload) | |||
return; // Toggling time mode | |||
ExitGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID }); | |||
IsInGame = false; | |||
loadingFinished = false; | |||
playerJoined = false; | |||
enteredGame = false; | |||
} | |||
public void Ready() | |||
{ | |||
if (GameReloadedPatch.IsReload) | |||
return; // Toggling time mode | |||
enteredGame = true; | |||
Player.Joined += OnPlayerJoined; | |||
} | |||
private void OnPlayerJoined(object sender, PlayerEventArgs args) | |||
{ | |||
if (args.Player.Type != PlayerType.Local) return; | |||
playerJoined = true; | |||
Player.Joined -= OnPlayerJoined; | |||
CheckJoinEvent(); | |||
} | |||
// game functionality | |||
@@ -54,7 +78,7 @@ namespace TechbloxModdingAPI.App | |||
{ | |||
if (async) | |||
{ | |||
ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_TimeRunningAndStopped); | |||
ExitCurrentGameAsync().RunOn(ClientLean.EveryFrameStepRunner_TimeRunningAndStopped); | |||
} | |||
else | |||
{ | |||
@@ -94,10 +118,23 @@ namespace TechbloxModdingAPI.App | |||
public void ToggleTimeMode() | |||
{ | |||
if (!entitiesDB.FoundInGroups<BlockTagEntityStruct>()) | |||
throw new AppStateException("At least one block must exist in the world to enter simulation"); | |||
SwitchAnimationUtil.Start(entitiesDB); | |||
} | |||
if (TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB)) | |||
FakeInput.ActionInput(toggleMode: true); | |||
else | |||
{ | |||
IEnumerator<TaskContract> ReloadBuildModeTask() | |||
{ | |||
SwitchAnimationUtil.Start(entitiesDB); | |||
while (SwitchAnimationUtil.IsFadeOutActive(entitiesDB)) | |||
yield return (TaskContract)Yield.It; | |||
FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer; | |||
AccessTools.Method(typeof(FullGameCompositionRoot), "ReloadGame") | |||
.Invoke(FullGameFields.Instance, new object[] { }); | |||
} | |||
ReloadBuildModeTask().RunOn(ClientLean.UIScheduler); | |||
} | |||
} | |||
public EGID[] GetAllBlocksInGame(BlockIDs filter = BlockIDs.Invalid) | |||
{ | |||
@@ -142,9 +179,16 @@ namespace TechbloxModdingAPI.App | |||
public void Remove(ref LoadingActionEntityStruct entityComponent, EGID egid) | |||
{ // Finished loading | |||
if (!enteredGame) return; | |||
enteredGame = false; | |||
loadingFinished = true; | |||
CheckJoinEvent(); | |||
} | |||
private void CheckJoinEvent() | |||
{ | |||
if (!loadingFinished || !playerJoined) return; | |||
EnterGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID }); | |||
IsInGame = true; | |||
enteredGame = false; | |||
} | |||
} | |||
} |
@@ -3,16 +3,15 @@ using System.Reflection; | |||
using HarmonyLib; | |||
using RobocraftX; | |||
using RobocraftX.Common; | |||
using RobocraftX.FrontEnd; | |||
using RobocraftX.GUI; | |||
using RobocraftX.GUI.MyGamesScreen; | |||
using RobocraftX.Multiplayer; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Experimental; | |||
using Techblox.GameSelection; | |||
using TechbloxModdingAPI.Engines; | |||
using TechbloxModdingAPI.Utility; | |||
using GameMode = RobocraftX.Common.GameMode; | |||
namespace TechbloxModdingAPI.App | |||
{ | |||
@@ -105,20 +104,16 @@ namespace TechbloxModdingAPI.App | |||
return EnterGame(mgdes.GameName, mgdes.FileId); | |||
} | |||
public bool EnterGame(string gameName, string fileId, bool autoEnterSim = false) | |||
public bool EnterGame(ECSString gameName, string fileId, bool autoEnterSim = false) | |||
{ | |||
GameMode.CurrentMode = autoEnterSim ? RCXMode.Play : RCXMode.Build; | |||
var data = new GameSelectionData | |||
{ | |||
gameMode = Techblox.GameSelection.GameMode.PlayGame, | |||
gameType = GameType.MachineEditor, | |||
saveName = gameName, | |||
saveType = SaveType.ExistingSave, | |||
gameID = "GAMEID_Road_Track", //TODO: Expose to the API | |||
userContentID = fileId | |||
}; | |||
// the private FullGameCompositionRoot.SwitchToGame() method gets passed to menu items for this reason | |||
AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame").Invoke(FullGameFields.Instance, new object[]{data}); | |||
FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer; | |||
ref var selection = ref entitiesDB.QueryEntity<GameSelectionComponent>(GameSelectionConstants.GameSelectionEGID); | |||
selection.userContentID.Set(fileId); | |||
selection.triggerStart = true; | |||
selection.saveType = SaveType.ExistingSave; | |||
selection.saveName = gameName; | |||
selection.gameMode = GameMode.PlayGame; | |||
selection.gameID.Set("GAMEID_Road_Track"); //TODO: Expose to the API | |||
return true; | |||
} | |||
@@ -161,6 +156,16 @@ namespace TechbloxModdingAPI.App | |||
{ | |||
return ref entitiesDB.QueryEntity<T>(id); | |||
} | |||
internal void CloseBetaPopup() | |||
{ | |||
var (buffer, count) = entitiesDB.QueryEntities<TogglePanelButtonEntityViewStruct>(ExclusiveGroup.Search("BetaPopup")); | |||
for (int index = 0; index < count; ++index) | |||
{ | |||
entitiesDB.QueryEntity<GUIEntityViewStruct>(buffer[index].TogglePanelButtonComponent.targetPanel) | |||
.guiRoot.enabled = false; | |||
} | |||
} | |||
} | |||
internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor<MyGameDataEntityStruct> { } | |||
@@ -178,7 +183,7 @@ namespace TechbloxModdingAPI.App | |||
public static MethodBase TargetMethod() | |||
{ | |||
return AccessTools.Method(typeof(FullGameCompositionRoot), "GoToMenu"); | |||
return AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu"); | |||
} | |||
} | |||
@@ -8,9 +8,10 @@ using Svelto.ECS.EntityStructs; | |||
using RobocraftX.Common; | |||
using RobocraftX.Blocks; | |||
using Unity.Mathematics; | |||
using Gamecraft.Blocks.GUI; | |||
using HarmonyLib; | |||
using RobocraftX.PilotSeat; | |||
using RobocraftX.Rendering; | |||
using Techblox.BlockLabels; | |||
using TechbloxModdingAPI.Blocks; | |||
using TechbloxModdingAPI.Blocks.Engines; | |||
@@ -339,11 +340,9 @@ namespace TechbloxModdingAPI | |||
[TestValue(null)] | |||
public string Label | |||
{ | |||
get => BlockEngine.GetBlockInfoViewComponent<TextLabelEntityViewStruct>(this).textLabelComponent?.text; | |||
get => BlockEngine.GetBlockInfo<LabelResourceIDComponent>(this).ToString(); //TODO: Block labels | |||
set | |||
{ | |||
var comp = BlockEngine.GetBlockInfoViewComponent<TextLabelEntityViewStruct>(this).textLabelComponent; | |||
if (comp != null) comp.text = value; | |||
{ //TODO | |||
} | |||
} | |||
@@ -1,4 +1,4 @@ | |||
using System; | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
@@ -273,6 +273,12 @@ namespace TechbloxModdingAPI.Blocks | |||
/// <summary> | |||
/// The grid block used by the world editor, named Small Grid like the other one | |||
/// </summary> | |||
SmallGridInWorldEditor | |||
SmallGridInWorldEditor, | |||
SegoeUITextblock = 376, | |||
GravtracTextblock, | |||
HauserTextblock, | |||
TechnopollasTextblock, | |||
BitBlock = 385, | |||
Timer | |||
} | |||
} |
@@ -22,7 +22,7 @@ namespace TechbloxModdingAPI.Blocks | |||
base(new EGID(id, CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP)) | |||
{ | |||
} | |||
/* | |||
/// <summary> | |||
/// Gets or sets the Engine's On property. May not be saved. | |||
/// </summary> | |||
@@ -34,6 +34,7 @@ namespace TechbloxModdingAPI.Blocks | |||
} | |||
set | |||
{ | |||
Techblox.BlockColours.BlockColoursCompositionRoot | |||
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).engineOn = value; | |||
} | |||
} | |||
@@ -377,6 +378,6 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).manualToAutoGearCoolOffTime = value; | |||
} | |||
} | |||
}*/ | |||
} | |||
} |
@@ -60,7 +60,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
copyToBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock}); | |||
ExclusiveGroupStruct group = WiresExclusiveGroups.WIRES_COPY_GROUP + playerID; | |||
ExclusiveGroupStruct group = BuildModeWiresGroups.WIRES_COPY_GROUP + playerID; | |||
copyWireToBlock.Invoke(Patch.createWireEngine, new object[] {group, pickedBlock.ID}); | |||
pickedBlock.placedBlockTweaksMustCopy = false; | |||
@@ -1,4 +1,4 @@ | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using Gamecraft.Blocks.BlockGroups; | |||
@@ -173,7 +173,8 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
foreach (var block in blocks) | |||
{ | |||
GhostChildUtility.BuildGhostChild(in playerID, block.Id, in pos, in rot, entitiesDB, | |||
BuildGhostBlueprintFactory, false, bssesopt.Get().buildingDroneReference); | |||
BuildGhostBlueprintFactory, false, bssesopt.Get().buildingDroneReference, | |||
FullGameFields._managers.blockLabelResourceManager); | |||
} | |||
} | |||
@@ -272,7 +273,8 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
uint ghostChildBlockId = CommonExclusiveGroups.GetNewGhostChildBlockID(); | |||
var ghostEntityReference = GhostBlockUtils.GetGhostEntityReference(sourceId.entityID, entitiesDB); | |||
var entityInitializer = BuildGhostBlueprintFactory.Build( | |||
new EGID(ghostChildBlockId, BoxSelectExclusiveGroups.GhostChildEntitiesExclusiveGroup), /*dbStruct.DBID*/ (uint)BlockIDs.Cube); | |||
new EGID(ghostChildBlockId, BoxSelectExclusiveGroups.GhostChildEntitiesExclusiveGroup), /*dbStruct.DBID*/ (uint)BlockIDs.Cube, | |||
FullGameFields._managers.blockLabelResourceManager); | |||
entityInitializer.Init(dbStruct); | |||
entityInitializer.Init(new GFXPrefabEntityStructGPUI( | |||
PrefabsID.GetOrCreatePrefabID((ushort)entityInitializer.Get<PrefabAssetIDComponent>().prefabAssetID, | |||
@@ -1,5 +1,5 @@ | |||
using RobocraftX.Common; | |||
using RobocraftX.UECS; | |||
using RobocraftX.DOTS; | |||
using Svelto.ECS; | |||
using Svelto.ECS.EntityStructs; | |||
using Unity.Mathematics; | |||
@@ -40,7 +40,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntityOrDefault<PositionEntityStruct>(block); | |||
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block); | |||
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block); | |||
ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<UECSPhysicsEntityStruct>(block); | |||
ref DOTSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<DOTSPhysicsEntityStruct>(block); | |||
// main (persistent) position | |||
posStruct.position = vector; | |||
// placement grid position | |||
@@ -50,7 +50,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
// collision position | |||
if (phyStruct.ID != default) | |||
{ //It exists | |||
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, new Translation | |||
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.dotsEntity, new Translation | |||
{ | |||
Value = posStruct.position | |||
}); | |||
@@ -54,7 +54,8 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
//RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine | |||
DBEntityStruct dbEntity = new DBEntityStruct {DBID = block}; | |||
EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.nextBlockEntityID, block); //The ghost block index is only used for triggers | |||
//TODO: Test | |||
EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.blockIDGeneratorClient.Next(), block); //The ghost block index is only used for triggers | |||
uint prefabAssetID = structInitializer.Has<PrefabAssetIDComponent>() | |||
? structInitializer.Get<PrefabAssetIDComponent>().prefabAssetID | |||
: throw new BlockException("Prefab asset ID not found!"); //Set by the game | |||
@@ -1,5 +1,5 @@ | |||
using RobocraftX.Common; | |||
using RobocraftX.UECS; | |||
using RobocraftX.DOTS; | |||
using Svelto.ECS; | |||
using Svelto.ECS.EntityStructs; | |||
using Unity.Mathematics; | |||
@@ -40,7 +40,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntityOrDefault<RotationEntityStruct>(block); | |||
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block); | |||
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block); | |||
ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<UECSPhysicsEntityStruct>(block); | |||
ref DOTSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<DOTSPhysicsEntityStruct>(block); | |||
// main (persistent) rotation | |||
Quaternion newRotation = rotStruct.rotation; | |||
newRotation.eulerAngles = vector; | |||
@@ -52,7 +52,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
// collision rotation | |||
if (phyStruct.ID != default) | |||
{ //It exists | |||
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, | |||
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.dotsEntity, | |||
new Unity.Transforms.Rotation | |||
{ | |||
Value = rotStruct.rotation | |||
@@ -2,7 +2,7 @@ | |||
using HarmonyLib; | |||
using RobocraftX.Common; | |||
using RobocraftX.UECS; | |||
using RobocraftX.DOTS; | |||
using Svelto.ECS; | |||
using Unity.Entities; | |||
@@ -13,7 +13,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
{ | |||
public class ScalingEngine : IApiEngine | |||
{ | |||
private static IReactOnAddAndRemove<UECSPhysicsEntityCreationStruct> physicsEngine; | |||
private static IReactOnAddAndRemove<DOTSPhysicsEntityCreationStruct> physicsEngine; | |||
public void Ready() | |||
{ | |||
@@ -34,16 +34,16 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
if (_entityManager == default) | |||
_entityManager = FullGameFields._physicsWorld.EntityManager; | |||
//Assuming the block exists | |||
var entity = entitiesDB.QueryEntity<UECSPhysicsEntityStruct>(egid).uecsEntity; | |||
var pes = new UECSPhysicsEntityCreationStruct(); | |||
physicsEngine.Add(ref pes, egid); //Create new UECS entity | |||
var entity = entitiesDB.QueryEntity<DOTSPhysicsEntityStruct>(egid).dotsEntity; | |||
var pes = new DOTSPhysicsEntityCreationStruct(); | |||
physicsEngine.Add(ref pes, egid); //Create new DOTS entity | |||
_entityManager.DestroyEntity(entity); | |||
} | |||
[HarmonyPatch] | |||
class PhysicsEnginePatch | |||
{ | |||
static void Postfix(IReactOnAddAndRemove<UECSPhysicsEntityCreationStruct> __instance) | |||
static void Postfix(IReactOnAddAndRemove<DOTSPhysicsEntityCreationStruct> __instance) | |||
{ | |||
physicsEngine = __instance; | |||
Logging.MetaDebugLog("Physics engine injected."); | |||
@@ -51,7 +51,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
static MethodBase TargetMethod(Harmony instance) | |||
{ | |||
return AccessTools.Method("RobocraftX.StateSync.HandleUECSPhysicEntitiesWithPrefabCreationEngine" + | |||
return AccessTools.Method("RobocraftX.StateSync.HandleDOTSPhysicEntitiesWithPrefabCreationEngine" + | |||
":Ready"); | |||
} | |||
} | |||
@@ -43,7 +43,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
public WireEntityStruct CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort) | |||
{ | |||
EGID wireEGID = new EGID(WiresExclusiveGroups.NewWireEntityId, NamedExclusiveGroup<WiresGroup>.Group); | |||
EGID wireEGID = new EGID(BuildModeWiresGroups.NewWireEntityId, BuildModeWiresGroups.WiresGroup.Group); | |||
EntityInitializer wireInitializer = Factory.BuildEntity<WireEntityDescriptor>(wireEGID); | |||
wireInitializer.Init(new WireEntityStruct | |||
{ | |||
@@ -77,8 +77,8 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
public ref PortEntityStruct GetPortByOffset(BlockPortsStruct bps, byte portNumber, bool input) | |||
{ | |||
ExclusiveGroup group = input | |||
? NamedExclusiveGroup<InputPortsGroup>.Group | |||
: NamedExclusiveGroup<OutputPortsGroup>.Group; | |||
? NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group | |||
: NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group; | |||
uint id = (input ? bps.firstInputID : bps.firstOutputID) + portNumber; | |||
EGID egid = new EGID(id, group); | |||
if (!entitiesDB.Exists<PortEntityStruct>(egid)) | |||
@@ -193,7 +193,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
EGID[] inputs = new EGID[ports.inputCount]; | |||
for (uint i = 0; i < ports.inputCount; i++) | |||
{ | |||
inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup<InputPortsGroup>.Group); | |||
inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group); | |||
} | |||
return inputs; | |||
} | |||
@@ -204,7 +204,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
EGID[] outputs = new EGID[ports.outputCount]; | |||
for (uint i = 0; i < ports.outputCount; i++) | |||
{ | |||
outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup<OutputPortsGroup>.Group); | |||
outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group); | |||
} | |||
return outputs; | |||
} | |||
@@ -219,8 +219,8 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
if (!entitiesDB.Exists<BlockPortsStruct>(block)) | |||
return default; | |||
var group = output | |||
? NamedExclusiveGroup<OutputPortsGroup>.Group | |||
: NamedExclusiveGroup<InputPortsGroup>.Group; | |||
? NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group | |||
: NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group; | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(block); | |||
if (!entitiesDB.TryQueryMappedEntities<PortEntityStruct>(group, out var mapper)) | |||
return default; | |||
@@ -237,7 +237,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
public ref WireEntityStruct MatchPortToWire(PortEntityStruct port, EGID blockID, out bool exists) | |||
{ | |||
var wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group); | |||
var wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group); | |||
var wiresB = wires.ToBuffer().buffer; | |||
for (uint i = 0; i < wires.count; i++) | |||
{ | |||
@@ -264,7 +264,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
else | |||
{ | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(startBlock); | |||
startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup<OutputPortsGroup>.Group) }; | |||
startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group) }; | |||
} | |||
EGID[] endPorts; | |||
@@ -276,10 +276,10 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
else | |||
{ | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(endBlock); | |||
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<InputPortsGroup>.Group) }; | |||
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group) }; | |||
} | |||
EntityCollection<WireEntityStruct> wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group); | |||
EntityCollection<WireEntityStruct> wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group); | |||
var wiresB = wires.ToBuffer().buffer; | |||
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++) | |||
{ | |||
@@ -304,7 +304,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
public OptionalRef<ChannelDataStruct> GetChannelDataStruct(EGID portID) | |||
{ | |||
var port = GetPort(portID); | |||
var channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group); | |||
var channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<BuildModeWiresGroups.ChannelDataGroup>.Group); | |||
var channelsB = channels.ToBuffer(); | |||
return port.firstChannelIndexCachedInSim < channels.count | |||
? new OptionalRef<ChannelDataStruct>(channelsB.buffer, port.firstChannelIndexCachedInSim) | |||
@@ -329,7 +329,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
public EGID[] WiredToInput(EGID block, byte port) | |||
{ | |||
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<WiresGroup>.Group, | |||
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group, | |||
(WireEntityStruct wes) => wes.destinationPortUsage == port && wes.destinationBlockEGID == block); | |||
EGID[] result = new EGID[wireEntityStructs.Length]; | |||
for (uint i = 0; i < wireEntityStructs.Length; i++) | |||
@@ -342,7 +342,7 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
public EGID[] WiredToOutput(EGID block, byte port) | |||
{ | |||
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<WiresGroup>.Group, | |||
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group, | |||
(WireEntityStruct wes) => wes.sourcePortUsage == port && wes.sourceBlockEGID == block); | |||
EGID[] result = new EGID[wireEntityStructs.Length]; | |||
for (uint i = 0; i < wireEntityStructs.Length; i++) | |||
@@ -371,13 +371,13 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
private EntityCollection<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true) | |||
{ | |||
ExclusiveGroup group = input | |||
? NamedExclusiveGroup<InputPortsGroup>.Group | |||
: NamedExclusiveGroup<OutputPortsGroup>.Group; | |||
? NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group | |||
: NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group; | |||
if (entitiesDB.Exists<PortEntityStruct>(signalID, group)) | |||
{ | |||
index = entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).anyChannelIndex; | |||
var channelData = | |||
entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group); | |||
entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<BuildModeWiresGroups.ChannelDataGroup>.Group); | |||
return channelData; | |||
} | |||
@@ -1,4 +1,4 @@ | |||
using System; | |||
using System; | |||
using Unity.Mathematics; | |||
using UnityEngine; | |||
@@ -1,34 +0,0 @@ | |||
using System; | |||
using System.Reflection; | |||
using HarmonyLib; | |||
using Svelto.ECS; | |||
using RobocraftX.CR.MainGame; | |||
using RobocraftX.Multiplayer; | |||
using RobocraftX.StateSync; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.Commands | |||
{ | |||
/// <summary> | |||
/// Patch of RobocraftX.CR.MainGame.MainGameCompositionRoot.DeterministicCompose<T>() | |||
/// Initializes custom commands | |||
/// </summary> | |||
[HarmonyPatch] | |||
static class CommandPatch | |||
{ | |||
public static void Postfix(StateSyncRegistrationHelper stateSyncReg) | |||
{ | |||
/*CommandLineCompositionRoot.Compose(contextHolder, stateSyncReg.enginesRoot, reloadGame, multiplayerParameters, | |||
stateSyncReg); - uREPL C# compilation not supported anymore */ | |||
var enginesRoot = stateSyncReg.enginesRoot; | |||
CommandManager.RegisterEngines(enginesRoot); | |||
} | |||
public static MethodInfo TargetMethod() | |||
{ | |||
return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose") | |||
.MakeGenericMethod(typeof(object)); | |||
} | |||
} | |||
} |
@@ -62,6 +62,7 @@ namespace TechbloxModdingAPI | |||
var id = initializer(this); | |||
if (!dict.ContainsKey(id)) // Multiple instances may be created | |||
dict.Add(id, this); | |||
Id = id; | |||
} | |||
#region ECS initializer stuff | |||
@@ -6,27 +6,67 @@ using RobocraftX.FrontEnd; | |||
using RobocraftX.StateSync; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Schedulers; | |||
using TechbloxModdingAPI.Commands; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.Engines | |||
{ | |||
[HarmonyPatch] | |||
class GameLoadedEnginePatch | |||
static class GameLoadedTimeStoppedEnginePatch | |||
{ | |||
public static EntitiesSubmissionScheduler Scheduler { get; private set; } | |||
public static void Postfix(StateSyncRegistrationHelper stateSyncReg) | |||
{ | |||
// register all game engines, including deterministic | |||
GameEngineManager.RegisterEngines(stateSyncReg); | |||
Scheduler = stateSyncReg.enginesRoot.scheduler; | |||
// register command engines | |||
/*CommandLineCompositionRoot.Compose(contextHolder, stateSyncReg.enginesRoot, reloadGame, multiplayerParameters, | |||
stateSyncReg); - uREPL C# compilation not supported anymore */ | |||
CommandManager.RegisterEngines(stateSyncReg.enginesRoot); | |||
} | |||
public static MethodBase TargetMethod() | |||
{ | |||
return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose").MakeGenericMethod(typeof(object)); | |||
return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicTimeStoppedCompose").MakeGenericMethod(typeof(object)); | |||
} | |||
} | |||
[HarmonyPatch] | |||
static class GameLoadedTimeRunningEnginePatch | |||
{ | |||
public static void Postfix(StateSyncRegistrationHelper stateSyncReg) | |||
{ | |||
GameEngineManager.RegisterEngines(stateSyncReg); | |||
CommandManager.RegisterEngines(stateSyncReg.enginesRoot); | |||
} | |||
public static MethodBase TargetMethod() | |||
{ | |||
return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicTimeRunningCompose").MakeGenericMethod(typeof(object)); | |||
} | |||
} | |||
[HarmonyPatch] | |||
static class GameReloadedPatch | |||
{ | |||
internal static bool IsReload; | |||
public static void Prefix() => IsReload = true; | |||
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "ReloadGame"); | |||
} | |||
[HarmonyPatch] | |||
static class GameSwitchedToPatch | |||
{ | |||
public static void Prefix() => GameReloadedPatch.IsReload = false; | |||
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame"); | |||
} | |||
[HarmonyPatch] | |||
static class MenuSwitchedToPatch | |||
{ | |||
public static void Prefix() => GameReloadedPatch.IsReload = false; | |||
public static MethodBase TargetMethod() => AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu"); | |||
} | |||
[HarmonyPatch] | |||
class MenuLoadedEnginePatch | |||
{ | |||
@@ -1,15 +1,13 @@ | |||
using System; | |||
using RobocraftX.Common.Input; | |||
using RobocraftX.Common; | |||
using RobocraftX.Common.Input; | |||
using Svelto.ECS; | |||
using TechbloxModdingAPI.App; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.Input | |||
{ | |||
public static class FakeInput | |||
{ | |||
private static readonly FakeInputEngine inputEngine = new FakeInputEngine(); | |||
internal static readonly FakeInputEngine inputEngine = new FakeInputEngine(); | |||
/// <summary> | |||
/// Customize the local input. | |||
@@ -103,39 +101,39 @@ namespace TechbloxModdingAPI.Input | |||
} | |||
public static void ActionInput(uint playerID = uint.MaxValue, bool toggleMode = false, bool forward = false, bool backward = false, bool up = false, bool down = false, bool left = false, bool right = false, bool sprint = false, bool toggleFly = false, bool alt = false, bool primary = false, bool secondary = false, bool tertiary = false, bool primaryHeld = false, bool secondaryHeld = false, bool toggleUnitGrid = false, bool ctrl = false, bool toggleColourMode = false, bool scaleBlockUp = false, bool scaleBlockDown = false, bool rotateBlockClockwise = false, bool rotateBlockCounterclockwise = false, bool cutSelection = false, bool copySelection = false, bool deleteSelection = false) | |||
{ | |||
if (playerID == uint.MaxValue) | |||
{ | |||
playerID = inputEngine.GetLocalPlayerID(); | |||
} | |||
ref LocalPlayerInputEntityStruct currentInput = ref inputEngine.GetPlayerInputRef(playerID); | |||
{ // TODO: We can only alter our own inputs clientside | |||
ref var currentInput = ref inputEngine._localInputCache; | |||
//Utility.Logging.CommandLog($"Current sim frame {currentInput.frame}"); | |||
// set inputs | |||
if (toggleMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleTimeRunningMode; | |||
if (forward) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Forward; | |||
if (backward) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Backward; | |||
if (up) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Up; | |||
if (down) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Down; | |||
if (left) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Left; | |||
if (right) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Right; | |||
if (sprint) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Sprint; | |||
//if (toggleFly) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SwitchFlyMode; | |||
//if (alt) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.AltAction; | |||
if (primary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryAction; | |||
if (secondary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryAction; | |||
if (tertiary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.TertiaryAction; | |||
if (primaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryActionHeld; | |||
if (secondaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryActionHeld; | |||
//if (toggleUnitGrid) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleUnitGrid; | |||
if (ctrl) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CtrlAction; | |||
if (toggleColourMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleColourMode; | |||
if (scaleBlockUp) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ScaleBlockUp; | |||
if (scaleBlockDown) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ScaleBlockDown; | |||
if (rotateBlockClockwise) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.RotateBlockClockwise; | |||
if (rotateBlockCounterclockwise) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.RotateBlockAnticlockwise; | |||
if (cutSelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CutSelection; | |||
if (copySelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CopySelection; | |||
if (deleteSelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.DeleteSelection; | |||
if (toggleMode) currentInput |= RobocraftX.Common.Input.ActionInput.ToggleTimeRunningModePlay; //TODO: Test, play | |||
if (forward) currentInput |= RobocraftX.Common.Input.ActionInput.Forward; | |||
if (backward) currentInput |= RobocraftX.Common.Input.ActionInput.Backward; | |||
if (up) currentInput |= RobocraftX.Common.Input.ActionInput.Up; | |||
if (down) currentInput |= RobocraftX.Common.Input.ActionInput.Down; | |||
if (left) currentInput |= RobocraftX.Common.Input.ActionInput.Left; | |||
if (right) currentInput |= RobocraftX.Common.Input.ActionInput.Right; | |||
if (sprint) currentInput |= RobocraftX.Common.Input.ActionInput.Sprint; | |||
//if (toggleFly) currentInput |= RobocraftX.Common.Input.ActionInput.SwitchFlyMode; | |||
//if (alt) currentInput |= RobocraftX.Common.Input.ActionInput.AltAction; | |||
if (primary) currentInput |= RobocraftX.Common.Input.ActionInput.PrimaryActionClick; | |||
if (secondary) currentInput |= RobocraftX.Common.Input.ActionInput.SecondaryActionClick; | |||
if (tertiary) currentInput |= RobocraftX.Common.Input.ActionInput.TertiaryAction; | |||
if (primaryHeld) currentInput |= RobocraftX.Common.Input.ActionInput.PrimaryActionHeld; | |||
if (secondaryHeld) currentInput |= RobocraftX.Common.Input.ActionInput.SecondaryActionHeld; | |||
//if (toggleUnitGrid) currentInput |= RobocraftX.Common.Input.ActionInput.ToggleUnitGrid; | |||
if (ctrl) currentInput |= RobocraftX.Common.Input.ActionInput.CtrlAction; | |||
if (toggleColourMode) currentInput |= RobocraftX.Common.Input.ActionInput.ToggleColourMode; | |||
if (scaleBlockUp) currentInput |= RobocraftX.Common.Input.ActionInput.ScaleBlockUp; | |||
if (scaleBlockDown) currentInput |= RobocraftX.Common.Input.ActionInput.ScaleBlockDown; | |||
if (rotateBlockClockwise) currentInput |= RobocraftX.Common.Input.ActionInput.RotateBlockClockwise; | |||
if (rotateBlockCounterclockwise) currentInput |= RobocraftX.Common.Input.ActionInput.RotateBlockAnticlockwise; | |||
if (cutSelection) currentInput |= RobocraftX.Common.Input.ActionInput.CutSelection; | |||
if (copySelection) currentInput |= RobocraftX.Common.Input.ActionInput.CopySelection; | |||
if (deleteSelection) currentInput |= RobocraftX.Common.Input.ActionInput.DeleteSelection; | |||
if(Game.CurrentGame().IsTimeStopped) | |||
inputEngine.HandleCustomInput(); // Only gets called when online, so calling it here as well | |||
} | |||
public static void Init() | |||
@@ -20,6 +20,8 @@ namespace TechbloxModdingAPI.Input | |||
public bool IsReady = false; | |||
internal ActionInput _localInputCache; | |||
public void Dispose() | |||
{ | |||
IsReady = false; | |||
@@ -86,6 +88,14 @@ namespace TechbloxModdingAPI.Input | |||
return ref entitiesDB.QueryEntity<LocalPlayerInputEntityStruct>(egid); | |||
} | |||
internal void HandleCustomInput() | |||
{ | |||
if (!LocalPlayerIDUtility.DoesLocalPlayerExist(entitiesDB)) | |||
return; | |||
GetPlayerInputRef(GetLocalPlayerID()).actionMask |= _localInputCache; | |||
_localInputCache = default; | |||
} | |||
public uint GetLocalPlayerID() | |||
{ | |||
return LocalPlayerIDUtility.GetLocalPlayerID(entitiesDB); | |||
@@ -0,0 +1,19 @@ | |||
using System.Reflection; | |||
using HarmonyLib; | |||
namespace TechbloxModdingAPI.Input | |||
{ | |||
[HarmonyPatch] | |||
public static class FakeInputPatch | |||
{ | |||
public static void Prefix() | |||
{ | |||
FakeInput.inputEngine.HandleCustomInput(); // This gets called right before the input is sent to the server | |||
} | |||
public static MethodBase TargetMethod() | |||
{ | |||
return AccessTools.Method("RobocraftX.Multiplayer.Input.NetworkInputRecorderEngine:RecordDeterministicInput"); | |||
} | |||
} | |||
} |
@@ -1,13 +1,7 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using TechbloxModdingAPI.App; | |||
using TechbloxModdingAPI.Utility; | |||
using Rewired.Internal; | |||
using Svelto.DataStructures; | |||
using Svelto.Tasks; | |||
using Svelto.Tasks.ExtraLean; | |||
using Svelto.Tasks.ExtraLean.Unity; | |||
using TechbloxModdingAPI.Tasks; | |||
using UnityEngine; | |||
namespace TechbloxModdingAPI.Interface.IMGUI | |||
@@ -3,13 +3,11 @@ using System.Reflection; | |||
using HarmonyLib; | |||
using RobocraftX; | |||
using RobocraftX.Schedulers; | |||
using RobocraftX.Services; | |||
using Svelto.Context; | |||
using Svelto.Tasks.ExtraLean; | |||
using TechbloxModdingAPI.App; | |||
using TechbloxModdingAPI.Blocks; | |||
using TechbloxModdingAPI.Events; | |||
using TechbloxModdingAPI.Tasks; | |||
using TechbloxModdingAPI.Utility; | |||
@@ -51,34 +49,42 @@ namespace TechbloxModdingAPI | |||
harmony.PatchAll(currentAssembly); | |||
} | |||
catch (Exception e) | |||
{ //Can't use ErrorBuilder or Logging.LogException (which eventually uses ErrorBuilder) yet | |||
Logging.Log(e.ToString()); | |||
Logging.LogWarning("Failed to patch Techblox. Attempting to patch to display error..."); | |||
harmony.Patch(AccessTools.Method(typeof(FullGameCompositionRoot), "OnContextInitialized") | |||
.MakeGenericMethod(typeof(UnityContext<FullGameCompositionRoot>)), | |||
new HarmonyMethod(((Action) OnPatchError).Method)); //Can't use lambdas here :( | |||
{ | |||
HandleError(e, "Failed to patch Techblox. Attempting to patch to display error...", OnPatchError); | |||
return; | |||
} | |||
// init utility | |||
Logging.MetaDebugLog($"Initializing Utility"); | |||
Utility.GameState.Init(); | |||
// init block implementors | |||
Logging.MetaDebugLog($"Initializing Blocks"); | |||
// init input | |||
Input.FakeInput.Init(); | |||
// init object-oriented classes | |||
Player.Init(); | |||
Block.Init(); | |||
BlockGroup.Init(); | |||
Wire.Init(); | |||
Logging.MetaDebugLog($"Initializing Client"); | |||
Client.Init(); | |||
Game.Init(); | |||
// init UI | |||
Interface.IMGUI.Constants.Init(); | |||
Interface.IMGUI.IMGUIManager.Init(); | |||
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); | |||
try | |||
{ | |||
// init utility | |||
Logging.MetaDebugLog($"Initializing Utility"); | |||
Utility.GameState.Init(); | |||
// init block implementors | |||
Logging.MetaDebugLog($"Initializing Blocks"); | |||
// init input | |||
Input.FakeInput.Init(); | |||
// init object-oriented classes | |||
Player.Init(); | |||
Block.Init(); | |||
BlockGroup.Init(); | |||
Wire.Init(); | |||
// init client | |||
Logging.MetaDebugLog($"Initializing Client"); | |||
Client.Init(); | |||
Game.Init(); | |||
// init UI | |||
Logging.MetaDebugLog($"Initializing UI"); | |||
Interface.IMGUI.Constants.Init(); | |||
Interface.IMGUI.IMGUIManager.Init(); | |||
// init anti-anticheat | |||
Logging.MetaDebugLog("Initializing anti-anticheat"); | |||
AntiAntiCheatPatch.Init(harmony); | |||
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); | |||
} | |||
catch (Exception e) | |||
{ | |||
HandleError(e, "Failed to initialize the API! Attempting to patch to display error...", OnInitError); | |||
} | |||
} | |||
/// <summary> | |||
@@ -109,5 +115,26 @@ namespace TechbloxModdingAPI | |||
ErrorBuilder.DisplayMustQuitError("Failed to patch Techblox!\n" + | |||
"Make sure you're using the latest version of TechbloxModdingAPI or disable mods if the API isn't released yet."); | |||
} | |||
private static void OnInitError() | |||
{ | |||
ErrorBuilder.DisplayMustQuitError("Failed to initialize the modding API!\n" + | |||
"Make sure you're using the latest version. If you are, please report the error."); | |||
} | |||
/// <summary> | |||
/// Handles an init error. Logs the exception, a log message, and allows displaying an error in-game. | |||
/// </summary> | |||
/// <param name="e">The exception</param> | |||
/// <param name="logMsg">The log message</param> | |||
/// <param name="onInit">The action to run when the game is ready to display error messages</param> | |||
private static void HandleError(Exception e, string logMsg, Action onInit) | |||
{ //Can't use ErrorBuilder or Logging.LogException (which eventually uses ErrorBuilder) yet | |||
Logging.Log(e.ToString()); | |||
Logging.LogWarning(logMsg); | |||
harmony.Patch(AccessTools.Method(typeof(FullGameCompositionRoot), "OnContextInitialized") | |||
.MakeGenericMethod(typeof(UnityContext<FullGameCompositionRoot>)), | |||
new HarmonyMethod(onInit.Method)); //Can't use lambdas here :( | |||
} | |||
} | |||
} |
@@ -25,7 +25,7 @@ namespace TechbloxModdingAPI.Persistence | |||
Logging.MetaDebugLog("Skipping component serialization: no serializers registered!"); | |||
return; | |||
} | |||
serializationData.data.ExpandBy((uint)frameStart.Length); | |||
serializationData.data.IncreaseCapacityBy((uint)frameStart.Length); | |||
BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out int buffLen), serializationData.dataPos); | |||
uint originalPos = serializationData.dataPos; | |||
Logging.MetaDebugLog($"dataPos: {originalPos}"); | |||
@@ -35,14 +35,14 @@ namespace TechbloxModdingAPI.Persistence | |||
bbw.Write(frameStart[i]); | |||
} | |||
Logging.MetaDebugLog($"dataPos (after frame start): {bbw.Position}"); | |||
serializationData.data.ExpandBy(4u); | |||
serializationData.data.IncreaseCapacityBy(4u); | |||
bbw.Write((uint)SerializerManager.GetSerializersCount()); | |||
string[] serializerKeys = SerializerManager.GetSerializerNames(); | |||
for (uint c = 0; c < serializerKeys.Length; c++) | |||
{ | |||
Logging.MetaDebugLog($"dataPos (loop start): {bbw.Position}"); | |||
// write component info | |||
serializationData.data.ExpandBy(4u + (uint)serializerKeys[c].Length); | |||
serializationData.data.IncreaseCapacityBy(4u + (uint)serializerKeys[c].Length); | |||
bbw.Write((uint)serializerKeys[c].Length); | |||
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}"); | |||
byte[] nameBytes = Encoding.UTF8.GetBytes(serializerKeys[c]); | |||
@@ -51,7 +51,7 @@ namespace TechbloxModdingAPI.Persistence | |||
bbw.Write(nameBytes[i]); | |||
} | |||
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}"); | |||
serializationData.data.ExpandBy(4u); | |||
serializationData.data.IncreaseCapacityBy(4u); | |||
serializationData.dataPos = bbw.Position + 4u; | |||
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}"); | |||
Logging.MetaDebugLog($"dataPos (appears to be): {serializationData.dataPos}"); | |||
@@ -73,8 +73,8 @@ namespace TechbloxModdingAPI.Persistence | |||
} | |||
public static MethodBase TargetMethod() | |||
{ | |||
return typeof(SaveGameEngine).GetMethod("SerializeGameToBuffer"); | |||
{ | |||
return AccessTools.TypeByName("RobocraftX.SaveAndLoad.SaveGameEngine").GetMethod("SerializeGameToBuffer"); | |||
} | |||
} | |||
} |
@@ -46,7 +46,7 @@ namespace TechbloxModdingAPI.Persistence | |||
public bool Serialize(ref ISerializationData serializationData, EntitiesDB entitiesDB, IEntitySerialization entitySerializer) | |||
{ | |||
serializationData.data.ExpandBy(4u); | |||
serializationData.data.IncreaseCapacityBy(4u); | |||
BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out int count), serializationData.dataPos); | |||
EGID[] toSerialize = getEntitiesToSerialize(entitiesDB); | |||
bbw.Write((uint)toSerialize.Length); | |||
@@ -20,6 +20,22 @@ namespace TechbloxModdingAPI | |||
add => seatExited += value; | |||
remove => seatExited -= value; | |||
} | |||
internal static WrappedHandler<PlayerEventArgs> joined; | |||
public static event EventHandler<PlayerEventArgs> Joined | |||
{ | |||
add => joined += value; | |||
remove => joined -= value; | |||
} | |||
internal static WrappedHandler<PlayerEventArgs> left; | |||
public static event EventHandler<PlayerEventArgs> Left | |||
{ | |||
add => left += value; | |||
remove => left -= value; | |||
} | |||
} | |||
public struct PlayerSeatEventArgs | |||
@@ -27,4 +43,10 @@ namespace TechbloxModdingAPI | |||
public EGID SeatId; | |||
public Seat Seat => (Seat)Block.New(SeatId); | |||
} | |||
public struct PlayerEventArgs | |||
{ | |||
public EGID PlayerId; | |||
public Player Player => Player.GetInstance(PlayerId.entityID); | |||
} | |||
} |
@@ -23,8 +23,8 @@ namespace TechbloxModdingAPI | |||
public partial class Player : EcsObjectBase, IEquatable<Player>, IEquatable<EGID> | |||
{ | |||
// static functionality | |||
private static PlayerEngine playerEngine = new PlayerEngine(); | |||
private static PlayerEventsEngine playerEventsEngine = new PlayerEventsEngine(); | |||
private static readonly PlayerEngine playerEngine = new PlayerEngine(); | |||
private static readonly PlayerEventsEngine playerEventsEngine = new PlayerEventsEngine(); | |||
private static Player localPlayer; | |||
/// <summary> | |||
@@ -76,6 +76,12 @@ namespace TechbloxModdingAPI | |||
} | |||
} | |||
internal static Player GetInstance(uint id) | |||
{ | |||
return EcsObjectBase.GetInstance(new EGID(id, CharacterExclusiveGroups.OnFootGroup), | |||
e => new Player(e.entityID)); | |||
} | |||
/// <summary> | |||
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Player"/> class. | |||
/// </summary> | |||
@@ -119,6 +125,7 @@ namespace TechbloxModdingAPI | |||
}) | |||
{ | |||
this.Type = player; | |||
Id = base.Id.entityID; | |||
} | |||
// object fields & properties | |||
@@ -187,8 +194,6 @@ namespace TechbloxModdingAPI | |||
public float Mass => | |||
1f / playerEngine.GetCharacterStruct<RigidBodyEntityStruct>(Id).Get().physicsMass.InverseMass; | |||
private float _ping = -1f; | |||
/// <summary> | |||
/// The player's latest network ping time. | |||
/// </summary> | |||
@@ -197,12 +202,7 @@ namespace TechbloxModdingAPI | |||
{ | |||
get | |||
{ | |||
var opt = playerEngine.GetPlayerStruct<PlayerNetworkStatsEntityStruct>(Id, Type); | |||
if (opt) | |||
{ | |||
_ping = opt.Get().lastPingTimeSinceLevelLoad ?? _ping; | |||
} | |||
return _ping; | |||
return playerEngine.GetPing() / 1000f; | |||
} | |||
} | |||
@@ -435,15 +435,38 @@ namespace TechbloxModdingAPI | |||
playerEngine.SetLocation(Id, location, exitSeat: exitSeat); | |||
} | |||
/// <summary> | |||
/// Enter the given seat. | |||
/// </summary> | |||
/// <param name="seat">The seat to enter.</param> | |||
public void EnterSeat(Seat seat) | |||
{ | |||
playerEngine.EnterSeat(Id, seat.Id); | |||
} | |||
/// <summary> | |||
/// Exit the seat the player is currently in. | |||
/// </summary> | |||
public void ExitSeat() | |||
{ | |||
playerEngine.ExitSeat(Id); | |||
} | |||
/// <summary> | |||
/// Spawn the machine the player is holding in time running mode. | |||
/// </summary> | |||
public bool SpawnMachine() | |||
{ | |||
return playerEngine.SpawnMachine(Id); | |||
} | |||
/// <summary> | |||
/// Despawn the player's machine in time running mode and place it in their hand. | |||
/// </summary> | |||
public bool DespawnMachine() | |||
{ | |||
return playerEngine.DespawnMachine(Id); | |||
} | |||
/// <summary> | |||
/// Returns the block the player is currently looking at in build mode. | |||
@@ -481,7 +504,7 @@ namespace TechbloxModdingAPI | |||
{ | |||
var egid = playerEngine.GetThingLookedAt(Id, maxDistance); | |||
return egid != default && egid.groupID == WiresGUIExclusiveGroups.WireGroup | |||
? EcsObjectBase.GetInstance(new EGID(egid.entityID, NamedExclusiveGroup<WiresGroup>.Group), | |||
? EcsObjectBase.GetInstance(new EGID(egid.entityID, BuildModeWiresGroups.WiresGroup.Group), | |||
e => new Wire(e)) | |||
: null; | |||
} | |||
@@ -10,7 +10,9 @@ using RobocraftX.Physics; | |||
using RobocraftX.Blocks.Ghost; | |||
using Gamecraft.GUI.HUDFeedbackBlocks; | |||
using RobocraftX.Blocks; | |||
using RobocraftX.Multiplayer; | |||
using RobocraftX.PilotSeat; | |||
using RobocraftX.SimulationModeState; | |||
using Svelto.ECS; | |||
using Techblox.Camera; | |||
using Unity.Mathematics; | |||
@@ -19,6 +21,7 @@ using Svelto.ECS.EntityStructs; | |||
using Techblox.BuildingDrone; | |||
using TechbloxModdingAPI.Engines; | |||
using TechbloxModdingAPI.Input; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.Players | |||
@@ -204,6 +207,8 @@ namespace TechbloxModdingAPI.Players | |||
public void EnterSeat(uint playerId, EGID seatId) | |||
{ | |||
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB)) | |||
return; | |||
PilotSeatGroupUtils.SwapTagTo<OCCUPIED_TAG>(Functions, seatId); | |||
var opt = GetCharacterStruct<CharacterPilotSeatEntityStruct>(playerId, out var group); | |||
if (!opt) return; | |||
@@ -221,11 +226,46 @@ namespace TechbloxModdingAPI.Players | |||
public void ExitSeat(uint playerId) | |||
{ | |||
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB)) | |||
return; | |||
EGID egid = new EGID(playerId, CharacterExclusiveGroups.InPilotSeatGroup); | |||
var opt = entitiesDB.QueryEntityOptional<CharacterPilotSeatEntityStruct>(egid); | |||
if (!opt) return; | |||
opt.Get().instantExit = true; | |||
entitiesDB.PublishEntityChange<CharacterPilotSeatEntityStruct>(egid); | |||
} | |||
public bool SpawnMachine(uint playerId) | |||
{ | |||
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB)) | |||
return false; | |||
EGID egid = new EGID(playerId, CharacterExclusiveGroups.MachineSpawningGroup); | |||
if (!entitiesDB.Exists<CharacterTagEntityStruct>(egid)) | |||
return false; | |||
//Functions.SwapEntityGroup<CharacterEntityDescriptor>(egid, CharacterExclusiveGroups.OnFootGroup); | |||
FakeInput.ActionInput(playerId, primary: true); | |||
return true; | |||
} | |||
public bool DespawnMachine(uint playerId) | |||
{ | |||
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB)) | |||
return false; | |||
GetCharacterStruct<CharacterTagEntityStruct>(playerId, out var group); | |||
if (group.isInvalid) | |||
return false; | |||
EGID egid = new EGID(playerId, group); | |||
if (!entitiesDB.Exists<CharacterTagEntityStruct>(egid)) | |||
return false; | |||
Functions.SwapEntityGroup<CharacterEntityDescriptor>(egid, CharacterExclusiveGroups.MachineSpawningGroup); | |||
return true; | |||
} | |||
public uint GetPing() | |||
{ | |||
return entitiesDB | |||
.QueryUniqueEntity<NetworkStatsEntityStruct>(MultiplayerExclusiveGroups.MultiplayerStateGroup) | |||
.networkStats.PingMs; | |||
} | |||
} | |||
} |
@@ -1,11 +1,13 @@ | |||
using RobocraftX.Character; | |||
using RobocraftX.Character.Movement; | |||
using RobocraftX.Common.Input; | |||
using Svelto.ECS; | |||
using TechbloxModdingAPI.Engines; | |||
namespace TechbloxModdingAPI.Players | |||
{ | |||
public class PlayerEventsEngine : IApiEngine, IReactOnSwap<CharacterPilotSeatEntityStruct> | |||
public class PlayerEventsEngine : IApiEngine, IReactOnSwap<CharacterPilotSeatEntityStruct>, IReactOnAddAndRemove<PlayerIDStruct> | |||
{ | |||
public void Ready() | |||
{ | |||
@@ -21,13 +23,22 @@ namespace TechbloxModdingAPI.Players | |||
public void MovedTo(ref CharacterPilotSeatEntityStruct entityComponent, ExclusiveGroupStruct previousGroup, EGID egid) | |||
{ | |||
var seatId = entityComponent.pilotSeatEntity.ToEGID(entitiesDB); | |||
var player = EcsObjectBase.GetInstance(new EGID(egid.entityID, CharacterExclusiveGroups.OnFootGroup), | |||
e => new Player(e.entityID)); | |||
entitiesDB.TryGetEGID(entityComponent.pilotSeatEntity, out var seatId); //TODO: Can't get EGID | |||
var player = Player.GetInstance(egid.entityID); | |||
if (previousGroup == CharacterExclusiveGroups.InPilotSeatGroup) | |||
player.seatExited.Invoke(this, new PlayerSeatEventArgs { SeatId = seatId}); | |||
else if (egid.groupID == CharacterExclusiveGroups.InPilotSeatGroup) | |||
player.seatEntered.Invoke(this, new PlayerSeatEventArgs { SeatId = seatId }); | |||
} | |||
public void Add(ref PlayerIDStruct entityComponent, EGID egid) | |||
{ | |||
Player.joined.Invoke(this, new PlayerEventArgs { PlayerId = egid }); | |||
} | |||
public void Remove(ref PlayerIDStruct entityComponent, EGID egid) | |||
{ | |||
Player.left.Invoke(this, new PlayerEventArgs { PlayerId = egid }); | |||
} | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
using System.Collections.Generic; | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.Tasks; | |||
using Svelto.Tasks.Enumerators; | |||
@@ -7,6 +8,7 @@ using Unity.Mathematics; | |||
using TechbloxModdingAPI.App; | |||
using TechbloxModdingAPI.Blocks; | |||
using TechbloxModdingAPI.Tests; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.Players | |||
{ | |||
@@ -45,7 +47,20 @@ namespace TechbloxModdingAPI.Players | |||
[APITestCase(TestType.SimulationMode)] | |||
public static IEnumerator<TaskContract> SeatEventTestSim() | |||
{ | |||
yield return new WaitForSecondsEnumerator(1).Continue(); | |||
Assert.Equal(Player.LocalPlayer.SpawnMachine(), true, "Failed to spawn the player's machine.", "Successfully spawned the player's machine."); | |||
yield return new WaitForSecondsEnumerator(1).Continue(); | |||
var seats = Game.CurrentGame().GetBlocksInGame(BlockIDs.DriverSeat); | |||
int c = 0; | |||
while (seats.Length == 0 && c < 10) | |||
{ | |||
Logging.MetaLog("Waiting for a seat to be spawned..."); | |||
yield return new WaitForSecondsEnumerator(1).Continue(); | |||
Console.WriteLine("Spawn machine: " + Player.LocalPlayer.SpawnMachine()); | |||
seats = Game.CurrentGame().GetBlocksInGame(BlockIDs.DriverSeat); | |||
c++; | |||
} | |||
if (seats.Length == 0) | |||
{ | |||
Assert.Fail("No driver seat found!"); | |||
@@ -0,0 +1,16 @@ | |||
using System.Collections; | |||
using Svelto.Tasks; | |||
using Svelto.Tasks.ExtraLean; | |||
using Svelto.Tasks.Unity.Internal; | |||
namespace TechbloxModdingAPI.Tasks | |||
{ | |||
public class OnGuiRunner : BaseRunner<ExtraLeanSveltoTask<IEnumerator>> | |||
{ | |||
public OnGuiRunner(string name, uint runningOrder = 0) | |||
: base(name) | |||
{ | |||
UnityCoroutineRunner.StartOnGuiCoroutine(this._processEnumerator, runningOrder); | |||
} | |||
} | |||
} |
@@ -20,7 +20,7 @@ namespace TechbloxModdingAPI.Tasks | |||
{ | |||
get | |||
{ | |||
return RobocraftX.Schedulers.Lean.UIScheduler; | |||
return RobocraftX.Schedulers.ClientLean.UIScheduler; | |||
} | |||
} | |||
@@ -28,7 +28,7 @@ namespace TechbloxModdingAPI.Tasks | |||
{ | |||
get | |||
{ | |||
return RobocraftX.Schedulers.ExtraLean.UIScheduler; | |||
return RobocraftX.Schedulers.ClientExtraLean.UIScheduler; | |||
} | |||
} | |||
@@ -10,12 +10,10 @@ using IllusionInjector; | |||
using RobocraftX.FrontEnd; | |||
using Unity.Mathematics; | |||
using UnityEngine; | |||
using RobocraftX.Common.Input; | |||
using Svelto.Tasks; | |||
using Svelto.Tasks.Lean; | |||
using TechbloxModdingAPI.Blocks; | |||
using TechbloxModdingAPI.Commands; | |||
using TechbloxModdingAPI.Input; | |||
using TechbloxModdingAPI.Players; | |||
using TechbloxModdingAPI.Tasks; | |||
using TechbloxModdingAPI.Utility; | |||
@@ -345,6 +343,11 @@ namespace TechbloxModdingAPI.Tests | |||
Logging.CommandLog(asset); | |||
} | |||
}).Build(); | |||
Client.EnterMenu += (sender, args) => Scheduler.Schedule(new Once(() => Client.Instance.CloseBetaPopup())); | |||
Game.Enter += (sender, args) => | |||
Console.WriteLine( | |||
$"Current game selection data: {FullGameFields._gameSelectionData.gameMode} - {FullGameFields._gameSelectionData.saveType}"); | |||
#if TEST | |||
TestRoot.RunTests(); | |||
#endif | |||
@@ -360,15 +363,6 @@ namespace TechbloxModdingAPI.Tests | |||
return modsString = sb.ToString(); | |||
} | |||
public override void OnUpdate() | |||
{ | |||
if (UnityEngine.Input.GetKeyDown(KeyCode.End)) | |||
{ | |||
Console.WriteLine("Pressed button to toggle console"); | |||
FakeInput.CustomInput(new LocalCosmeticInputEntityComponent {commandLineToggleInput = true}); | |||
} | |||
} | |||
[HarmonyPatch] | |||
public class MinimumSpecsPatch | |||
{ | |||
@@ -7,7 +7,9 @@ using System.Linq; // welcome to the dark side | |||
using Svelto.Tasks; | |||
using Svelto.Tasks.Lean; | |||
using Svelto.Tasks.Enumerators; | |||
using Svelto.Tasks.Lean.Unity; | |||
using UnityEngine; | |||
using TechbloxModdingAPI.App; | |||
using TechbloxModdingAPI.Tasks; | |||
using TechbloxModdingAPI.Utility; | |||
@@ -64,7 +66,7 @@ namespace TechbloxModdingAPI.Tests | |||
_testsCountPassed = 0; | |||
_testsCountFailed = 0; | |||
// flow control | |||
Game.Enter += (sender, args) => { GameTests().RunOn(RobocraftX.Schedulers.Lean.EveryFrameStepRunner_TimeRunningAndStopped); }; | |||
Game.Enter += (sender, args) => { GameTests().RunOn(new UpdateMonoRunner("TechbloxModdingAPITestRunner")); }; | |||
Game.Exit += (s, a) => state = "ReturningFromGame"; | |||
Client.EnterMenu += (sender, args) => | |||
{ | |||
@@ -129,7 +131,7 @@ namespace TechbloxModdingAPI.Tests | |||
private static IEnumerator<TaskContract> GoToGameTests() | |||
{ | |||
Client app = new Client(); | |||
Client app = Client.Instance; | |||
int oldLength = 0; | |||
while (app.MyGames.Length == 0 || oldLength != app.MyGames.Length) | |||
{ | |||
@@ -137,7 +139,15 @@ namespace TechbloxModdingAPI.Tests | |||
yield return new WaitForSecondsEnumerator(1).Continue(); | |||
} | |||
yield return Yield.It; | |||
app.MyGames[0].EnterGame(); | |||
try | |||
{ | |||
app.MyGames[0].EnterGame(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.WriteLine("Failed to go to game tests"); | |||
Console.WriteLine(e); | |||
} | |||
/*Game newGame = Game.NewGame(); | |||
yield return new WaitForSecondsEnumerator(5).Continue(); // wait for sync | |||
newGame.EnterGame();*/ | |||
@@ -157,6 +167,7 @@ namespace TechbloxModdingAPI.Tests | |||
}; | |||
for (var index = 0; index < testTypesToRun.Length; index++) | |||
{ | |||
Logging.MetaLog($"Running test type {testTypesToRun[index]}"); | |||
foreach (Type t in testTypes) | |||
{ | |||
foreach (MethodBase m in t.GetMethods()) | |||
@@ -198,7 +209,16 @@ namespace TechbloxModdingAPI.Tests | |||
} | |||
if (index + 1 < testTypesToRun.Length) //Don't toggle on the last test | |||
{ | |||
bool running = currentGame.IsTimeRunning; | |||
currentGame.ToggleTimeMode(); | |||
while (running ? !currentGame.IsTimeStopped : !currentGame.IsTimeRunning) | |||
{ | |||
Logging.MetaLog($"Waiting for time to {(running?"stop":"start")}..."); | |||
yield return new WaitForSecondsEnumerator(1).Continue(); | |||
} | |||
} | |||
yield return new WaitForSecondsEnumerator(5).Continue(); | |||
} | |||
// exit game | |||
@@ -1,20 +1,14 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using DataLoader; | |||
using DataLoader; | |||
using HarmonyLib; | |||
using RobocraftX; | |||
using RobocraftX.Common.Utilities; | |||
using RobocraftX.CR.MainGame; | |||
using RobocraftX.GUI; | |||
using RobocraftX.Multiplayer; | |||
using RobocraftX.Rendering; | |||
using Svelto.Context; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Schedulers; | |||
using Svelto.ECS.GUI; | |||
using Techblox.GameSelection; | |||
using UnityEngine; | |||
using Unity.Entities; | |||
using Unity.Physics.Systems; | |||
@@ -104,14 +98,6 @@ namespace TechbloxModdingAPI.Utility | |||
} | |||
} | |||
public static PhysicsUtility _physicsUtility | |||
{ | |||
get | |||
{ | |||
return (PhysicsUtility)fgcr?.Field("_physicsUtility").GetValue(); | |||
} | |||
} | |||
/*public static UnityEntitySubmissionScheduler _frontEndSubmissionScheduler | |||
{ | |||
get | |||
@@ -136,11 +122,11 @@ namespace TechbloxModdingAPI.Utility | |||
} | |||
} | |||
public static ECSGameObjectResourceManager _eCsGameObjectResourceManager | |||
public static ECSResourceManagers _managers | |||
{ | |||
get | |||
{ | |||
return (ECSGameObjectResourceManager)fgcr?.Field("_eCsGameObjectResourceManager").GetValue(); | |||
return (ECSResourceManagers)fgcr?.Field("_managers").GetValue(); | |||
} | |||
} | |||
@@ -160,6 +146,22 @@ namespace TechbloxModdingAPI.Utility | |||
} | |||
} | |||
public static SveltoGUI _frontEndGUI | |||
{ | |||
get | |||
{ | |||
return (SveltoGUI)fgcr?.Field("_frontEndGUI").GetValue(); | |||
} | |||
} | |||
public static GameSelectionData _gameSelectionData | |||
{ | |||
get | |||
{ | |||
return (GameSelectionData)fgcr?.Field("_gameSelectionData").GetValue(); | |||
} | |||
} | |||
private static Traverse fgcr; | |||
public static void Init(FullGameCompositionRoot instance) | |||
@@ -1,8 +1,5 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using RobocraftX.StateSync; | |||
using Svelto.ECS; | |||
@@ -34,6 +34,12 @@ namespace TechbloxModdingAPI.Utility | |||
Logging.LogWarning(wrappedException.ToString()); | |||
} | |||
}; | |||
if (wrappers.ContainsKey(added)) | |||
{ | |||
original.eventHandler -= wrapped; | |||
wrappers.Remove(added); | |||
} | |||
wrappers.Add(added, wrapped); | |||
return new WrappedHandler<T> { eventHandler = original.eventHandler + wrapped }; | |||
} | |||