# Conflicts: # GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cstags/v1.8.0
@@ -0,0 +1,67 @@ | |||
#!/usr/bin/python3 | |||
import argparse | |||
import re | |||
# this assumes a mostly semver-complient version number | |||
if __name__ == "__main__": | |||
parser = argparse.ArgumentParser(description="Increment GamecraftModdingAPI version") | |||
parser.add_argument('version', metavar="VN", type=str, help="The version number to increment, or the index of the number (zero-indexed).") | |||
args = parser.parse_args() | |||
version_index = -1 | |||
try: | |||
version_index = int(args.version) | |||
except Exception: | |||
if args.version.lower() == "major": | |||
version_index = 0 | |||
elif args.version.lower() == "minor": | |||
version_index = 1 | |||
elif args.version.lower() == "patch": | |||
version_index = 2 | |||
if version_index < 0: | |||
print("Could not parse version argument.") | |||
exit(version_index) | |||
print(version_index) | |||
old_version = "" | |||
new_version = "" | |||
with open("../GamecraftModdingAPI/GamecraftModdingAPI.csproj", "r") as xmlFile: | |||
print("Parsing GamecraftModdingAPI.csproj") | |||
fileStr = xmlFile.read() | |||
versionMatch = re.search(r"<Version>(.+)</Version>", fileStr) | |||
if versionMatch is None: | |||
print("Unable to find version number in GamecraftModdingAPI.csproj") | |||
exit(1) | |||
old_version = versionMatch.group(1) | |||
versionList = old_version.split(".") | |||
if len(versionList) <= version_index: | |||
print("Invalid version string") | |||
exit(1) | |||
versionList[version_index] = str(int(versionList[version_index]) + 1) | |||
for i in range(version_index + 1, len(versionList)): | |||
try: | |||
int(versionList[i]) | |||
versionList[i] = "0" | |||
except Exception: | |||
tmp = versionList[i].split("-") | |||
tmp[0] = "0" | |||
versionList[i] = "-".join(tmp) | |||
new_version = ".".join(versionList) | |||
print(new_version) | |||
newFileContents = fileStr.replace("<Version>"+old_version+"</Version>", "<Version>"+new_version+"</Version>") | |||
with open("../GamecraftModdingAPI/GamecraftModdingAPI.csproj", "w") as xmlFile: | |||
print("Writing new version to project file") | |||
xmlFile.write(newFileContents) | |||
with open("../doxygen.conf", "r") as doxFile: | |||
print("Parsing doxygen.conf") | |||
doxStr = doxFile.read() | |||
newFileContents = doxStr.replace("= \"v" + old_version + "\"", "= \"v" + new_version + "\"") | |||
with open("../doxygen.conf", "w") as doxFile: | |||
print("Writing new version to doxygen config") | |||
doxFile.write(newFileContents) |
@@ -9,12 +9,15 @@ Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
Release|Any CPU = Release|Any CPU | |||
Test|Any CPU = Test|Any CPU | |||
EndGlobalSection | |||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Test|Any CPU.ActiveCfg = Test|Any CPU | |||
{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Test|Any CPU.Build.0 = Test|Any CPU | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
@@ -0,0 +1,35 @@ | |||
using System; | |||
using GamecraftModdingAPI.Tests; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
#if TEST | |||
/// <summary> | |||
/// App callbacks tests. | |||
/// Only available in TEST builds. | |||
/// </summary> | |||
[APITestClass] | |||
public static class AppCallbacksTest | |||
{ | |||
[APITestStartUp] | |||
public static void StartUp() | |||
{ | |||
// this could be split into 6 separate test cases | |||
Game.Enter += Assert.CallsBack<GameEventArgs>("GameEnter"); | |||
Game.Exit += Assert.CallsBack<GameEventArgs>("GameExit"); | |||
Game.Simulate += Assert.CallsBack<GameEventArgs>("GameSimulate"); | |||
Game.Edit += Assert.CallsBack<GameEventArgs>("GameEdit"); | |||
Client.EnterMenu += Assert.CallsBack<MenuEventArgs>("MenuEnter"); | |||
Client.ExitMenu += Assert.CallsBack<MenuEventArgs>("MenuExit"); | |||
} | |||
[APITestCase(TestType.Game)] | |||
public static void Test() | |||
{ | |||
// the test is actually completely implemented in StartUp() | |||
// this is here just so it looks less weird (not required) | |||
} | |||
} | |||
#endif | |||
} |
@@ -0,0 +1,63 @@ | |||
using System; | |||
using RobocraftX.GUI.MyGamesScreen; | |||
using RobocraftX.GUI; | |||
using Svelto.ECS; | |||
using GamecraftModdingAPI.Engines; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
public class AppEngine : IFactoryEngine | |||
{ | |||
public event EventHandler<MenuEventArgs> EnterMenu; | |||
public event EventHandler<MenuEventArgs> ExitMenu; | |||
public IEntityFactory Factory { set; private get; } | |||
public string Name => "GamecraftModdingAPIAppEngine"; | |||
public bool isRemovable => false; | |||
public EntitiesDB entitiesDB { set; private get; } | |||
public void Dispose() | |||
{ | |||
IsInMenu = false; | |||
ExceptionUtil.InvokeEvent(ExitMenu, this, new MenuEventArgs { }); | |||
} | |||
public void Ready() | |||
{ | |||
IsInMenu = true; | |||
ExceptionUtil.InvokeEvent(EnterMenu, this, new MenuEventArgs { }); | |||
} | |||
// app functionality | |||
public bool IsInMenu | |||
{ | |||
get; | |||
private set; | |||
} = false; | |||
public Game[] GetMyGames() | |||
{ | |||
EntityCollection<MyGameDataEntityStruct> mgsevs = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames); | |||
Game[] games = new Game[mgsevs.count]; | |||
for (int i = 0; i < mgsevs.count; i++) | |||
{ | |||
Utility.Logging.MetaDebugLog($"Found game named {mgsevs[i].GameName}"); | |||
games[i] = new Game(mgsevs[i].ID); | |||
} | |||
return games; | |||
} | |||
} | |||
public struct MenuEventArgs | |||
{ | |||
} | |||
} |
@@ -0,0 +1,42 @@ | |||
using System; | |||
using System.Runtime.Serialization; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
public class AppException : GamecraftModdingAPIException | |||
{ | |||
public AppException() | |||
{ | |||
} | |||
public AppException(string message) : base(message) | |||
{ | |||
} | |||
public AppException(string message, Exception innerException) : base(message, innerException) | |||
{ | |||
} | |||
} | |||
public class AppStateException : AppException | |||
{ | |||
public AppStateException() | |||
{ | |||
} | |||
public AppStateException(string message) : base(message) | |||
{ | |||
} | |||
} | |||
public class GameNotFoundException : AppException | |||
{ | |||
public GameNotFoundException() | |||
{ | |||
} | |||
public GameNotFoundException(string message) : base(message) | |||
{ | |||
} | |||
} | |||
} |
@@ -0,0 +1,159 @@ | |||
using System; | |||
using System.Reflection; | |||
using HarmonyLib; | |||
using RobocraftX.Services; | |||
using UnityEngine; | |||
using GamecraftModdingAPI.Utility; | |||
using RobocraftX.Common; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
/// <summary> | |||
/// The Gamecraft application that is running this code right now. | |||
/// </summary> | |||
public class Client | |||
{ | |||
// extensible engine | |||
protected static AppEngine appEngine = new AppEngine(); | |||
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> | |||
public static event EventHandler<MenuEventArgs> EnterMenu | |||
{ | |||
add => appEngine.EnterMenu += value; | |||
remove => appEngine.EnterMenu -= value; | |||
} | |||
/// <summary> | |||
/// An event that fire whenever the main menu is exited. | |||
/// </summary> | |||
public static event EventHandler<MenuEventArgs> ExitMenu | |||
{ | |||
add => appEngine.ExitMenu += value; | |||
remove => appEngine.ExitMenu -= value; | |||
} | |||
/// <summary> | |||
/// Gamecraft build version string. | |||
/// Usually this is in the form YYYY.mm.DD.HH.MM.SS | |||
/// </summary> | |||
/// <value>The version.</value> | |||
public string Version | |||
{ | |||
get => Application.version; | |||
} | |||
/// <summary> | |||
/// Unity version string. | |||
/// </summary> | |||
/// <value>The unity version.</value> | |||
public string UnityVersion | |||
{ | |||
get => Application.unityVersion; | |||
} | |||
/// <summary> | |||
/// Game saves currently visible in the menu. | |||
/// These take a second to completely populate after the EnterMenu event fires. | |||
/// </summary> | |||
/// <value>My games.</value> | |||
public Game[] MyGames | |||
{ | |||
get | |||
{ | |||
if (!appEngine.IsInMenu) return new Game[0]; | |||
return appEngine.GetMyGames(); | |||
} | |||
} | |||
/// <summary> | |||
/// Whether Gamecraft is in the Main Menu | |||
/// </summary> | |||
/// <value><c>true</c> if in menu; <c>false</c> when loading or in a game.</value> | |||
public bool InMenu | |||
{ | |||
get => appEngine.IsInMenu; | |||
} | |||
/// <summary> | |||
/// Open a popup which prompts the user to click a button. | |||
/// This reuses Gamecraft's error dialog popup | |||
/// </summary> | |||
/// <param name="popup">The popup to display. Use an instance of SingleChoicePrompt or DualChoicePrompt.</param> | |||
public void PromptUser(Error popup) | |||
{ | |||
// if the stuff wasn't mostly set to internal, this would be written as: | |||
// RobocraftX.Services.ErrorHandler.Instance.EqueueError(error); | |||
object errorHandlerInstance = ErrorHandlerInstanceGetter(); | |||
EnqueueError(errorHandlerInstance, popup); | |||
} | |||
// TODO | |||
/*public void CloseCurrentPrompt() | |||
{ | |||
// 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); | |||
}*/ | |||
internal static void Init() | |||
{ | |||
// this would have been so much simpler if this didn't involve a bunch of internal fields & classes | |||
Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); | |||
Type errorHandle = AccessTools.TypeByName("RobocraftX.Services.ErrorHandle"); | |||
ErrorHandlerInstanceGetter = (Func<object>) AccessTools.Method("GamecraftModdingAPI.App.Client:GenInstanceGetter") | |||
.MakeGenericMethod(errorHandler) | |||
.Invoke(null, new object[0]); | |||
EnqueueError = (Action<object, Error>) AccessTools.Method("GamecraftModdingAPI.App.Client:GenEnqueueError") | |||
.MakeGenericMethod(errorHandler, errorHandle) | |||
.Invoke(null, new object[0]); | |||
/*HandleErrorClosed = (Action<object>) AccessTools.Method("GamecraftModdingAPI.App.Client:GenHandlePopupClosed") | |||
.MakeGenericMethod(errorHandler) | |||
.Invoke(null, new object[0]);*/ | |||
// register engines | |||
MenuEngineManager.AddMenuEngine(appEngine); | |||
} | |||
// Creating delegates once is faster than reflection every time | |||
// Admittedly, this way is more difficult to code and less readable | |||
private static Func<object> GenInstanceGetter<T>() | |||
{ | |||
Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); | |||
MethodInfo instance = AccessTools.PropertyGetter(errorHandler, "Instance"); | |||
Func<T> getterSimple = (Func<T>) Delegate.CreateDelegate(typeof(Func<T>), null, instance); | |||
Func<object> getterCasted = () => (object) getterSimple(); | |||
return getterCasted; | |||
} | |||
private static Action<object, Error> GenEnqueueError<T, TRes>() | |||
{ | |||
Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); | |||
MethodInfo enqueueError = AccessTools.Method(errorHandler, "EnqueueError"); | |||
Func<T, Error, TRes> enqueueSimple = | |||
(Func<T, Error, TRes>) Delegate.CreateDelegate(typeof(Func<T, Error, TRes>), enqueueError); | |||
Action<object, Error> enqueueCasted = | |||
(object instance, Error error) => { enqueueSimple((T) instance, error); }; | |||
return enqueueCasted; | |||
} | |||
private static Action<object> GenHandlePopupClosed<T>() | |||
{ | |||
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; | |||
} | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
using System; | |||
using HarmonyLib; | |||
using RobocraftX.Services; | |||
using GamecraftModdingAPI.Tests; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
#if TEST | |||
/// <summary> | |||
/// Client popups tests. | |||
/// Only available in TEST builds. | |||
/// </summary> | |||
[APITestClass] | |||
public static class ClientAlertTest | |||
{ | |||
private static DualChoicePrompt popup2 = null; | |||
private static SingleChoicePrompt popup1 = null; | |||
[APITestStartUp] | |||
public static void StartUp2() | |||
{ | |||
popup2 = new DualChoicePrompt("This is a test double-button popup", | |||
"The cake is a lie", | |||
"lmao", | |||
() => { }, | |||
"kek", | |||
() => { }); | |||
} | |||
[APITestStartUp] | |||
public static void StartUp1() | |||
{ | |||
popup1 = new SingleChoicePrompt("The cake is a lie", | |||
"This is a test single-button popup", | |||
"qwertyuiop", | |||
() => { }); | |||
} | |||
[APITestCase(TestType.Menu)] | |||
public static void TestPopUp2() | |||
{ | |||
Client c = new Client(); | |||
c.PromptUser(popup2); | |||
//c.CloseCurrentPrompt(); | |||
} | |||
[APITestCase(TestType.Menu)] | |||
public static void TestPopUp1() | |||
{ | |||
Client c = new Client(); | |||
c.PromptUser(popup1); | |||
//c.CloseCurrentPrompt(); | |||
} | |||
} | |||
#endif | |||
} |
@@ -0,0 +1,477 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using RobocraftX.Common; | |||
using RobocraftX.GUI.MyGamesScreen; | |||
using RobocraftX.StateSync; | |||
using Svelto.ECS; | |||
using GamecraftModdingAPI; | |||
using GamecraftModdingAPI.Blocks; | |||
using GamecraftModdingAPI.Tasks; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
/// <summary> | |||
/// An in-game save. | |||
/// This can be a menu item for a local save or the currently loaded save. | |||
/// Support for Steam Workshop coming soon (hopefully). | |||
/// </summary> | |||
public class Game | |||
{ | |||
// extensible engines | |||
protected static GameGameEngine gameEngine = new GameGameEngine(); | |||
protected static GameMenuEngine menuEngine = new GameMenuEngine(); | |||
protected static DebugInterfaceEngine debugOverlayEngine = new DebugInterfaceEngine(); | |||
protected static GameBuildSimEventEngine buildSimEventEngine = new GameBuildSimEventEngine(); | |||
private List<string> debugIds = new List<string>(); | |||
private bool menuMode = true; | |||
private bool hasId = false; | |||
/// <summary> | |||
/// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.App.Game"/> class. | |||
/// </summary> | |||
/// <param name="id">Menu identifier.</param> | |||
public Game(uint id) : this(new EGID(id, MyGamesScreenExclusiveGroups.MyGames)) | |||
{ | |||
} | |||
/// <summary> | |||
/// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.App.Game"/> class. | |||
/// </summary> | |||
/// <param name="id">Menu identifier.</param> | |||
public Game(EGID id) | |||
{ | |||
this.Id = id.entityID; | |||
this.EGID = id; | |||
this.hasId = true; | |||
menuMode = true; | |||
if (!VerifyMode()) throw new AppStateException("Game cannot be created while not in a game nor in a menu (is the game in a loading screen?)"); | |||
} | |||
/// <summary> | |||
/// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.App.Game"/> class without id. | |||
/// This is assumed to be the current game. | |||
/// </summary> | |||
public Game() | |||
{ | |||
menuMode = false; | |||
if (!VerifyMode()) throw new AppStateException("Game cannot be created while not in a game nor in a menu (is the game in a loading screen?)"); | |||
if (menuEngine.IsInMenu) throw new GameNotFoundException("Game not found."); | |||
} | |||
/// <summary> | |||
/// Returns the currently loaded game. | |||
/// If in a menu, manipulating the returned object may not work as intended. | |||
/// </summary> | |||
/// <returns>The current game.</returns> | |||
public static Game CurrentGame() | |||
{ | |||
return new Game(); | |||
} | |||
/// <summary> | |||
/// Creates a new game and adds it to the menu. | |||
/// If not in a menu, this will throw AppStateException. | |||
/// </summary> | |||
/// <returns>The new game.</returns> | |||
public static Game NewGame() | |||
{ | |||
if (!menuEngine.IsInMenu) throw new AppStateException("New Game cannot be created while not in a menu."); | |||
uint nextId = menuEngine.HighestID() + 1; | |||
EGID egid = new EGID(nextId, MyGamesScreenExclusiveGroups.MyGames); | |||
menuEngine.CreateMyGame(egid); | |||
return new Game(egid); | |||
} | |||
/// <summary> | |||
/// An event that fires whenever a game is switched to simulation mode (time running mode). | |||
/// </summary> | |||
public static event EventHandler<GameEventArgs> Simulate | |||
{ | |||
add => buildSimEventEngine.SimulationMode += value; | |||
remove => buildSimEventEngine.SimulationMode -= value; | |||
} | |||
/// <summary> | |||
/// An event that fires whenever a game is switched to edit mode (time stopped mode). | |||
/// This does not fire when a game is loaded. | |||
/// </summary> | |||
public static event EventHandler<GameEventArgs> Edit | |||
{ | |||
add => buildSimEventEngine.BuildMode += value; | |||
remove => buildSimEventEngine.BuildMode -= value; | |||
} | |||
/// <summary> | |||
/// An event that fires right after a game is completely loaded. | |||
/// </summary> | |||
public static event EventHandler<GameEventArgs> Enter | |||
{ | |||
add => gameEngine.EnterGame += value; | |||
remove => gameEngine.EnterGame -= value; | |||
} | |||
/// <summary> | |||
/// An event that fires right before a game returns to the main menu. | |||
/// At this point, Gamecraft is transitioning state so many things are invalid/unstable here. | |||
/// </summary> | |||
public static event EventHandler<GameEventArgs> Exit | |||
{ | |||
add => gameEngine.ExitGame += value; | |||
remove => gameEngine.ExitGame -= value; | |||
} | |||
/// <summary> | |||
/// The game's unique menu identifier. | |||
/// </summary> | |||
/// <value>The identifier.</value> | |||
public uint Id | |||
{ | |||
get; | |||
private set; | |||
} | |||
/// <summary> | |||
/// The game's unique menu EGID. | |||
/// </summary> | |||
/// <value>The egid.</value> | |||
public EGID EGID | |||
{ | |||
get; | |||
private set; | |||
} | |||
/// <summary> | |||
/// Whether the game is a (valid) menu item. | |||
/// </summary> | |||
/// <value><c>true</c> if menu item; otherwise, <c>false</c>.</value> | |||
public bool MenuItem | |||
{ | |||
get => menuMode && hasId; | |||
} | |||
/// <summary> | |||
/// The game's name. | |||
/// </summary> | |||
/// <value>The name.</value> | |||
public string Name | |||
{ | |||
get | |||
{ | |||
if (!VerifyMode()) return null; | |||
if (menuMode) return menuEngine.GetGameInfo(EGID).GameName; | |||
return GameMode.SaveGameDetails.Name; | |||
} | |||
set | |||
{ | |||
if (!VerifyMode()) return; | |||
if (menuMode) | |||
{ | |||
menuEngine.SetGameName(EGID, value); | |||
} | |||
else | |||
{ | |||
GameMode.SaveGameDetails.Name = value; | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// The game's description. | |||
/// </summary> | |||
/// <value>The description.</value> | |||
public string Description | |||
{ | |||
get | |||
{ | |||
if (!VerifyMode()) return null; | |||
if (menuMode) return menuEngine.GetGameInfo(EGID).GameDescription; | |||
return ""; | |||
} | |||
set | |||
{ | |||
if (!VerifyMode()) return; | |||
if (menuMode) | |||
{ | |||
menuEngine.SetGameDescription(EGID, value); | |||
} | |||
else | |||
{ | |||
// No description exists in-game | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// The path to the game's save folder. | |||
/// </summary> | |||
/// <value>The path.</value> | |||
public string Path | |||
{ | |||
get | |||
{ | |||
if (!VerifyMode()) return null; | |||
if (menuMode) return menuEngine.GetGameInfo(EGID).SavedGamePath; | |||
return GameMode.SaveGameDetails.Folder; | |||
} | |||
set | |||
{ | |||
if (!VerifyMode()) return; | |||
if (menuMode) | |||
{ | |||
menuEngine.GetGameInfo(EGID).SavedGamePath.Set(value); | |||
} | |||
else | |||
{ | |||
// this likely breaks things | |||
GameMode.SaveGameDetails = new SaveGameDetails(GameMode.SaveGameDetails.Name, value, GameMode.SaveGameDetails.WorkshopId); | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// The Steam Workshop Id of the game save. | |||
/// In most cases this is invalid and returns 0, so this can be ignored. | |||
/// </summary> | |||
/// <value>The workshop identifier.</value> | |||
public ulong WorkshopId | |||
{ | |||
get | |||
{ | |||
if (!VerifyMode()) return 0uL; | |||
if (menuMode) return 0uL; // MyGames don't have workshop IDs | |||
return GameMode.SaveGameDetails.WorkshopId; | |||
} | |||
set | |||
{ | |||
VerifyMode(); | |||
if (menuMode) | |||
{ | |||
// MyGames don't have workshop IDs | |||
// menuEngine.GetGameInfo(EGID).GameName.Set(value); | |||
} | |||
else | |||
{ | |||
// this likely breaks things | |||
GameMode.SaveGameDetails = new SaveGameDetails(GameMode.SaveGameDetails.Name, GameMode.SaveGameDetails.Folder, value); | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// Whether the game is in simulation mode. | |||
/// </summary> | |||
/// <value><c>true</c> if is simulating; otherwise, <c>false</c>.</value> | |||
public bool IsSimulating | |||
{ | |||
get | |||
{ | |||
if (!VerifyMode()) return false; | |||
return !menuMode && gameEngine.IsTimeRunningMode(); | |||
} | |||
set | |||
{ | |||
if (!VerifyMode()) return; | |||
if (!menuMode && gameEngine.IsTimeRunningMode() != value) | |||
gameEngine.ToggleTimeMode(); | |||
} | |||
} | |||
/// <summary> | |||
/// Whether the game is in time-running mode. | |||
/// Alias of IsSimulating. | |||
/// </summary> | |||
/// <value><c>true</c> if is time running; otherwise, <c>false</c>.</value> | |||
public bool IsTimeRunning | |||
{ | |||
get => IsSimulating; | |||
set | |||
{ | |||
IsSimulating = value; | |||
} | |||
} | |||
/// <summary> | |||
/// Whether the game is in time-stopped mode. | |||
/// </summary> | |||
/// <value><c>true</c> if is time stopped; otherwise, <c>false</c>.</value> | |||
public bool IsTimeStopped | |||
{ | |||
get | |||
{ | |||
if (!VerifyMode()) return false; | |||
return !menuMode && gameEngine.IsTimeStoppedMode(); | |||
} | |||
set | |||
{ | |||
if (!VerifyMode()) return; | |||
if (!menuMode && gameEngine.IsTimeStoppedMode() != value) | |||
gameEngine.ToggleTimeMode(); | |||
} | |||
} | |||
/// <summary> | |||
/// Toggles the time mode. | |||
/// </summary> | |||
public void ToggleTimeMode() | |||
{ | |||
if (!VerifyMode()) return; | |||
if (menuMode || !gameEngine.IsInGame) | |||
{ | |||
throw new AppStateException("Game menu item cannot toggle it's time mode"); | |||
} | |||
gameEngine.ToggleTimeMode(); | |||
} | |||
/// <summary> | |||
/// Load the game save. | |||
/// This happens asynchronously, so when this method returns the game not loaded yet. | |||
/// Use the Game.Enter event to perform operations after the game has completely loaded. | |||
/// </summary> | |||
public void EnterGame() | |||
{ | |||
if (!VerifyMode()) return; | |||
if (!hasId) | |||
{ | |||
throw new GameNotFoundException("Game has an invalid ID"); | |||
} | |||
ISchedulable task = new Once(() => { menuEngine.EnterGame(EGID); this.menuMode = false; }); | |||
Scheduler.Schedule(task); | |||
} | |||
/// <summary> | |||
/// Return to the menu. | |||
/// Part of this always happens asynchronously, so when this method returns the game has not exited yet. | |||
/// Use the Client.EnterMenu event to perform operations after the game has completely exited. | |||
/// </summary> | |||
/// <param name="async">If set to <c>true</c>, do this async.</param> | |||
public void ExitGame(bool async = false) | |||
{ | |||
if (!VerifyMode()) return; | |||
if (menuMode) | |||
{ | |||
throw new GameNotFoundException("Cannot exit game using menu ID"); | |||
} | |||
gameEngine.ExitCurrentGame(async); | |||
this.menuMode = true; | |||
} | |||
/// <summary> | |||
/// Saves the game. | |||
/// Part of this happens asynchronously, so when this method returns the game has not been saved yet. | |||
/// </summary> | |||
public void SaveGame() | |||
{ | |||
if (!VerifyMode()) return; | |||
if (menuMode) | |||
{ | |||
throw new GameNotFoundException("Cannot save game using menu ID"); | |||
} | |||
gameEngine.SaveCurrentGame(); | |||
} | |||
/// <summary> | |||
/// Add information to the in-game debug display. | |||
/// When this object is garbage collected, this debug info is automatically removed. | |||
/// </summary> | |||
/// <param name="id">Debug info identifier.</param> | |||
/// <param name="contentGetter">Content getter.</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); | |||
} | |||
/// <summary> | |||
/// Remove 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 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); | |||
} | |||
/// <summary> | |||
/// Gets the blocks in the game. | |||
/// This returns null when in a loading state, and throws AppStateException when in menu. | |||
/// </summary> | |||
/// <returns>The blocks in game.</returns> | |||
/// <param name="filter">The block to search for. BlockIDs.Invalid will return all blocks.</param> | |||
public Block[] GetBlocksInGame(BlockIDs filter = BlockIDs.Invalid) | |||
{ | |||
if (!VerifyMode()) return null; | |||
if (menuMode) | |||
{ | |||
throw new AppStateException("Game object references a menu item but GetBlocksInGame only works on the currently-loaded game"); | |||
} | |||
EGID[] blockEGIDs = gameEngine.GetAllBlocksInGame(filter); | |||
Block[] blocks = new Block[blockEGIDs.Length]; | |||
for (int b = 0; b < blockEGIDs.Length; b++) | |||
{ | |||
blocks[b] = new Block(blockEGIDs[b]); | |||
} | |||
return blocks; | |||
} | |||
~Game() | |||
{ | |||
foreach (string id in debugIds) | |||
{ | |||
debugOverlayEngine.RemoveInfo(id); | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
private bool VerifyMode() | |||
{ | |||
if (menuMode && (!menuEngine.IsInMenu || gameEngine.IsInGame)) | |||
{ | |||
// either game loading or API is broken | |||
return false; | |||
} | |||
if (!menuMode && (menuEngine.IsInMenu || !gameEngine.IsInGame)) | |||
{ | |||
// either game loading or API is broken | |||
return false; | |||
} | |||
return true; | |||
} | |||
internal static void Init() | |||
{ | |||
GameEngineManager.AddGameEngine(gameEngine); | |||
GameEngineManager.AddGameEngine(debugOverlayEngine); | |||
MenuEngineManager.AddMenuEngine(menuEngine); | |||
} | |||
internal static void InitDeterministic(StateSyncRegistrationHelper stateSyncReg) | |||
{ | |||
stateSyncReg.AddDeterministicEngine(buildSimEventEngine); | |||
} | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
using System; | |||
using RobocraftX.Common; | |||
using RobocraftX.StateSync; | |||
using Svelto.ECS; | |||
using Unity.Jobs; | |||
using GamecraftModdingAPI.Engines; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
public class GameBuildSimEventEngine : IApiEngine, IUnorderedInitializeOnTimeRunningModeEntered, IUnorderedInitializeOnTimeStoppedModeEntered | |||
{ | |||
public event EventHandler<GameEventArgs> SimulationMode; | |||
public event EventHandler<GameEventArgs> BuildMode; | |||
public string Name => "GamecraftModdingAPIBuildSimEventGameEngine"; | |||
public bool isRemovable => false; | |||
public EntitiesDB entitiesDB { set; private get; } | |||
public void Dispose() { } | |||
public void Ready() { } | |||
public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps) | |||
{ | |||
ExceptionUtil.InvokeEvent(SimulationMode, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); | |||
return inputDeps; | |||
} | |||
public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps) | |||
{ | |||
ExceptionUtil.InvokeEvent(BuildMode, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); | |||
return inputDeps; | |||
} | |||
} | |||
public struct GameEventArgs | |||
{ | |||
public string GameName; | |||
public string GamePath; | |||
} | |||
} |
@@ -0,0 +1,119 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using HarmonyLib; | |||
using RobocraftX; | |||
using RobocraftX.Common; | |||
using RobocraftX.Schedulers; | |||
using RobocraftX.SimulationModeState; | |||
using Svelto.ECS; | |||
using Svelto.Tasks; | |||
using Svelto.Tasks.Lean; | |||
using GamecraftModdingAPI.Blocks; | |||
using GamecraftModdingAPI.Engines; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
public class GameGameEngine : IApiEngine | |||
{ | |||
public event EventHandler<GameEventArgs> EnterGame; | |||
public event EventHandler<GameEventArgs> ExitGame; | |||
public string Name => "GamecraftModdingAPIGameInfoMenuEngine"; | |||
public bool isRemovable => false; | |||
public EntitiesDB entitiesDB { set; private get; } | |||
public void Dispose() | |||
{ | |||
ExceptionUtil.InvokeEvent(ExitGame, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); | |||
IsInGame = false; | |||
} | |||
public void Ready() | |||
{ | |||
ExceptionUtil.InvokeEvent(EnterGame, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); | |||
IsInGame = true; | |||
} | |||
// game functionality | |||
public bool IsInGame | |||
{ | |||
get; | |||
private set; | |||
} = false; | |||
public void ExitCurrentGame(bool async = false) | |||
{ | |||
if (async) | |||
{ | |||
ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING); | |||
} | |||
else | |||
{ | |||
entitiesDB.QueryEntity<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID).WantsToQuit = true; | |||
entitiesDB.PublishEntityChange<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID); | |||
} | |||
} | |||
public IEnumerator<TaskContract> ExitCurrentGameAsync() | |||
{ | |||
/* | |||
while (Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING.isStopping) { yield return Yield.It; } | |||
AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu").Invoke(FullGameFields.Instance, new object[0]);*/ | |||
yield return Yield.It; | |||
entitiesDB.QueryEntity<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID).WantsToQuit = true; | |||
entitiesDB.PublishEntityChange<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID); | |||
} | |||
public void SaveCurrentGame() | |||
{ | |||
ref GameSceneEntityStruct gses = ref entitiesDB.QueryEntity<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID); | |||
gses.LoadAfterSaving = false; | |||
gses.SaveNow = true; | |||
entitiesDB.PublishEntityChange<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID); | |||
} | |||
public bool IsTimeRunningMode() | |||
{ | |||
return TimeRunningModeUtil.IsTimeRunningMode(entitiesDB); | |||
} | |||
public bool IsTimeStoppedMode() | |||
{ | |||
return TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB); | |||
} | |||
public void ToggleTimeMode() | |||
{ | |||
TimeRunningModeUtil.ToggleTimeRunningState(entitiesDB); | |||
} | |||
public EGID[] GetAllBlocksInGame(BlockIDs filter = BlockIDs.Invalid) | |||
{ | |||
var allBlocks = entitiesDB.QueryEntities<DBEntityStruct>(); | |||
List<EGID> blockEGIDs = new List<EGID>(); | |||
if (filter == BlockIDs.Invalid) | |||
{ | |||
foreach (var (blocks, _) in allBlocks) | |||
foreach (var block in blocks) | |||
blockEGIDs.Add(block.ID); | |||
return blockEGIDs.ToArray(); | |||
} | |||
else | |||
{ | |||
foreach (var (blocks, _) in allBlocks) | |||
foreach (var block in blocks) | |||
if (block.DBID == (ulong) filter) | |||
blockEGIDs.Add(block.ID); | |||
return blockEGIDs.ToArray(); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,139 @@ | |||
using System; | |||
using HarmonyLib; | |||
using RobocraftX; | |||
using RobocraftX.Common; | |||
using RobocraftX.GUI; | |||
using RobocraftX.GUI.MyGamesScreen; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Experimental; | |||
using GamecraftModdingAPI.Engines; | |||
using GamecraftModdingAPI.Utility; | |||
using Svelto.DataStructures; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
public class GameMenuEngine : IFactoryEngine | |||
{ | |||
public IEntityFactory Factory { set; private get; } | |||
public string Name => "GamecraftModdingAPIGameInfoGameEngine"; | |||
public bool isRemovable => false; | |||
public EntitiesDB entitiesDB { set; private get; } | |||
public void Dispose() | |||
{ | |||
IsInMenu = false; | |||
} | |||
public void Ready() | |||
{ | |||
IsInMenu = true; | |||
} | |||
// game functionality | |||
public bool IsInMenu | |||
{ | |||
get; | |||
private set; | |||
} = false; | |||
public bool CreateMyGame(EGID id, string path = "", uint thumbnailId = 0, string gameName = "", string creatorName = "", string description = "", long createdDate = 0L) | |||
{ | |||
EntityComponentInitializer eci = Factory.BuildEntity<MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal>(id); | |||
eci.Init(new MyGameDataEntityStruct | |||
{ | |||
SavedGamePath = new ECSString(path), | |||
ThumbnailId = thumbnailId, | |||
GameName = new ECSString(gameName), | |||
CreatorName = new ECSString(creatorName), | |||
GameDescription = new ECSString(description), | |||
CreatedDate = createdDate, | |||
}); | |||
// entitiesDB.PublishEntityChange<MyGameDataEntityStruct>(id); // this will always fail | |||
return true; | |||
} | |||
public uint HighestID() | |||
{ | |||
EntityCollection<MyGameDataEntityStruct> games = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames); | |||
uint max = 0; | |||
for (int i = 0; i < games.count; i++) | |||
{ | |||
if (games[i].ID.entityID > max) | |||
{ | |||
max = games[i].ID.entityID; | |||
} | |||
} | |||
return max; | |||
} | |||
public bool EnterGame(EGID id) | |||
{ | |||
if (!ExistsGameInfo(id)) return false; | |||
ref MyGameDataEntityStruct mgdes = ref GetGameInfo(id); | |||
return EnterGame(mgdes.GameName, mgdes.SavedGamePath); | |||
} | |||
public bool EnterGame(string gameName, string path, ulong workshopId = 0uL, bool autoEnterSim = false) | |||
{ | |||
GameMode.CurrentMode = autoEnterSim ? RCXMode.Play : RCXMode.Build; | |||
GameMode.SaveGameDetails = new SaveGameDetails(gameName, path, workshopId); | |||
// the private FullGameCompositionRoot.SwitchToGame() method gets passed to menu items for this reason | |||
AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame").Invoke(FullGameFields.Instance, new object[0]); | |||
return true; | |||
} | |||
public bool SetGameName(EGID id, string name) | |||
{ | |||
if (!ExistsGameInfo(id)) return false; | |||
GetGameInfo(id).GameName.Set(name); | |||
GetGameViewInfo(id).MyGamesSlotComponent.GameName = StringUtil.SanitiseString(name); | |||
return true; | |||
} | |||
public bool SetGameDescription(EGID id, string name) | |||
{ | |||
if (!ExistsGameInfo(id)) return false; | |||
GetGameInfo(id).GameDescription.Set(name); | |||
GetGameViewInfo(id).MyGamesSlotComponent.GameDescription = StringUtil.SanitiseString(name); | |||
return true; | |||
} | |||
public bool ExistsGameInfo(EGID id) | |||
{ | |||
return entitiesDB.Exists<MyGameDataEntityStruct>(id); | |||
} | |||
public ref MyGameDataEntityStruct GetGameInfo(EGID id) | |||
{ | |||
return ref GetComponent<MyGameDataEntityStruct>(id); | |||
} | |||
public ref MyGamesSlotEntityViewStruct GetGameViewInfo(EGID id) | |||
{ | |||
EntityCollection<MyGamesSlotEntityViewStruct> entities = | |||
entitiesDB.QueryEntities<MyGamesSlotEntityViewStruct>(MyGamesScreenExclusiveGroups.GameSlotGuiEntities); | |||
for (int i = 0; i < entities.count; i++) | |||
{ | |||
if (entities[i].ID.entityID == id.entityID) | |||
{ | |||
return ref entities[i]; | |||
} | |||
} | |||
MyGamesSlotEntityViewStruct[] defRef = new MyGamesSlotEntityViewStruct[1]; | |||
return ref defRef[0]; | |||
} | |||
public ref T GetComponent<T>(EGID id) where T: unmanaged, IEntityComponent | |||
{ | |||
return ref entitiesDB.QueryEntity<T>(id); | |||
} | |||
} | |||
internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor<MyGameDataEntityStruct> { } | |||
} |
@@ -0,0 +1,26 @@ | |||
using System; | |||
using System.Reflection; | |||
using RobocraftX.CR.MainGame; | |||
using RobocraftX.StateSync; | |||
using HarmonyLib; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
[HarmonyPatch] | |||
class StateSyncRegPatch | |||
{ | |||
public static void Postfix(StateSyncRegistrationHelper stateSyncReg) | |||
{ | |||
// register sim/build events engines | |||
Game.InitDeterministic(stateSyncReg); | |||
} | |||
[HarmonyTargetMethod] | |||
public static MethodBase Target() | |||
{ | |||
return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose").MakeGenericMethod(typeof(object)); | |||
} | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
using System; | |||
using HarmonyLib; | |||
using RobocraftX.Services; | |||
namespace GamecraftModdingAPI.App | |||
{ | |||
public class DualChoicePrompt : MultiChoiceError | |||
{ | |||
public DualChoicePrompt(string errorMessage, string title, string firstButtonText, Action firstButtonAction, string secondButtonText, Action secondButtonAction) : base(errorMessage, firstButtonText, firstButtonAction, secondButtonText, secondButtonAction) | |||
{ | |||
// internal readonly field smh | |||
new Traverse(this).Field<string>("Title").Value = title; | |||
} | |||
} | |||
public class SingleChoicePrompt : SingleChoiceError | |||
{ | |||
public SingleChoicePrompt(string errorMessage, string buttonText, Action buttonClickAction) : base(errorMessage, buttonText, buttonClickAction) | |||
{ | |||
} | |||
public SingleChoicePrompt(string titleText, string errorMessage, string buttonText, Action buttonClickAction) : base(titleText, errorMessage, buttonText, buttonClickAction) | |||
{ | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using System; | |||
using System.Reflection; | |||
using System.Threading.Tasks; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Reflection.Emit; | |||
using Svelto.ECS; | |||
using Svelto.ECS.EntityStructs; | |||
@@ -28,7 +29,7 @@ namespace GamecraftModdingAPI | |||
protected static readonly SignalEngine SignalEngine = new SignalEngine(); | |||
protected static readonly BlockEventsEngine BlockEventsEngine = new BlockEventsEngine(); | |||
protected static readonly ScalingEngine ScalingEngine = new ScalingEngine(); | |||
protected internal static readonly BlockEngine BlockEngine = new BlockEngine(); | |||
/// <summary> | |||
@@ -54,23 +55,13 @@ namespace GamecraftModdingAPI | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
return new Block(PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation)); | |||
} | |||
return null; | |||
return PlaceNew<Block>(block, position, rotation, color, darkness, uscale, scale, player); | |||
} | |||
/// <summary> | |||
/// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position. | |||
/// Place blocks next to each other to connect them. | |||
/// The placed block will be a complete block with a placement grid and collision which will be saved along with the game. | |||
/// <para></para> | |||
/// <para>This method waits for the block to be constructed in the game which may take a significant amount of time. | |||
/// Only use this to place a single block. | |||
/// For placing multiple blocks, use PlaceNew() then AsyncUtils.WaitForSubmission() when done with placing blocks.</para> | |||
/// </summary> | |||
/// <param name="block">The block's type</param> | |||
/// <param name="color">The block's color</param> | |||
@@ -81,23 +72,18 @@ namespace GamecraftModdingAPI | |||
/// <param name="scale">The block's non-uniform scale - 0 means <paramref name="uscale"/> is used</param> | |||
/// <param name="player">The player who placed the block</param> | |||
/// <returns>The placed block or null if failed</returns> | |||
public static async Task<Block> PlaceNewAsync(BlockIDs block, float3 position, | |||
public static T PlaceNew<T>(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
int uscale = 1, float3 scale = default, Player player = null) where T : Block | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
try | |||
{ | |||
var ret = new Block(PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation)); | |||
await AsyncUtils.WaitForSubmission(); | |||
return ret; | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.MetaDebugLog(e); | |||
} | |||
var egid = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation, out var initializer); | |||
var bl = New<T>(egid.entityID, egid.groupID); | |||
bl.InitData.Group = BlockEngine.InitGroup(initializer); | |||
Placed += bl.OnPlacedInit; | |||
return bl; | |||
} | |||
return null; | |||
@@ -109,7 +95,7 @@ namespace GamecraftModdingAPI | |||
/// <returns>The block object</returns> | |||
public static Block GetLastPlacedBlock() | |||
{ | |||
return new Block(BlockIdentifiers.LatestBlockID); | |||
return New<Block>(BlockIdentifiers.LatestBlockID); | |||
} | |||
/// <summary> | |||
@@ -130,27 +116,125 @@ namespace GamecraftModdingAPI | |||
remove => BlockEventsEngine.Removed -= value; | |||
} | |||
private static Dictionary<Type, Func<EGID, Block>> initializers = new Dictionary<Type, Func<EGID, Block>>(); | |||
private static Dictionary<Type, ExclusiveGroupStruct[]> typeToGroup = | |||
new Dictionary<Type, ExclusiveGroupStruct[]> | |||
{ | |||
{typeof(ConsoleBlock), new[] {CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP}}, | |||
{typeof(LogicGate), new [] {CommonExclusiveGroups.BUILD_LOGIC_BLOCK_GROUP}}, | |||
{typeof(Motor), new[] {CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP}}, | |||
{typeof(MusicBlock), new[] {CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP}}, | |||
{typeof(Piston), new[] {CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP}}, | |||
{typeof(Servo), new[] {CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP}}, | |||
{ | |||
typeof(SpawnPoint), | |||
new[] | |||
{ | |||
CommonExclusiveGroups.BUILD_SPAWNPOINT_BLOCK_GROUP, | |||
CommonExclusiveGroups.BUILD_BUILDINGSPAWN_BLOCK_GROUP | |||
} | |||
}, | |||
{typeof(TextBlock), new[] {CommonExclusiveGroups.BUILD_TEXT_BLOCK_GROUP}}, | |||
{typeof(Timer), new[] {CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP}} | |||
}; | |||
/// <summary> | |||
/// Constructs a new instance of T with the given ID and group using dynamically created delegates. | |||
/// It's equivalent to new T(EGID) with a minimal overhead thanks to caching the created delegates. | |||
/// </summary> | |||
/// <param name="id">The block ID</param> | |||
/// <param name="group">The block group</param> | |||
/// <typeparam name="T">The block's type or Block itself</typeparam> | |||
/// <returns>An instance of the provided type</returns> | |||
/// <exception cref="BlockTypeException">The block group doesn't match or cannot be found</exception> | |||
/// <exception cref="MissingMethodException">The block class doesn't have the needed constructor</exception> | |||
private static T New<T>(uint id, ExclusiveGroupStruct? group = null) where T : Block | |||
{ | |||
var type = typeof(T); | |||
EGID egid; | |||
if (!group.HasValue) | |||
{ | |||
if (typeToGroup.TryGetValue(type, out var gr) && gr.Length == 1) | |||
egid = new EGID(id, gr[0]); | |||
else | |||
egid = BlockEngine.FindBlockEGID(id) ?? throw new BlockTypeException("Could not find block group!"); | |||
} | |||
else | |||
{ | |||
egid = new EGID(id, group.Value); | |||
if (typeToGroup.TryGetValue(type, out var gr) | |||
&& gr.All(egs => egs != group.Value)) //If this subclass has a specific group, then use that - so Block should still work | |||
throw new BlockTypeException($"Incompatible block type! Type {type.Name} belongs to group {gr.Select(g => g.ToString()).Aggregate((a, b) => a + ", " + b)} instead of {group.Value}"); | |||
} | |||
if (initializers.TryGetValue(type, out var func)) | |||
{ | |||
var bl = (T) func(egid); | |||
return bl; | |||
} | |||
//https://stackoverflow.com/a/10593806/2703239 | |||
var ctor = type.GetConstructor(new[] {typeof(EGID)}); | |||
if (ctor == null) | |||
throw new MissingMethodException("There is no constructor with an EGID parameter for this object"); | |||
DynamicMethod dynamic = new DynamicMethod(string.Empty, | |||
type, | |||
new[] {typeof(EGID)}, | |||
type); | |||
ILGenerator il = dynamic.GetILGenerator(); | |||
il.DeclareLocal(type); | |||
il.Emit(OpCodes.Ldarg_0); //Load EGID and pass to constructor | |||
il.Emit(OpCodes.Newobj, ctor); //Call constructor | |||
//il.Emit(OpCodes.Stloc_0); - doesn't seem like we need these | |||
//il.Emit(OpCodes.Ldloc_0); | |||
il.Emit(OpCodes.Ret); | |||
func = (Func<EGID, T>) dynamic.CreateDelegate(typeof(Func<EGID, T>)); | |||
initializers.Add(type, func); | |||
var block = (T) func(egid); | |||
return block; | |||
} | |||
public Block(EGID id) | |||
{ | |||
Id = id; | |||
var type = GetType(); | |||
if (typeToGroup.TryGetValue(type, out var groups)) | |||
{ | |||
if (groups.All(gr => gr != id.groupID)) | |||
throw new BlockTypeException("The block has the wrong group! The type is " + GetType() + | |||
" while the group is " + id.groupID); | |||
} | |||
else if (type != typeof(Block)) | |||
Logging.LogWarning($"Unknown block type! Add {type} to the dictionary."); | |||
} | |||
public Block(uint id) : this(new EGID(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP)) | |||
/// <summary> | |||
/// This overload searches for the correct group the block is in. | |||
/// It will throw an exception if the block doesn't exist. | |||
/// Use the EGID constructor where possible or subclasses of Block as those specify the group. | |||
/// </summary> | |||
public Block(uint id) | |||
{ | |||
Id = BlockEngine.FindBlockEGID(id) ?? throw new BlockTypeException("Could not find the appropriate group for the block. The block probably doesn't exist or hasn't been submitted."); | |||
} | |||
public EGID Id { get; } | |||
internal BlockEngine.BlockInitData InitData; | |||
/// <summary> | |||
/// The block's current position or zero if the block no longer exists. | |||
/// A block is 0.2 wide by default in terms of position. | |||
/// </summary> | |||
public float3 Position | |||
{ | |||
get => Exists ? MovementEngine.GetPosition(Id.entityID) : float3.zero; | |||
get => MovementEngine.GetPosition(Id, InitData); | |||
set | |||
{ | |||
if (Exists) MovementEngine.MoveBlock(Id.entityID, value); | |||
MovementEngine.MoveBlock(Id, InitData, value); | |||
} | |||
} | |||
@@ -159,10 +243,10 @@ namespace GamecraftModdingAPI | |||
/// </summary> | |||
public float3 Rotation | |||
{ | |||
get => Exists ? RotationEngine.GetRotation(Id.entityID) : float3.zero; | |||
get => RotationEngine.GetRotation(Id, InitData); | |||
set | |||
{ | |||
if (Exists) RotationEngine.RotateBlock(Id.entityID, value); | |||
RotationEngine.RotateBlock(Id, InitData, value); | |||
} | |||
} | |||
@@ -172,12 +256,11 @@ namespace GamecraftModdingAPI | |||
/// </summary> | |||
public float3 Scale | |||
{ | |||
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(Id).scale; | |||
get => BlockEngine.GetBlockInfo(this, (ScalingEntityStruct st) => st.scale); | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, float3 val) => st.scale = val, value); | |||
if (!Exists) return; //UpdateCollision needs the block to exist | |||
ref var scaling = ref BlockEngine.GetBlockInfo<ScalingEntityStruct>(Id); | |||
scaling.scale = value; | |||
ScalingEngine.UpdateCollision(Id); | |||
} | |||
} | |||
@@ -188,11 +271,11 @@ namespace GamecraftModdingAPI | |||
/// </summary> | |||
public int UniformScale | |||
{ | |||
get => BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(Id).scaleFactor; | |||
get => BlockEngine.GetBlockInfo(this, (UniformBlockScaleEntityStruct st) => st.scaleFactor); | |||
set | |||
{ | |||
ref var scaleStruct = ref BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(Id); | |||
scaleStruct.scaleFactor = value; | |||
BlockEngine.SetBlockInfo(this, (ref UniformBlockScaleEntityStruct st, int val) => st.scaleFactor = val, | |||
value); | |||
Scale = new float3(value, value, value); | |||
} | |||
} | |||
@@ -204,8 +287,7 @@ namespace GamecraftModdingAPI | |||
{ | |||
get | |||
{ | |||
var id = (BlockIDs) BlockEngine.GetBlockInfo<DBEntityStruct>(Id, out var exists).DBID; | |||
return exists ? id : BlockIDs.Invalid; | |||
return BlockEngine.GetBlockInfo(this, (DBEntityStruct st) => (BlockIDs) st.DBID, BlockIDs.Invalid); | |||
} | |||
} | |||
@@ -216,17 +298,19 @@ namespace GamecraftModdingAPI | |||
{ | |||
get | |||
{ | |||
byte index = BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(Id, out var exists).indexInPalette; | |||
if (!exists) index = byte.MaxValue; | |||
byte index = BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.indexInPalette, | |||
byte.MaxValue); | |||
return new BlockColor(index); | |||
} | |||
set | |||
{ | |||
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(Id); | |||
color.indexInPalette = (byte)(value.Color + value.Darkness * 10); | |||
color.overridePaletteColour = false; | |||
color.needsUpdate = true; | |||
BlockEngine.SetBlockColorFromPalette(ref color); | |||
BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, BlockColor val) => | |||
{ | |||
color.indexInPalette = (byte) (val.Color + val.Darkness * 10); | |||
color.overridePaletteColour = false; | |||
color.needsUpdate = true; | |||
BlockEngine.SetBlockColorFromPalette(ref color); | |||
}, value); | |||
} | |||
} | |||
@@ -235,32 +319,37 @@ namespace GamecraftModdingAPI | |||
/// </summary> | |||
public float4 CustomColor | |||
{ | |||
get => BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(Id).overriddenColour; | |||
get => BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.overriddenColour); | |||
set | |||
{ | |||
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(Id); | |||
color.overriddenColour = value; | |||
color.overridePaletteColour = true; | |||
color.needsUpdate = true; | |||
BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, float4 val) => | |||
{ | |||
color.overriddenColour = val; | |||
color.overridePaletteColour = true; | |||
color.needsUpdate = true; | |||
}, value); | |||
} | |||
} | |||
/// <summary> | |||
/// The short text displayed on the block if applicable, or null. | |||
/// The text displayed on the block if applicable, or null. | |||
/// Setting it is temporary to the session, it won't be saved. | |||
/// </summary> | |||
public string Label | |||
{ | |||
get => BlockEngine.GetBlockInfo<TextLabelEntityViewStruct>(Id).textLabelComponent?.text; | |||
get => BlockEngine.GetBlockInfoViewStruct(this, (TextLabelEntityViewStruct st) => st.textLabelComponent?.text); | |||
set | |||
{ | |||
ref var text = ref BlockEngine.GetBlockInfo<TextLabelEntityViewStruct>(Id); | |||
if (text.textLabelComponent != null) text.textLabelComponent.text = value; | |||
BlockEngine.SetBlockInfoViewStruct(this, (ref TextLabelEntityViewStruct text, string val) => | |||
{ | |||
if (text.textLabelComponent != null) text.textLabelComponent.text = val; | |||
}, value); | |||
} | |||
} | |||
/// <summary> | |||
/// Whether the block exists. The other properties will return a default value if the block doesn't exist. | |||
/// If the block was just placed, then this will also return false but the properties will work correctly. | |||
/// </summary> | |||
public bool Exists => BlockEngine.BlockExists(Id); | |||
@@ -276,14 +365,21 @@ namespace GamecraftModdingAPI | |||
public bool Remove() => RemovalEngine.RemoveBlock(Id); | |||
/// <summary> | |||
/// Returns the rigid body of the cluster of blocks this one belongs to during simulation. | |||
/// Returns the rigid body of the chunk of blocks this one belongs to during simulation. | |||
/// Can be used to apply forces or move the block around while the simulation is running. | |||
/// </summary> | |||
/// <returns>The SimBody of the cluster or null if the block doesn't exist.</returns> | |||
/// <returns>The SimBody of the chunk or null if the block doesn't exist.</returns> | |||
public SimBody GetSimBody() | |||
{ | |||
uint id = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(Id, out var exists).machineRigidBodyId; | |||
return exists ? new SimBody(id) : null; | |||
return BlockEngine.GetBlockInfo(this, | |||
(GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId, st.clusterId)); | |||
} | |||
private void OnPlacedInit(object sender, BlockPlacedRemovedEventArgs e) | |||
{ //Member method instead of lambda to avoid constantly creating delegates | |||
if (e.ID != Id) return; | |||
Placed -= OnPlacedInit; //And we can reference it | |||
InitData = default; //Remove initializer as it's no longer valid - if the block gets removed it shouldn't be used again | |||
} | |||
public override string ToString() | |||
@@ -325,6 +421,8 @@ namespace GamecraftModdingAPI | |||
GameEngineManager.AddGameEngine(BlockEngine); | |||
GameEngineManager.AddGameEngine(BlockEventsEngine); | |||
GameEngineManager.AddGameEngine(ScalingEngine); | |||
GameEngineManager.AddGameEngine(SignalEngine); | |||
Wire.signalEngine = SignalEngine; // requires same functionality, no need to duplicate the engine | |||
} | |||
/// <summary> | |||
@@ -338,12 +436,11 @@ namespace GamecraftModdingAPI | |||
// C# can't cast to a child of Block unless the object was originally that child type | |||
// And C# doesn't let me make implicit cast operators for child types | |||
// So thanks to Microsoft, we've got this horrible implementation using reflection | |||
ConstructorInfo ctor = typeof(T).GetConstructor(types: new System.Type[] { typeof(EGID) }); | |||
if (ctor == null) | |||
{ | |||
throw new BlockSpecializationException("Specialized block constructor does not accept an EGID"); | |||
} | |||
return (T)ctor.Invoke(new object[] { Id }); | |||
//Lets improve that using delegates | |||
var block = New<T>(Id.entityID, Id.groupID); | |||
block.InitData = this.InitData; | |||
return block; | |||
} | |||
#if DEBUG | |||
@@ -1,4 +1,6 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using Gamecraft.Wires; | |||
using RobocraftX.Blocks; | |||
@@ -8,16 +10,16 @@ using RobocraftX.Physics; | |||
using RobocraftX.Scene.Simulation; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Hybrid; | |||
using GamecraftModdingAPI.Engines; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
/// <summary> | |||
/// Engine for executing general block actions | |||
/// </summary> | |||
public class BlockEngine : IApiEngine | |||
public partial class BlockEngine : IApiEngine | |||
{ | |||
public string Name { get; } = "GamecraftModdingAPIBlockGameEngine"; | |||
@@ -25,8 +27,6 @@ namespace GamecraftModdingAPI.Blocks | |||
public bool isRemovable => false; | |||
internal bool Synced = true; | |||
public void Dispose() | |||
{ | |||
} | |||
@@ -38,14 +38,15 @@ namespace GamecraftModdingAPI.Blocks | |||
public Block[] GetConnectedBlocks(EGID blockID) | |||
{ | |||
if (!BlockExists(blockID)) return new Block[0]; | |||
Stack<uint> cubeStack = new Stack<uint>(); | |||
FasterList<uint> cubes = new FasterList<uint>(10); | |||
var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>(CommonExclusiveGroups | |||
.OWNED_BLOCKS_GROUP); | |||
for (int i = 0; i < coll.count; i++) | |||
coll[i].isProcessed = false; | |||
Stack<EGID> cubeStack = new Stack<EGID>(); | |||
FasterList<EGID> cubes = new FasterList<EGID>(10); | |||
var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>(); | |||
foreach (var (ecoll, _) in coll) | |||
foreach (ref var conn in ecoll) | |||
conn.isProcessed = false; | |||
ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID.entityID, cubeStack, cubes, (in GridConnectionsEntityStruct g) => { return false; }); | |||
ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes, | |||
(in GridConnectionsEntityStruct g) => { return false; }); | |||
var ret = new Block[cubes.count]; | |||
for (int i = 0; i < cubes.count; i++) | |||
@@ -60,75 +61,110 @@ namespace GamecraftModdingAPI.Blocks | |||
color.paletteColour = paletteEntry.Colour; | |||
} | |||
/// <summary> | |||
/// Get a struct of a block. Can be used to set properties. | |||
/// Returns a default value if not found. | |||
/// </summary> | |||
/// <param name="blockID">The block's ID</param> | |||
/// <typeparam name="T">The struct to query</typeparam> | |||
/// <returns>An editable reference to the struct</returns> | |||
public ref T GetBlockInfo<T>(EGID blockID) where T : struct, IEntityComponent | |||
public ref T GetBlockInfo<T>(EGID blockID) where T : unmanaged, IEntityComponent | |||
{ | |||
if (!Synced) | |||
{ | |||
Sync(); | |||
Synced = true; | |||
} | |||
if (entitiesDB.Exists<T>(blockID)) | |||
return ref entitiesDB.QueryEntity<T>(blockID); | |||
T[] structHolder = new T[1]; //Create something that can be referenced | |||
return ref structHolder[0]; //Gets a default value automatically | |||
} | |||
public ref T GetBlockInfoViewStruct<T>(EGID blockID) where T : struct, INeedEGID, IEntityComponent | |||
{ | |||
if (entitiesDB.Exists<T>(blockID)) | |||
{ | |||
// TODO: optimize by using EntitiesDB internal calls instead of iterating over everything | |||
EntityCollection<T> entities = entitiesDB.QueryEntities<T>(blockID.groupID); | |||
for (int i = 0; i < entities.count; i++) | |||
{ | |||
if (entities[i].ID == blockID) | |||
{ | |||
return ref entities[i]; | |||
} | |||
} | |||
} | |||
T[] structHolder = new T[1]; //Create something that can be referenced | |||
return ref structHolder[0]; //Gets a default value automatically | |||
} | |||
public U GetBlockInfo<T, U>(Block block, Func<T, U> getter, | |||
U def = default) where T : unmanaged, IEntityComponent | |||
{ | |||
if (entitiesDB.Exists<T>(block.Id)) | |||
return getter(entitiesDB.QueryEntity<T>(block.Id)); | |||
return GetBlockInitInfo(block, getter, def); | |||
} | |||
public U GetBlockInfoViewStruct<T, U>(Block block, Func<T, U> getter, | |||
U def = default) where T : struct, IEntityViewComponent | |||
{ | |||
if (entitiesDB.Exists<T>(block.Id)) | |||
return getter(entitiesDB.QueryEntity<T>(block.Id)); | |||
return GetBlockInitInfo(block, getter, def); | |||
} | |||
private U GetBlockInitInfo<T, U>(Block block, Func<T, U> getter, U def) where T : struct, IEntityComponent | |||
{ | |||
if (block.InitData.Group == null) return def; | |||
var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); | |||
if (initializer.Has<T>()) | |||
return getter(initializer.Get<T>()); | |||
return def; | |||
} | |||
public delegate void Setter<T, U>(ref T component, U value) where T : struct, IEntityComponent; | |||
public void SetBlockInfoViewStruct<T, U>(Block block, Setter<T, U> setter, U value) where T : struct, IEntityViewComponent | |||
{ | |||
if (entitiesDB.Exists<T>(block.Id)) | |||
setter(ref entitiesDB.QueryEntity<T>(block.Id), value); | |||
else | |||
SetBlockInitInfo(block, setter, value); | |||
} | |||
public void SetBlockInfo<T, U>(Block block, Setter<T, U> setter, U value) where T : unmanaged, IEntityComponent | |||
{ | |||
if (entitiesDB.Exists<T>(block.Id)) | |||
setter(ref entitiesDB.QueryEntity<T>(block.Id), value); | |||
else | |||
SetBlockInitInfo(block, setter, value); | |||
} | |||
/// <summary> | |||
/// Get a struct of a block. Can be used to set properties. | |||
/// Returns a default value if not found. | |||
/// </summary> | |||
/// <param name="blockID">The block's ID</param> | |||
/// <param name="exists">Whether the specified struct exists for the block</param> | |||
/// <typeparam name="T">The struct to query</typeparam> | |||
/// <returns>An editable reference to the struct</returns> | |||
public ref T GetBlockInfo<T>(EGID blockID, out bool exists) where T : struct, IEntityComponent | |||
private void SetBlockInitInfo<T, U>(Block block, Setter<T, U> setter, U value) | |||
where T : struct, IEntityComponent | |||
{ | |||
if (!Synced) | |||
if (block.InitData.Group != null) | |||
{ | |||
Sync(); | |||
Synced = true; | |||
var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); | |||
T component = initializer.Has<T>() ? initializer.Get<T>() : default; | |||
ref T structRef = ref component; | |||
setter(ref structRef, value); | |||
initializer.Init(structRef); | |||
} | |||
exists = entitiesDB.Exists<T>(blockID); | |||
if (exists) | |||
return ref entitiesDB.QueryEntity<T>(blockID); | |||
T[] structHolder = new T[1]; | |||
return ref structHolder[0]; | |||
} | |||
public bool BlockExists(EGID id) | |||
public bool BlockExists(EGID blockID) | |||
{ | |||
if (!Synced) | |||
{ | |||
Sync(); | |||
Synced = true; | |||
} | |||
return entitiesDB.Exists<DBEntityStruct>(id); | |||
return entitiesDB.Exists<DBEntityStruct>(blockID); | |||
} | |||
public bool GetBlockInfoExists<T>(EGID blockID) where T : struct, IEntityComponent | |||
public bool GetBlockInfoExists<T>(Block block) where T : struct, IEntityComponent | |||
{ | |||
if (!Synced) | |||
{ | |||
Sync(); | |||
Synced = true; | |||
} | |||
return entitiesDB.Exists<T>(blockID); | |||
if (entitiesDB.Exists<T>(block.Id)) | |||
return true; | |||
if (block.InitData.Group == null) | |||
return false; | |||
var init = new EntityComponentInitializer(block.Id, block.InitData.Group); | |||
return init.Has<T>(); | |||
} | |||
public SimBody[] GetSimBodiesFromID(byte id) | |||
{ | |||
var ret = new FasterList<SimBody>(4); | |||
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP)) | |||
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) | |||
return new SimBody[0]; | |||
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
var connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); | |||
var connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); | |||
foreach (ref ObjectIdEntityStruct oid in oids) | |||
{ | |||
if (oid.objectId != id) continue; | |||
@@ -147,9 +183,9 @@ namespace GamecraftModdingAPI.Blocks | |||
public ObjectIdentifier[] GetObjectIDsFromID(byte id, bool sim) | |||
{ | |||
var ret = new FasterList<ObjectIdentifier>(4); | |||
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP)) | |||
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) | |||
return new ObjectIdentifier[0]; | |||
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); | |||
foreach (ref ObjectIdEntityStruct oid in oids) | |||
if (sim ? oid.simObjectId == id : oid.objectId == id) | |||
ret.Add(new ObjectIdentifier(oid.ID)); | |||
@@ -170,15 +206,47 @@ namespace GamecraftModdingAPI.Blocks | |||
return list.ToArray(); | |||
} | |||
/// <summary> | |||
/// Synchronize newly created entity components with entities DB. | |||
/// This forces a partial game tick, so it may be slow. | |||
/// This also has the potential to make Gamecraft unstable. | |||
/// Use this sparingly. | |||
/// </summary> | |||
private static void Sync() | |||
public SimBody[] GetClusterBodies(uint cid) | |||
{ | |||
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>(); | |||
var bodies = new HashSet<uint>(); | |||
foreach (var (coll, _) in groups) | |||
{ | |||
foreach (var conn in coll) | |||
{ | |||
if (conn.clusterId == cid) | |||
bodies.Add(conn.machineRigidBodyId); | |||
} | |||
} | |||
return bodies.Select(id => new SimBody(id)).ToArray(); | |||
} | |||
public EGID? FindBlockEGID(uint id) | |||
{ | |||
DeterministicStepCompositionRootPatch.SubmitEntitiesNow(); | |||
var groups = entitiesDB.FindGroups<DBEntityStruct>(); | |||
foreach (ExclusiveGroupStruct group in groups) | |||
{ | |||
if (entitiesDB.Exists<DBEntityStruct>(id, group)) | |||
return new EGID(id, group); | |||
} | |||
return null; | |||
} | |||
public Cluster GetCluster(uint sbid) | |||
{ | |||
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>(); | |||
foreach (var (coll, _) in groups) | |||
{ | |||
foreach (var conn in coll) | |||
{ | |||
if (conn.machineRigidBodyId == sbid) | |||
return new Cluster(conn.clusterId); | |||
} | |||
} | |||
return null; | |||
} | |||
#if DEBUG | |||
@@ -0,0 +1,52 @@ | |||
using System; | |||
using System.Linq.Expressions; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Internal; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public partial class BlockEngine | |||
{ | |||
/// <summary> | |||
/// Holds information needed to construct a component initializer | |||
/// </summary> | |||
internal struct BlockInitData | |||
{ | |||
public FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> Group; | |||
} | |||
internal delegate FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> GetInitGroup( | |||
EntityComponentInitializer initializer); | |||
/// <summary> | |||
/// Accesses the group field of the initializer | |||
/// </summary> | |||
internal GetInitGroup InitGroup = CreateAccessor<GetInitGroup>("_group"); | |||
//https://stackoverflow.com/questions/55878525/unit-testing-ref-structs-with-private-fields-via-reflection | |||
internal static TDelegate CreateAccessor<TDelegate>(string memberName) where TDelegate : Delegate | |||
{ | |||
var invokeMethod = typeof(TDelegate).GetMethod("Invoke"); | |||
if (invokeMethod == null) | |||
throw new InvalidOperationException($"{typeof(TDelegate)} signature could not be determined."); | |||
var delegateParameters = invokeMethod.GetParameters(); | |||
if (delegateParameters.Length != 1) | |||
throw new InvalidOperationException("Delegate must have a single parameter."); | |||
var paramType = delegateParameters[0].ParameterType; | |||
var objParam = Expression.Parameter(paramType, "obj"); | |||
var memberExpr = Expression.PropertyOrField(objParam, memberName); | |||
Expression returnExpr = memberExpr; | |||
if (invokeMethod.ReturnType != memberExpr.Type) | |||
returnExpr = Expression.ConvertChecked(memberExpr, invokeMethod.ReturnType); | |||
var lambda = | |||
Expression.Lambda<TDelegate>(returnExpr, $"Access{paramType.Name}_{memberName}", new[] {objParam}); | |||
return lambda.Compile(); | |||
} | |||
} | |||
} |
@@ -1,9 +1,11 @@ | |||
using System; | |||
using GamecraftModdingAPI.Engines; | |||
using GamecraftModdingAPI.Utility; | |||
using RobocraftX.Common; | |||
using Svelto.ECS; | |||
using GamecraftModdingAPI.Engines; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class BlockEventsEngine : IReactionaryEngine<DBEntityStruct> | |||
@@ -16,6 +18,7 @@ namespace GamecraftModdingAPI.Blocks | |||
} | |||
public EntitiesDB entitiesDB { get; set; } | |||
public void Dispose() | |||
{ | |||
} | |||
@@ -23,14 +26,21 @@ namespace GamecraftModdingAPI.Blocks | |||
public string Name { get; } = "GamecraftModdingAPIBlockEventsEngine"; | |||
public bool isRemovable { get; } = false; | |||
private bool shouldAddRemove; | |||
public void Add(ref DBEntityStruct entityComponent, EGID egid) | |||
{ | |||
ExceptionUtil.InvokeEvent(Placed, this, new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); | |||
if (!(shouldAddRemove = !shouldAddRemove)) | |||
return; | |||
ExceptionUtil.InvokeEvent(Placed, this, | |||
new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); | |||
} | |||
public void Remove(ref DBEntityStruct entityComponent, EGID egid) | |||
{ | |||
ExceptionUtil.InvokeEvent(Removed, this, new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); | |||
if (!(shouldAddRemove = !shouldAddRemove)) | |||
return; | |||
ExceptionUtil.InvokeEvent(Removed, this, | |||
new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); | |||
} | |||
} | |||
@@ -38,5 +48,8 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public EGID ID; | |||
public BlockIDs Type; | |||
private Block block; | |||
public Block Block => block ?? (block = new Block(ID)); | |||
} | |||
} |
@@ -40,4 +40,26 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
} | |||
} | |||
public class WiringException : BlockException | |||
{ | |||
public WiringException() | |||
{ | |||
} | |||
public WiringException(string message) : base(message) | |||
{ | |||
} | |||
} | |||
public class WireInvalidException : WiringException | |||
{ | |||
public WireInvalidException() | |||
{ | |||
} | |||
public WireInvalidException(string message) : base(message) | |||
{ | |||
} | |||
} | |||
} |
@@ -6,7 +6,7 @@ namespace GamecraftModdingAPI.Blocks | |||
public enum BlockIDs : ushort | |||
{ | |||
/// <summary> | |||
/// A custom value for the API. Doesn't exist for Gamecraft. | |||
/// Called "nothing" in Gamecraft. (DBID.NOTHING) | |||
/// </summary> | |||
Invalid = ushort.MaxValue, | |||
AluminiumCube = 0, | |||
@@ -192,6 +192,9 @@ namespace GamecraftModdingAPI.Blocks | |||
PlayerFilter, | |||
TeamFilter, | |||
Number2Text, //193 | |||
DestructionManager = 260, | |||
ChunkHealthModifier, | |||
ClusterHealthModifier, //262 | |||
BeachTree1 = 200, | |||
BeachTree2, | |||
BeachTree3, | |||
@@ -243,6 +246,8 @@ namespace GamecraftModdingAPI.Blocks | |||
AdvancedRotator, | |||
MusicBlock, //256 | |||
PlasmaCannonBlock, | |||
QuantumRiflePickup = 300, | |||
QuantumRifleAmmoPickup, | |||
MagmaRockCube=777, | |||
MagmaRockCubeSliced, | |||
MagmaRockSlope, | |||
@@ -12,8 +12,8 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
/// <summary> | |||
/// Blocks placed by the player | |||
/// </summary> | |||
public static ExclusiveGroup OWNED_BLOCKS { get { return CommonExclusiveGroups.OWNED_BLOCKS_GROUP; } } | |||
/// </summary> - TODO | |||
//public static ExclusiveGroup OWNED_BLOCKS { get { return CommonExclusiveGroups.REAL_BLOCKS_GROUPS_DON_T_USE_IN_NEW_CODE; } } | |||
/// <summary> | |||
/// Extra parts used in functional blocks | |||
@@ -23,7 +23,7 @@ namespace GamecraftModdingAPI.Blocks | |||
/// <summary> | |||
/// Blocks which are disabled in Simulation mode | |||
/// </summary> | |||
public static ExclusiveGroup SIM_BLOCKS_DISABLED { get { return CommonExclusiveGroups.BLOCKS_DISABLED_IN_SIM_GROUP; } } | |||
public static ExclusiveGroup SIM_BLOCKS_DISABLED { get { return CommonExclusiveGroups.DISABLED_JOINTS_IN_SIM_GROUP; } } | |||
//public static ExclusiveGroup SPAWN_POINTS { get { return CommonExclusiveGroups.SPAWN_POINTS_GROUP; } } | |||
@@ -34,7 +34,7 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public static uint LatestBlockID { | |||
get | |||
{ | |||
{ //Need the private field as the property increments itself | |||
return ((uint) AccessTools.Field(typeof(CommonExclusiveGroups), "_nextBlockEntityID").GetValue(null)) - 1; | |||
} | |||
} | |||
@@ -0,0 +1,124 @@ | |||
using System; | |||
using Gamecraft.Wires; | |||
using GamecraftModdingAPI; | |||
using GamecraftModdingAPI.Tests; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
#if TEST | |||
/// <summary> | |||
/// Block test cases. Not accessible in release versions. | |||
/// </summary> | |||
[APITestClass] | |||
public static class BlockTests | |||
{ | |||
[APITestCase(TestType.EditMode)] | |||
public static void TestPlaceNew() | |||
{ | |||
Block newBlock = Block.PlaceNew(BlockIDs.AluminiumCube, Unity.Mathematics.float3.zero); | |||
Assert.NotNull(newBlock.Id, "Newly placed block is missing Id. This should be populated when the block is placed.", "Newly placed block Id is not null, block successfully placed."); | |||
} | |||
[APITestCase(TestType.EditMode)] | |||
public static void TestInitProperty() | |||
{ | |||
Block newBlock = Block.PlaceNew(BlockIDs.AluminiumCube, Unity.Mathematics.float3.zero + 2); | |||
if (!Assert.CloseTo(newBlock.Position, (Unity.Mathematics.float3.zero + 2), $"Newly placed block at {newBlock.Position} is expected at {Unity.Mathematics.float3.zero + 2}.", "Newly placed block position matches.")) return; | |||
//Assert.Equal(newBlock.Exists, true, "Newly placed block does not exist, possibly because Sync() skipped/missed/failed.", "Newly placed block exists, Sync() successful."); | |||
} | |||
[APITestCase(TestType.EditMode)] | |||
public static void TestTextBlock() | |||
{ | |||
TextBlock textBlock = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler | |||
Assert.Errorless(() => { textBlock = Block.PlaceNew<TextBlock>(BlockIDs.TextBlock, Unity.Mathematics.float3.zero + 1); }, "Block.PlaceNew<TextBlock>() raised an exception: ", "Block.PlaceNew<TextBlock>() completed without issue."); | |||
if (!Assert.NotNull(textBlock, "Block.PlaceNew<TextBlock>() returned null, possibly because it failed silently.", "Specialized TextBlock is not null.")) return; | |||
if (!Assert.NotNull(textBlock.Text, "TextBlock.Text is null, possibly because it failed silently.", "TextBlock.Text is not null.")) return; | |||
if (!Assert.NotNull(textBlock.TextBlockId, "TextBlock.TextBlockId is null, possibly because it failed silently.", "TextBlock.TextBlockId is not null.")) return; | |||
} | |||
[APITestCase(TestType.EditMode)] | |||
public static void TestMotor() | |||
{ | |||
Block newBlock = Block.PlaceNew(BlockIDs.MotorS, Unity.Mathematics.float3.zero + 1); | |||
Motor b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler | |||
Assert.Errorless(() => { b = newBlock.Specialise<Motor>(); }, "Block.Specialize<Motor>() raised an exception: ", "Block.Specialize<Motor>() completed without issue."); | |||
if (!Assert.NotNull(b, "Block.Specialize<Motor>() returned null, possibly because it failed silently.", "Specialized Motor is not null.")) return; | |||
if (!Assert.CloseTo(b.Torque, 75f, $"Motor.Torque {b.Torque} does not equal default value, possibly because it failed silently.", "Motor.Torque close enough to default.")) return; | |||
if (!Assert.CloseTo(b.TopSpeed, 30f, $"Motor.TopSpeed {b.TopSpeed} does not equal default value, possibly because it failed silently.", "Motor.Torque is close enough to default.")) return; | |||
if (!Assert.Equal(b.Reverse, false, $"Motor.Reverse {b.Reverse} does not equal default value, possibly because it failed silently.", "Motor.Reverse is default.")) return; | |||
} | |||
[APITestCase(TestType.EditMode)] | |||
public static void TestPiston() | |||
{ | |||
Block newBlock = Block.PlaceNew(BlockIDs.PneumaticPiston, Unity.Mathematics.float3.zero + 1); | |||
Piston b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler | |||
Assert.Errorless(() => { b = newBlock.Specialise<Piston>(); }, "Block.Specialize<Piston>() raised an exception: ", "Block.Specialize<Piston>() completed without issue."); | |||
if (!Assert.NotNull(b, "Block.Specialize<Piston>() returned null, possibly because it failed silently.", "Specialized Piston is not null.")) return; | |||
if (!Assert.CloseTo(b.MaximumExtension, 1.01f, $"Piston.MaximumExtension {b.MaximumExtension} does not equal default value, possibly because it failed silently.", "Piston.MaximumExtension is close enough to default.")) return; | |||
if (!Assert.CloseTo(b.MaximumForce, 750f, $"Piston.MaximumForce {b.MaximumForce} does not equal default value, possibly because it failed silently.", "Piston.MaximumForce is close enough to default.")) return; | |||
} | |||
[APITestCase(TestType.EditMode)] | |||
public static void TestServo() | |||
{ | |||
Block newBlock = Block.PlaceNew(BlockIDs.ServoAxle, Unity.Mathematics.float3.zero + 1); | |||
Servo b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler | |||
Assert.Errorless(() => { b = newBlock.Specialise<Servo>(); }, "Block.Specialize<Servo>() raised an exception: ", "Block.Specialize<Servo>() completed without issue."); | |||
if (!Assert.NotNull(b, "Block.Specialize<Servo>() returned null, possibly because it failed silently.", "Specialized Servo is not null.")) return; | |||
if (!Assert.CloseTo(b.MaximumAngle, 180f, $"Servo.MaximumAngle {b.MaximumAngle} does not equal default value, possibly because it failed silently.", "Servo.MaximumAngle is close enough to default.")) return; | |||
if (!Assert.CloseTo(b.MinimumAngle, -180f, $"Servo.MinimumAngle {b.MinimumAngle} does not equal default value, possibly because it failed silently.", "Servo.MinimumAngle is close enough to default.")) return; | |||
if (!Assert.CloseTo(b.MaximumForce, 750f, $"Servo.MaximumForce {b.MaximumForce} does not equal default value, possibly because it failed silently.", "Servo.MaximumForce is close enough to default.")) return; | |||
} | |||
[APITestCase(TestType.Game)] | |||
public static void TestMusicBlock1() | |||
{ | |||
Block newBlock = Block.PlaceNew(BlockIDs.MusicBlock, Unity.Mathematics.float3.zero + 2); | |||
MusicBlock b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler | |||
Assert.Errorless(() => { b = newBlock.Specialise<MusicBlock>(); }, "Block.Specialize<MusicBlock>() raised an exception: ", "Block.Specialize<MusicBlock>() completed without issue."); | |||
if (!Assert.NotNull(b, "Block.Specialize<MusicBlock>() returned null, possibly because it failed silently.", "Specialized MusicBlock is not null.")) return; | |||
if (!Assert.CloseTo(b.Volume, 100f, $"MusicBlock.Volume {b.Volume} does not equal default value, possibly because it failed silently.", "MusicBlock.Volume is close enough to default.")) return; | |||
if (!Assert.Equal(b.TrackIndex, 0, $"MusicBlock.TrackIndex {b.TrackIndex} does not equal default value, possibly because it failed silently.", "MusicBlock.TrackIndex is equal to default.")) return; | |||
_musicBlock = b; | |||
} | |||
private static MusicBlock _musicBlock; | |||
[APITestCase(TestType.EditMode)] | |||
public static void TestMusicBlock2() | |||
{ | |||
//Block newBlock = Block.GetLastPlacedBlock(); | |||
var b = _musicBlock; | |||
if (!Assert.NotNull(b, "Block.Specialize<MusicBlock>() returned null, possibly because it failed silently.", "Specialized MusicBlock is not null.")) return; | |||
b.IsPlaying = true; // play sfx | |||
if (!Assert.Equal(b.IsPlaying, true, $"MusicBlock.IsPlaying {b.IsPlaying} does not equal true, possibly because it failed silently.", "MusicBlock.IsPlaying is set properly.")) return; | |||
if (!Assert.Equal(b.ChannelType, ChannelType.None, $"MusicBlock.ChannelType {b.ChannelType} does not equal default value, possibly because it failed silently.", "MusicBlock.ChannelType is equal to default.")) return; | |||
//Assert.Log(b.Track.ToString()); | |||
if (!Assert.Equal(b.Track.ToString(), new Guid("3237ff8f-f5f2-4f84-8144-496ca280f8c0").ToString(), $"MusicBlock.Track {b.Track} does not equal default value, possibly because it failed silently.", "MusicBlock.Track is equal to default.")) return; | |||
} | |||
[APITestCase(TestType.EditMode)] | |||
public static void TestLogicGate() | |||
{ | |||
Block newBlock = Block.PlaceNew(BlockIDs.NOTLogicBlock, Unity.Mathematics.float3.zero + 1); | |||
LogicGate b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler | |||
Assert.Errorless(() => { b = newBlock.Specialise<LogicGate>(); }, "Block.Specialize<LogicGate>() raised an exception: ", "Block.Specialize<LogicGate>() completed without issue."); | |||
if (!Assert.NotNull(b, "Block.Specialize<LogicGate>() returned null, possibly because it failed silently.", "Specialized LogicGate is not null.")) return; | |||
if (!Assert.Equal(b.InputCount, 1u, $"LogicGate.InputCount {b.InputCount} does not equal default value, possibly because it failed silently.", "LogicGate.InputCount is default.")) return; | |||
if (!Assert.Equal(b.OutputCount, 1u, $"LogicGate.OutputCount {b.OutputCount} does not equal default value, possibly because it failed silently.", "LogicGate.OutputCount is default.")) return; | |||
if (!Assert.NotNull(b, "Block.Specialize<LogicGate>() returned null, possibly because it failed silently.", "Specialized LogicGate is not null.")) return; | |||
//if (!Assert.Equal(b.PortName(0, true), "Input", $"LogicGate.PortName(0, input:true) {b.PortName(0, true)} does not equal default value, possibly because it failed silently.", "LogicGate.PortName(0, input:true) is close enough to default.")) return; | |||
LogicGate target = null; | |||
if (!Assert.Errorless(() => { target = Block.PlaceNew<LogicGate>(BlockIDs.ANDLogicBlock, Unity.Mathematics.float3.zero + 2); })) return; | |||
Wire newWire = null; | |||
if (!Assert.Errorless(() => { newWire = b.Connect(0, target, 0);})) return; | |||
if (!Assert.NotNull(newWire, "SignalingBlock.Connect(...) returned null, possible because it failed silently.", "SignalingBlock.Connect(...) returned a non-null value.")) return; | |||
} | |||
} | |||
#endif | |||
} |
@@ -1,6 +1,7 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using RobocraftX.Common; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
@@ -9,81 +10,66 @@ using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class ConsoleBlock : Block | |||
public class ConsoleBlock : SignalingBlock | |||
{ | |||
public static ConsoleBlock PlaceNew(float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
public ConsoleBlock(EGID id): base(id) | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(BlockIDs.ConsoleBlock, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
return new ConsoleBlock(id); | |||
} | |||
return null; | |||
} | |||
public ConsoleBlock(EGID id): base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<ConsoleBlockEntityStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public ConsoleBlock(uint id): base(id) | |||
public ConsoleBlock(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP)) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<ConsoleBlockEntityStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom console block properties | |||
/// <summary> | |||
/// Setting a nonexistent command will crash the game when switching to simulation | |||
/// </summary> | |||
public string Command | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).commandName; | |||
return BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.commandName); | |||
} | |||
set | |||
{ | |||
BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).commandName.Set(value); | |||
BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.commandName.Set(val), | |||
value); | |||
} | |||
} | |||
public string Arg1 | |||
{ | |||
get => BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg1; | |||
get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg1); | |||
set | |||
{ | |||
BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg1.Set(value); | |||
BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg1.Set(val), | |||
value); | |||
} | |||
} | |||
public string Arg2 | |||
{ | |||
get => BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg2; | |||
get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg2); | |||
set | |||
{ | |||
BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg2.Set(value); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg2.Set(val), | |||
value); | |||
} | |||
} | |||
public string Arg3 | |||
{ | |||
get => BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg3; | |||
get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg3); | |||
set | |||
{ | |||
BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg3.Set(value); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg3.Set(val), | |||
value); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
using RobocraftX.Common; | |||
using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class LogicGate : SignalingBlock | |||
{ | |||
public LogicGate(EGID id) : base(id) | |||
{ | |||
} | |||
public LogicGate(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_LOGIC_BLOCK_GROUP)) | |||
{ | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using RobocraftX.Common; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
@@ -8,45 +9,14 @@ using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Motor : Block | |||
public class Motor : SignalingBlock | |||
{ | |||
/// <summary> | |||
/// Places a new motor. | |||
/// Any valid motor type is accepted. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new Motor PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (!(block == BlockIDs.MotorS || block == BlockIDs.MotorM)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {typeof(Motor).Name} block"); | |||
} | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
return new Motor(id); | |||
} | |||
return null; | |||
} | |||
public Motor(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<MotorReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public Motor(uint id) : base(id) | |||
public Motor(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP)) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<MotorReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom motor properties | |||
@@ -58,13 +28,12 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).maxVelocity; | |||
return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.maxVelocity); | |||
} | |||
set | |||
{ | |||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id); | |||
motor.maxVelocity = value; | |||
BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, float val) => st.maxVelocity = val, value); | |||
} | |||
} | |||
@@ -75,13 +44,12 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).maxForce; | |||
return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.maxForce); | |||
} | |||
set | |||
{ | |||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id); | |||
motor.maxForce = value; | |||
BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, float val) => st.maxForce = val, value); | |||
} | |||
} | |||
@@ -92,13 +60,12 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).reverse; | |||
return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.reverse); | |||
} | |||
set | |||
{ | |||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id); | |||
motor.reverse = value; | |||
BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, bool val) => st.reverse = val, value); | |||
} | |||
} | |||
} | |||
@@ -35,12 +35,21 @@ namespace GamecraftModdingAPI.Blocks | |||
// implementations for Movement static class | |||
public float3 MoveBlock(uint blockID, float3 vector) | |||
internal float3 MoveBlock(EGID blockID, BlockEngine.BlockInitData data, float3 vector) | |||
{ | |||
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity<GridRotationStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity<LocalTransformEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity<UECSPhysicsEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
if (!entitiesDB.Exists<PositionEntityStruct>(blockID)) | |||
{ | |||
if (data.Group == null) return float3.zero; | |||
var init = new EntityComponentInitializer(blockID, data.Group); | |||
init.Init(new PositionEntityStruct {position = vector}); | |||
init.Init(new GridRotationStruct {position = vector}); | |||
init.Init(new LocalTransformEntityStruct {position = vector}); | |||
return vector; | |||
} | |||
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID); | |||
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity<GridRotationStruct>(blockID); | |||
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity<LocalTransformEntityStruct>(blockID); | |||
ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity<UECSPhysicsEntityStruct>(blockID); | |||
// main (persistent) position | |||
posStruct.position = vector; | |||
// placement grid position | |||
@@ -52,13 +61,19 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
Value = posStruct.position | |||
}); | |||
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; | |||
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(blockID).isProcessed = false; | |||
return posStruct.position; | |||
} | |||
public float3 GetPosition(uint blockID) | |||
internal float3 GetPosition(EGID blockID, BlockEngine.BlockInitData data) | |||
{ | |||
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
if (!entitiesDB.Exists<PositionEntityStruct>(blockID)) | |||
{ | |||
if (data.Group == null) return float3.zero; | |||
var init = new EntityComponentInitializer(blockID, data.Group); | |||
return init.Has<PositionEntityStruct>() ? init.Get<PositionEntityStruct>().position : float3.zero; | |||
} | |||
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID); | |||
return posStruct.position; | |||
} | |||
} | |||
@@ -0,0 +1,146 @@ | |||
using System; | |||
using FMOD.Studio; | |||
using FMODUnity; | |||
using Gamecraft.Wires; | |||
using RobocraftX.Common; | |||
using RobocraftX.Blocks; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI; | |||
using GamecraftModdingAPI.Tests; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class MusicBlock : SignalingBlock | |||
{ | |||
public MusicBlock(EGID id) : base(id) | |||
{ | |||
} | |||
public MusicBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP)) | |||
{ | |||
} | |||
public byte TrackIndex | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, (MusicBlockDataEntityStruct st) => st.trackIndx); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref MusicBlockDataEntityStruct msdes, byte val) => msdes.trackIndx = val, value); | |||
} | |||
} | |||
public Guid Track | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, | |||
(MusicBlockDataEntityStruct msdes) => msdes.fmod2DEventPaths.Get<Guid>(msdes.trackIndx)); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref MusicBlockDataEntityStruct msdes, Guid val) => | |||
{ | |||
for (byte i = 0; i < msdes.fmod2DEventPaths.Count<Guid>(); i++) | |||
{ | |||
Guid track = msdes.fmod2DEventPaths.Get<Guid>(i); | |||
if (track == val) | |||
{ | |||
msdes.trackIndx = i; | |||
break; | |||
} | |||
} | |||
}, value); | |||
} | |||
} | |||
public Guid[] Tracks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, (MusicBlockDataEntityStruct msdes) => | |||
{ | |||
Guid[] tracks = new Guid[msdes.fmod2DEventPaths.Count<Guid>()]; | |||
for (byte i = 0; i < tracks.Length; i++) | |||
{ | |||
tracks[i] = msdes.fmod2DEventPaths.Get<Guid>(i); | |||
} | |||
return tracks; | |||
}); | |||
} | |||
} | |||
public float Volume | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, (MusicBlockDataEntityStruct msdes) => msdes.tweakableVolume); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref MusicBlockDataEntityStruct msdes, float val) => msdes.tweakableVolume = val, value); | |||
} | |||
} | |||
public ChannelType ChannelType | |||
{ | |||
get | |||
{ | |||
Assert.Log("Block exists: " + Exists); | |||
return BlockEngine.GetBlockInfo(this, | |||
(MusicBlockDataEntityStruct msdes) => (ChannelType) msdes.channelType); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref MusicBlockDataEntityStruct msdes, ChannelType val) => msdes.channelType = (byte) val, value); | |||
} | |||
} | |||
public bool IsPlaying | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, | |||
(MusicBlockDataEntityStruct msdes) => msdes.isPlaying); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref MusicBlockDataEntityStruct msdes, bool val) => | |||
{ | |||
if (msdes.isPlaying == val) return; | |||
if (val) | |||
{ | |||
// start playing | |||
EventInstance inst = RuntimeManager.CreateInstance(msdes.fmod2DEventPaths.Get<Guid>(msdes.trackIndx)); | |||
inst.setVolume(msdes.tweakableVolume / 100f); | |||
inst.start(); | |||
msdes.eventHandle = inst.handle; | |||
} | |||
else | |||
{ | |||
// stop playing | |||
EventInstance inst = default(EventInstance); | |||
inst.handle = msdes.eventHandle; | |||
inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); | |||
inst.release(); | |||
} | |||
msdes.isPlaying = val; | |||
}, value); | |||
} | |||
} | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
using Gamecraft.Wires; | |||
using RobocraftX.Common; | |||
using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Blocks | |||
@@ -7,27 +8,22 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public ObjectIdentifier(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<ObjectIdEntityStruct>(Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {GetType().Name} block"); | |||
} | |||
} | |||
public ObjectIdentifier(uint id) : base(id) | |||
public ObjectIdentifier(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<ObjectIdEntityStruct>(Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {GetType().Name} block"); | |||
} | |||
} | |||
public char Identifier | |||
{ | |||
get => (char) (BlockEngine.GetBlockInfo<ObjectIdEntityStruct>(Id).objectId + 'A'); | |||
get => (char) BlockEngine.GetBlockInfo(this, (ObjectIdEntityStruct st) => st.objectId + 'A'); | |||
set | |||
{ | |||
BlockEngine.GetBlockInfo<ObjectIdEntityStruct>(Id).objectId = (byte) (value - 'A'); | |||
Label = value + ""; //The label isn't updated automatically | |||
BlockEngine.SetBlockInfo(this, (ref ObjectIdEntityStruct st, char val) => | |||
{ | |||
st.objectId = (byte) (val - 'A'); | |||
Label = val + ""; //The label isn't updated automatically | |||
}, value); | |||
} | |||
} | |||
@@ -36,7 +32,7 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public byte SimID | |||
{ | |||
get => BlockEngine.GetBlockInfo<ObjectIdEntityStruct>(Id).simObjectId; | |||
get => BlockEngine.GetBlockInfo(this, (ObjectIdEntityStruct st) => st.simObjectId); | |||
} | |||
/// <summary> | |||
@@ -5,48 +5,18 @@ using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI.Utility; | |||
using RobocraftX.Common; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Piston : Block | |||
public class Piston : SignalingBlock | |||
{ | |||
/// <summary> | |||
/// Places a new piston. | |||
/// Any valid piston type is accepted. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new Piston PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (!(block == BlockIDs.ServoPiston || block == BlockIDs.StepperPiston || block == BlockIDs.PneumaticPiston)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {typeof(Piston).Name} block"); | |||
} | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
return new Piston(id); | |||
} | |||
return null; | |||
} | |||
public Piston(EGID id) : base(id) | |||
public Piston(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<PistonReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public Piston(uint id) : base(id) | |||
public Piston(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP)) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<PistonReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom piston properties | |||
@@ -55,13 +25,13 @@ namespace GamecraftModdingAPI.Blocks | |||
/// The piston's max extension distance. | |||
/// </summary> | |||
public float MaximumExtension | |||
{ | |||
get => BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id).maxDeviation; | |||
{ | |||
get => BlockEngine.GetBlockInfo(this, (PistonReadOnlyStruct st) => st.maxDeviation); | |||
set | |||
{ | |||
ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id); | |||
piston.maxDeviation = value; | |||
BlockEngine.SetBlockInfo(this, (ref PistonReadOnlyStruct st, float val) => st.maxDeviation = val, | |||
value); | |||
} | |||
} | |||
@@ -69,13 +39,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// The piston's max extension force. | |||
/// </summary> | |||
public float MaximumForce | |||
{ | |||
get => BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id).maxForce; | |||
{ | |||
get => BlockEngine.GetBlockInfo(this, (PistonReadOnlyStruct st) => st.maxForce); | |||
set | |||
{ | |||
ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id); | |||
piston.maxForce = value; | |||
BlockEngine.SetBlockInfo(this, (ref PistonReadOnlyStruct st, float val) => st.maxForce = val, value); | |||
} | |||
} | |||
} | |||
@@ -40,15 +40,16 @@ namespace GamecraftModdingAPI.Blocks | |||
private static BlockEntityFactory _blockEntityFactory; //Injected from PlaceBlockEngine | |||
public EGID PlaceBlock(BlockIDs block, BlockColors color, byte darkness, float3 position, int uscale, | |||
float3 scale, Player player, float3 rotation) | |||
float3 scale, Player player, float3 rotation, out EntityComponentInitializer initializer) | |||
{ //It appears that only the non-uniform scale has any visible effect, but if that's not given here it will be set to the uniform one | |||
if (darkness > 9) | |||
throw new Exception("That is too dark. Make sure to use 0-9 as darkness. (0 is default.)"); | |||
return BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation, | |||
initializer = BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation, | |||
(player ?? new Player(PlayerType.Local)).Id); | |||
return initializer.EGID; | |||
} | |||
private EGID BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId) | |||
private EntityComponentInitializer BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId) | |||
{ | |||
if (_blockEntityFactory == null) | |||
throw new Exception("The factory is null."); | |||
@@ -66,8 +67,6 @@ namespace GamecraftModdingAPI.Blocks | |||
RotationEntityStruct rotation = new RotationEntityStruct {rotation = rotQ}; | |||
GridRotationStruct gridRotation = new GridRotationStruct | |||
{position = position, rotation = rotQ}; | |||
CubeCategoryStruct category = new CubeCategoryStruct | |||
{category = CubeCategory.General, type = CubeType.Block}; | |||
DBEntityStruct dbEntity = new DBEntityStruct {DBID = dbid}; | |||
BlockPlacementScaleEntityStruct placementScale = new BlockPlacementScaleEntityStruct | |||
{ | |||
@@ -76,21 +75,10 @@ namespace GamecraftModdingAPI.Blocks | |||
unitSnapOffset = 0, isUsingUnitSize = true | |||
}; | |||
EquippedColourStruct colour = new EquippedColourStruct {indexInPalette = color}; | |||
EGID newBlockID; | |||
switch (category.category) | |||
{ | |||
case CubeCategory.SpawnPoint: | |||
case CubeCategory.BuildingSpawnPoint: | |||
newBlockID = MachineEditingGroups.NewUncheckedBlockEGID; | |||
break; | |||
default: | |||
newBlockID = MachineEditingGroups.NewBlockID; | |||
break; | |||
} | |||
EntityComponentInitializer | |||
structInitializer = | |||
_blockEntityFactory.Build(newBlockID, dbid); //The ghost block index is only used for triggers | |||
_blockEntityFactory.Build(CommonExclusiveGroups.nextBlockEntityID, dbid); //The ghost block index is only used for triggers | |||
if (colour.indexInPalette != byte.MaxValue) | |||
structInitializer.Init(new ColourParameterEntityStruct | |||
{ | |||
@@ -117,10 +105,9 @@ namespace GamecraftModdingAPI.Blocks | |||
PrimaryRotationUtility.InitialisePrimaryDirection(rotation.rotation, ref structInitializer); | |||
EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup); | |||
ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity<PickedBlockExtraDataStruct>(playerEGID); | |||
pickedBlock.placedBlockEntityID = playerEGID; | |||
pickedBlock.placedBlockEntityID = structInitializer.EGID; | |||
pickedBlock.placedBlockWasAPickedBlock = false; | |||
Block.BlockEngine.Synced = false; // Block entities will need to be submitted before properties can be used | |||
return newBlockID; | |||
return structInitializer; | |||
} | |||
public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine"; | |||
@@ -35,37 +35,55 @@ namespace GamecraftModdingAPI.Blocks | |||
// implementations for Rotation static class | |||
public float3 RotateBlock(uint blockID, Vector3 vector) | |||
internal float3 RotateBlock(EGID blockID, BlockEngine.BlockInitData data, Vector3 vector) | |||
{ | |||
ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntity<RotationEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity<GridRotationStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity<LocalTransformEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity<UECSPhysicsEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
if (!entitiesDB.Exists<RotationEntityStruct>(blockID)) | |||
{ | |||
if (data.Group == null) return float3.zero; | |||
var init = new EntityComponentInitializer(blockID, data.Group); | |||
init.Init(new RotationEntityStruct {rotation = new Quaternion {eulerAngles = vector}}); | |||
init.Init(new GridRotationStruct {rotation = new Quaternion {eulerAngles = vector}}); | |||
init.Init(new LocalTransformEntityStruct {rotation = new Quaternion {eulerAngles = vector}}); | |||
return vector; | |||
} | |||
ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntity<RotationEntityStruct>(blockID); | |||
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity<GridRotationStruct>(blockID); | |||
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity<LocalTransformEntityStruct>(blockID); | |||
ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity<UECSPhysicsEntityStruct>(blockID); | |||
// main (persistent) position | |||
Quaternion newRotation = (Quaternion)rotStruct.rotation; | |||
newRotation.eulerAngles += vector; | |||
rotStruct.rotation = (quaternion)newRotation; | |||
Quaternion newRotation = rotStruct.rotation; | |||
newRotation.eulerAngles = vector; | |||
rotStruct.rotation = newRotation; | |||
// placement grid rotation | |||
Quaternion newGridRotation = (Quaternion)gridStruct.rotation; | |||
newGridRotation.eulerAngles += vector; | |||
gridStruct.rotation = (quaternion)newGridRotation; | |||
Quaternion newGridRotation = gridStruct.rotation; | |||
newGridRotation.eulerAngles = vector; | |||
gridStruct.rotation = newGridRotation; | |||
// rendered position | |||
Quaternion newTransRotation = (Quaternion)rotStruct.rotation; | |||
newTransRotation.eulerAngles += vector; | |||
Quaternion newTransRotation = rotStruct.rotation; | |||
newTransRotation.eulerAngles = vector; | |||
transStruct.rotation = newTransRotation; | |||
// collision position | |||
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, new Unity.Transforms.Rotation | |||
{ | |||
Value = rotStruct.rotation | |||
}); | |||
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; | |||
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(blockID).isProcessed = false; | |||
return ((Quaternion)rotStruct.rotation).eulerAngles; | |||
} | |||
public float3 GetRotation(uint blockID) | |||
internal float3 GetRotation(EGID blockID, BlockEngine.BlockInitData data) | |||
{ | |||
ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntity<RotationEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
if (!entitiesDB.Exists<RotationEntityStruct>(blockID)) | |||
{ | |||
if (data.Group == null) return float3.zero; | |||
var init = new EntityComponentInitializer(blockID, data.Group); | |||
return init.Has<RotationEntityStruct>() | |||
? (float3) ((Quaternion) init.Get<RotationEntityStruct>().rotation).eulerAngles | |||
: float3.zero; | |||
} | |||
ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntity<RotationEntityStruct>(blockID); | |||
return ((Quaternion) rotStruct.rotation).eulerAngles; | |||
} | |||
} | |||
@@ -1,6 +1,7 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using RobocraftX.Common; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
@@ -8,45 +9,14 @@ using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Servo : Block | |||
public class Servo : SignalingBlock | |||
{ | |||
/// <summary> | |||
/// Places a new servo. | |||
/// Any valid servo type is accepted. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new Servo PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (!(block == BlockIDs.ServoAxle || block == BlockIDs.ServoHinge || block == BlockIDs.ServoPiston)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {nameof(Servo)} block"); | |||
} | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
return new Servo(id); | |||
} | |||
return null; | |||
} | |||
public Servo(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<ServoReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public Servo(uint id) : base(id) | |||
public Servo(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP)) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<ServoReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom servo properties | |||
@@ -55,13 +25,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// The servo's minimum angle. | |||
/// </summary> | |||
public float MinimumAngle | |||
{ | |||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).minDeviation; | |||
{ | |||
get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.minDeviation); | |||
set | |||
{ | |||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id); | |||
servo.minDeviation = value; | |||
BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.minDeviation = val, value); | |||
} | |||
} | |||
@@ -70,13 +39,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public float MaximumAngle | |||
{ | |||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).maxDeviation; | |||
get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.maxDeviation); | |||
set | |||
{ | |||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id); | |||
servo.maxDeviation = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.maxDeviation = val, value); | |||
} | |||
} | |||
/// <summary> | |||
@@ -84,13 +52,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public float MaximumForce | |||
{ | |||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).maxForce; | |||
get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.maxForce); | |||
set | |||
{ | |||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id); | |||
servo.maxForce = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.maxForce = val, value); | |||
} | |||
} | |||
/// <summary> | |||
@@ -98,13 +65,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public bool Reverse | |||
{ | |||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).reverse; | |||
get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.reverse); | |||
set | |||
{ | |||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id); | |||
servo.reverse = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, bool val) => st.reverse = val, value); | |||
} | |||
} | |||
} | |||
} |
@@ -1,4 +1,6 @@ | |||
using Svelto.ECS; | |||
using System; | |||
using Svelto.ECS; | |||
using Svelto.DataStructures; | |||
using Gamecraft.Wires; | |||
using GamecraftModdingAPI.Engines; | |||
@@ -8,7 +10,7 @@ namespace GamecraftModdingAPI.Blocks | |||
/// <summary> | |||
/// Engine which executes signal actions | |||
/// </summary> | |||
public class SignalEngine : IApiEngine | |||
public class SignalEngine : IApiEngine, IFactoryEngine | |||
{ | |||
public const float POSITIVE_HIGH = 1.0f; | |||
public const float NEGATIVE_HIGH = -1.0f; | |||
@@ -19,6 +21,8 @@ namespace GamecraftModdingAPI.Blocks | |||
public EntitiesDB entitiesDB { set; private get; } | |||
public IEntityFactory Factory { get; set; } | |||
public bool isRemovable => false; | |||
public bool IsInGame = false; | |||
@@ -33,7 +37,74 @@ namespace GamecraftModdingAPI.Blocks | |||
IsInGame = true; | |||
} | |||
// implementations for Signal static class | |||
// implementations for block wiring | |||
public WireEntityStruct CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort) | |||
{ | |||
EGID wireEGID = new EGID(WiresExclusiveGroups.NewWireEntityId, NamedExclusiveGroup<WiresGroup>.Group); | |||
EntityComponentInitializer wireInitializer = Factory.BuildEntity<WireEntityDescriptor>(wireEGID); | |||
wireInitializer.Init(new WireEntityStruct | |||
{ | |||
sourceBlockEGID = startBlock, | |||
sourcePortUsage = startPort, | |||
destinationBlockEGID = endBlock, | |||
destinationPortUsage = endPort, | |||
ID = wireEGID | |||
}); | |||
return wireInitializer.Get<WireEntityStruct>(); | |||
} | |||
public ref WireEntityStruct GetWire(EGID wire) | |||
{ | |||
if (!entitiesDB.Exists<WireEntityStruct>(wire)) | |||
{ | |||
throw new WiringException($"Wire {wire} does not exist"); | |||
} | |||
return ref entitiesDB.QueryEntity<WireEntityStruct>(wire); | |||
} | |||
public ref PortEntityStruct GetPort(EGID port) | |||
{ | |||
if (!entitiesDB.Exists<PortEntityStruct>(port)) | |||
{ | |||
throw new WiringException($"Port {port} does not exist (yet?)"); | |||
} | |||
return ref entitiesDB.QueryEntity<PortEntityStruct>(port); | |||
} | |||
public ref PortEntityStruct GetPortByOffset(BlockPortsStruct bps, byte portNumber, bool input) | |||
{ | |||
ExclusiveGroup group = input | |||
? NamedExclusiveGroup<InputPortsGroup>.Group | |||
: NamedExclusiveGroup<OutputPortsGroup>.Group; | |||
uint id = (input ? bps.firstInputID : bps.firstOutputID) + portNumber; | |||
EGID egid = new EGID(id, group); | |||
if (!entitiesDB.Exists<PortEntityStruct>(egid)) | |||
{ | |||
throw new WiringException("Port does not exist"); | |||
} | |||
return ref entitiesDB.QueryEntity<PortEntityStruct>(egid); | |||
} | |||
public ref PortEntityStruct GetPortByOffset(Block block, byte portNumber, bool input) | |||
{ | |||
BlockPortsStruct bps = GetFromDbOrInitData<BlockPortsStruct>(block, block.Id, out bool exists); | |||
if (!exists) | |||
{ | |||
throw new BlockException("Block does not exist"); | |||
} | |||
return ref GetPortByOffset(bps, portNumber, input); | |||
} | |||
public ref T GetComponent<T>(EGID egid) where T : unmanaged, IEntityComponent | |||
{ | |||
return ref entitiesDB.QueryEntity<T>(egid); | |||
} | |||
public bool Exists<T>(EGID egid) where T : struct, IEntityComponent | |||
{ | |||
return entitiesDB.Exists<T>(egid); | |||
} | |||
public bool SetSignal(EGID blockID, float signal, out uint signalID, bool input = true) | |||
{ | |||
@@ -122,7 +193,7 @@ namespace GamecraftModdingAPI.Blocks | |||
return inputs; | |||
} | |||
public EGID[] GetSignalOutputs(EGID blockID) | |||
public EGID[] GetSignalOutputs(EGID blockID) | |||
{ | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID); | |||
EGID[] outputs = new EGID[ports.outputCount]; | |||
@@ -133,6 +204,42 @@ namespace GamecraftModdingAPI.Blocks | |||
return outputs; | |||
} | |||
public EGID MatchBlockInputToPort(Block block, byte portUsage, out bool exists) | |||
{ | |||
BlockPortsStruct ports = GetFromDbOrInitData<BlockPortsStruct>(block, block.Id, out exists); | |||
return new EGID(ports.firstInputID + portUsage, NamedExclusiveGroup<InputPortsGroup>.Group); | |||
} | |||
public EGID MatchBlockInputToPort(EGID block, byte portUsage, out bool exists) | |||
{ | |||
if (!entitiesDB.Exists<BlockPortsStruct>(block)) | |||
{ | |||
exists = false; | |||
return default; | |||
} | |||
exists = true; | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(block); | |||
return new EGID(ports.firstInputID + portUsage, NamedExclusiveGroup<InputPortsGroup>.Group); | |||
} | |||
public EGID MatchBlockOutputToPort(Block block, byte portUsage, out bool exists) | |||
{ | |||
BlockPortsStruct ports = GetFromDbOrInitData<BlockPortsStruct>(block, block.Id, out exists); | |||
return new EGID(ports.firstOutputID + portUsage, NamedExclusiveGroup<OutputPortsGroup>.Group); | |||
} | |||
public EGID MatchBlockOutputToPort(EGID block, byte portUsage, out bool exists) | |||
{ | |||
if (!entitiesDB.Exists<BlockPortsStruct>(block)) | |||
{ | |||
exists = false; | |||
return default; | |||
} | |||
exists = true; | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(block); | |||
return new EGID(ports.firstOutputID + portUsage, NamedExclusiveGroup<OutputPortsGroup>.Group); | |||
} | |||
public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists) | |||
{ | |||
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID); | |||
@@ -151,6 +258,57 @@ namespace GamecraftModdingAPI.Blocks | |||
return ref defRef[0]; | |||
} | |||
public ref WireEntityStruct MatchBlocksToWire(EGID startBlock, EGID endBlock, out bool exists, byte startPort = byte.MaxValue, | |||
byte endPort = byte.MaxValue) | |||
{ | |||
EGID[] startPorts; | |||
if (startPort == byte.MaxValue) | |||
{ | |||
// search all output ports on source block | |||
startPorts = GetSignalOutputs(startBlock); | |||
} | |||
else | |||
{ | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(startBlock); | |||
startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup<OutputPortsGroup>.Group) }; | |||
} | |||
EGID[] endPorts; | |||
if (startPort == byte.MaxValue) | |||
{ | |||
// search all input ports on destination block | |||
endPorts = GetSignalInputs(endBlock); | |||
} | |||
else | |||
{ | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(endBlock); | |||
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<InputPortsGroup>.Group) }; | |||
} | |||
EntityCollection<WireEntityStruct> wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group); | |||
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++) | |||
{ | |||
PortEntityStruct endPES = entitiesDB.QueryEntity<PortEntityStruct>(endPorts[endIndex]); | |||
for (int startIndex = 0; startIndex < startPorts.Length; startIndex++) | |||
{ | |||
PortEntityStruct startPES = entitiesDB.QueryEntity<PortEntityStruct>(startPorts[startIndex]); | |||
for (int w = 0; w < wires.count; w++) | |||
{ | |||
if ((wires[w].destinationPortUsage == endPES.usage && wires[w].destinationBlockEGID == endBlock) | |||
&& (wires[w].sourcePortUsage == startPES.usage && wires[w].sourceBlockEGID == startBlock)) | |||
{ | |||
exists = true; | |||
return ref wires[w]; | |||
} | |||
} | |||
} | |||
} | |||
exists = false; | |||
WireEntityStruct[] defRef = new WireEntityStruct[1]; | |||
return ref defRef[0]; | |||
} | |||
public ref ChannelDataStruct GetChannelDataStruct(EGID portID, out bool exists) | |||
{ | |||
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID); | |||
@@ -166,21 +324,75 @@ namespace GamecraftModdingAPI.Blocks | |||
} | |||
public EGID[] GetElectricBlocks() | |||
{ | |||
uint count = entitiesDB.Count<BlockPortsStruct>(BlockIdentifiers.OWNED_BLOCKS) + entitiesDB.Count<BlockPortsStruct>(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); | |||
uint i = 0; | |||
EGID[] res = new EGID[count]; | |||
foreach (ref BlockPortsStruct s in entitiesDB.QueryEntities<BlockPortsStruct>(BlockIdentifiers.OWNED_BLOCKS)) | |||
{ | |||
res[i] = s.ID; | |||
i++; | |||
} | |||
foreach (ref BlockPortsStruct s in entitiesDB.QueryEntities<BlockPortsStruct>(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS)) | |||
{ | |||
res[i] = s.ID; | |||
i++; | |||
} | |||
return res; | |||
{ | |||
var res = new FasterList<EGID>(); | |||
foreach (var (coll, _) in entitiesDB.QueryEntities<BlockPortsStruct>()) | |||
foreach (ref BlockPortsStruct s in coll) | |||
res.Add(s.ID); | |||
return res.ToArray(); | |||
} | |||
public EGID[] WiredToInput(EGID block, byte port) | |||
{ | |||
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<WiresGroup>.Group, | |||
(WireEntityStruct wes) => wes.destinationPortUsage == port && wes.destinationBlockEGID == block); | |||
EGID[] result = new EGID[wireEntityStructs.Length]; | |||
for (uint i = 0; i < wireEntityStructs.Length; i++) | |||
{ | |||
result[i] = wireEntityStructs[i].ID; | |||
} | |||
return result; | |||
} | |||
public EGID[] WiredToOutput(EGID block, byte port) | |||
{ | |||
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<WiresGroup>.Group, | |||
(WireEntityStruct wes) => wes.sourcePortUsage == port && wes.sourceBlockEGID == block); | |||
EGID[] result = new EGID[wireEntityStructs.Length]; | |||
for (uint i = 0; i < wireEntityStructs.Length; i++) | |||
{ | |||
result[i] = wireEntityStructs[i].ID; | |||
} | |||
return result; | |||
} | |||
private T[] Search<T>(ExclusiveGroup group, Func<T, bool> isMatch) where T : struct, IEntityComponent | |||
{ | |||
FasterList<T> results = new FasterList<T>(); | |||
EntityCollection<T> components = entitiesDB.QueryEntities<T>(group); | |||
for (uint i = 0; i < components.count; i++) | |||
{ | |||
if (isMatch(components[i])) | |||
{ | |||
results.Add(components[i]); | |||
} | |||
} | |||
return results.ToArray(); | |||
} | |||
private ref T GetFromDbOrInitData<T>(Block block, EGID id, out bool exists) where T : unmanaged, IEntityComponent | |||
{ | |||
T[] defRef = new T[1]; | |||
if (entitiesDB.Exists<T>(id)) | |||
{ | |||
exists = true; | |||
return ref entitiesDB.QueryEntity<T>(id); | |||
} | |||
if (block == null || block.InitData.Group == null) | |||
{ | |||
exists = false; | |||
return ref defRef[0]; | |||
} | |||
EntityComponentInitializer initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); | |||
if (initializer.Has<T>()) | |||
{ | |||
exists = true; | |||
return ref initializer.Get<T>(); | |||
} | |||
exists = false; | |||
return ref defRef[0]; | |||
} | |||
private EntityCollection<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true) | |||
@@ -14,44 +14,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public class SignalingBlock : Block | |||
{ | |||
/// <summary> | |||
/// Places a new signaling block. | |||
/// Any valid functional block type with IO ports will work. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new SignalingBlock PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
return new SignalingBlock(id); | |||
} | |||
return null; | |||
} | |||
public SignalingBlock(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<BlockPortsStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public SignalingBlock(uint id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<BlockPortsStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
protected ref BlockPortsStruct GetBlockPortsStruct() | |||
{ | |||
return ref BlockEngine.GetBlockInfo<BlockPortsStruct>(Id); | |||
} | |||
/// <summary> | |||
@@ -72,16 +40,6 @@ namespace GamecraftModdingAPI.Blocks | |||
return SignalEngine.GetSignalOutputs(Id); | |||
} | |||
/// <summary> | |||
/// Gets the port struct. | |||
/// </summary> | |||
/// <returns>The port struct.</returns> | |||
/// <param name="portId">Port identifier.</param> | |||
protected ref PortEntityStruct GetPortStruct(EGID portId) | |||
{ | |||
return ref BlockEngine.GetBlockInfo<PortEntityStruct>(portId); | |||
} | |||
/// <summary> | |||
/// Gets the connected wire. | |||
/// </summary> | |||
@@ -108,16 +66,102 @@ namespace GamecraftModdingAPI.Blocks | |||
/// The input port count. | |||
/// </summary> | |||
public uint InputCount | |||
{ | |||
get => GetBlockPortsStruct().inputCount; | |||
} | |||
{ | |||
get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.inputCount); | |||
} | |||
/// <summary> | |||
/// The output port count. | |||
/// </summary> | |||
public uint OutputCount | |||
{ | |||
get => GetBlockPortsStruct().outputCount; | |||
get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.outputCount); | |||
} | |||
/// <summary> | |||
/// Connect an output on this block to an input on another block. | |||
/// </summary> | |||
/// <param name="sourcePort">Output port number.</param> | |||
/// <param name="destination">Input block.</param> | |||
/// <param name="destinationPort">Input port number.</param> | |||
/// <returns>The wire connection</returns> | |||
/// <exception cref="WiringException">The wire could not be created.</exception> | |||
public Wire Connect(byte sourcePort, SignalingBlock destination, byte destinationPort) | |||
{ | |||
if (sourcePort >= OutputCount) | |||
{ | |||
throw new WiringException("Source port does not exist"); | |||
} | |||
if (destinationPort >= destination.InputCount) | |||
{ | |||
throw new WiringException("Destination port does not exist"); | |||
} | |||
return Wire.Connect(this, sourcePort, destination, destinationPort); | |||
} | |||
/// <summary> | |||
/// The port's name. | |||
/// This is localized to the user's language, so this is not reliable for port identification. | |||
/// </summary> | |||
/// <param name="port">Port number.</param> | |||
/// <param name="input">Whether the port is an input (true) or an output (false).</param> | |||
/// <returns>The localized port name.</returns> | |||
public string PortName(byte port, bool input) | |||
{ | |||
BlockPortsStruct bps = BlockEngine.GetBlockInfo(this, (BlockPortsStruct a) => a); | |||
PortEntityStruct pes = SignalEngine.GetPortByOffset(this, port, input); | |||
return pes.portNameLocalised; | |||
} | |||
/// <summary> | |||
/// The input port's name. | |||
/// </summary> | |||
/// <param name="port">Input port number.</param> | |||
/// <returns>The port name, localized to the user's language.</returns> | |||
public string InputPortName(byte port) => PortName(port, true); | |||
/// <summary> | |||
/// The output port's name. | |||
/// </summary> | |||
/// <param name="port">Output port number.</param> | |||
/// <returns>The port name, localized to the user's language.</returns> | |||
public string OutputPortName(byte port) => PortName(port, false); | |||
/// <summary> | |||
/// All wires connected to the input port. | |||
/// These wires will always be wired output -> input. | |||
/// </summary> | |||
/// <param name="port">Port number.</param> | |||
/// <returns>Wires connected to the input port.</returns> | |||
public Wire[] ConnectedToInput(byte port) | |||
{ | |||
if (port >= InputCount) throw new WiringException($"Port input {port} does not exist"); | |||
EGID[] wireEgids = SignalEngine.WiredToInput(Id, port); | |||
Wire[] wires = new Wire[wireEgids.Length]; | |||
for (uint i = 0; i < wireEgids.Length; i++) | |||
{ | |||
wires[i] = new Wire(wireEgids[i]); | |||
} | |||
return wires; | |||
} | |||
/// <summary> | |||
/// All wires connected to the output port. | |||
/// These wires will always be wired output -> input. | |||
/// </summary> | |||
/// <param name="port">Port number.</param> | |||
/// <returns>Wires connected to the output port.</returns> | |||
public Wire[] ConnectedToOutput(byte port) | |||
{ | |||
if (port >= OutputCount) throw new WiringException($"Port output {port} does not exist"); | |||
EGID[] wireEgids = SignalEngine.WiredToOutput(Id, port); | |||
Wire[] wires = new Wire[wireEgids.Length]; | |||
for (uint i = 0; i < wireEgids.Length; i++) | |||
{ | |||
wires[i] = new Wire(wireEgids[i]); | |||
} | |||
return wires; | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using RobocraftX.Common; | |||
using Gamecraft.CharacterVulnerability; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
@@ -12,43 +13,12 @@ namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class SpawnPoint : Block | |||
{ | |||
/// <summary> | |||
/// Places a new spawn point. | |||
/// Any valid spawn block type is accepted. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new SpawnPoint PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (!(block == BlockIDs.LargeSpawn || block == BlockIDs.SmallSpawn || block == BlockIDs.MediumSpawn || block == BlockIDs.PlayerSpawn)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {nameof(SpawnPoint)} block"); | |||
} | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
return new SpawnPoint(id); | |||
} | |||
return null; | |||
} | |||
public SpawnPoint(EGID id) : base(id) | |||
public SpawnPoint(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<SpawnPointStatsEntityStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public SpawnPoint(uint id) : base(id) | |||
public SpawnPoint(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SPAWNPOINT_BLOCK_GROUP)) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<SpawnPointStatsEntityStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom spawn point properties | |||
@@ -58,16 +28,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public uint Lives | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).lives; | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.lives); | |||
set | |||
{ | |||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id); | |||
spses.lives = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, uint val) => st.lives = val, value); | |||
} | |||
} | |||
/// <summary> | |||
@@ -75,16 +41,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public bool Damageable | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).canTakeDamage; | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.canTakeDamage); | |||
set | |||
{ | |||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id); | |||
spses.canTakeDamage = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, bool val) => st.canTakeDamage = val, value); | |||
} | |||
} | |||
/// <summary> | |||
@@ -92,16 +54,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public bool GameOverEnabled | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).gameOverScreen; | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.gameOverScreen); | |||
set | |||
{ | |||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id); | |||
spses.gameOverScreen = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, bool val) => st.gameOverScreen = val, value); | |||
} | |||
} | |||
/// <summary> | |||
@@ -109,16 +67,12 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public byte Team | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<SpawnPointIdsEntityStruct>(Id).teamId; | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (SpawnPointIdsEntityStruct st) => st.teamId); | |||
set | |||
{ | |||
ref SpawnPointIdsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointIdsEntityStruct>(Id); | |||
spses.teamId = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref SpawnPointIdsEntityStruct st, byte val) => st.teamId = val, value); | |||
} | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using System; | |||
using Gamecraft.Blocks.GUI; | |||
using RobocraftX.Common; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
@@ -9,37 +10,14 @@ using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class TextBlock : Block | |||
public class TextBlock : SignalingBlock | |||
{ | |||
public static TextBlock PlaceNew(float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(BlockIDs.TextBlock, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
return new TextBlock(id); | |||
} | |||
return null; | |||
} | |||
public TextBlock(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<TextBlockDataStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public TextBlock(uint id) : base(id) | |||
public TextBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TEXT_BLOCK_GROUP)) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<TextBlockDataStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom text block properties | |||
@@ -49,35 +27,34 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public string Text | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TextBlockDataStruct>(Id).textCurrent; | |||
} | |||
set | |||
{ | |||
ref TextBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TextBlockDataStruct>(Id); | |||
tbds.textCurrent.Set(value); | |||
tbds.textStored.Set(value); | |||
BlockEngine.GetBlockInfo<TextBlockNetworkDataStruct>(Id).newTextBlockStringContent.Set(value); | |||
} | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (TextBlockDataStruct st) => st.textCurrent); | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) => | |||
{ | |||
tbds.textCurrent.Set(val); | |||
tbds.textStored.Set(val); | |||
}, value); | |||
BlockEngine.SetBlockInfo(this, | |||
(ref TextBlockNetworkDataStruct st, string val) => st.newTextBlockStringContent.Set(val), value); | |||
} | |||
} | |||
/// <summary> | |||
/// The text block's current text block ID (used in ChangeTextBlockCommand). | |||
/// The text block's current text block ID (used in ChangeTextBlockCommand). | |||
/// </summary> | |||
public string TextBlockId | |||
public string TextBlockId | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TextBlockDataStruct>(Id).textBlockID; | |||
} | |||
set | |||
{ | |||
BlockEngine.GetBlockInfo<TextBlockDataStruct>(Id).textBlockID.Set(value); | |||
BlockEngine.GetBlockInfo<TextBlockNetworkDataStruct>(Id).newTextBlockID.Set(value); | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (TextBlockDataStruct st) => st.textBlockID); | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) => | |||
tbds.textBlockID.Set(val), value); | |||
BlockEngine.SetBlockInfo(this, | |||
(ref TextBlockNetworkDataStruct st, string val) => st.newTextBlockID.Set(val), value); | |||
} | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using RobocraftX.Common; | |||
using Gamecraft.Blocks.TimerBlock; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
@@ -10,39 +11,14 @@ using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Timer : Block | |||
public class Timer : SignalingBlock | |||
{ | |||
/// <summary> | |||
/// Places a new timer block. | |||
/// </summary> | |||
public static Timer PlaceNew(float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(BlockIDs.Timer, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
return new Timer(id); | |||
} | |||
return null; | |||
} | |||
public Timer(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<TimerBlockDataStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public Timer(uint id) : base(id) | |||
public Timer(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP)) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<TimerBlockDataStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom timer properties | |||
@@ -52,16 +28,13 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public float Start | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).startTime; | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.startTime); | |||
set | |||
{ | |||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id); | |||
tbds.startTime = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, float val) => tbds.startTime = val, | |||
value); | |||
} | |||
} | |||
/// <summary> | |||
@@ -69,16 +42,13 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public float End | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).endTime; | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.endTime); | |||
set | |||
{ | |||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id); | |||
tbds.endTime = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, float val) => tbds.endTime = val, | |||
value); | |||
} | |||
} | |||
/// <summary> | |||
@@ -86,16 +56,13 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public bool DisplayMilliseconds | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).outputFormatHasMS; | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.outputFormatHasMS); | |||
set | |||
{ | |||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id); | |||
tbds.outputFormatHasMS = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, bool val) => tbds.outputFormatHasMS = val, | |||
value); | |||
} | |||
} | |||
/// <summary> | |||
@@ -103,16 +70,13 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
public int CurrentTime | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TimerBlockLabelCacheEntityStruct>(Id).timeLastRenderFrameMS; | |||
} | |||
get => BlockEngine.GetBlockInfo(this, (TimerBlockLabelCacheEntityStruct st) => st.timeLastRenderFrameMS); | |||
set | |||
{ | |||
ref TimerBlockLabelCacheEntityStruct tblces = ref BlockEngine.GetBlockInfo<TimerBlockLabelCacheEntityStruct>(Id); | |||
tblces.timeLastRenderFrameMS = value; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref TimerBlockLabelCacheEntityStruct tbds, int val) => tbds.timeLastRenderFrameMS = val, | |||
value); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,355 @@ | |||
using System; | |||
using Gamecraft.Wires; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Experimental; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Wire | |||
{ | |||
internal static SignalEngine signalEngine; | |||
protected EGID startPortEGID; | |||
protected EGID endPortEGID; | |||
protected EGID startBlockEGID; | |||
protected EGID endBlockEGID; | |||
protected EGID wireEGID; | |||
protected bool inputToOutput; | |||
protected byte startPort; | |||
protected byte endPort; | |||
public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort) | |||
{ | |||
WireEntityStruct wire = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort); | |||
return new Wire(wire, start, end); | |||
} | |||
/// <summary> | |||
/// An existing wire connection ending at the specified input. | |||
/// If multiple exist, this will return the first one found. | |||
/// </summary> | |||
/// <param name="end">Destination block.</param> | |||
/// <param name="endPort">Port number.</param> | |||
/// <returns>The wire, where the end of the wire is the block port specified, or null if does not exist.</returns> | |||
public static Wire ConnectedToInputPort(SignalingBlock end, byte endPort) | |||
{ | |||
EGID port = signalEngine.MatchBlockInputToPort(end, endPort, out bool exists); | |||
if (!exists) return null; | |||
WireEntityStruct wire = signalEngine.MatchPortToWire(port, end.Id, out exists); | |||
if (exists) | |||
{ | |||
return new Wire(new Block(wire.sourceBlockEGID), end, wire.sourcePortUsage, endPort); | |||
} | |||
return null; | |||
} | |||
/// <summary> | |||
/// An existing wire connection starting at the specified output. | |||
/// If multiple exist, this will return the first one found. | |||
/// </summary> | |||
/// <param name="start">Source block entity ID.</param> | |||
/// <param name="startPort">Port number.</param> | |||
/// <returns>The wire, where the start of the wire is the block port specified, or null if does not exist.</returns> | |||
public static Wire ConnectedToOutputPort(SignalingBlock start, byte startPort) | |||
{ | |||
EGID port = signalEngine.MatchBlockOutputToPort(start, startPort, out bool exists); | |||
if (!exists) return null; | |||
WireEntityStruct wire = signalEngine.MatchPortToWire(port, start.Id, out exists); | |||
if (exists) | |||
{ | |||
return new Wire(start, new Block(wire.destinationBlockEGID), startPort, wire.destinationPortUsage); | |||
} | |||
return null; | |||
} | |||
/// <summary> | |||
/// Construct a wire object from an existing connection. | |||
/// </summary> | |||
/// <param name="start">Starting block ID.</param> | |||
/// <param name="end">Ending block ID.</param> | |||
/// <param name="startPort">Starting port number, or guess if omitted.</param> | |||
/// <param name="endPort">Ending port number, or guess if omitted.</param> | |||
/// <exception cref="WireInvalidException">Guessing failed or wire does not exist.</exception> | |||
public Wire(Block start, Block end, byte startPort = Byte.MaxValue, byte endPort = Byte.MaxValue) | |||
{ | |||
startBlockEGID = start.Id; | |||
endBlockEGID = end.Id; | |||
// find block ports | |||
WireEntityStruct wire = signalEngine.MatchBlocksToWire(start.Id, end.Id, out bool exists, startPort, endPort); | |||
if (exists) | |||
{ | |||
wireEGID = wire.ID; | |||
endPortEGID = signalEngine.MatchBlockInputToPort(end, wire.destinationPortUsage, out exists); | |||
if (!exists) throw new WireInvalidException("Wire end port not found"); | |||
startPortEGID = signalEngine.MatchBlockOutputToPort(start, wire.sourcePortUsage, out exists); | |||
if (!exists) throw new WireInvalidException("Wire start port not found"); | |||
inputToOutput = false; | |||
endPort = wire.destinationPortUsage; | |||
startPort = wire.sourcePortUsage; | |||
} | |||
else | |||
{ | |||
// flip I/O around and try again | |||
wire = signalEngine.MatchBlocksToWire(end.Id, start.Id, out exists, endPort, startPort); | |||
if (exists) | |||
{ | |||
wireEGID = wire.ID; | |||
endPortEGID = signalEngine.MatchBlockOutputToPort(end, wire.sourcePortUsage, out exists); | |||
if (!exists) throw new WireInvalidException("Wire end port not found"); | |||
startPortEGID = signalEngine.MatchBlockInputToPort(start, wire.destinationPortUsage, out exists); | |||
if (!exists) throw new WireInvalidException("Wire start port not found"); | |||
inputToOutput = true; // end is actually the source | |||
// NB: start and end are handled exactly as they're received as params. | |||
// This makes wire traversal easier, but makes logic in this class a bit more complex | |||
endPort = wire.sourcePortUsage; | |||
startPort = wire.destinationPortUsage; | |||
} | |||
else | |||
{ | |||
throw new WireInvalidException("Wire not found"); | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// Construct a wire object from an existing wire connection. | |||
/// </summary> | |||
/// <param name="start">Starting block ID.</param> | |||
/// <param name="end">Ending block ID.</param> | |||
/// <param name="startPort">Starting port number.</param> | |||
/// <param name="endPort">Ending port number.</param> | |||
/// <param name="wire">The wire ID.</param> | |||
/// <param name="inputToOutput">Whether the wire direction goes input -> output (true) or output -> input (false, preferred).</param> | |||
public Wire(Block start, Block end, byte startPort, byte endPort, EGID wire, bool inputToOutput) | |||
{ | |||
this.startBlockEGID = start.Id; | |||
this.endBlockEGID = end.Id; | |||
this.inputToOutput = inputToOutput; | |||
this.wireEGID = wire; | |||
if (inputToOutput) | |||
{ | |||
endPortEGID = signalEngine.MatchBlockOutputToPort(start, startPort, out bool exists); | |||
if (!exists) throw new WireInvalidException("Wire end port not found"); | |||
startPortEGID = signalEngine.MatchBlockInputToPort(end, endPort, out exists); | |||
if (!exists) throw new WireInvalidException("Wire start port not found"); | |||
} | |||
else | |||
{ | |||
endPortEGID = signalEngine.MatchBlockInputToPort(end, endPort, out bool exists); | |||
if (!exists) throw new WireInvalidException("Wire end port not found"); | |||
startPortEGID = signalEngine.MatchBlockOutputToPort(start, startPort, out exists); | |||
if (!exists) throw new WireInvalidException("Wire start port not found"); | |||
} | |||
this.startPort = startPort; | |||
this.endPort = endPort; | |||
} | |||
/// <summary> | |||
/// Construct a wire object from an existing wire connection. | |||
/// </summary> | |||
/// <param name="wireEgid">The wire ID.</param> | |||
public Wire(EGID wireEgid) | |||
{ | |||
this.wireEGID = wireEgid; | |||
WireEntityStruct wire = signalEngine.GetWire(wireEGID); | |||
this.startBlockEGID = wire.sourceBlockEGID; | |||
this.endBlockEGID = wire.destinationBlockEGID; | |||
this.inputToOutput = false; | |||
endPortEGID = signalEngine.MatchBlockInputToPort(wire.destinationBlockEGID, wire.destinationPortUsage, out bool exists); | |||
if (!exists) throw new WireInvalidException("Wire end port not found"); | |||
startPortEGID = signalEngine.MatchBlockOutputToPort(wire.sourceBlockEGID, wire.sourcePortUsage, out exists); | |||
if (!exists) throw new WireInvalidException("Wire start port not found"); | |||
this.endPort = wire.destinationPortUsage; | |||
this.startPort = wire.sourcePortUsage; | |||
} | |||
internal Wire(WireEntityStruct wire, SignalingBlock src, SignalingBlock dest) | |||
{ | |||
this.wireEGID = wire.ID; | |||
this.startBlockEGID = wire.sourceBlockEGID; | |||
this.endBlockEGID = wire.destinationBlockEGID; | |||
inputToOutput = false; | |||
endPortEGID = signalEngine.MatchBlockInputToPort(dest, wire.destinationPortUsage, out bool exists); | |||
if (!exists) throw new WireInvalidException("Wire end port not found"); | |||
startPortEGID = signalEngine.MatchBlockOutputToPort(src, wire.sourcePortUsage, out exists); | |||
if (!exists) throw new WireInvalidException("Wire start port not found"); | |||
this.endPort = wire.destinationPortUsage; | |||
this.startPort = wire.sourcePortUsage; | |||
} | |||
/// <summary> | |||
/// The wire's in-game id. | |||
/// </summary> | |||
public EGID Id | |||
{ | |||
get => wireEGID; | |||
} | |||
/// <summary> | |||
/// The wire's signal value, as a float. | |||
/// </summary> | |||
public float Float | |||
{ | |||
get | |||
{ | |||
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); | |||
if (!exists) return 0f; | |||
return cds.valueAsFloat; | |||
} | |||
set | |||
{ | |||
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); | |||
if (!exists) return; | |||
cds.valueAsFloat = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The wire's string signal. | |||
/// </summary> | |||
public string String | |||
{ | |||
get | |||
{ | |||
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); | |||
if (!exists) return ""; | |||
return cds.valueAsEcsString; | |||
} | |||
set | |||
{ | |||
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); | |||
if (!exists) return; | |||
cds.valueAsEcsString.Set(value); | |||
} | |||
} | |||
/// <summary> | |||
/// The wire's raw string signal. | |||
/// </summary> | |||
public ECSString ECSString | |||
{ | |||
get | |||
{ | |||
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); | |||
if (!exists) return default; | |||
return cds.valueAsEcsString; | |||
} | |||
set | |||
{ | |||
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); | |||
if (!exists) return; | |||
cds.valueAsEcsString = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The wire's signal id. | |||
/// I'm 50% sure this is useless. | |||
/// </summary> | |||
public uint SignalId | |||
{ | |||
get | |||
{ | |||
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); | |||
if (!exists) return uint.MaxValue; | |||
return cds.valueAsID; | |||
} | |||
set | |||
{ | |||
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); | |||
if (!exists) return; | |||
cds.valueAsID = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The block at the beginning of the wire. | |||
/// </summary> | |||
public SignalingBlock Start | |||
{ | |||
get => new SignalingBlock(startBlockEGID); | |||
} | |||
/// <summary> | |||
/// The port number that the beginning of the wire connects to. | |||
/// </summary> | |||
public byte StartPort | |||
{ | |||
get => startPort; | |||
} | |||
/// <summary> | |||
/// The block at the end of the wire. | |||
/// </summary> | |||
public SignalingBlock End | |||
{ | |||
get => new SignalingBlock(endBlockEGID); | |||
} | |||
/// <summary> | |||
/// The port number that the end of the wire connects to. | |||
/// </summary> | |||
public byte EndPort | |||
{ | |||
get => endPort; | |||
} | |||
/// <summary> | |||
/// Create a copy of the wire object where the direction of the wire is guaranteed to be from a block output to a block input. | |||
/// This is simply a different memory configuration and does not affect the in-game wire (which is always output -> input). | |||
/// </summary> | |||
/// <returns>A copy of the wire object.</returns> | |||
public Wire OutputToInputCopy() | |||
{ | |||
return new Wire(wireEGID); | |||
} | |||
/// <summary> | |||
/// Convert the wire object to the direction the signal flows. | |||
/// Signals on wires always flow from a block output port to a block input port. | |||
/// This is simply a different memory configuration and does not affect the in-game wire (which is always output -> input). | |||
/// </summary> | |||
public void OutputToInputInPlace() | |||
{ | |||
if (inputToOutput) | |||
{ | |||
inputToOutput = false; | |||
// swap inputs and outputs | |||
EGID temp = endBlockEGID; | |||
endBlockEGID = startBlockEGID; | |||
startBlockEGID = temp; | |||
temp = endPortEGID; | |||
endPortEGID = startPortEGID; | |||
startPortEGID = temp; | |||
byte tempPortNumber = endPort; | |||
endPort = startPort; | |||
startPort = tempPortNumber; | |||
} | |||
} | |||
public override string ToString() | |||
{ | |||
if (signalEngine.Exists<WireEntityStruct>(wireEGID)) | |||
{ | |||
return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(End.Id)}: {End.Id}, ({Start.Type}::{StartPort} aka {Start.PortName(StartPort, inputToOutput)}) -> ({End.Type}::{EndPort} aka {End.PortName(EndPort, !inputToOutput)})"; | |||
} | |||
return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(End.Id)}: {End.Id}, ({Start.Type}::{StartPort} -> {End.Type}::{EndPort})"; | |||
} | |||
internal static void Init() { } | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
using Gamecraft.Damage; | |||
using RobocraftX.Common; | |||
using Svelto.ECS; | |||
namespace GamecraftModdingAPI | |||
{ | |||
/// <summary> | |||
/// Represnts a cluster of blocks in time running mode, meaning blocks that are connected either directly or via joints. | |||
/// </summary> | |||
public class Cluster | |||
{ | |||
public EGID Id { get; } | |||
public Cluster(EGID id) | |||
{ | |||
Id = id; | |||
} | |||
public Cluster(uint id) : this(new EGID(id, CommonExclusiveGroups.SIMULATION_CLUSTERS_GROUP)) | |||
{ | |||
} | |||
public float InitialHealth | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth = value; | |||
} | |||
public float CurrentHealth | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth = value; | |||
} | |||
public float HealthMultiplier | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier = value; | |||
} | |||
} | |||
} |
@@ -18,7 +18,8 @@ namespace GamecraftModdingAPI.Events | |||
/// Patch of RobocraftX.StateSync.DeterministicStepCompositionRoot.ComposeEnginesGroups(...) | |||
/// </summary> | |||
//[HarmonyPatch(typeof(DeterministicStepCompositionRoot), "DeterministicCompose")] | |||
[HarmonyPatch] | |||
[Obsolete] | |||
[HarmonyPatch] | |||
class GameHostTransitionDeterministicGroupEnginePatch | |||
{ | |||
@@ -4,6 +4,7 @@ using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
[Obsolete] | |||
public class EmitterBuilder | |||
{ | |||
private string name; | |||
@@ -11,6 +11,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Convenient factories for mod event engines | |||
/// </summary> | |||
[Obsolete] | |||
public static class EventEngineFactory | |||
{ | |||
/// <summary> | |||
@@ -14,6 +14,7 @@ namespace GamecraftModdingAPI.Events | |||
/// Keeps track of event handlers and emitters. | |||
/// This is used to add, remove and get API event handlers and emitters. | |||
/// </summary> | |||
[Obsolete("This will be removed in an upcoming update. Use the new C# event architecture from GamecraftModdingAPI.App")] | |||
public static class EventManager | |||
{ | |||
private static Dictionary<string, IEventEmitterEngine> _eventEmitters = new Dictionary<string, IEventEmitterEngine>(); | |||
@@ -17,6 +17,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Patch of RobocraftX.FullGameCompositionRoot.ActivateGame() | |||
/// </summary> | |||
[Obsolete] | |||
[HarmonyPatch] | |||
class GameActivatedComposePatch | |||
{ | |||
@@ -14,6 +14,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Patch of RobocraftX.FullGameCompositionRoot.ReloadGame() | |||
/// </summary> | |||
[Obsolete] | |||
[HarmonyPatch(typeof(FullGameCompositionRoot), "ReloadGame")] | |||
class GameReloadedPatch | |||
{ | |||
@@ -12,6 +12,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Event emitter engine for switching to to build mode. | |||
/// </summary> | |||
[Obsolete] | |||
public class GameStateBuildEmitterEngine : IEventEmitterEngine, IUnorderedInitializeOnTimeStoppedModeEntered | |||
{ | |||
public string Name { get; } = "GamecraftModdingAPIGameStateBuildEventEmitter" ; | |||
@@ -43,10 +44,10 @@ namespace GamecraftModdingAPI.Events | |||
} | |||
} | |||
public JobHandle OnInitializeTimeStoppedMode() | |||
public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps) | |||
{ | |||
Emit(); | |||
return default(JobHandle); | |||
return inputDeps; | |||
} | |||
public void Ready() { } | |||
@@ -12,6 +12,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Event emitter engine for switching to simulation mode. | |||
/// </summary> | |||
[Obsolete] | |||
public class GameStateSimulationEmitterEngine : IEventEmitterEngine, IUnorderedInitializeOnTimeRunningModeEntered | |||
{ | |||
public string Name { get; } = "GamecraftModdingAPIGameStateSimulationEventEmitter" ; | |||
@@ -42,10 +43,10 @@ namespace GamecraftModdingAPI.Events | |||
} | |||
} | |||
public JobHandle OnInitializeTimeRunningMode() | |||
public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps) | |||
{ | |||
Emit(); | |||
return default(JobHandle); | |||
return inputDeps; | |||
} | |||
public void Ready() { } | |||
@@ -18,6 +18,7 @@ namespace GamecraftModdingAPI.Events | |||
/// Patch of RobocraftX.FullGameCompositionRoot.ActivateGame() | |||
/// (scheduled for execution during RobocraftX.FullGameCompositionRoot.SwitchToGame()) | |||
/// </summary> | |||
[Obsolete] | |||
[HarmonyPatch(typeof(FullGameCompositionRoot), "SwitchToGame")] | |||
class GameSwitchedToPatch | |||
{ | |||
@@ -4,6 +4,7 @@ using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
[Obsolete] | |||
public class HandlerBuilder | |||
{ | |||
private string name; | |||
@@ -13,6 +13,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Engine interface to create a ModEventEntityStruct in entitiesDB when a specific event occurs. | |||
/// </summary> | |||
[Obsolete] | |||
public interface IEventEmitterEngine : IFactoryEngine | |||
{ | |||
/// <summary> | |||
@@ -14,6 +14,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Engine interface to handle ModEventEntityStruct events emitted by IEventEmitterEngines. | |||
/// </summary> | |||
[Obsolete] | |||
public interface IEventHandlerEngine : IReactionaryEngine<ModEventEntityStruct> | |||
{ | |||
} | |||
@@ -15,6 +15,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Patch of RobocraftX.FullGameCompositionRoot.ActivateMenu() | |||
/// </summary> | |||
[Obsolete] | |||
[HarmonyPatch(typeof(FullGameCompositionRoot), "ActivateMenu")] | |||
class MenuActivatedPatch | |||
{ | |||
@@ -31,6 +32,7 @@ namespace GamecraftModdingAPI.Events | |||
{ | |||
firstLoad = false; | |||
FullGameFields.Init(__instance); | |||
//Application.Application.SetFullGameCompositionRoot(__instance); | |||
Logging.Log("Dispatching App Init event"); | |||
EventManager.GetEventEmitter("GamecraftModdingAPIApplicationInitializedEventEmitter").Emit(); | |||
} | |||
@@ -15,6 +15,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// Patch of RobocraftX.FullGameCompositionRoot.SwitchToMenu() | |||
/// </summary> | |||
[Obsolete] | |||
[HarmonyPatch(typeof(FullGameCompositionRoot), "SwitchToMenu")] | |||
class MenuSwitchedToPatch | |||
{ | |||
@@ -12,6 +12,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// A simple implementation of IEventEmitterEngine sufficient for most uses | |||
/// </summary> | |||
[Obsolete] | |||
public class SimpleEventEmitterEngine : IEventEmitterEngine | |||
{ | |||
public string Name { get; set; } | |||
@@ -13,6 +13,7 @@ namespace GamecraftModdingAPI.Events | |||
/// <summary> | |||
/// A simple implementation of IEventHandlerEngine sufficient for most uses | |||
/// </summary> | |||
[Obsolete] | |||
public class SimpleEventHandlerEngine : IEventHandlerEngine | |||
{ | |||
public int type { get; set; } | |||
@@ -20,6 +21,10 @@ namespace GamecraftModdingAPI.Events | |||
private bool isActivated = false; | |||
private bool jankActivateFix = false; | |||
private bool jankDestroyFix = false; | |||
private readonly Action<EntitiesDB> onActivated; | |||
private readonly Action<EntitiesDB> onDestroyed; | |||
@@ -32,6 +37,8 @@ namespace GamecraftModdingAPI.Events | |||
{ | |||
if (entityView.type.Equals(this.type)) | |||
{ | |||
jankActivateFix = !jankActivateFix; | |||
if (jankActivateFix) return; | |||
isActivated = true; | |||
onActivatedInvokeCatchError(entitiesDB); | |||
} | |||
@@ -51,12 +58,19 @@ namespace GamecraftModdingAPI.Events | |||
} | |||
} | |||
public void Deactivate() | |||
{ | |||
isActivated = false; | |||
} | |||
public void Ready() { } | |||
public void Remove(ref ModEventEntityStruct entityView, EGID egid) | |||
{ | |||
if (entityView.type.Equals(this.type) && isActivated) | |||
{ | |||
jankDestroyFix = !jankDestroyFix; | |||
if (jankDestroyFix) return; | |||
isActivated = false; | |||
onDestroyedInvokeCatchError(entitiesDB); | |||
} | |||
@@ -1,9 +1,8 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>net472</TargetFramework> | |||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> | |||
<Version>1.2.0</Version> | |||
<Version>1.5.0</Version> | |||
<Authors>Exmods</Authors> | |||
<PackageLicenseExpression>GNU General Public Licence 3+</PackageLicenseExpression> | |||
<PackageProjectUrl>https://git.exmods.org/modtainers/GamecraftModdingAPI</PackageProjectUrl> | |||
@@ -14,17 +13,16 @@ | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Test|AnyCPU' "> | |||
<DefineConstants>DEBUG;TEST;TRACE</DefineConstants> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Lib.Harmony" Version="2.0.0.10" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Reference Include="Microsoft.CSharp" /> | |||
</ItemGroup> | |||
<!--Start Dependencies--> | |||
<ItemGroup> | |||
<Reference Include="IllusionInjector"> | |||
@@ -35,405 +33,221 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath> | |||
</Reference> | |||
<Reference Include="JWT"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath> | |||
<Reference Include="Analytics"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Analytics.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Analytics.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Burst.Unsafe"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath> | |||
<Reference Include="Assembly-CSharp-firstpass"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Facepunch.Steamworks.Win64"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath> | |||
<Reference Include="Assembly-CSharp"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Rewired_Core"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath> | |||
<Reference Include="Authentication"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Authentication.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Authentication.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Rewired_Windows"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath> | |||
<Reference Include="Blocks.HUDFeedbackBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="mscorlib"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath> | |||
<Reference Include="CommandLine"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\CommandLine.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\CommandLine.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Newtonsoft.Json"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath> | |||
<Reference Include="CommandLineCompositionRoot"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\CommandLineCompositionRoot.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\CommandLineCompositionRoot.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AccessibilityModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath> | |||
<Reference Include="ConsoleBlockComposotionRoot"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\ConsoleBlockComposotionRoot.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\ConsoleBlockComposotionRoot.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AIModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll</HintPath> | |||
<Reference Include="ConsoleCommand"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\ConsoleCommand.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\ConsoleCommand.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AndroidJNIModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath> | |||
<Reference Include="DataLoader"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\DataLoader.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\DataLoader.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AnimationModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll</HintPath> | |||
<Reference Include="DDNA"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ARModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll</HintPath> | |||
<Reference Include="FMOD"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AssetBundleModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath> | |||
<Reference Include="FullGame"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\FullGame.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\FullGame.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AudioModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll</HintPath> | |||
<Reference Include="Gamecraft.AudioBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ClothModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll</HintPath> | |||
<Reference Include="Gamecraft.BlockCompositionRoot"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.BlockCompositionRoot.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlockCompositionRoot.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ClusterInputModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath> | |||
<Reference Include="Gamecraft.BlockEntityFactory"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.BlockEntityFactory.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlockEntityFactory.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ClusterRendererModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Blocks.ConsoleBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.CoreModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Blocks.DamagingSurfaceBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.CrashReportingModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Blocks.DestructionBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DestructionBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DestructionBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.DirectorModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Blocks.GenericPhysicsBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.dll</HintPath> | |||
<Reference Include="Gamecraft.Blocks.LogicBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.DSPGraphModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath> | |||
<Reference Include="GameCraft.Blocks.ProjectileBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.GameCenterModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Blocks.TextBlock.CompositionRoot"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TextBlock.CompositionRoot.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TextBlock.CompositionRoot.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.GridModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Blocks.TimerBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.HotReloadModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath> | |||
<Reference Include="Gamecraft.BlocksEntityDescriptors"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.BlocksEntityDescriptors.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlocksEntityDescriptors.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ImageConversionModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath> | |||
<Reference Include="Gamecraft.CharacterVulnerability"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.IMGUIModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath> | |||
<Reference Include="Gamecraft.CharacterVulnerabilityGui"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.InputLegacyModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Damage"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Damage.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Damage.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.InputModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Effects"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.JSONSerializeModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath> | |||
<Reference Include="Gamecraft.ExplosionFragments"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.ExplosionFragments.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.ExplosionFragments.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.LocalizationModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath> | |||
<Reference Include="Gamecraft.GraphicsSettings"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GraphicsSettings.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GraphicsSettings.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ParticleSystemModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath> | |||
<Reference Include="Gamecraft.GUI.ConsoleBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.PerformanceReportingModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath> | |||
<Reference Include="Gamecraft.GUI.GraphicsScreen"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.Physics2DModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath> | |||
<Reference Include="Gamecraft.GUI.HUDFeedbackBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.PhysicsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath> | |||
<Reference Include="Gamecraft.GUI.Tweaks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ProfilerModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath> | |||
<Reference Include="Gamecraft.GUI.Wires"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ScreenCaptureModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath> | |||
<Reference Include="Gamecraft.GUI.Wires.Mockup"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.Mockup.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.Mockup.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SharedInternalsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath> | |||
<Reference Include="Gamecraft.GUI.WorldSpaceGuis"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SpriteMaskModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath> | |||
<Reference Include="Gamecraft.InventoryTimeRunning"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.InventoryTimeRunning.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.InventoryTimeRunning.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SpriteShapeModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath> | |||
<Reference Include="Gamecraft.JointBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.JointBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.JointBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.StreamingModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Music"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SubstanceModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath> | |||
<Reference Include="Gamecraft.PerformanceWarnings"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SubsystemsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll</HintPath> | |||
<Reference Include="Gamecraft.PickupBlck"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.PickupBlck.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.PickupBlck.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TerrainModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll</HintPath> | |||
<Reference Include="Gamecraft.PickupsCommon"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.PickupsCommon.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.PickupsCommon.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TerrainPhysicsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath> | |||
<Reference Include="Gamecraft.PopupMessage"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.PopupMessage.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.PopupMessage.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TextCoreModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Projectiles"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Projectiles.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Projectiles.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TextRenderingModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Tweaks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TilemapModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Tweaks.Mockup"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TLSModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath> | |||
<Reference Include="Gamecraft.VisualEffects.Decals"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.Decals.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.Decals.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UIElementsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath> | |||
<Reference Include="Gamecraft.VisualEffects"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UIModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Wires"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UmbraModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll</HintPath> | |||
<Reference Include="Gamecraft.Wires.Mockup"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UNETModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll</HintPath> | |||
<Reference Include="GameState"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityAnalyticsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityConnectModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityTestProtocolModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestAudioModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestTextureModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestWWWModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.VehiclesModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.VFXModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.VideoModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.VRModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.WindModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.XRModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Analytics"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Analytics.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Analytics.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Assembly-CSharp-firstpass"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Assembly-CSharp"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Authentication"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Authentication.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Authentication.dll</HintPath> | |||
</Reference> | |||
<Reference Include="BlockEntityFactory"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Blocks.HUDFeedbackBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="ClusterToWireConversion.Mock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="CommandLine"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\CommandLine.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\CommandLine.dll</HintPath> | |||
</Reference> | |||
<Reference Include="DataLoader"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\DataLoader.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\DataLoader.dll</HintPath> | |||
</Reference> | |||
<Reference Include="DDNA"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath> | |||
</Reference> | |||
<Reference Include="FMOD"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath> | |||
</Reference> | |||
<Reference Include="FullGame"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\FullGame.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\FullGame.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Blocks.ConsoleBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Blocks.GenericPhysicsBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Blocks.LogicBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Blocks.TimerBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.CharacterVulnerability"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.CharacterVulnerabilityGui"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Effects"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.GUI.ConsoleBlock"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.GUI.GraphicsScreen"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.GUI.HUDFeedbackBlocks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.GUI.Tweaks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.GUI.Wires"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.GUI.Wires.Mockup"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.Mockup.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.Mockup.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.GUI.WorldSpaceGuis"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Tweaks"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Tweaks.Mockup"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Wires"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Wires.Input"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Wires.Mockup"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll</HintPath> | |||
</Reference> | |||
<Reference Include="GameState"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath> | |||
</Reference> | |||
<Reference Include="GPUInstancer"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath> | |||
<Reference Include="GPUInstancer"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Havok.Physics"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Havok.Physics.dll</HintPath> | |||
@@ -459,6 +273,10 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftECS"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftECS.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftECS.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.AccountPreferences"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll</HintPath> | |||
@@ -631,6 +449,14 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll</HintPath> | |||
</Reference> | |||
<Reference Include="SpawningPointCompositionRoot"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\SpawningPointCompositionRoot.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\SpawningPointCompositionRoot.dll</HintPath> | |||
</Reference> | |||
<Reference Include="SpecializedDescriptors"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\SpecializedDescriptors.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\SpecializedDescriptors.dll</HintPath> | |||
</Reference> | |||
<Reference Include="StringFormatter"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\StringFormatter.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\StringFormatter.dll</HintPath> | |||
@@ -651,10 +477,46 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UltimateDecals"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UltimateDecals.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UltimateDecals.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Addressables"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Animation.Curves"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Animation.Curves.Hybrid"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.Hybrid.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.Hybrid.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Animation.DefaultGraphPipeline"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Animation.DefaultGraphPipeline.Hybrid"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.Hybrid.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.Hybrid.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Animation"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Animation.Graph"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.Graph.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Graph.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Animation.Hybrid"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Animation.Hybrid.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Hybrid.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Build.SlimPlayerRuntime"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Burst"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Burst.dll</HintPath> | |||
@@ -663,6 +525,10 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Collections.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Collections.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.DataFlowGraph"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.DataFlowGraph.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.DataFlowGraph.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Deformations"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll</HintPath> | |||
@@ -691,6 +557,10 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.Hybrid.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.Hybrid.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.MemoryProfiler"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.MemoryProfiler.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.MemoryProfiler.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Physics"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Physics.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Physics.dll</HintPath> | |||
@@ -775,6 +645,10 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.VisualEffectGraph.Runtime"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.VisualEffectGraph.Runtime.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.VisualEffectGraph.Runtime.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UI"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath> | |||
@@ -787,7 +661,286 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Accessibility"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Accessibility.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Accessibility.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Facepunch.Steamworks.Win64"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath> | |||
</Reference> | |||
<Reference Include="JWT"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath> | |||
</Reference> | |||
<Reference Include="mscorlib"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath> | |||
</Reference> | |||
<Reference Include="netstandard"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\netstandard.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\netstandard.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Newtonsoft.Json"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Novell.Directory.Ldap"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Rewired_Core"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Rewired_Windows"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Burst.Unsafe"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AccessibilityModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AIModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AndroidJNIModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AnimationModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ARModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AssetBundleModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.AudioModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ClothModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ClusterInputModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ClusterRendererModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.CoreModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.CrashReportingModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.DirectorModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.DSPGraphModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.GameCenterModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.GridModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.HotReloadModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ImageConversionModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.IMGUIModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.InputLegacyModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.InputModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.JSONSerializeModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.LocalizationModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ParticleSystemModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.PerformanceReportingModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.Physics2DModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.PhysicsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ProfilerModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.ScreenCaptureModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SharedInternalsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SpriteMaskModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SpriteShapeModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.StreamingModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SubstanceModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.SubsystemsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TerrainModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TerrainPhysicsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TextCoreModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TextRenderingModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TilemapModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.TLSModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UIElementsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UIModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UmbraModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UNETModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityAnalyticsModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityConnectModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityTestProtocolModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestAudioModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestTextureModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.UnityWebRequestWWWModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.VehiclesModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.VFXModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.VideoModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.VRModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.WindModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll</HintPath> | |||
</Reference> | |||
<Reference Include="UnityEngine.XRModule"> | |||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath> | |||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath> | |||
</Reference> | |||
</ItemGroup> | |||
<!--End Dependencies--> | |||
</Project> | |||
</Project> |
@@ -4,7 +4,7 @@ using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using System.Reflection; | |||
using GamecraftModdingAPI.Blocks; | |||
using HarmonyLib; | |||
using GamecraftModdingAPI.Utility; | |||
@@ -49,6 +49,7 @@ namespace GamecraftModdingAPI | |||
harmony.PatchAll(currentAssembly); | |||
// init utility | |||
Logging.MetaDebugLog($"Initializing Utility"); | |||
#pragma warning disable 0612,0618 | |||
Utility.GameState.Init(); | |||
Utility.VersionTracking.Init(); | |||
// create default event emitters | |||
@@ -61,6 +62,7 @@ namespace GamecraftModdingAPI | |||
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false)); | |||
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.buildEngine); | |||
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.simEngine); | |||
#pragma warning restore 0612,0618 | |||
// init block implementors | |||
Logging.MetaDebugLog($"Initializing Blocks"); | |||
// init inventory | |||
@@ -70,8 +72,11 @@ namespace GamecraftModdingAPI | |||
// init object-oriented classes | |||
Player.Init(); | |||
Block.Init(); | |||
Wire.Init(); | |||
GameClient.Init(); | |||
AsyncUtils.Init(); | |||
GamecraftModdingAPI.App.Client.Init(); | |||
GamecraftModdingAPI.App.Game.Init(); | |||
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); | |||
} | |||
@@ -12,13 +12,7 @@ namespace GamecraftModdingAPI.Persistence | |||
/// </summary> | |||
public interface IEntitySerializer : IDeserializationFactory, IQueryingEntitiesEngine | |||
{ | |||
/// <summary> | |||
/// The entity factory used for creating entities and entity components. | |||
/// </summary> | |||
/// <value>The entity factory.</value> | |||
IEntityFactory EntityFactory { set; } | |||
/// <summary> | |||
/// <summary> | |||
/// Serialize the entities. | |||
/// </summary> | |||
/// <returns>Whether serialization was successful.</returns> | |||
@@ -29,7 +29,6 @@ namespace GamecraftModdingAPI.Persistence | |||
_registrations[name] = (IEntitySerialization ies) => { ies.RegisterSerializationFactory<T>(serializer); }; | |||
if (_lastEnginesRoot != null) | |||
{ | |||
serializer.EntityFactory = _lastEnginesRoot.GenerateEntityFactory(); | |||
_registrations[name].Invoke(_lastEnginesRoot.GenerateEntitySerializer()); | |||
_lastEnginesRoot.AddEngine(serializer); | |||
} | |||
@@ -63,12 +62,10 @@ namespace GamecraftModdingAPI.Persistence | |||
public static void RegisterSerializers(EnginesRoot enginesRoot) | |||
{ | |||
_lastEnginesRoot = enginesRoot; | |||
IEntityFactory factory = enginesRoot.GenerateEntityFactory(); | |||
IEntitySerialization ies = enginesRoot.GenerateEntitySerializer(); | |||
foreach (string key in _serializers.Keys) | |||
{ | |||
Logging.MetaDebugLog($"Registering IEntitySerializer for {key}"); | |||
_serializers[key].EntityFactory = factory; | |||
_registrations[key].Invoke(ies); | |||
enginesRoot.AddEngine(_serializers[key]); | |||
} | |||
@@ -21,13 +21,11 @@ namespace GamecraftModdingAPI.Persistence | |||
protected int serializationType; | |||
public IEntityFactory EntityFactory { set; protected get; } | |||
public EntitiesDB entitiesDB { set; protected get; } | |||
public EntityComponentInitializer BuildDeserializedEntity(EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType, IEntitySerialization entitySerialization) | |||
public EntityComponentInitializer BuildDeserializedEntity(EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType, IEntitySerialization entitySerialization, IEntityFactory factory, bool enginesRootIsDeserializationOnly) | |||
{ | |||
EntityComponentInitializer esi = EntityFactory.BuildEntity<Descriptor>(egid); | |||
EntityComponentInitializer esi = factory.BuildEntity<Descriptor>(egid); | |||
entitySerialization.DeserializeEntityComponents(serializationData, entityDescriptor, ref esi, serializationType); | |||
return esi; | |||
} | |||
@@ -45,6 +45,15 @@ namespace GamecraftModdingAPI | |||
return playerEngine.ExistsById(player); | |||
} | |||
/// <summary> | |||
/// The amount of Players in the current game. | |||
/// </summary> | |||
/// <returns>The count.</returns> | |||
public static uint Count() | |||
{ | |||
return (uint) playerEngine.GetAllPlayerCount(); | |||
} | |||
/// <summary> | |||
/// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.Player"/> class. | |||
/// </summary> | |||
@@ -348,7 +357,7 @@ namespace GamecraftModdingAPI | |||
public Block GetBlockLookedAt(float maxDistance = -1f) | |||
{ | |||
var egid = playerEngine.GetThingLookedAt(Id, maxDistance); | |||
return egid.HasValue && egid.Value.groupID == CommonExclusiveGroups.OWNED_BLOCKS_GROUP | |||
return egid.HasValue && egid.Value.groupID != CommonExclusiveGroups.SIMULATION_BODIES_GROUP | |||
? new Block(egid.Value) | |||
: null; | |||
} | |||
@@ -404,7 +413,7 @@ namespace GamecraftModdingAPI | |||
// internal methods | |||
public static void Init() | |||
internal static void Init() | |||
{ | |||
Utility.GameEngineManager.AddGameEngine(playerEngine); | |||
} | |||
@@ -1,4 +1,6 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using RobocraftX.Character; | |||
@@ -10,14 +12,16 @@ using RobocraftX.Physics; | |||
using RobocraftX.Blocks.Ghost; | |||
using RobocraftX.Character.Camera; | |||
using RobocraftX.Character.Factories; | |||
using Gamecraft.CharacterVulnerability; | |||
using Gamecraft.CharacterVulnerability.Entities; | |||
using Gamecraft.GUI.HUDFeedbackBlocks; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using Unity.Physics; | |||
using UnityEngine; | |||
using GamecraftModdingAPI.Engines; | |||
using HarmonyLib; | |||
using RobocraftX.Common; | |||
using Svelto.ECS.DataStructures; | |||
namespace GamecraftModdingAPI.Players | |||
{ | |||
@@ -65,14 +69,39 @@ namespace GamecraftModdingAPI.Players | |||
return uint.MaxValue; | |||
} | |||
public long GetAllPlayerCount() | |||
{ | |||
if (entitiesDB == null) return 0; | |||
long count = 0; | |||
foreach (ExclusiveGroupStruct eg in PlayersExclusiveGroups.AllPlayers) | |||
{ | |||
count += entitiesDB.Count<PlayerIDStruct>(eg); | |||
} | |||
return count; | |||
} | |||
public long GetLocalPlayerCount() | |||
{ | |||
if (entitiesDB == null) return 0; | |||
return entitiesDB.Count<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers); | |||
} | |||
public long GetRemotePlayerCount() | |||
{ | |||
if (entitiesDB == null) return 0; | |||
return entitiesDB.Count<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers); | |||
} | |||
public bool ExistsById(uint playerId) | |||
{ | |||
if (entitiesDB == null) return false; | |||
return entitiesDB.Exists<PlayerIDStruct>(playerId, PlayersExclusiveGroups.LocalPlayers) | |||
|| entitiesDB.Exists<PlayerIDStruct>(playerId, PlayersExclusiveGroups.RemotePlayers); | |||
} | |||
public float3 GetLocation(uint playerId) | |||
{ | |||
if (entitiesDB == null) return float3.zero; | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -83,6 +112,7 @@ namespace GamecraftModdingAPI.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++) | |||
{ | |||
@@ -104,16 +134,18 @@ namespace GamecraftModdingAPI.Players | |||
public float3 GetRotation(uint playerId) | |||
{ | |||
if (entitiesDB == null) return float3.zero; | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
return ((Quaternion) rbes.rotation).eulerAngles; | |||
} | |||
return default; | |||
return default(float3); | |||
} | |||
public bool SetRotation(uint playerId, float3 value) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -127,6 +159,7 @@ namespace GamecraftModdingAPI.Players | |||
public float3 GetLinearVelocity(uint playerId) | |||
{ | |||
if (entitiesDB == null) return float3.zero; | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -137,6 +170,7 @@ namespace GamecraftModdingAPI.Players | |||
public bool SetLinearVelocity(uint playerId, float3 value) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -148,6 +182,7 @@ namespace GamecraftModdingAPI.Players | |||
public float3 GetAngularVelocity(uint playerId) | |||
{ | |||
if (entitiesDB == null) return float3.zero; | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -158,6 +193,7 @@ namespace GamecraftModdingAPI.Players | |||
public bool SetAngularVelocity(uint playerId, float3 value) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -169,16 +205,18 @@ namespace GamecraftModdingAPI.Players | |||
public PhysicsMass GetMass(uint playerId) | |||
{ | |||
if (entitiesDB == null) return default(PhysicsMass); | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
return rbes.physicsMass; | |||
} | |||
return default; | |||
return default(PhysicsMass); | |||
} | |||
public bool SetInverseMass(uint playerId, float inverseMass) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var rbes = ref GetCharacterStruct<RigidBodyEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -190,6 +228,7 @@ namespace GamecraftModdingAPI.Players | |||
public float? GetLastPingTime(uint playerId, PlayerType type) | |||
{ | |||
if (entitiesDB == null) return null; | |||
EGID egid = new EGID(playerId, PlayerGroupFromEnum(type)); | |||
if (entitiesDB.Exists<PlayerNetworkStatsEntityStruct>(egid)) | |||
{ | |||
@@ -200,6 +239,7 @@ namespace GamecraftModdingAPI.Players | |||
public float GetInitialHealth(uint playerId) | |||
{ | |||
if (entitiesDB == null) return 0; | |||
ref var c = ref GetCharacterStruct<CharacterHealthEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -210,6 +250,7 @@ namespace GamecraftModdingAPI.Players | |||
public bool SetInitialHealth(uint playerId, float val) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var c = ref GetCharacterStruct<CharacterHealthEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -221,6 +262,7 @@ namespace GamecraftModdingAPI.Players | |||
public float GetCurrentHealth(uint playerId) | |||
{ | |||
if (entitiesDB == null) return 0; | |||
ref var c = ref GetCharacterStruct<CharacterHealthEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -231,6 +273,7 @@ namespace GamecraftModdingAPI.Players | |||
public bool SetCurrentHealth(uint playerId, float val) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var c = ref GetCharacterStruct<CharacterHealthEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -242,18 +285,13 @@ namespace GamecraftModdingAPI.Players | |||
public bool DamagePlayer(uint playerId, float amount) | |||
{ | |||
Factory.BuildEntity<DamageEntityDescriptor>( | |||
new EGID(CharacterVulnerabilityExclusiveGroups.NextDamageEntityId, CharacterVulnerabilityExclusiveGroups.CharacterDamageExclusiveGroup) | |||
).Init(new DamageEntityStruct | |||
{ | |||
damage = amount, | |||
targetPlayerEntityId = playerId, | |||
}); | |||
return true; | |||
if (entitiesDB == null) return false; | |||
return SetCurrentHealth(playerId, GetCurrentHealth(playerId) - amount); | |||
} | |||
public bool GetDamageable(uint playerId) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var c = ref GetCharacterStruct<CharacterHealthEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -264,6 +302,7 @@ namespace GamecraftModdingAPI.Players | |||
public bool SetDamageable(uint playerId, bool val) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var ches = ref GetCharacterStruct<CharacterHealthEntityStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -276,6 +315,7 @@ namespace GamecraftModdingAPI.Players | |||
public uint GetInitialLives(uint playerId) | |||
{ | |||
if (entitiesDB == null) return 0; | |||
ref var c = ref GetCharacterStruct<CharacterLivesEntityComponent>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -286,6 +326,7 @@ namespace GamecraftModdingAPI.Players | |||
public bool SetInitialLives(uint playerId, uint val) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var c = ref GetCharacterStruct<CharacterLivesEntityComponent>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -297,6 +338,7 @@ namespace GamecraftModdingAPI.Players | |||
public uint GetCurrentLives(uint playerId) | |||
{ | |||
if (entitiesDB == null) return 0; | |||
ref var c = ref GetCharacterStruct<CharacterLivesEntityComponent>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -307,6 +349,7 @@ namespace GamecraftModdingAPI.Players | |||
public bool SetCurrentLives(uint playerId, uint val) | |||
{ | |||
if (entitiesDB == null) return false; | |||
ref var c = ref GetCharacterStruct<CharacterLivesEntityComponent>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -318,21 +361,21 @@ namespace GamecraftModdingAPI.Players | |||
public bool GetGameOverScreen(uint playerId) | |||
{ | |||
ref var c = ref GetCharacterStruct<CharacterLivesEntityComponent>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
return c.gameOverScreen; | |||
} | |||
return false; | |||
if (entitiesDB == null) return false; | |||
ref HudActivatedBlocksEntityStruct habes = ref entitiesDB.QueryEntity<HudActivatedBlocksEntityStruct>(HUDFeedbackBlocksGUIExclusiveGroups.GameOverHudEgid); | |||
NativeDynamicArrayCast<EGID> nativeDynamicArrayCast = new NativeDynamicArrayCast<EGID>(habes.activatedBlocksOrdered); | |||
return nativeDynamicArrayCast.count > 0; | |||
} | |||
public bool IsDead(uint playerId) | |||
public bool IsDead(uint playerId) | |||
{ | |||
if (entitiesDB == null) return true; | |||
return entitiesDB.Exists<RigidBodyEntityStruct>(playerId, CharacterExclusiveGroups.DeadCharacters); | |||
} | |||
public int GetSelectedBlock(uint playerId) | |||
{ | |||
if (entitiesDB == null) return 0; | |||
ref var c = ref GetCharacterStruct<EquippedPartStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -343,6 +386,7 @@ namespace GamecraftModdingAPI.Players | |||
public byte GetSelectedColor(uint playerId) | |||
{ | |||
if (entitiesDB == null) return 0; | |||
ref var c = ref GetCharacterStruct<EquippedColourStruct>(playerId, out bool exists); | |||
if (exists) | |||
{ | |||
@@ -0,0 +1,42 @@ | |||
using System; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI; | |||
using GamecraftModdingAPI.Tests; | |||
namespace GamecraftModdingAPI.Players | |||
{ | |||
#if TEST | |||
/// <summary> | |||
/// Player test cases. Not accessible in release versions. | |||
/// </summary> | |||
[APITestClass] | |||
public static class PlayerTests | |||
{ | |||
[APITestCase(TestType.EditMode)] | |||
public static void ExistsTest() | |||
{ | |||
if (!Assert.Equal(Player.Exists(PlayerType.Local), true, "Local player does not exist.", "Local player detected.")) return; | |||
Assert.Equal(Player.Count(), 1u, "Player.Count() is not one, possibly because it failed silently.", "Player count is one for single player game."); | |||
} | |||
[APITestCase(TestType.EditMode)] | |||
public static void PositionTest() | |||
{ | |||
Player p = new Player(PlayerType.Local); | |||
if (!Assert.Errorless(() => { p.Teleport(0, 0, 0, relative: false); }, "Player.Teleport(origin) errored: ", "Player teleported to origin successfully.")) return; | |||
if (!Assert.CloseTo(p.Position, float3.zero, "Player is not close to origin despite being teleported there.", "Player.Position is at origin.")) return; | |||
if (!Assert.Errorless(() => { p.Position = float3.zero + 1; }, "Player.Position = origin+1 errored: ", "Player moved to origin+1.")) return; | |||
Assert.CloseTo(p.Position, float3.zero + 1, "Player is not close to origin+1 despite being teleported there.", "Player.Position is at origin+1."); | |||
} | |||
[APITestCase(TestType.Menu)] | |||
public static void InvalidStateTest() | |||
{ | |||
if (!Assert.Errorless(() => { Player.Count(); }, "Player.Count() errored in menu.", "Player.Count() succeeded in menu.")) return; | |||
Assert.Equal(Player.Count(), 0u, "Player.Count() is not zero in menu.", "Player count is zero in menu as expected."); | |||
} | |||
} | |||
#endif | |||
} |
@@ -3,18 +3,27 @@ using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using UnityEngine; | |||
using Gamecraft.Damage; | |||
using RobocraftX.Common; | |||
using RobocraftX.Physics; | |||
namespace GamecraftModdingAPI | |||
{ | |||
/// <summary> | |||
/// A rigid body (like a cluster of connected blocks) during simulation. | |||
/// A rigid body (like a chunk of connected blocks) during simulation. | |||
/// </summary> | |||
public class SimBody : IEquatable<SimBody>, IEquatable<EGID> | |||
{ | |||
public EGID Id { get; } | |||
/// <summary> | |||
/// The cluster this chunk belongs to, or null if the chunk doesn't exist. Get the SimBody from a Block if possible for good performance here. | |||
/// </summary> | |||
public Cluster Cluster => cluster ?? (cluster = clusterId == uint.MaxValue ? Block.BlockEngine.GetCluster(Id.entityID) : new Cluster(clusterId)); | |||
private Cluster cluster; | |||
private uint clusterId; | |||
public SimBody(EGID id) | |||
{ | |||
Id = id; | |||
@@ -24,6 +33,11 @@ namespace GamecraftModdingAPI | |||
{ | |||
} | |||
internal SimBody(uint id, uint clusterID) : this(id) | |||
{ | |||
clusterId = clusterID; | |||
} | |||
/// <summary> | |||
/// The position of this body. When setting the position, update the position of the connected bodies as well, | |||
/// otherwise unexpected forces may arise. | |||
@@ -70,6 +84,29 @@ namespace GamecraftModdingAPI | |||
//set => GetStruct().physicsMass.CenterOfMass = value; | |||
} | |||
public float Volume | |||
{ | |||
get => GetStruct().volume; | |||
} | |||
public float InitialHealth | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth = value; | |||
} | |||
public float CurrentHealth | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth = value; | |||
} | |||
public float HealthMultiplier | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier = value; | |||
} | |||
/// <summary> | |||
/// Whether the body can be moved or static. | |||
/// </summary> | |||
@@ -0,0 +1,65 @@ | |||
using System; | |||
namespace GamecraftModdingAPI.Tests | |||
{ | |||
/// <summary> | |||
/// Test type. | |||
/// When provided to APITestCaseAttribute, this dictates when the test case is called. | |||
/// </summary> | |||
public enum TestType | |||
{ | |||
Menu, | |||
Game, | |||
SimulationMode, | |||
EditMode, | |||
} | |||
/// <summary> | |||
/// API Test Class attribute. | |||
/// Classes without this attribute will be ignored when searching for test cases. | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Class)] | |||
public class APITestClassAttribute : Attribute | |||
{ | |||
internal string Name; | |||
public APITestClassAttribute(string name = "") | |||
{ | |||
this.Name = name; | |||
} | |||
} | |||
/// <summary> | |||
/// API Test Case attribute. | |||
/// Static methods with this attribute will be called when the API test system is running. | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Method)] | |||
public class APITestCaseAttribute : Attribute | |||
{ | |||
internal TestType TestType; | |||
public APITestCaseAttribute(TestType testType) | |||
{ | |||
this.TestType = testType; | |||
} | |||
} | |||
/// <summary> | |||
/// API Test StartUp attribute. | |||
/// Static methods with this attribute will be called before any test case is run by the API test system. | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Method)] | |||
public class APITestStartUpAttribute : Attribute | |||
{ | |||
} | |||
/// <summary> | |||
/// API Test TearDown attribute. | |||
/// Static methods with this attribute will be called after all API test system test cases have completed (failed or succeeded). | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Method)] | |||
public class APITestTearDownAttribute : Attribute | |||
{ | |||
} | |||
} |
@@ -0,0 +1,220 @@ | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.IO; | |||
using System.Runtime.CompilerServices; | |||
using Unity.Mathematics; | |||
namespace GamecraftModdingAPI.Tests | |||
{ | |||
/// <summary> | |||
/// API test system assertion utilities. | |||
/// </summary> | |||
public static class Assert | |||
{ | |||
private static StreamWriter logFile = null; | |||
private static ConcurrentDictionary<string, string> callbacks = new ConcurrentDictionary<string, string>(); | |||
private const string PASS = "SUCCESS: "; | |||
private const string FAIL = "FAILURE: "; | |||
private const string WARN = "WARNING: "; | |||
private const string INFO = "DEBUG: "; | |||
/// <summary> | |||
/// Log a message to the test log. | |||
/// </summary> | |||
/// <param name="msg">Message.</param> | |||
/// <param name="end">Message ending.</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void Log(string msg, string end = "\n") | |||
{ | |||
if (logFile == null) openTestLog(); | |||
logFile.Write(msg + end); | |||
logFile.Flush(); | |||
} | |||
/// <summary> | |||
/// Asserts that the event receives a callback... eventually. | |||
/// Add the eventhandler returned by this method to the relevant event. | |||
/// This does not assert that the callback happens under that event's intended circumstances. | |||
/// Add another event handler to assert specific circumstance requirements. | |||
/// </summary> | |||
/// <returns>The callback event handler.</returns> | |||
/// <param name="eventName">Event name.</param> | |||
/// <param name="eventMsg">Event error message.</param> | |||
/// <typeparam name="T">The event handler callback argument object.</typeparam> | |||
public static EventHandler<T> CallsBack<T>(string eventName, string eventMsg = null) | |||
{ | |||
if (eventMsg == null) eventMsg = $"expected callback to {eventName} but it never occurred..."; | |||
callbacks[eventName] = eventMsg; | |||
return (sender, args) => | |||
{ | |||
string value = null; | |||
if (!callbacks.TryRemove(eventName, out value)) { Log(WARN + $"callback to {eventName} occurred again or a related error occurred... (Received '{args.ToString()}' from '{(sender == null ? (string)sender : sender.ToString())}')"); } | |||
Log(PASS + $"callback to {eventName} occurred... (Received '{args.ToString()}' from '{(sender == null ? (string)sender : sender.ToString())}')"); | |||
TestRoot.TestsPassed = true; | |||
}; | |||
} | |||
public static bool NotNull<T>(T obj, string err = null, string success = null) | |||
{ | |||
if (err == null) err = $"{nameof(T)} object was null."; | |||
if (success == null) success = $"{nameof(T)} '{obj}' not null"; | |||
if (obj == null) | |||
{ | |||
Log(FAIL + err); | |||
TestRoot.TestsPassed = false; | |||
return false; | |||
} | |||
else | |||
{ | |||
Log(PASS + success); | |||
TestRoot.TestsPassed = true; | |||
return true; | |||
} | |||
} | |||
public static bool Equal<T>(T obj1, T obj2, string err = null, string success = null) | |||
{ | |||
if (err == null) err = $"{nameof(T)} '{obj1}' is not equal to '{obj2}'."; | |||
if (success == null) success = $"{nameof(T)} '{obj1}' is equal to '{obj2}'."; | |||
if ((obj1 == null && obj2 == null) | |||
|| (obj1 != null && obj2 != null && obj1.Equals(obj2) && obj2.Equals(obj1))) | |||
{ | |||
// pass | |||
Log(PASS + success); | |||
TestRoot.TestsPassed = true; | |||
return true; | |||
} | |||
else | |||
{ | |||
// fail | |||
Log(FAIL + err); | |||
TestRoot.TestsPassed = false; | |||
return false; | |||
} | |||
} | |||
public static bool Errorless(Action tryThis, string err = null, string success = null) | |||
{ | |||
if (err == null) err = $"{tryThis} raised an exception: "; | |||
if (success == null) success = $"{tryThis} completed without raising an exception."; | |||
try | |||
{ | |||
tryThis(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Log(FAIL + err + e); | |||
TestRoot.TestsPassed = false; | |||
return false; | |||
} | |||
TestRoot.TestsPassed = true; | |||
Log(PASS + success); | |||
return true; | |||
} | |||
public static bool CloseTo(float a, float b, string err = null, string success = null, float delta = float.Epsilon) | |||
{ | |||
if (err == null) err = $"{a} is not within {delta} of {b}."; | |||
if (success == null) success = $"{a} is close enough to {b}."; | |||
if (Math.Abs(a - b) > delta) | |||
{ | |||
Log(FAIL + err); | |||
TestRoot.TestsPassed = false; | |||
return false; | |||
} | |||
else | |||
{ | |||
TestRoot.TestsPassed = true; | |||
Log(PASS + success); | |||
return true; | |||
} | |||
} | |||
public static bool CloseTo(double a, double b, string err = null, string success = null, double delta = double.Epsilon) | |||
{ | |||
if (err == null) err = $"{a} is not within {delta} of {b}."; | |||
if (success == null) success = $"{a} is close enough to {b}."; | |||
if (Math.Abs(a - b) > delta) | |||
{ | |||
Log(FAIL + err); | |||
TestRoot.TestsPassed = false; | |||
return false; | |||
} | |||
else | |||
{ | |||
TestRoot.TestsPassed = true; | |||
Log(PASS + success); | |||
return true; | |||
} | |||
} | |||
public static bool CloseTo(float3 a, float3 b, string err = null, string success = null, float delta = float.Epsilon) | |||
{ | |||
if (err == null) err = $"{a} is not within {delta} of {b} in every direction."; | |||
if (success == null) success = $"{a} is close enough to {b}."; | |||
bool xClose = CloseTo(a.x, b.x, err, success, delta); | |||
bool yClose = CloseTo(a.y, b.y, err, success, delta); | |||
bool zClose = CloseTo(a.z, b.z, err, success, delta); | |||
if (xClose && yClose && zClose) | |||
{ | |||
//TestRoot.TestsPassed = true; | |||
//Log(PASS + success); | |||
return true; | |||
} | |||
else | |||
{ | |||
//Log(FAIL + err); | |||
//TestRoot.TestsPassed = false; | |||
return false; | |||
} | |||
} | |||
public static void Fail(string msg = null) | |||
{ | |||
if (msg == null) msg = $"Manual test failure with no message provided."; | |||
Log(FAIL + msg); | |||
TestRoot.TestsPassed = false; | |||
} | |||
public static void Pass(string msg = null) | |||
{ | |||
if (msg == null) msg = $"Manual test pass with no message provided."; | |||
Log(PASS + msg); | |||
TestRoot.TestsPassed = true; | |||
} | |||
public static void Warn(string msg = null) | |||
{ | |||
if (msg == null) msg = $"Manual test warning with no message provided."; | |||
Log(WARN + msg); | |||
TestRoot.TestsPassed = true; | |||
} | |||
internal static void CallsComplete() | |||
{ | |||
foreach(string key in callbacks.Keys) | |||
{ | |||
Log(FAIL + callbacks[key]); | |||
TestRoot.TestsPassed = false; | |||
} | |||
} | |||
internal static void CloseLog() | |||
{ | |||
if (logFile != null) logFile.Close(); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
private static void openTestLog() | |||
{ | |||
logFile = File.CreateText(TestRoot.ReportFile); | |||
} | |||
} | |||
} |
@@ -25,37 +25,33 @@ using GamecraftModdingAPI.Players; | |||
namespace GamecraftModdingAPI.Tests | |||
{ | |||
#if DEBUG | |||
// unused by design | |||
/// <summary> | |||
/// Modding API implemented as a standalone IPA Plugin. | |||
/// Ideally, GamecraftModdingAPI should be loaded by another mod; not itself | |||
/// </summary> | |||
public class GamecraftModdingAPIPluginTest | |||
#if DEBUG | |||
: IllusionPlugin.IEnhancedPlugin | |||
#endif | |||
public class GamecraftModdingAPIPluginTest : IllusionPlugin.IEnhancedPlugin | |||
{ | |||
private static Harmony harmony { get; set; } | |||
public string[] Filter { get; } = new string[] { "Gamecraft", "GamecraftPreview" }; | |||
public override string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name; | |||
public string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name; | |||
public string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString(); | |||
public override string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString(); | |||
public string HarmonyID { get; } = "org.git.exmods.modtainers.gamecraftmoddingapi"; | |||
public void OnApplicationQuit() | |||
public override void OnApplicationQuit() | |||
{ | |||
GamecraftModdingAPI.Main.Shutdown(); | |||
} | |||
public void OnApplicationStart() | |||
{ | |||
public override void OnApplicationStart() | |||
{ | |||
FileLog.Reset(); | |||
Harmony.DEBUG = true; | |||
GamecraftModdingAPI.Main.Init(); | |||
GamecraftModdingAPI.Main.Init(); | |||
Logging.MetaDebugLog($"Version group id {(uint)ApiExclusiveGroups.versionGroup}"); | |||
// in case Steam is not installed/running | |||
// this will crash the game slightly later during startup | |||
@@ -65,12 +61,13 @@ namespace GamecraftModdingAPI.Tests | |||
// disable some Gamecraft analytics | |||
//AnalyticsDisablerPatch.DisableAnalytics = true; | |||
// disable background music | |||
Logging.MetaDebugLog("Audio Mixers: "+string.Join(",", AudioTools.GetMixers())); | |||
Logging.MetaDebugLog("Audio Mixers: " + string.Join(",", AudioTools.GetMixers())); | |||
//AudioTools.SetVolume(0.0f, "Music"); // The game now sets this from settings again after this is called :( | |||
//Utility.VersionTracking.Enable();//(very) unstable | |||
// debug/test handlers | |||
#pragma warning disable 0612 | |||
HandlerBuilder.Builder() | |||
.Name("appinit API debug") | |||
.Handle(EventType.ApplicationInitialized) | |||
@@ -79,60 +76,68 @@ namespace GamecraftModdingAPI.Tests | |||
HandlerBuilder.Builder("menuact API debug") | |||
.Handle(EventType.Menu) | |||
.OnActivation(() => { Logging.Log("Menu Activated event!"); }) | |||
.OnActivation(() => { Logging.Log("Menu Activated event!"); }) | |||
.OnDestruction(() => { Logging.Log("Menu Destroyed event!"); }) | |||
.Build(); | |||
HandlerBuilder.Builder("menuswitch API debug") | |||
.Handle(EventType.MenuSwitchedTo) | |||
.OnActivation(() => { Logging.Log("Menu Switched To event!"); }) | |||
.Build(); | |||
.Handle(EventType.MenuSwitchedTo) | |||
.OnActivation(() => { Logging.Log("Menu Switched To event!"); }) | |||
.Build(); | |||
HandlerBuilder.Builder("gameact API debug") | |||
.Handle(EventType.Menu) | |||
.OnActivation(() => { Logging.Log("Game Activated event!"); }) | |||
.OnDestruction(() => { Logging.Log("Game Destroyed event!"); }) | |||
.Build(); | |||
.Handle(EventType.Menu) | |||
.OnActivation(() => { Logging.Log("Game Activated event!"); }) | |||
.OnDestruction(() => { Logging.Log("Game Destroyed event!"); }) | |||
.Build(); | |||
HandlerBuilder.Builder("gamerel API debug") | |||
.Handle(EventType.GameReloaded) | |||
.OnActivation(() => { Logging.Log("Game Reloaded event!"); }) | |||
.Build(); | |||
.Handle(EventType.GameReloaded) | |||
.OnActivation(() => { Logging.Log("Game Reloaded event!"); }) | |||
.Build(); | |||
HandlerBuilder.Builder("gameswitch API debug") | |||
.Handle(EventType.GameSwitchedTo) | |||
.OnActivation(() => { Logging.Log("Game Switched To event!"); }) | |||
.Build(); | |||
.Handle(EventType.GameSwitchedTo) | |||
.OnActivation(() => { Logging.Log("Game Switched To event!"); }) | |||
.Build(); | |||
HandlerBuilder.Builder("simulationswitch API debug") | |||
.Handle(EventType.SimulationSwitchedTo) | |||
.OnActivation(() => { Logging.Log("Game Mode Simulation Switched To event!"); }) | |||
.Build(); | |||
.Handle(EventType.SimulationSwitchedTo) | |||
.OnActivation(() => { Logging.Log("Game Mode Simulation Switched To event!"); }) | |||
.Build(); | |||
HandlerBuilder.Builder("buildswitch API debug") | |||
.Handle(EventType.BuildSwitchedTo) | |||
.OnActivation(() => { Logging.Log("Game Mode Build Switched To event!"); }) | |||
.Build(); | |||
.Handle(EventType.BuildSwitchedTo) | |||
.OnActivation(() => { Logging.Log("Game Mode Build Switched To event!"); }) | |||
.Build(); | |||
HandlerBuilder.Builder("menu activated API error thrower test") | |||
.Handle(EventType.Menu) | |||
.OnActivation(() => { throw new Exception("Event Handler always throws an exception!"); }) | |||
.Build(); | |||
#pragma warning restore 0612 | |||
/*HandlerBuilder.Builder("enter game from menu test") | |||
.Handle(EventType.Menu) | |||
.OnActivation(() => | |||
{ | |||
Tasks.Scheduler.Schedule(new Tasks.Repeatable(enterGame, shouldRetry, 0.2f)); | |||
}) | |||
.Build();*/ | |||
// debug/test commands | |||
// debug/test commands | |||
if (Dependency.Hell("ExtraCommands")) | |||
{ | |||
CommandBuilder.Builder() | |||
.Name("Exit") | |||
.Description("Close Gamecraft immediately, without any prompts") | |||
.Action(() => { UnityEngine.Application.Quit(); }) | |||
.Build(); | |||
.Name("Exit") | |||
.Description("Close Gamecraft immediately, without any prompts") | |||
.Action(() => { UnityEngine.Application.Quit(); }) | |||
.Build(); | |||
CommandBuilder.Builder() | |||
.Name("SetFOV") | |||
.Description("Set the player camera's field of view") | |||
.Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; }) | |||
.Build(); | |||
.Name("SetFOV") | |||
.Description("Set the player camera's field of view") | |||
.Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; }) | |||
.Build(); | |||
CommandBuilder.Builder() | |||
.Name("MoveLastBlock") | |||
@@ -147,14 +152,14 @@ namespace GamecraftModdingAPI.Tests | |||
}).Build(); | |||
CommandBuilder.Builder() | |||
.Name("PlaceAluminium") | |||
.Description("Place a block of aluminium at the given coordinates") | |||
.Action((float x, float y, float z) => | |||
{ | |||
var block = Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x, y, z)); | |||
Logging.CommandLog("Block placed with type: " + block.Type); | |||
}) | |||
.Build(); | |||
.Name("PlaceAluminium") | |||
.Description("Place a block of aluminium at the given coordinates") | |||
.Action((float x, float y, float z) => | |||
{ | |||
var block = Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x, y, z)); | |||
Logging.CommandLog("Block placed with type: " + block.Type); | |||
}) | |||
.Build(); | |||
CommandBuilder.Builder() | |||
.Name("PlaceAluminiumLots") | |||
@@ -164,8 +169,8 @@ namespace GamecraftModdingAPI.Tests | |||
Logging.CommandLog("Starting..."); | |||
var sw = Stopwatch.StartNew(); | |||
for (int i = 0; i < 100; i++) | |||
for (int j = 0; j < 100; j++) | |||
Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x + i, y, z + j)); | |||
for (int j = 0; j < 100; j++) | |||
Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x + i, y, z + j)); | |||
//Block.Sync(); | |||
sw.Stop(); | |||
Logging.CommandLog("Finished in " + sw.ElapsedMilliseconds + "ms"); | |||
@@ -174,10 +179,10 @@ namespace GamecraftModdingAPI.Tests | |||
//With Sync(): 1135ms | |||
//Without Sync(): 134ms | |||
//Async: 348 794ms, doesn't freeze game | |||
//Without Sync() but wait for submission: 530ms | |||
//With Sync() at the end: 380ms | |||
//Without Sync() but wait for submission: 530ms | |||
//With Sync() at the end: 380ms | |||
Block b = null; | |||
Block b = null; | |||
CommandBuilder.Builder("moveBlockInSim", "Run in build mode first while looking at a block, then in sim to move it up") | |||
.Action(() => | |||
{ | |||
@@ -207,7 +212,7 @@ namespace GamecraftModdingAPI.Tests | |||
return; | |||
} | |||
new Player(PlayerType.Local).GetBlockLookedAt().Color = | |||
new BlockColor {Color = color}; | |||
new BlockColor { Color = color }; | |||
Logging.CommandLog("Colored block to " + color); | |||
}).Build(); | |||
@@ -227,13 +232,58 @@ namespace GamecraftModdingAPI.Tests | |||
} | |||
}).Build(); | |||
CommandBuilder.Builder() | |||
.Name("PlaceConsole") | |||
.Description("Place a bunch of console block with a given text - entering simulation with them crashes the game as the cmd doesn't exist") | |||
.Action((float x, float y, float z) => | |||
{ | |||
Stopwatch sw = new Stopwatch(); | |||
sw.Start(); | |||
for (int i = 0; i < 100; i++) | |||
{ | |||
for (int j = 0; j < 100; j++) | |||
{ | |||
var block = Block.PlaceNew<ConsoleBlock>(BlockIDs.ConsoleBlock, | |||
new float3(x + i, y, z + j)); | |||
block.Command = "test_command"; | |||
} | |||
} | |||
sw.Stop(); | |||
Logging.CommandLog($"Blocks placed in {sw.ElapsedMilliseconds} ms"); | |||
}) | |||
.Build(); | |||
CommandBuilder.Builder() | |||
.Name("WireTest") | |||
.Description("Place two blocks and then wire them together") | |||
.Action(() => | |||
{ | |||
LogicGate notBlock = Block.PlaceNew<LogicGate>(BlockIDs.NOTLogicBlock, new float3(1, 2, 0)); | |||
LogicGate andBlock = Block.PlaceNew<LogicGate>(BlockIDs.ANDLogicBlock, new float3(2, 2, 0)); | |||
// connect NOT Gate output to AND Gate input #2 (ports are zero-indexed, so 1 is 2nd position and 0 is 1st position) | |||
Wire conn = notBlock.Connect(0, andBlock, 1); | |||
Logging.CommandLog(conn.ToString()); | |||
}) | |||
.Build(); | |||
CommandBuilder.Builder("TestChunkHealth", "Sets the chunk looked at to the given health.") | |||
.Action((float val, float max) => | |||
{ | |||
var body = new Player(PlayerType.Local).GetSimBodyLookedAt(); | |||
if (body == null) return; | |||
body.CurrentHealth = val; | |||
body.InitialHealth = max; | |||
Logging.CommandLog("Health set to: " + val); | |||
}).Build(); | |||
GameClient.SetDebugInfo("InstalledMods", InstalledMods); | |||
Block.Placed += (sender, args) => | |||
Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID); | |||
Block.Removed += (sender, args) => | |||
Logging.MetaDebugLog("Removed block " + args.Type + " with ID " + args.ID); | |||
/* | |||
/* | |||
CommandManager.AddCommand(new SimpleCustomCommandEngine<float>((float d) => { UnityEngine.Camera.main.fieldOfView = d; }, | |||
"SetFOV", "Set the player camera's field of view")); | |||
CommandManager.AddCommand(new SimpleCustomCommandEngine<float, float, float>( | |||
@@ -277,8 +327,8 @@ namespace GamecraftModdingAPI.Tests | |||
*/ | |||
} | |||
// dependency test | |||
if (Dependency.Hell("GamecraftScripting", new Version("0.0.1.0"))) | |||
// dependency test | |||
if (Dependency.Hell("GamecraftScripting", new Version("0.0.1.0"))) | |||
{ | |||
Logging.LogWarning("You're in GamecraftScripting dependency hell"); | |||
} | |||
@@ -302,7 +352,11 @@ namespace GamecraftModdingAPI.Tests | |||
o1.Merge(o2, new JsonMergeSettings {MergeArrayHandling = MergeArrayHandling.Union}); | |||
File.WriteAllText(@"Gamecraft_Data\StreamingAssets\aa\Windows\catalog.json", o1.ToString());*/ | |||
CustomBlock.Prep().RunOn(ExtraLean.UIScheduler); | |||
} | |||
#if TEST | |||
TestRoot.RunTests(); | |||
#endif | |||
} | |||
private string modsString; | |||
private string InstalledMods() | |||
@@ -314,15 +368,39 @@ namespace GamecraftModdingAPI.Tests | |||
return modsString = sb.ToString(); | |||
} | |||
public void OnFixedUpdate() { } | |||
private bool retry = true; | |||
public void OnLateUpdate() { } | |||
private bool shouldRetry() | |||
{ | |||
return retry; | |||
} | |||
public void OnLevelWasInitialized(int level) { } | |||
public void OnLevelWasLoaded(int level) { } | |||
public void OnUpdate() { } | |||
private void enterGame() | |||
{ | |||
App.Client app = new App.Client(); | |||
App.Game[] myGames = app.MyGames; | |||
Logging.MetaDebugLog($"MyGames count {myGames.Length}"); | |||
if (myGames.Length != 0) | |||
{ | |||
Logging.MetaDebugLog($"MyGames[0] EGID {myGames[0].EGID}"); | |||
retry = false; | |||
try | |||
{ | |||
//myGames[0].Description = "test msg pls ignore"; // make sure game exists first | |||
Logging.MetaDebugLog($"Entering game {myGames[0].Name}"); | |||
myGames[0].EnterGame(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.MetaDebugLog($"Failed to enter game; exception: {e}"); | |||
retry = true; | |||
} | |||
} | |||
else | |||
{ | |||
Logging.MetaDebugLog("MyGames not populated yet :("); | |||
} | |||
} | |||
[HarmonyPatch] | |||
public class MinimumSpecsPatch | |||
@@ -338,4 +416,5 @@ namespace GamecraftModdingAPI.Tests | |||
} | |||
} | |||
} | |||
#endif | |||
} |
@@ -0,0 +1,295 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.Reflection; | |||
using System.Linq; // welcome to the dark side | |||
using Svelto.Tasks; | |||
using Svelto.Tasks.Lean; | |||
using Svelto.Tasks.Enumerators; | |||
using UnityEngine; | |||
using GamecraftModdingAPI.App; | |||
using GamecraftModdingAPI.Tasks; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Tests | |||
{ | |||
/// <summary> | |||
/// API test system root class. | |||
/// </summary> | |||
public static class TestRoot | |||
{ | |||
public static bool AutoShutdown = true; | |||
public const string ReportFile = "GamecraftModdingAPI_tests.log"; | |||
private static bool _testsPassed = false; | |||
private static uint _testsCount = 0; | |||
private static uint _testsCountPassed = 0; | |||
private static uint _testsCountFailed = 0; | |||
private static string state = "StartingUp"; | |||
private static Stopwatch timer; | |||
private static List<Type> testTypes = null; | |||
public static bool TestsPassed | |||
{ | |||
get => _testsPassed; | |||
set | |||
{ | |||
_testsPassed = _testsPassed && value; | |||
_testsCount++; | |||
if (value) | |||
{ | |||
_testsCountPassed++; | |||
} | |||
else | |||
{ | |||
_testsCountFailed++; | |||
} | |||
} | |||
} | |||
private static void StartUp() | |||
{ | |||
// init | |||
timer = Stopwatch.StartNew(); | |||
_testsPassed = true; | |||
_testsCount = 0; | |||
_testsCountPassed = 0; | |||
_testsCountFailed = 0; | |||
// flow control | |||
Game.Enter += (sender, args) => { GameTests().RunOn(RobocraftX.Schedulers.Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING); }; | |||
Game.Exit += (s, a) => state = "ReturningFromGame"; | |||
Client.EnterMenu += (sender, args) => | |||
{ | |||
if (state == "EnteringMenu") | |||
{ | |||
MenuTests().RunOn(Scheduler.leanRunner); | |||
state = "EnteringGame"; | |||
} | |||
if (state == "ReturningFromGame") | |||
{ | |||
TearDown().RunOn(Scheduler.leanRunner); | |||
state = "ShuttingDown"; | |||
} | |||
}; | |||
// init tests here | |||
foreach (Type t in testTypes) | |||
{ | |||
foreach (MethodBase m in t.GetMethods()) | |||
{ | |||
if (m.GetCustomAttribute<APITestStartUpAttribute>() != null) | |||
{ | |||
try | |||
{ | |||
m.Invoke(null, new object[0]); | |||
} | |||
catch (Exception e) | |||
{ | |||
Assert.Fail($"Start up method '{m}' raised an exception: {e.ToString()}"); | |||
} | |||
} | |||
} | |||
} | |||
state = "EnteringMenu"; | |||
} | |||
private static IEnumerator<TaskContract> MenuTests() | |||
{ | |||
yield return Yield.It; | |||
// menu tests | |||
foreach (Type t in testTypes) | |||
{ | |||
foreach (MethodBase m in t.GetMethods()) | |||
{ | |||
APITestCaseAttribute a = m.GetCustomAttribute<APITestCaseAttribute>(); | |||
if (a != null && a.TestType == TestType.Menu) | |||
{ | |||
try | |||
{ | |||
m.Invoke(null, new object[0]); | |||
} | |||
catch (Exception e) | |||
{ | |||
Assert.Fail($"Menu test '{m}' raised an exception: {e.ToString()}"); | |||
} | |||
yield return Yield.It; | |||
} | |||
} | |||
} | |||
// load game | |||
yield return GoToGameTests().Continue(); | |||
} | |||
private static IEnumerator<TaskContract> GoToGameTests() | |||
{ | |||
Client app = new Client(); | |||
int oldLength = 0; | |||
while (app.MyGames.Length == 0 || oldLength != app.MyGames.Length) | |||
{ | |||
oldLength = app.MyGames.Length; | |||
yield return new WaitForSecondsEnumerator(1).Continue(); | |||
} | |||
yield return Yield.It; | |||
app.MyGames[0].EnterGame(); | |||
/*Game newGame = Game.NewGame(); | |||
yield return new WaitForSecondsEnumerator(5).Continue(); // wait for sync | |||
newGame.EnterGame();*/ | |||
} | |||
private static IEnumerator<TaskContract> GameTests() | |||
{ | |||
yield return Yield.It; | |||
Game currentGame = Game.CurrentGame(); | |||
// in-game tests | |||
yield return new WaitForSecondsEnumerator(5).Continue(); // wait for game to finish loading | |||
foreach (Type t in testTypes) | |||
{ | |||
foreach (MethodBase m in t.GetMethods()) | |||
{ | |||
APITestCaseAttribute a = m.GetCustomAttribute<APITestCaseAttribute>(); | |||
if (a != null && a.TestType == TestType.Game) | |||
{ | |||
try | |||
{ | |||
m.Invoke(null, new object[0]); | |||
} | |||
catch (Exception e) | |||
{ | |||
Assert.Fail($"Game test '{m}' raised an exception: {e.ToString()}"); | |||
} | |||
yield return Yield.It; | |||
} | |||
} | |||
} | |||
currentGame.ToggleTimeMode(); | |||
yield return new WaitForSecondsEnumerator(5).Continue(); | |||
// simulation tests | |||
foreach (Type t in testTypes) | |||
{ | |||
foreach (MethodBase m in t.GetMethods()) | |||
{ | |||
APITestCaseAttribute a = m.GetCustomAttribute<APITestCaseAttribute>(); | |||
if (a != null && a.TestType == TestType.SimulationMode) | |||
{ | |||
try | |||
{ | |||
m.Invoke(null, new object[0]); | |||
} | |||
catch (Exception e) | |||
{ | |||
Assert.Fail($"Simulation test '{m}' raised an exception: {e.ToString()}"); | |||
} | |||
yield return Yield.It; | |||
} | |||
} | |||
} | |||
currentGame.ToggleTimeMode(); | |||
yield return new WaitForSecondsEnumerator(5).Continue(); | |||
// build tests | |||
foreach (Type t in testTypes) | |||
{ | |||
foreach (MethodBase m in t.GetMethods()) | |||
{ | |||
APITestCaseAttribute a = m.GetCustomAttribute<APITestCaseAttribute>(); | |||
if (a != null && a.TestType == TestType.EditMode) | |||
{ | |||
try | |||
{ | |||
m.Invoke(null, new object[0]); | |||
} | |||
catch (Exception e) | |||
{ | |||
Assert.Fail($"Build test '{m}' raised an exception: {e.ToString()}"); | |||
} | |||
yield return Yield.It; | |||
} | |||
} | |||
} | |||
// exit game | |||
yield return new WaitForSecondsEnumerator(5).Continue(); | |||
yield return ReturnToMenu().Continue(); | |||
} | |||
private static IEnumerator<TaskContract> ReturnToMenu() | |||
{ | |||
Logging.MetaLog("Returning to main menu"); | |||
yield return Yield.It; | |||
Game.CurrentGame().ExitGame(); | |||
} | |||
private static IEnumerator<TaskContract> TearDown() | |||
{ | |||
yield return new WaitForSecondsEnumerator(5).Continue(); | |||
Logging.MetaLog("Tearing down test run"); | |||
// dispose tests here | |||
foreach (Type t in testTypes) | |||
{ | |||
foreach (MethodBase m in t.GetMethods()) | |||
{ | |||
if (m.GetCustomAttribute<APITestTearDownAttribute>() != null) | |||
{ | |||
try | |||
{ | |||
m.Invoke(null, new object[0]); | |||
} | |||
catch (Exception e) | |||
{ | |||
Assert.Warn($"Tear down method '{m}' raised an exception: {e.ToString()}"); | |||
} | |||
yield return Yield.It; | |||
} | |||
} | |||
} | |||
// finish up | |||
Assert.CallsComplete(); | |||
timer.Stop(); | |||
string verdict = _testsPassed ? "--- PASSED :) ---" : "--- FAILED :( ---"; | |||
Assert.Log($"VERDICT: {verdict} ({_testsCountPassed}/{_testsCountFailed}/{_testsCount} P/F/T in {timer.ElapsedMilliseconds}ms)"); | |||
yield return Yield.It; | |||
// end game | |||
Logging.MetaLog("Completed test run: " + verdict); | |||
yield return Yield.It; | |||
Assert.CloseLog(); | |||
if (AutoShutdown) Application.Quit(); | |||
} | |||
private static void FindTests(Assembly asm) | |||
{ | |||
testTypes = new List<Type>(); | |||
foreach (Type t in asm.GetTypes()) | |||
{ | |||
if (t.GetCustomAttribute<APITestClassAttribute>() != null) | |||
{ | |||
testTypes.Add(t); | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// Runs the tests. | |||
/// </summary> | |||
/// <param name="asm">Assembly to search for tests. When set to null, this uses the GamecraftModdingAPI assembly. </param> | |||
public static void RunTests(Assembly asm = null) | |||
{ | |||
if (asm == null) asm = Assembly.GetExecutingAssembly(); | |||
FindTests(asm); | |||
Logging.MetaLog("Starting test run"); | |||
// log metadata | |||
Assert.Log($"Unity {Application.unityVersion}"); | |||
Assert.Log($"Gamecraft {Application.version}"); | |||
Assert.Log($"GamecraftModdingAPI {Assembly.GetExecutingAssembly().GetName().Version}"); | |||
Assert.Log($"Testing {asm.GetName().Name} {asm.GetName().Version}"); | |||
Assert.Log($"START: --- {DateTime.Now.ToString()} --- ({testTypes.Count} tests classes detected)"); | |||
StartUp(); | |||
Logging.MetaLog("Test StartUp complete"); | |||
} | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
using System; | |||
using System.Reflection; | |||
using HarmonyLib; | |||
namespace GamecraftModdingAPI.Tests | |||
{ | |||
#if TEST | |||
/// <summary> | |||
/// Test test test. | |||
/// </summary> | |||
[APITestClass] | |||
public static class TestTest | |||
{ | |||
public static event EventHandler<TestEventArgs> StartUp; | |||
public static event EventHandler<TestEventArgs> Test; | |||
public static event EventHandler<TestEventArgs> TearDown; | |||
[APITestStartUp] | |||
public static void Init() | |||
{ | |||
StartUp += Assert.CallsBack<TestEventArgs>("TestStartUp"); | |||
Test += Assert.CallsBack<TestEventArgs>("TestCase"); | |||
TearDown += Assert.CallsBack<TestEventArgs>("TestTearDown"); | |||
StartUp(null, default(TestEventArgs)); | |||
} | |||
[APITestCase(TestType.Menu)] | |||
public static void RunTest() | |||
{ | |||
Test(null, default(TestEventArgs)); | |||
} | |||
[APITestTearDown] | |||
public static void End() | |||
{ | |||
TearDown(null, default(TestEventArgs)); | |||
} | |||
} | |||
public struct TestEventArgs | |||
{ | |||
public override string ToString() | |||
{ | |||
return "TestEventArgs{}"; | |||
} | |||
} | |||
#endif | |||
} |
@@ -3,6 +3,7 @@ using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Reflection; | |||
using System.Reflection.Emit; | |||
using System.Text; | |||
using System.Text.Formatting; | |||
using GamecraftModdingAPI.Blocks; | |||
using GamecraftModdingAPI.Engines; | |||
@@ -46,9 +47,9 @@ namespace GamecraftModdingAPI.Utility | |||
var array = new CodeInstruction[] | |||
{ | |||
new CodeInstruction(OpCodes.Ldloc_0), //StringBuffer | |||
new CodeInstruction(OpCodes.Call, ((Action<StringBuffer>)AddInfo).Method) | |||
new CodeInstruction(OpCodes.Call, ((Action<StringBuilder>)AddInfo).Method) | |||
}; | |||
list.InsertRange(index, array); | |||
list.InsertRange(index - 1, array); //-1: ldloc.1 ("local") before ldfld | |||
} | |||
catch (Exception e) | |||
{ | |||
@@ -58,13 +59,15 @@ namespace GamecraftModdingAPI.Utility | |||
return list; | |||
} | |||
public static void AddInfo(StringBuffer sb) | |||
public static void AddInfo(StringBuilder sb) | |||
{ | |||
foreach (var info in _extraInfo) | |||
{ | |||
try | |||
{ | |||
sb.Append(info.Value() + "\n"); | |||
string text = info.Value().Trim(); | |||
if (text.Length != 0) | |||
sb.Append(text + "\n"); | |||
} | |||
catch (Exception e) | |||
{ | |||
@@ -1,25 +0,0 @@ | |||
using System; | |||
using RobocraftX.StateSync; | |||
using Svelto.ECS; | |||
using HarmonyLib; | |||
namespace GamecraftModdingAPI.Utility | |||
{ | |||
[HarmonyPatch(typeof(DeterministicStepCompositionRoot), "ResetWorld")] | |||
public static class DeterministicStepCompositionRootPatch | |||
{ | |||
private static SimpleEntitiesSubmissionScheduler engineRootScheduler; | |||
public static void Postfix(SimpleEntitiesSubmissionScheduler scheduler) | |||
{ | |||
engineRootScheduler = scheduler; | |||
} | |||
internal static void SubmitEntitiesNow() | |||
{ | |||
if (engineRootScheduler != null) | |||
engineRootScheduler.SubmitEntities(); | |||
} | |||
} | |||
} |
@@ -25,8 +25,15 @@ namespace GamecraftModdingAPI.Utility | |||
/// </summary> | |||
public static class FullGameFields | |||
{ | |||
public static FullGameCompositionRoot Instance | |||
{ | |||
private set; | |||
get; | |||
} = null; | |||
public static MultiplayerInitParameters _multiplayerParams | |||
{ get | |||
{ | |||
get | |||
{ | |||
return (MultiplayerInitParameters)fgcr?.Field("_multiplayerParams").GetValue(); | |||
} | |||
@@ -157,6 +164,7 @@ namespace GamecraftModdingAPI.Utility | |||
public static void Init(FullGameCompositionRoot instance) | |||
{ | |||
fgcr = new Traverse(instance); | |||
FullGameFields.Instance = instance; | |||
} | |||
} | |||
} |
@@ -14,6 +14,7 @@ namespace GamecraftModdingAPI.Utility | |||
/// Tracks the API version the current game was built for. | |||
/// For compatibility reasons, this must be enabled before it will work. | |||
/// </summary> | |||
[Obsolete] | |||
public static class VersionTracking | |||
{ | |||
private static readonly VersionTrackingEngine versionEngine = new VersionTrackingEngine(); | |||
@@ -58,6 +59,7 @@ namespace GamecraftModdingAPI.Utility | |||
} | |||
[Obsolete] | |||
internal class VersionTrackingEngine : IEventEmitterEngine | |||
{ | |||
public string Name { get; } = "GamecraftModdingAPIVersionTrackingGameEngine"; | |||
@@ -94,11 +96,13 @@ namespace GamecraftModdingAPI.Utility | |||
public void Emit() { } | |||
} | |||
[Obsolete] | |||
public struct ModVersionStruct : IEntityComponent | |||
{ | |||
public uint version; | |||
} | |||
[Obsolete] | |||
public class ModVersionDescriptor: SerializableEntityDescriptor<ModVersionDescriptor._ModVersionDescriptor> | |||
{ | |||
[HashName("GamecraftModdingAPIVersionV0")] | |||
@@ -10,10 +10,16 @@ This means your code won't break when the GamecraftModdingAPI or Gamecraft updat | |||
For more info, please check out the [official documentation](https://mod.exmods.org). | |||
For more support, join the ExMods [Discord](https://discord.gg/xjnFxQV). | |||
For more support, join the ExMods [Discord](https://discord.exmods.org). | |||
## Installation | |||
[Please follow the official mod installation guide](https://www.exmods.org/guides/install.html) | |||
[Please follow the official mod installation guide](https://www.exmods.org/guides/install.html) or use GCMM. | |||
## Development | |||
To get started, create a symbolic link called `ref` in the root of the project, or one folder higher, linking to the Gamecraft install folder. | |||
This will allow your IDE to resolve references to Gamecraft files for building and IDE tools. | |||
GamecraftModdingAPI version numbers follow the [Semantic Versioning guidelines](https://semver.org/). | |||
## External Libraries | |||
GamecraftModdingAPI includes [Harmony](https://github.com/pardeike/Harmony) to modify the behaviour of existing Gamecraft code. | |||
@@ -21,4 +27,5 @@ GamecraftModdingAPI includes [Harmony](https://github.com/pardeike/Harmony) to m | |||
# Disclaimer | |||
This API is an unofficial modification of Gamecraft software, and is not endorsed or supported by FreeJam or Gamecraft. | |||
The GamecraftModdingAPI developer(s) claim no rights on the Gamecraft code referenced within this project. | |||
All code contained in this project is licensed under the [GNU Public License v3](https://git.exmods.org/modtainers/GamecraftModdingAPI/src/branch/master/LICENSE). | |||
@@ -38,7 +38,7 @@ PROJECT_NAME = "GamecraftModdingAPI" | |||
# could be handy for archiving the generated documentation or if some version | |||
# control system is used. | |||
PROJECT_NUMBER = "v1.2.0" | |||
PROJECT_NUMBER = "v1.5.0" | |||
# Using the PROJECT_BRIEF tag one can provide an optional one line description | |||
# for a project that appears at the top of each page and should give viewer a | |||